Teams & Templates

Teams, membership, estimate scales, task templates, and custom-field plumbing in the Operation plugin.

Backend code lives under backend/plugins/operation_api/src/modules/{team,template,fields}/. Teams are the scoping unit: statuses, cycles, triage queues, and task estimate scales all hang off a team.

Data models

  • operation_teams: { icon, name, description, memberIds: [String], estimateType: Int, cycleEnabled: Boolean, triageEnabled: Boolean }.
  • operation_team_members: { memberId, teamId, role }; role supports admin / member / lead in the model but is deprecated on the GraphQL type.
  • operation_templates: { name, defaults: JSON, teamId, createdBy }; per-team task templates whose defaults prefill a new task.

Creating a team (teamAddTeam.createTeam) inserts TeamMember rows for the creator and memberIds, then seeds the five default statuses (backlog, todo, in progress, done, cancelled); see Tasks & Statuses.

Estimate scales

estimateType is one of TeamEstimateTypes (team/utils.ts): NOT_IN_USE=1, DEFAULT=2 (0–5), FIBONACCI=3 (0,1,2,3,5,8), EXPONENTIAL=4 (0,1,2,4,8,16). getTeamEstimateChoises(teamId) (sic; the operation name is misspelled in the schema) returns the { value, label } list for the team's type, or null when estimates are off.

Switching estimateType wipes estimates

updateTeam sets estimatePoint: null on every task of the team when estimateType changes to NOT_IN_USE. Other scale switches keep existing values even if they are not in the new scale.

Toggling cycleEnabled on SaaS (VERSION=saas) also updates the organization's cycleEnabled flag, which is what the daily cycle worker filters on; see Projects, Cycles & Milestones.

Queries and mutations

OperationKindPermission
getTeam(_id) / getTeams(name, userId, teamIds, projectId, isTriageEnabled, teamId, orderBy)queryteamRead
getTeamMembers(teamId, teamIds)queryteamRead
getTeamEstimateChoises(teamId)queryteamRead
teamAdd(name, description, icon, memberIds) / teamUpdate(_id, …estimateType, cycleEnabled, triageEnabled)mutationteamCreate / teamUpdate
teamRemove(_id)mutationteamRemove
teamAddMembers(_id, memberIds) / teamRemoveMember(teamId, memberId) / teamUpdateMember(_id)mutationteamMemberManage
operationTemplates(teamId) / operationTemplateDetail(_id)querylogin only; no checkPermission
operationTemplateAdd(name, defaults, teamId) / operationTemplateEdit / operationTemplateRemovemutationlogin only; no checkPermission

Custom fields

fields.getFieldList on the plugin tRPC router returns the filterable/inputable field list for moduleType: 'task' or 'project'. modules/fields/fieldUtils.ts builds it from the Mongoose schemas plus hand-declared options: priority renders No Priority/Minor/Medium/High/Critical (values 0–4), statusType maps to the STATUS_TYPES labels, and teamId, assigneeId, createdBy, tagIds get selection configs (e.g. queryName: 'users').

Custom property values are stored on the record under propertiesData keyed by Core field id; the plugin meta exposes task and project property types with systemFields code/name/type shown as "Basic information" in Settings → Properties. propertiesData is only written through task.createFromSource; the task GraphQL type does not expose it.

Permissions

Team module actions: teamRead (always granted), teamCreate, teamUpdate, teamRemove, teamMemberManage (membership changes). Template resolvers perform no checkPermission call, so they fall back to the platform default (any logged-in user). Scopes are own (creator), group (member's teams), all. A member who cannot see a team has lost the group scope; re-add them with teamAddMembers.

Was this helpful?