# Plan: Utilization Categories on Projects **Date:** 2026-03-13 **Status:** Draft **Depends on:** - ## Problem The chargeability report categorizes all work into utilization buckets. Currently Planarchy projects have no utilization classification. Every project needs a utilization category so that hours booked against it flow into the correct reporting bucket. ## Utilization Categories From the Dispo Categories file (adapted to ACN naming): | Short | Name | Description | |---|---|---| | Chg | Chargeable | Billable client project work | | BD | Business Development | Sales, proposals, presales activities | | MD&I | Market Development and Initiative | R&D, innovation, market development | | M&O | Management and Operations | Internal admin, management overhead | | PD&R | Personal Development and Recruitment | Training, hiring, onboarding | | Absence | Absence & Non Standard | Reduces Standard Available Hours: vacation, illness, non-standard leave | Notes from the Dispo file: - "Absent" and "Not available" are merged into "Absence & Non Standard" - "Unassigned" hours are calculated automatically (SAH minus all categorized hours) - Categories follow ACN naming convention ## Schema ### New: `UtilizationCategory` model ```prisma model UtilizationCategory { id String @id @default(cuid()) code String @unique // "Chg", "BD", "MD&I", etc. name String // Full display name description String? // Editable explanation sortOrder Int @default(0) isActive Boolean @default(true) isDefault Boolean @default(false) // One category can be the default for new projects createdAt DateTime @default(now()) updatedAt DateTime @updatedAt projects Project[] } ``` ### Project model extension ```prisma model Project { // ... existing fields ... utilizationCategoryId String? utilizationCategory UtilizationCategory? @relation(fields: [utilizationCategoryId], references: [id]) } ``` Why on Project (not on Allocation/Assignment): - The Dispo model maps categories to projects, not to individual time entries - A project is either "Chargeable" or "Business Development" — the category is a project-level attribute - Hours assigned to a project inherit the project's utilization category for reporting ## Shared Types ```typescript // packages/shared/src/types/utilization-category.ts interface UtilizationCategory { id: string; code: string; // "Chg", "BD", "MD&I", "M&O", "PD&R", "Absence" name: string; description?: string; sortOrder: number; isActive: boolean; isDefault: boolean; } ``` ## API Location: `packages/api/src/router/utilization-category.ts` | Procedure | Access | Description | |---|---|---| | `list` | protected | Returns all active categories (sorted) | | `getById` | protected | Single category | | `create` | admin | Create new category | | `update` | admin | Edit code, name, description, sort order | | `deactivate` | admin | Soft-delete | ## UI ### Admin: Utilization Category Management (`/admin/utilization-categories`) - Table listing all categories with code, name, description - Inline editing of name and description - Add new categories (for future extensibility) - Reorder via sort order - Mark one as default for new projects ### Project: Category Assignment - `ProjectModal.tsx` gets a `UtilizationCategory` dropdown (required or defaults to "Chg") - `ProjectWizard.tsx` Step 1 includes category selection - Project list shows category badge ### Chargeability Report Hours are bucketed by looking up `project.utilizationCategory.code`: - `Chg` hours → chargeability numerator - `BD` hours → business development column - `MD&I` hours → market development column - `M&O` hours → management overhead column - `PD&R` hours → personal development column - `Absence` hours → reduce SAH (already handled by vacation system, this is the project-side booking) **Unassigned hours** = SAH - sum of all categorized hours (calculated, not stored) ## Absence Category and Vacation System The "Absence & Non Standard" category overlaps with Phase 9 Vacation Pro. Relationship: - Vacation/illness from the vacation system reduces SAH directly (date-based) - An "Absence" project may additionally exist for booking non-standard absence hours - The chargeability calculator deducts both: vacation days (from vacation system) and hours booked to Absence-category projects This avoids double-counting: vacation days reduce available days in SAH, while Absence-project hours capture remaining non-standard time. ## Seed Data ```sql INSERT INTO "UtilizationCategory" (code, name, description, "sortOrder", "isDefault") VALUES ('Chg', 'Chargeable', 'Billable client project work', 1, true), ('BD', 'Business Development', 'Sales, proposals, presales activities', 2, false), ('MD&I', 'Market Development and Initiative', 'R&D, innovation, market development', 3, false), ('M&O', 'Management and Operations', 'Internal admin, management overhead', 4, false), ('PD&R', 'Personal Development and Recruitment','Training, hiring, onboarding', 5, false), ('Absence', 'Absence & Non Standard', 'Vacation, illness, non-standard leave (reduces SAH)', 6, false); ``` ## Migration 1. Create `UtilizationCategory` table with seed data 2. Add `utilizationCategoryId` to Project (nullable initially) 3. Default all existing projects to "Chg" (or let admin assign manually) 4. Make required once all projects are assigned ## Acceptance Criteria - [ ] `UtilizationCategory` model with code, name, description - [ ] Project linked to UtilizationCategory - [ ] Admin UI for category CRUD (code, name, description editable) - [ ] Project modal/wizard includes category dropdown - [ ] Seed data for all 6 categories - [ ] Chargeability report buckets hours by project category - [ ] Unassigned hours computed as SAH minus all categorized hours