Projects, Cycles & Milestones

Projects, sprints (cycles), and milestone progress rollups in the Operation plugin.

Backend code lives under backend/plugins/operation_api/src/modules/{project,cycle,milestone}/.

Data models

  • operation_projects (model): { name, description, status: Int, priority: Int, icon, teamIds: [ObjectId] (required), tagIds, startDate, targetDate, leadId, memberIds, createdBy, convertedFromId }. convertedFromId links a project back to the task it was converted from; creating a second project from the same task fails with "Project has been converted already."
  • operation_cycles: { name, description, startDate, endDate, teamId, isCompleted, isActive, statistics, donePercent, unFinishedTasks: [ObjectId], number }.
  • operation_milestones: { name, description, targetDate, projectId (required), createdBy }.

Queries and mutations

Projects

OperationKindPermission
getProject(_id) / getProjects(filter: IProjectFilter)queryprojectRead
getProjectProgress / getProjectProgressByMember / getProjectProgressByTeam / getProjectProgressChart (_id)queryprojectRead
getConvertedProject(convertedFromId)queryprojectRead
cpGetProjectsqueryforClientPortal + cpUserRequired; Client Portal users only
createProject / updateProject / removeProject(_id)mutationprojectCreate / projectUpdate / projectRemove

IProjectFilter accepts _ids, name, status, priority, teamIds, tagIds, leadId, memberIds/memberId, userId, active, taskId, date bounds, and cursor params.

Cycles

OperationKindPermission
getCycle(_id) / getCycles(teamId, …) / getCyclesActive(teamId, taskId, …)querycycleRead
getCycleProgress / getCycleProgressChart / getCycleProgressByMember / getCycleProgressByProject (_id, assigneeId?)querycycleRead
createCycle(input: CycleInput) / updateCycle(input) / removeCycle(_id)mutationcycleCreate / cycleUpdate / cycleRemove
endCycle(_id)mutationcycleEnd

Milestones

OperationKindPermission
getMilestone(_id) / milestones(projectId, searchValue, …)querymilestoneRead
milestoneProgress(projectId)querymilestoneRead; per-milestone totalScope, totalStartedScope, totalCompletedScope
createMilestone / updateMilestone / removeMilestonemutationmilestoneCreate / milestoneUpdate / milestoneRemove

Cycle lifecycle

Cycles are per-team sprints with date boundaries:

  • createCycle/updateCycle reject date ranges that overlap another cycle of the same team ("New cycle overlaps with an existing cycle"), and a completed cycle cannot be updated.
  • startCycle activates a cycle only when no other cycle of that team is active.
  • endCycle snapshots statistics (chart data + progress by member and project), marks the cycle completed, and activates the team's next uncompleted cycle (or auto-creates one with the same duration: Cycle <date>, number + 1). Unfinished tasks move into it via Task.moveCycle and their ids are recorded in unFinishedTasks (Cycle model).
  • The operations-daily-cycles-check BullMQ scheduler (hourly 0 * * * * UTC) runs checkCycle per tenant at midnight in the tenant's TIMEZONE core config: it ends cycles whose endDate fell yesterday and activates cycles whose startDate is today. On SaaS (VERSION=saas) it fans out per organization; otherwise it runs for the os tenant (dailyCheckCycles.ts).

Cycle errors

startCycle fails with "Previous cycle is active" if the team already has an active cycle; end it first. If daily rollover does not happen, checkCycle only acts at hour 0 in the tenant TIMEZONE core config, so make sure the operations-daily-cycles-check queue is running and the config is set.

Progress rollups

getProjectProgress* aggregate task scope/estimate over the project's tasks, grouped by member and team, plus a time-series chart. getCycleProgress* does the same per cycle with an optional assigneeId filter. milestoneProgress returns per-milestone totals (totalScope, totalStartedScope, totalCompletedScope) for one project.

Subscriptions operationProjectChanged(_id) and operationProjectListChanged(filter) publish project updates; task updates that affect rollups publish on the task channels (see Tasks & Statuses).

Segments and automations

Projects are a declared segment content type (operation:project.projects). The declaration registers the content type and dependent modules but answers no field producers. Automation triggers "Project", "Project completed" (every task done), "Milestone reached", and "Team work completed" plus the "Create project" action are described in GitHub Integration & Automations.

Was this helpful?