6.0 KiB
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
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
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
// 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.tsxgets aUtilizationCategorydropdown (required or defaults to "Chg")ProjectWizard.tsxStep 1 includes category selection- Project list shows category badge
Chargeability Report
Hours are bucketed by looking up project.utilizationCategory.code:
Chghours → chargeability numeratorBDhours → business development columnMD&Ihours → market development columnM&Ohours → management overhead columnPD&Rhours → personal development columnAbsencehours → 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
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
- Create
UtilizationCategorytable with seed data - Add
utilizationCategoryIdto Project (nullable initially) - Default all existing projects to "Chg" (or let admin assign manually)
- Make required once all projects are assigned
Acceptance Criteria
UtilizationCategorymodel 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