# Plan: Resource Model Extensions (EID Attributes)

**Date:** 2026-03-13
**Status:** Draft
**Depends on:** Country/SAH, OrgUnit hierarchy

## Problem

The Dispo Categories file defines a rich set of EID (employee) attributes that CapaKraken's Resource model currently does not cover. These attributes are needed for chargeability reporting, resource filtering, and organizational grouping.

## Current Resource Model (relevant fields)

```
Resource {
  id, name, email, skills (JSONB), isActive, postalCode, federalState,
  portfolioUrl, roleId, aiSummary, fte, userId, ...
}
```

## Required New Attributes

### Attributes that need DB storage

| Attribute | Type | Source | Notes |
|---|---|---|---|
| Enterprise ID | String | manual/import | ACN-style username (e.g. "a.kasperovich") |
| Country | FK → Country | manual | See plan-country-sah-fte.md |
| Metro City | FK → MetroCity | manual | See plan-country-sah-fte.md |
| Org Unit (L7) | FK → OrgUnit | manual | See plan-org-unit-hierarchy.md |
| Management Level Group | FK → ManagementLevel | manual | See below |
| Management Level | derived from group | - | Sub-level within group |
| FTE | Float | manual | Already exists, ensure 2+ decimal precision |
| Resource Type | Enum | manual | Apprentice, Employee, Freelancer, Intern, Student |
| Chg Responsibility | Boolean | manual | Default: true. Drives "Accenture" resource type derivation |
| Rolled Off | Boolean | manual | Status flag, default: false |
| Departed | Boolean | manual | Status flag, default: false |
| Client Unit | FK → Client? or String | manual | Primary client assignment for reporting |

### Attributes that are derived (no DB input)

| Attribute | Derivation Rule |
|---|---|
| Long-term absence | Derived from vacation/absence system (extended leave) |
| Chapter | Derived from OrgUnit L7 → name |
| Department | Derived from OrgUnit L6 → name |
| MV Ressource Type (reporting) | Derived: see resource type derivation rules |

### Resource Type Derivation for Reporting

The chargeability report uses a "MV Ressource Type" that differs from the stored Resource Type:

| Reporting Type | Derivation Rule |
|---|---|
| Production Studios | `chgResponsibility = true` AND country is Germany |
| Near&Offshore | Country is NOT Germany AND resource type is Employee/Freelancer |
| Accenture | `chgResponsibility = false` (regardless of country) |
| Long-term absence | Has active long-term absence flag |

These are computed at query time, not stored. An admin UI can make the country→reporting-type mapping configurable.

## Management Level Model

### New: `ManagementLevelGroup` model

```prisma
model ManagementLevelGroup {
  id               String   @id @default(cuid())
  name             String   @unique              // "Analyst", "Consultant", "Manager", etc.
  targetPercentage Float                         // Official chargeability target (e.g. 0.805)
  sortOrder        Int      @default(0)
  createdAt        DateTime @default(now())
  updatedAt        DateTime @updatedAt

  levels           ManagementLevel[]
  resources        Resource[]
}
```

### New: `ManagementLevel` model

```prisma
model ManagementLevel {
  id      String               @id @default(cuid())
  name    String               @unique   // "10-Senior Analyst", "11-Analyst", etc.
  groupId String
  group   ManagementLevelGroup @relation(fields: [groupId], references: [id])

  resources Resource[]
}
```

### Seed Data

| Group | Target % | Levels |
|---|---|---|
| Accenture Leadership | 36.5% | *(levels 1-4, names TBD)* |
| Senior Manager | 54.6% | 5-Associate Director, 6-Senior Manager |
| Manager | 74.7% | 7-Manager |
| Consultant | 80.8% | 8-Associate Manager, 9-Team Lead/Consultant |
| Analyst | 80.5% | 10-Senior Analyst, 11-Analyst |
| Associate | 77.0% | 12-Associate, 13-New Associate |

## Schema Changes on Resource

```prisma
model Resource {
  // ... existing fields ...

  enterpriseId            String?   @unique       // ACN enterprise ID
  countryId               String?                 // FK → Country
  country                 Country?  @relation(...)
  metroCityId             String?                 // FK → MetroCity
  metroCity               MetroCity? @relation(...)
  orgUnitId               String?                 // FK → OrgUnit (L7)
  orgUnit                 OrgUnit?  @relation(...)
  managementLevelGroupId  String?                 // FK → ManagementLevelGroup
  managementLevelGroup    ManagementLevelGroup? @relation(...)
  managementLevelId       String?                 // FK → ManagementLevel
  managementLevel         ManagementLevel? @relation(...)
  resourceType            ResourceType @default(EMPLOYEE)
  chgResponsibility       Boolean   @default(true)
  rolledOff               Boolean   @default(false)
  departed                Boolean   @default(false)
  clientUnitId            String?                 // Primary client for reporting
  clientUnit              Client?   @relation("ResourceClientUnit", fields: [clientUnitId], references: [id])
}

enum ResourceType {
  EMPLOYEE
  FREELANCER
  APPRENTICE
  INTERN
  STUDENT
}
```

## UI Changes

### Resource Modal Extensions

Add to `ResourceModal.tsx`:

| Field | UI Element | Notes |
|---|---|---|
| Enterprise ID | Text input | Optional, unique |
| Country | Dropdown | Required for SAH |
| Metro City | Dropdown (filtered by country) | Optional |
| Org Unit | Cascading L5→L6→L7 picker | Stores L7 |
| Management Level Group | Dropdown | Drives target % |
| Management Level | Dropdown (filtered by group) | Specific level |
| Resource Type | Dropdown (5 values) | Default: Employee |
| Chg Responsibility | Toggle | Default: on |
| Client Unit | Client picker | Primary client for reporting |
| Rolled Off | Toggle | Status |
| Departed | Toggle | Status |

### Admin: Management Level Management (`/admin/management-levels`)

- Table of management level groups with target percentages
- Nested levels within each group
- Editable target % (changes over time)
- Add/edit levels

### Resource List Enhancements

- New columns: Enterprise ID, Country, Org Unit, Management Level, Client Unit
- Filters for: Country, Org Unit (L6/L7), Management Level Group, Resource Type, Client Unit
- Status filter: active / rolled off / departed

## LCR and UCR

The Dispo file mentions LCR (Local Cost Rate) and UCR (Unit Cost Rate) but has no defined values yet. These are likely cost rates per resource used in budget calculations.

Recommendation: Add placeholder fields now, define schema when values become available.

```prisma
model Resource {
  // ...
  lcrCents  Int?   // Local Cost Rate in cents per hour
  ucrCents  Int?   // Unit Cost Rate in cents per hour
}
```

Follows the integer-cents pattern from CLAUDE.md.

## Migration

1. Add new columns to Resource (all nullable initially)
2. Create ManagementLevelGroup + ManagementLevel tables with seed data
3. Add ResourceType enum
4. Admin populates existing resources via batch import or manual assignment

## Acceptance Criteria

- [ ] Enterprise ID field on Resource (unique, optional)
- [ ] Resource linked to Country, MetroCity, OrgUnit, ManagementLevel
- [ ] ResourceType enum with 5 values
- [ ] chgResponsibility, rolledOff, departed boolean flags
- [ ] Client Unit FK for primary client assignment
- [ ] ManagementLevelGroup with target percentages
- [ ] ManagementLevel with group membership
- [ ] Resource modal with all new fields
- [ ] Resource list with new columns and filters
- [ ] Management level admin UI
- [ ] LCR/UCR placeholder fields (integer cents)
- [ ] Reporting resource type derivation logic
