Domain model¶
Everything hangs off the issue: a typed record in a project, with a parent for hierarchy, a status owned by a workflow, and a JSONB bag for custom fields. Every change writes a history row, which drives the activity stream, metrics (cycle time, time in status, burndowns) and the Jira importer's replay of the past.
Entities¶
| Entity | Purpose | Key fields |
|---|---|---|
| Project | Container for issues and configuration | key (old keys kept as aliases), name, lead, template, open role or private |
| Issue type | Epic, Story, Task, Bug, Sub-task (per project) | key, name, hierarchy level (epic 1, standard 0, sub-task −1), icon, workflow |
| Issue | The work item | project, number, type, parent, status, workflow version, assignee, reporter, priority, rank, sprint, story points, estimates, dates, labels, resolution, custom fields (JSONB), version |
| Issue link | Non-hierarchical relationships | source, target, type (blocks, relates, duplicates, clones) |
| Field definition | Custom fields | key, type (text, number, select, multi-select, user, date, version, checkbox, URL), projects and types |
| Workflow, workflow version | Versioned state machines | YAML source and compiled definition; issues pin a version |
| Board, column | Views over issues | Scrum or Kanban, filter, columns → statuses, WIP limits, swimlanes, card fields |
| Sprint, release | Time boxes and versions | dates, goal, state; sprints snapshot what was committed and completed |
| Comment, attachment, watcher | Collaboration | Markdown body, file (PostgreSQL or S3), who follows the issue |
| Worklog | Time spent | issue, author, started at, duration |
| Issue history | Append-only changelog | issue, actor, field, from, to, time, and what acted ("via" an AI assistant) |
| Dev link | Git artefacts tied to an issue | provider, repository, kind (branch, commit, pull/merge request, pipeline), state, URL |
| Automation rule, run | Rules and their history | trigger, CEL condition, actions, target (issue, parent, children) |
| Dashboard | Personal or shared gadgets | gadget layout and configuration |
| User, group, role | People and access | source (SSO, SCIM, Google, Keycloak, local…), organisation role, groups mapped to roles, project and custom roles |
Hierarchy¶
The rule is parent level = child level + 1, taken from the issue type: epics hold stories, tasks and bugs, which hold sub-tasks. The query language's epic field follows the epic ancestor, so sub-tasks count under their story's epic.
Issue keys¶
Each project has a counter, locked with SELECT … FOR UPDATE when an issue is created. When a project key is renamed, the old key is kept as an alias so keys in commit messages and links still resolve.
Ranking and concurrency¶
Boards and backlogs use fractional string ranks compared with COLLATE "C", so dragging a card updates one row. Every issue carries a version; an update with a stale version is refused with 409, so two people editing at once cannot overwrite each other silently.
Configuration¶
Project templates (Scrum, Kanban, Bug tracking, and the service desk) copy a workflow and a set of issue types into the project; workflows can then be changed per project and per issue type.