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 }.convertedFromIdlinks 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
| Operation | Kind | Permission |
|---|---|---|
getProject(_id) / getProjects(filter: IProjectFilter) | query | projectRead |
getProjectProgress / getProjectProgressByMember / getProjectProgressByTeam / getProjectProgressChart (_id) | query | projectRead |
getConvertedProject(convertedFromId) | query | projectRead |
cpGetProjects | query | forClientPortal + cpUserRequired; Client Portal users only |
createProject / updateProject / removeProject(_id) | mutation | projectCreate / projectUpdate / projectRemove |
IProjectFilter accepts _ids, name, status, priority, teamIds, tagIds, leadId, memberIds/memberId, userId, active, taskId, date bounds, and cursor params.
Cycles
| Operation | Kind | Permission |
|---|---|---|
getCycle(_id) / getCycles(teamId, …) / getCyclesActive(teamId, taskId, …) | query | cycleRead |
getCycleProgress / getCycleProgressChart / getCycleProgressByMember / getCycleProgressByProject (_id, assigneeId?) | query | cycleRead |
createCycle(input: CycleInput) / updateCycle(input) / removeCycle(_id) | mutation | cycleCreate / cycleUpdate / cycleRemove |
endCycle(_id) | mutation | cycleEnd |
Milestones
| Operation | Kind | Permission |
|---|---|---|
getMilestone(_id) / milestones(projectId, searchValue, …) | query | milestoneRead |
milestoneProgress(projectId) | query | milestoneRead; per-milestone totalScope, totalStartedScope, totalCompletedScope |
createMilestone / updateMilestone / removeMilestone | mutation | milestoneCreate / milestoneUpdate / milestoneRemove |
Cycle lifecycle
Cycles are per-team sprints with date boundaries:
createCycle/updateCyclereject date ranges that overlap another cycle of the same team ("New cycle overlaps with an existing cycle"), and a completed cycle cannot be updated.startCycleactivates a cycle only when no other cycle of that team is active.endCyclesnapshotsstatistics(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 viaTask.moveCycleand their ids are recorded inunFinishedTasks(Cycle model).- The
operations-daily-cycles-checkBullMQ scheduler (hourly0 * * * *UTC) runscheckCycleper tenant at midnight in the tenant'sTIMEZONEcore config: it ends cycles whoseendDatefell yesterday and activates cycles whosestartDateis today. On SaaS (VERSION=saas) it fans out per organization; otherwise it runs for theostenant (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.