# Position Management

## Overview

Position Management maintains **posts** and their **role definitions (job profiles)** — `Position` and `JobProfile`. A Position exists independently of any incumbent: it can be vacant or to-be-hired (TBH), belongs to an organization Department (and optionally a Site), references a JobProfile, and carries a headcount. Occupancy is derived from open Assignments against headcount rather than stored (see `listVacantPositions`). Positions are effective-dated (ADR-013) so structural changes are versioned; JobProfiles are stable classification templates shared across many Positions. This is the "Position" and "Job" of the Worker / Position / Job separation that lets headcount and org structure be managed on the seat rather than the person (issue #7).

## Business Purpose

- Manage headcount and organizational structure at the level of the post, so vacancies and planned seats are first-class
- Provide a shared role definition (JobProfile) that many Positions reference, keeping role metadata consistent
- Supply the Department/Site/JobProfile context that Assignment resolves for downstream "whose / where" queries
- Preserve structural history for point-in-time org-chart reconstruction

## Process Flow

```mermaid
flowchart TD
    A[Create JobProfile: role template] --> B[Create Position under Department/Site referencing JobProfile]
    B --> C[Position has no incumbent: derived-vacant until assigned]
    C --> D{Assignment created?}
    D -- Yes --> E[Derived occupancy: filled]
    D -- No --> F[Remains derived-vacant]
    E --> G{Structural change: department, headcount}
    G -- Change on date D --> H[Close current generation, insert new effective-dated generation]
    G --> I{Abolish post}
    I -- Yes --> J[Close current generation; preserved for history]
```

## Scenario Patterns

- **New post with role**: create a JobProfile, then a Position referencing it under a Department; the Position starts vacant
- **Vacant / TBH seat**: a Position exists with no incumbent for headcount planning and recruiting
- **Headcount > 1**: a Position with headcount N accepts up to N current primary Assignments
- **Structural change**: moving a Position to a different Department or changing headcount creates a new effective-dated generation
- **Abolish post**: closing a Position preserves it for historical reconstruction; it is not hard-deleted while Assignments reference it
- **Shared JobProfile**: many "Store Staff" Positions across sites reference one JobProfile; deleting a referenced JobProfile is rejected

## Test Cases

- creating a Position requires an existing Department and JobProfile
- a newly created Position with no Assignment reports as vacant
- the count of current open primary Assignments cannot exceed the Position headcount
- a structural change closes the prior Position generation and inserts a new one
- abolishing a Position preserves it while Assignments reference it
- deleting a JobProfile referenced by any Position is rejected

## Reference Links

- Data-model design research (Position independent of person, Job Profile template): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/7
- Organization module (bundled) — Company / Department / Site that Positions reference: node_modules/@tailor-platform/erp-kit/src/modules/organization/README.md
