# Plan: Org Unit Hierarchy (Level 5 / 6 / 7) **Date:** 2026-03-13 **Status:** Draft **Depends on:** - ## Problem The chargeability report groups resources by a 3-level organizational hierarchy: ``` Level 5: Content Production (department) Level 6: CGI Content | CGI Technology | Creative Content Production | VFX (division) Level 7: Art Direction | CGI Production | 3D | IT Development | ... (chapter/team) ``` Every resource must be mapped to an Org Unit Level 7. Level 7 rolls up to Level 6, which rolls up to Level 5. The names of org units can change over time, so they must be editable. Planarchy already has a `Role` model, but roles represent skills/functions (e.g. "3D Artist"), not organizational placement. A person's org unit and their role are different dimensions. ## Current Data ### Level 5 → Level 6 | Level 5 | Level 6 | |---|---| | Content Production | CGI Content | | Content Production | CGI Technology | | Content Production | Creative Content Production | | Content Production | VFX | ### Level 6 → Level 7 | Level 6 | Level 7 | |---|---| | CGI Content | Art Direction | | CGI Content | Capability Development | | CGI Content | CGI Production | | CGI Content | Product Data Management | | CGI Content | Program/Delivery Mgmt | | CGI Technology | CGI Development | | CGI Technology | IT Development | | Creative Content Production | *(direct, no sub-teams)* | | VFX | 2D & Art Direction | | VFX | 3D | | VFX | Program/Delivery Mgmt & Other | ## Schema ### New: `OrgUnit` model (self-referencing tree) ```prisma model OrgUnit { id String @id @default(cuid()) name String shortName String? // optional abbreviation level Int // 5, 6, or 7 parentId String? parent OrgUnit? @relation("OrgUnitTree", fields: [parentId], references: [id]) children OrgUnit[] @relation("OrgUnitTree") sortOrder Int @default(0) isActive Boolean @default(true) // soft-delete for renamed/retired units createdAt DateTime @default(now()) updatedAt DateTime @updatedAt resources Resource[] // resources assigned to this org unit (level 7) @@unique([parentId, name]) } ``` ### Resource model extension ```prisma model Resource { // ... existing fields ... orgUnitId String? orgUnit OrgUnit? @relation(fields: [orgUnitId], references: [id]) } ``` Constraint: A resource should only be assigned to a Level 7 org unit. The UI enforces this; the schema allows any level for flexibility. ## Shared Types ```typescript // packages/shared/src/types/org-unit.ts interface OrgUnit { id: string; name: string; shortName?: string; level: number; // 5, 6, or 7 parentId?: string; sortOrder: number; isActive: boolean; } interface OrgUnitTree extends OrgUnit { children: OrgUnitTree[]; } ``` ## API Location: `packages/api/src/router/org-unit.ts` | Procedure | Access | Description | |---|---|---| | `list` | protected | Returns flat list, optionally filtered by level or parentId | | `getTree` | protected | Returns nested tree structure for UI rendering | | `create` | admin | Create org unit with parent reference | | `update` | admin | Rename, re-parent, change sort order | | `deactivate` | admin | Soft-delete (sets `isActive = false`) | ## UI ### Admin: Org Unit Management (`/admin/org-units`) - Tree view showing L5 → L6 → L7 hierarchy - Inline editing of names (since names can change) - Add/remove units at each level - Drag-and-drop reordering within a level - Deactivate (not hard delete) to preserve historical data ### Resource: Org Unit Assignment - `ResourceModal.tsx` gets cascading dropdowns: 1. Level 5 (pre-filtered or single value) 2. Level 6 (filtered by selected L5) 3. Level 7 (filtered by selected L6) — this is what gets stored on the resource - Alternative: single tree picker showing full path ### Chargeability Report The report groups by L6 → L7 (see `plan-chargeability-report.md`). The OrgUnit tree drives the row structure of the report. ## Seed Data Seed the initial hierarchy from the Dispo Categories file: ``` Content Production (L5) ├── CGI Content (L6) │ ├── Art Direction (L7) │ ├── Capability Development (L7) │ ├── CGI Production (L7) │ ├── Product Data Management (L7) │ └── Program/Delivery Mgmt (L7) ├── CGI Technology (L6) │ ├── CGI Development (L7) │ └── IT Development (L7) ├── Creative Content Production (L6) │ └── Creative Content Production (L7) └── VFX (L6) ├── 2D & Art Direction (L7) ├── 3D (L7) └── Program/Delivery Mgmt & Other (L7) ``` ## Migration 1. Create `OrgUnit` table and seed data 2. Add `orgUnitId` to Resource (nullable) 3. Admin assigns org units to existing resources 4. No automated backfill possible — org unit assignment is business knowledge ## Acceptance Criteria - [ ] `OrgUnit` model with self-referencing parent/child tree - [ ] Resource linked to OrgUnit (level 7) - [ ] Admin UI: tree view with CRUD for all levels - [ ] Resource modal: cascading L5 → L6 → L7 dropdowns - [ ] Org unit names are editable without breaking historical references - [ ] Seed data for the known hierarchy - [ ] `getTree` API returns nested structure for UI