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_id to sprints table
  • have a migration to create a iterations_cadences record 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_id to 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. Update project#inherit_cadence_from_group_id to 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

Edited by Alexandru Croitor