non-linear-docs/02-data-model.md

127 lines
4.6 KiB
Markdown

# Non-Linear: Data Model
## Overview
The data model consists of two overlaid graphs on the same set of nodes:
1. **Decomposition Tree** — strict parent→child hierarchy (DAG)
2. **Association Graph** — lateral many-to-many connections with typed edges
These are deliberately separated. The decomposition tree is the *spine* of the product. The association graph is an *overlay* that adds context without defining structure.
## Issue Node (Atomic Unit)
Every node in the graph is an **issue**. Issues are intentionally untyped — their depth in the decomposition tree implies their abstraction level.
| Field | Type | Description |
|-------|------|-------------|
| `id` | UUID | Unique identifier |
| `title` | string | Short descriptive title |
| `description` | text | Detailed description (markdown) |
| `status` | enum | Current state (see Status below) |
| `labels` | string[] | Freeform tags for orthogonal concerns |
| `assignee` | actor_id? | User or agent assigned |
| `parent_id` | issue_id? | Parent in decomposition tree (null = root) |
| `created_at` | timestamp | Creation time |
| `updated_at` | timestamp | Last modification |
| `created_by` | actor_id | Creator (user or agent) |
### Status
Default statuses (customizable per project):
- `backlog` — not yet planned
- `todo` — planned, not started
- `in_progress` — actively being worked on
- `in_review` — awaiting review
- `done` — completed
- `cancelled` — abandoned
### Labels
Labels handle all classification orthogonal to hierarchy:
- **Kind:** `bug`, `feature`, `chore`, `spike`
- **Area:** `frontend`, `backend`, `infra`, `docs`
- **Priority:** `p0`, `p1`, `p2`, `p3`
- **Custom:** anything the team defines
### Why Untyped
Traditional trackers have explicit types: Epic, Story, Task, Subtask, Bug. This creates rigidity — teams argue about what level something belongs at, and refactoring the hierarchy means changing types.
In Non-Linear, depth *is* type:
```
Root (depth 0) → "project level"
├── Child (depth 1) → "component/epic level"
│ ├── Child (depth 2) → "feature/story level"
│ │ └── Child (depth 3) → "task level"
```
A node's abstraction level is determined by its position, not a type field. Moving a node to a different depth changes its conceptual level automatically.
## Decomposition Tree
The decomposition tree is a strict hierarchy with these properties:
- **Single parent:** Every node has exactly one parent (except roots)
- **Directed:** Edges flow from abstract (parent) to concrete (child)
- **Acyclic:** No node can be its own ancestor
- **Single root per project:** Each project has one root node (v0.1)
### Reparenting
Moving a node to a different parent is a **structural change**. It affects:
- The node's implied abstraction level
- Agent permissions (if scoped to a subtree)
- The layered view layout
- Who can access the node (if resource-scoped policies apply)
The system should warn when reparenting changes permission boundaries.
## Association Graph (Lateral Links)
Lateral links are typed, many-to-many relationships that don't affect hierarchy.
### Link Types
| Type | Semantics | Directionality |
|------|-----------|----------------|
| `blocks` | A blocks B (B can't proceed until A is done) | Directed |
| `blocked_by` | Inverse of blocks | Directed (auto-created) |
| `relates_to` | General association | Undirected |
| `duplicates` | A is a duplicate of B | Directed |
### Cross-Project Links (v0.2+)
In future versions, lateral links can cross project boundaries. This enables:
- Freelancer's client project depending on a shared library
- Shared infrastructure components blocking multiple projects
- Cross-team dependency tracking
Cross-project links add complexity to permissions (an agent scoped to Project A sees a link to Project B but may not access the target) and are deferred to v0.2.
### Link vs. Parent Relationship
| Property | Parent→Child | Lateral Link |
|----------|-------------|--------------|
| Cardinality | One parent per node | Many-to-many |
| Affects hierarchy | Yes | No |
| Affects layered view | Yes | Shown as overlay edges |
| Affects permissions | Yes (subtree scoping) | No |
| Removal impact | Structural (node needs new parent) | Annotation only |
## Project (v0.1)
| Field | Type | Description |
|-------|------|-------------|
| `id` | UUID | Unique identifier |
| `name` | string | Project name |
| `root_id` | issue_id | Root node of decomposition tree |
| `created_at` | timestamp | Creation time |
| `members` | actor_id[] | Users and agents with access |
In v0.1, each project has exactly one root node and one decomposition tree. Multi-root or cross-project features are deferred.