Iteration Cadences: implementation approach and architecture solution validation
DB table iterations_cadences
This table/model will act as a configuration for iterations as well as an iterations container(set). This will help us restrict iterations date overlapping within the cadence container.
| column | type | notes |
|---|---|---|
| id | integer | |
| title | string | title for the cadence and the iterations that are going to be generated as part of this cadence. |
| group_id | integer | The group for which this iteration cadence was defined |
| duration | integer | Duration of an iteration in days, i.e. cadence |
| is_active | boolean | Determines if given iteration cadence is active. We need to be able to de-activate a cadence at the level where it is defined, which should propagate how it is inherited down the hierarchy. |
| automatic | boolean | Determines if iteration are generated automatically for this cadence or need to be created manually. This has poped up in some customer discussion where some customers manage the iterations manually. |
| start_date | datetime | the date/time when iterations with this cadence should start |
| next_run_date | datetime | the date time when next set of iterations should be created |
| iterations_in_advance | integer | how many iterations in advance should we create. We can skip this column for now and just use a constant hardcoded in the code, so this is not configurable |
| created_at | datetime | |
| updated_at | datetime |
DB table group_inherited_cadences
| column | type | notes |
|---|---|---|
| id | integer | |
| group_id | integer | The id of the group that inherits given iteration. We'll need to do permission check that specific cadence can be inherited. |
| inherited_from_group_id | integer | The group from which this iteration cadence is inherited. It can be a group where the cadence was created or group that respectively inherited it. When inheritance is removed at one level all sub-groups & sub-projects would lose the inheritance as well |
| iteration_cadence_id | integer | The id of the cadence being inherited |
| is_active | boolean | Determines if given inherited iteration cadence is active. When a group opts to inherit iterations from another group, it inherits all the iterations, but may opt to set some to disable if it only needs to use a subset of the iterations defined in the original group. Or parent group may opt to enforce an iteration to be used or not |
| state_toggled_by_group_id | boolean | The id of the group that toggled the cadence state. This should offer the ability to determine if the status of the iteration was enforced from a top group or was it disabled by inheriting group |
| created_at | datetime | |
| updated_at | datetime |
Link iterations to iterations_cadences
- add
iteration_cadence_idtosprintstable - have a migration to create a
iterations_cadencesrecord for each group that has at least one iteration and link group's iterations to newly created cadence.
Update projects table
- add
inherit_cadence_from_group_idto denote from which group project inherits iteration cadences. If a project needs to inherit cadences form multiple groups it will need to inherit from a group that on its turn inherits cadences from which the project needs to inherit from. have a migration that goes through all projects within groups hierarchies that have at least one iteration and update it to inherit iterations from its first ancestor that has iteration cadence defined.- add a migration that would fetch distinct projects that use iterations and find its first ancestor group that defines iteration cadence introduced at the previous steps. Use that ancestor group to aggregates cadences from all groups ancestors that have cadences through
group_inherited_cadences. Updateproject#inherit_cadence_from_group_idto the group that aggregates all cadences.
Fetch iterations on Issues > Iterations Page
I think on iterations page we will have 3 collections of iteration cadences: Active(Open), Inactive(Closed), ALL somewhat similar to current iteration page but for cadences. Each cadence would show a collection of its respective closed and open iterations.
- Pseudo queries
-
fetch active cadences:
SELECT * FROM iterations_cadences INNER JOIN inherited_cadences ON iterations_cadences.id = inherited_cadences.iteration_cadence_id WHERE inherited_cadences.is_active = true AND inherited_cadences.group_id = <project.inherit_cadence_from_group_id> -
fetch open iterations for given cadence:
SELECT * FROM sprints INNER JOIN iterations_cadences ON iterations_cadences.id = sprints.iteration_cadence_id INNER JOIN inherited_cadences ON iterations_cadences.id = inherited_cadences.iteration_cadence_id WHERE inherited_cadences.is_active = true AND iterations_cadences.id = <given_cadence> AND inherited_cadences.group_id = <project.inherit_cadence_from_group_id> -
<project.inherit_cadence_from_group_id> - is a value passed from current project.
-
<given_cadence> - cadence for which to fetch iterations
-
For iteration dropdowns on issue page and in filter bars(issue list and board) we will need to have a limit of iteration cadences and iteration that we can load in one request or have a 2 step way to select the iteration by first selecting the cadence and then select the iteration within that cadence, maybe an accordion style dropdown. Another option perhaps is to limit the number of cadences that can be inherited initially, eg. 5 as well as number of iterations past and in front of
current iterations, e.g. 5 + 5, resulting in a max number of 5 cadences * 10 iterations each => 50
-
Known limitations
Given the bellow flow requirement
graph TD
Group_A --> Subgroup_B --> Project
Group_X --> Iteration_Cadence3
Subgroup_B --> Iteration_Cadence2
Group_A --> Iteration_Cadence1
Project --> IssueA
Project --> IssueB
Project --> IssueC
Group_X .->|Group Share|Project
IssueA .-> Iteration_Cadence3
IssueB .-> Iteration_Cadence2
IssueC .-> Iteration_Cadence1
The proposed DB tables structure would not allow Project to inherit cadences from GroupX. To allow that we would need to add project_inherited_cadences simply because currently we allow group sharing at project level only. Or we need to add group sharing to group level, at which point we can aggregate all cadences in a single group(e.g GroupX) by sharing GroupA, GroupB with GroupX, let GroupX inherit cadences from GroupA and GroupB and use GroupX as the inherit_cadence_from_group_id value for projects.
So we would have a flow more like:
graph TD
Group_A --> Subgroup_B --> Project
Group_A --> Iteration_Cadence1
Subgroup_B --> Iteration_Cadence2
Project --> IssueA
Project --> IssueB
Project --> IssueC
IssueA .-> Iteration_Cadence3
IssueB .-> Iteration_Cadence2
IssueC .-> Iteration_Cadence1
Group_X --> Iteration_Cadence3
Group_X .->|Group Share|Project
Group_X .->|Group Share|Group_A
Group_X .->|Group Share|Subgroup_B
Group_X .->|inherited_from_group_id=Subgroup_B|Iteration_Cadence2
Group_X .->|inherited_from_group_id=Group_A|Iteration_Cadence1
Group_X .->|inherit_cadence_from_group_id=GroupX|Project
Context
There is much more context on the feature request and product aspect of this in the Epic &5077