# Plan: Utilization Categories on Projects

**Date:** 2026-03-13
**Status:** Draft
**Depends on:** -

## Problem

The chargeability report categorizes all work into utilization buckets. Currently CapaKraken 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
