Reuses the existing identity/teams, identity/agents, and orchestration/hierarchy scaffold directories per doc 07's documented module placement. Key decisions: last-write-wins availability (not optimistic locking — operational telemetry, not a durable record), compound-unique skill upsert, cycle detection only on reparenting edits (not creation, which can't form a cycle), and a capability-eligibility read path that composes hierarchy scope with caller-supplied skills while deliberately excluding availability per doc 05's own ordering. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.4 KiB
Phase 1 Data Model: Support Organization
All new models use cuid() ids. Refines docs/06-database-schema.md's conceptual Team/
Agent/AgentSkill/AgentAvailability/HierarchyNode shapes with explicit constraints
(research.md).
Team
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| name | String | |
| active | Boolean @default(true) | Deactivation never cascades to its agents (FR-004) |
| createdAt | DateTime @default(now()) | |
| updatedAt | DateTime @updatedAt |
Relations: agents Agent[].
Agent
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| teamId | String | FK → Team |
| name | String | |
| active | Boolean @default(true) | Excluded from active listings when false, never deleted (FR-003) |
| createdAt | DateTime @default(now()) | |
| updatedAt | DateTime @updatedAt |
Relations: team Team, skills AgentSkill[], availability AgentAvailability?.
Index: (teamId, active) — the exact shape "active agents on this team" queries on.
AgentSkill
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| agentId | String | FK → Agent |
| skillTag | String | Free-text capability tag, e.g. "docuqube_pdf_conversion" |
| level | Int | Proficiency, read by a future SKILL_BASED assignment strategy — not interpreted here |
Constraints: @@unique([agentId, skillTag]) — FR-006's "update, never duplicate" guarantee
(research.md).
AgentAvailability
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| agentId | String @unique | FK → Agent — the uniqueness itself is FR-007's "exactly one current record per agent" |
| status | String | available | busy | away | offline (FR-008, validated at the schema/service layer, not a DB enum — consistent with every other status field in this codebase) |
| workingHours | Json | Per business calendar — opaque to this feature, consumed by a future SLA/business-calendar phase |
| currentLoad | Int @default(0) | |
| updatedAt | DateTime @updatedAt | Last-write-wins (research.md) — no expectedVersion |
HierarchyNode
| Field | Type | Notes |
|---|---|---|
| id | String @id @default(cuid()) | |
| name | String | |
| parentId | String? | FK → HierarchyNode (self-relation); null = root node |
| order | Int | Sibling order under the same parent (FR-013) |
| teamId | String? | FK → Team — optional; a node need not yet point at a team |
| skills | String[] | Capability tags this node covers |
| productScope | String[] | External product ids; empty = matches every product (research.md) |
| categoryScope | String[] | Free-text, empty = matches every category |
| priorityScope | String[] | Free-text, empty = matches every priority |
| assignmentStrategy | String | Free-text reference; not validated against a real strategy enum yet (spec.md Assumptions — Phase 7) |
| slaPolicyId | String? | Free-text reference; no SlaPolicy table exists yet (Phase 8) |
| escalationPolicyId | String? | Free-text reference; no EscalationPolicy table exists yet (Phase 8) |
| entryConditions | Json? | Opaque rule expression — stored, not evaluated, by this feature |
| exitConditions | Json? | Opaque rule expression — stored, not evaluated, by this feature |
| active | Boolean @default(true) | Deactivation never cascades to children (FR-012) |
| createdAt | DateTime @default(now()) | |
| updatedAt | DateTime @updatedAt |
Relations: parent HierarchyNode? @relation("HierarchyTree"),
children HierarchyNode[] @relation("HierarchyTree"), team Team?.
Index: (parentId, order) — the exact shape "this parent's children, in order" queries on;
(active) for the active-tree query.
Cycle guarantee (not a DB constraint, enforced in the repository's edit path — research.md):
before applying a parentId change, walk the new parent's ancestor chain to the root; reject if
the node being edited appears in it.
Existing models — no changes
Doc 06's conceptual HierarchyNode doesn't currently carry a back-relation from Product/
Category/Priority (catalog module) — productScope/categoryScope/priorityScope stay
loosely-typed string arrays, matching KnowledgeEntry.categoryScope's existing precedent (004),
not a new FK relationship this feature would otherwise have to add to three existing catalog
models for no requirement that asks for it.