Add task management data model spec
Defines the target data model for hierarchical task tracking: teams, workflow states, issues, projects, milestones, initiatives, labels, relations, comments, and sub-issues. Includes entity relationships and recommended implementation priority. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
407
doc/TASKS.md
Normal file
407
doc/TASKS.md
Normal file
@@ -0,0 +1,407 @@
|
||||
# Task Management Data Model
|
||||
|
||||
Reference for how task tracking works in Paperclip. Describes the entities, their
|
||||
relationships, and the rules governing task lifecycle. Written as a target model
|
||||
-- some of this is already implemented, some is aspirational.
|
||||
|
||||
---
|
||||
|
||||
## Entity Hierarchy
|
||||
|
||||
```
|
||||
Workspace
|
||||
Initiatives (roadmap-level objectives, span quarters)
|
||||
Projects (time-bound deliverables, can span teams)
|
||||
Milestones (stages within a project)
|
||||
Issues (units of work, the core entity)
|
||||
Sub-issues (broken-down work under a parent issue)
|
||||
```
|
||||
|
||||
Everything flows down. An initiative contains projects; a project contains
|
||||
milestones and issues; an issue can have sub-issues. Each level adds
|
||||
granularity.
|
||||
|
||||
---
|
||||
|
||||
## Issues (Core Entity)
|
||||
|
||||
An issue is the fundamental unit of work.
|
||||
|
||||
### Fields
|
||||
|
||||
| Field | Type | Required | Notes |
|
||||
| ------------- | ---------------- | -------- | ----------------------------------------------------------------- |
|
||||
| `id` | uuid | yes | Primary key |
|
||||
| `identifier` | string | computed | Human-readable, e.g. `ENG-123` (team key + auto-increment number) |
|
||||
| `title` | string | yes | Short summary |
|
||||
| `description` | text/markdown | no | Full description, supports markdown |
|
||||
| `status` | WorkflowState FK | yes | Defaults to team's default state |
|
||||
| `priority` | enum (0-4) | no | Defaults to 0 (none). See Priority section. |
|
||||
| `estimate` | number | no | Complexity/size points |
|
||||
| `dueDate` | date | no | |
|
||||
| `teamId` | uuid FK | yes | Every issue belongs to exactly one team |
|
||||
| `projectId` | uuid FK | no | At most one project per issue |
|
||||
| `milestoneId` | uuid FK | no | At most one milestone per issue |
|
||||
| `assigneeId` | uuid FK | no | **Single assignee.** See Assignees section. |
|
||||
| `creatorId` | uuid FK | no | Who created it |
|
||||
| `parentId` | uuid FK (self) | no | Parent issue, for sub-issue relationships |
|
||||
| `goalId` | uuid FK | no | Linked objective/goal |
|
||||
| `sortOrder` | float | no | Ordering within views |
|
||||
| `createdAt` | timestamp | yes | |
|
||||
| `updatedAt` | timestamp | yes | |
|
||||
| `startedAt` | timestamp | computed | When issue entered a "started" state |
|
||||
| `completedAt` | timestamp | computed | When issue entered a "completed" state |
|
||||
| `cancelledAt` | timestamp | computed | When issue entered a "cancelled" state |
|
||||
| `archivedAt` | timestamp | no | Soft archive |
|
||||
|
||||
---
|
||||
|
||||
## Workflow States
|
||||
|
||||
Issue status is **not** a flat enum. It's a team-specific set of named states,
|
||||
each belonging to one of these fixed **categories**:
|
||||
|
||||
| Category | Purpose | Example States |
|
||||
| ------------- | ---------------------------- | ------------------------------- |
|
||||
| **Triage** | Incoming, needs review | Triage |
|
||||
| **Backlog** | Accepted, not ready for work | Backlog, Icebox |
|
||||
| **Unstarted** | Ready but not begun | Todo, Ready |
|
||||
| **Started** | Active work | In Progress, In Review, In QA |
|
||||
| **Completed** | Done | Done, Shipped |
|
||||
| **Cancelled** | Rejected or abandoned | Cancelled, Won't Fix, Duplicate |
|
||||
|
||||
### Rules
|
||||
|
||||
- Each team defines its own workflow states within these categories
|
||||
- Teams must have at least one state per category (Triage is optional)
|
||||
- Custom states can be added within any category (e.g. "In Review" under Started)
|
||||
- Categories are fixed and ordered -- you can reorder states _within_ a category
|
||||
but not the categories themselves
|
||||
- New issues default to the team's first Backlog state
|
||||
- Moving an issue to a Started state auto-sets `startedAt`; Completed sets
|
||||
`completedAt`; Cancelled sets `cancelledAt`
|
||||
- Marking an issue as a duplicate auto-moves it to a Cancelled state
|
||||
|
||||
### WorkflowState Fields
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | ------- | ----------------------------------------------------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | Display name, e.g. "In Review" |
|
||||
| `type` | enum | One of: `triage`, `backlog`, `unstarted`, `started`, `completed`, `cancelled` |
|
||||
| `color` | string | Hex color |
|
||||
| `description` | string | Optional guidance text |
|
||||
| `position` | float | Ordering within the category |
|
||||
| `teamId` | uuid FK | Each state belongs to one team |
|
||||
|
||||
---
|
||||
|
||||
## Priority
|
||||
|
||||
A fixed, non-customizable numeric scale:
|
||||
|
||||
| Value | Label | Notes |
|
||||
| ----- | ----------- | -------------------------------------- |
|
||||
| 0 | No priority | Default. Sorts last in priority views. |
|
||||
| 1 | Urgent | Could trigger immediate notification |
|
||||
| 2 | High | |
|
||||
| 3 | Medium | |
|
||||
| 4 | Low | |
|
||||
|
||||
The scale is intentionally small and fixed. Use labels for additional
|
||||
categorization rather than adding more priority levels.
|
||||
|
||||
---
|
||||
|
||||
## Teams
|
||||
|
||||
Teams are the primary organizational unit. Almost everything is scoped to a
|
||||
team.
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | ------ | -------------------------------------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | e.g. "Engineering" |
|
||||
| `key` | string | Short uppercase prefix, e.g. "ENG". Used in issue identifiers. |
|
||||
| `description` | string | |
|
||||
|
||||
### Team Scoping
|
||||
|
||||
- Each issue belongs to exactly one team
|
||||
- Workflow states are per-team
|
||||
- Labels can be team-scoped or workspace-wide
|
||||
- Projects can span multiple teams
|
||||
|
||||
In our context (AI company), teams map to functional areas. Each agent reports
|
||||
to a team based on role.
|
||||
|
||||
---
|
||||
|
||||
## Projects
|
||||
|
||||
Projects group issues toward a specific, time-bound deliverable. They can span
|
||||
multiple teams.
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | --------- | ------------------------------------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | |
|
||||
| `description` | text | |
|
||||
| `summary` | string | Short blurb |
|
||||
| `status` | enum | `backlog`, `planned`, `in_progress`, `completed`, `cancelled` |
|
||||
| `leadId` | uuid FK | Single owner for accountability |
|
||||
| `startDate` | date | |
|
||||
| `targetDate` | date | |
|
||||
| `createdAt` | timestamp | |
|
||||
| `updatedAt` | timestamp | |
|
||||
|
||||
### Rules
|
||||
|
||||
- An issue belongs to at most one project
|
||||
- Project status is **manually** updated (not auto-derived from issue states)
|
||||
- Projects can contain documents (specs, briefs) as linked entities
|
||||
|
||||
---
|
||||
|
||||
## Milestones
|
||||
|
||||
Milestones subdivide a project into meaningful stages.
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | ------- | ------------------------------ |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | |
|
||||
| `description` | text | |
|
||||
| `targetDate` | date | |
|
||||
| `projectId` | uuid FK | Belongs to exactly one project |
|
||||
| `sortOrder` | float | |
|
||||
|
||||
Issues within a project can optionally be assigned to a milestone.
|
||||
|
||||
---
|
||||
|
||||
## Labels / Tags
|
||||
|
||||
Labels provide categorical tagging. They exist at two scopes:
|
||||
|
||||
- **Workspace labels** -- available across all teams
|
||||
- **Team labels** -- restricted to a specific team
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | -------------- | ------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | |
|
||||
| `color` | string | Hex color |
|
||||
| `description` | string | Contextual guidance |
|
||||
| `teamId` | uuid FK | Null for workspace-level labels |
|
||||
| `groupId` | uuid FK (self) | Parent label for grouping |
|
||||
|
||||
### Label Groups
|
||||
|
||||
Labels can be organized into one level of nesting (group -> labels):
|
||||
|
||||
- Labels within a group are **mutually exclusive** on an issue (only one can be
|
||||
applied from each group)
|
||||
- Groups cannot contain other groups (single nesting level only)
|
||||
- Example: group "Type" contains labels "Bug", "Feature", "Chore" -- an issue
|
||||
gets at most one
|
||||
|
||||
### Issue-Label Junction
|
||||
|
||||
Many-to-many via `issue_labels` join table:
|
||||
|
||||
| Field | Type |
|
||||
| --------- | ------- |
|
||||
| `issueId` | uuid FK |
|
||||
| `labelId` | uuid FK |
|
||||
|
||||
---
|
||||
|
||||
## Issue Relations / Dependencies
|
||||
|
||||
Four relation types between issues:
|
||||
|
||||
| Type | Meaning | Behavior |
|
||||
| ------------ | -------------------------------- | --------------------------------------------- |
|
||||
| `related` | General connection | Informational link |
|
||||
| `blocks` | This issue blocks another | Blocked issue shown with flag |
|
||||
| `blocked_by` | This issue is blocked by another | Inverse of blocks |
|
||||
| `duplicate` | This issue duplicates another | Auto-moves the duplicate to a Cancelled state |
|
||||
|
||||
### IssueRelation Fields
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ---------------- | ------- | ---------------------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `type` | enum | `related`, `blocks`, `blocked_by`, `duplicate` |
|
||||
| `issueId` | uuid FK | Source issue |
|
||||
| `relatedIssueId` | uuid FK | Target issue |
|
||||
|
||||
### Rules
|
||||
|
||||
- When a blocking issue is resolved, the relation becomes informational (flag
|
||||
turns green)
|
||||
- Duplicate is one-directional (you mark the duplicate, not the canonical)
|
||||
- Blocking is **not transitive** at the system level (A blocks B, B blocks C
|
||||
does not auto-block A->C)
|
||||
|
||||
---
|
||||
|
||||
## Assignees
|
||||
|
||||
**Single-assignee model** by design.
|
||||
|
||||
- Each issue has at most one assignee at a time
|
||||
- This is deliberate: clear ownership prevents diffusion of responsibility
|
||||
- For collaborative work involving multiple people, use **sub-issues** with
|
||||
different assignees
|
||||
|
||||
In our context, agents are the assignees. The `assigneeId` FK on issues
|
||||
points to the `agents` table.
|
||||
|
||||
---
|
||||
|
||||
## Sub-issues (Parent/Child)
|
||||
|
||||
Issues support parent/child nesting.
|
||||
|
||||
- Setting `parentId` on an issue makes it a sub-issue
|
||||
- Sub-issues can themselves have sub-issues (multi-level nesting)
|
||||
- Sub-issues inherit **project** from their parent at creation
|
||||
time (not retroactively), but NOT team, labels, or assignee
|
||||
|
||||
### Auto-close
|
||||
|
||||
- **Sub-issue auto-close**: when parent completes, remaining sub-issues
|
||||
auto-complete
|
||||
|
||||
### Conversions
|
||||
|
||||
- Existing issues can be reparented (add or remove `parentId`)
|
||||
- A parent issue with many sub-issues can be "promoted" to a project
|
||||
|
||||
---
|
||||
|
||||
## Estimates
|
||||
|
||||
Point-based estimation, configured per-team.
|
||||
|
||||
### Available Scales
|
||||
|
||||
| Scale | Values |
|
||||
| ----------- | ------------------------ |
|
||||
| Exponential | 1, 2, 4, 8, 16 (+32, 64) |
|
||||
|
||||
Unestimated issues default to 1 point for progress/velocity calculations.
|
||||
|
||||
---
|
||||
|
||||
## Comments
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------ | -------------- | -------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `body` | text/markdown | |
|
||||
| `issueId` | uuid FK | |
|
||||
| `authorId` | uuid FK | Can be a user or agent |
|
||||
| `parentId` | uuid FK (self) | For threaded replies |
|
||||
| `resolvedAt` | timestamp | If the thread was resolved |
|
||||
| `createdAt` | timestamp | |
|
||||
| `updatedAt` | timestamp | |
|
||||
|
||||
---
|
||||
|
||||
## Initiatives
|
||||
|
||||
The highest-level planning construct. Groups projects toward a strategic
|
||||
objective. Initiatives have strategic owners, and are typically measured by outcomes/OKRs, not “done/not done.”
|
||||
|
||||
| Field | Type | Notes |
|
||||
| ------------- | ------- | -------------------------------- |
|
||||
| `id` | uuid | |
|
||||
| `name` | string | |
|
||||
| `description` | text | |
|
||||
| `ownerId` | uuid FK | Single owner |
|
||||
| `status` | enum | `planned`, `active`, `completed` |
|
||||
| `targetDate` | date | |
|
||||
|
||||
Initiatives contain projects (many-to-many) and provide a rollup view of
|
||||
progress across all contained projects.
|
||||
|
||||
---
|
||||
|
||||
## Identifiers
|
||||
|
||||
Issues use human-readable identifiers: `{TEAM_KEY}-{NUMBER}`
|
||||
|
||||
- Team key: short uppercase string set per team (e.g. "ENG", "DES")
|
||||
- Number: auto-incrementing integer per team
|
||||
- Examples: `ENG-123`, `DES-45`, `OPS-7`
|
||||
- If an issue moves between teams, it gets a new identifier and the old one is
|
||||
preserved in `previousIdentifiers`
|
||||
|
||||
This is far better for human communication than UUIDs. People say "grab ENG-42"
|
||||
not "grab 7f3a...".
|
||||
|
||||
---
|
||||
|
||||
## Entity Relationships
|
||||
|
||||
```
|
||||
Team (1) ----< (many) Issue
|
||||
Team (1) ----< (many) WorkflowState
|
||||
Team (1) ----< (many) Label (team-scoped)
|
||||
|
||||
Issue (many) >---- (1) WorkflowState
|
||||
Issue (many) >---- (0..1) Assignee (Agent)
|
||||
Issue (many) >---- (0..1) Project
|
||||
Issue (many) >---- (0..1) Milestone
|
||||
Issue (many) >---- (0..1) Parent Issue
|
||||
Issue (1) ----< (many) Sub-issues
|
||||
Issue (many) >---< (many) Labels (via issue_labels)
|
||||
Issue (many) >---< (many) Issue Relations (via issue_relations)
|
||||
Issue (1) ----< (many) Comments
|
||||
|
||||
Project (many) >---- (0..1) Lead (Agent)
|
||||
Project (1) ----< (many) Milestones
|
||||
Project (1) ----< (many) Issues
|
||||
|
||||
Initiative (many) >---< (many) Projects (via initiative_projects)
|
||||
Initiative (many) >---- (1) Owner (Agent)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
Recommended build order, highest value first:
|
||||
|
||||
### High Value
|
||||
|
||||
1. **Teams** -- `teams` table + `teamId` FK on issues. Foundation for
|
||||
human-readable identifiers (`ENG-123`) and per-team workflow states. Most
|
||||
other features depend on team scoping, so build this first.
|
||||
2. **Workflow states** -- `workflow_states` table + `stateId` FK on issues.
|
||||
Per-team custom workflows with category-based state transitions.
|
||||
3. **Labels** -- `labels` + `issue_labels` tables. Categorization
|
||||
(bug/feature/chore, area tags, etc.) without polluting the status field.
|
||||
4. **Issue Relations** -- `issue_relations` table. Blocking/blocked-by is
|
||||
essential for agent coordination (agent A can't start until agent B finishes).
|
||||
5. **Sub-issues** -- `parentId` self-FK on `issues`. Lets agents break down
|
||||
large tasks.
|
||||
6. **Comments** -- `comments` table. Agents need to communicate about issues
|
||||
without overwriting the description.
|
||||
|
||||
### Medium Value
|
||||
|
||||
7. **Transition timestamps** -- `startedAt`, `completedAt`, `cancelledAt` on
|
||||
issues, auto-set by workflow state changes. Enables velocity tracking and SLA
|
||||
measurement.
|
||||
|
||||
### Lower Priority (For Later)
|
||||
|
||||
8. **Milestones** -- Useful once projects get complex enough to need stages.
|
||||
9. **Initiatives** -- Useful once we have multiple projects that serve a common
|
||||
strategic goal.
|
||||
10. **Estimates** -- Useful once we want to measure throughput and predict
|
||||
capacity.
|
||||
Reference in New Issue
Block a user