# ApprovalPolicy

## Description

ApprovalPolicy is the reusable template that captures an approval routing chain for a given business `purpose`. Each policy carries a header (`purpose`, `name`, optional `description`) and a lifecycle status of `DRAFT` / `ACTIVE` / `INACTIVE`. Policies are composed of an ordered list of `ApprovalPolicyStep` rows and per-step `ApprovalPolicyStepAssignee` rows.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Draft: createApprovalPolicy
    Draft --> Draft: updateApprovalPolicy
    Draft --> Active: activateApprovalPolicy
    Active --> Inactive: deactivateApprovalPolicy
```

| Operation | From | To | Command |
|-----------|------|----|---------|
| update | DRAFT | DRAFT | [updateApprovalPolicy](../command/UpdateApprovalPolicy.md) |
| activate | DRAFT | ACTIVE | [activateApprovalPolicy](../command/ActivateApprovalPolicy.md) |
| deactivate | ACTIVE | INACTIVE | [deactivateApprovalPolicy](../command/DeactivateApprovalPolicy.md) |

### Command Definitions

- [createApprovalPolicy](../command/CreateApprovalPolicy.md)
- [updateApprovalPolicy](../command/UpdateApprovalPolicy.md)
- [activateApprovalPolicy](../command/ActivateApprovalPolicy.md)
- [deactivateApprovalPolicy](../command/DeactivateApprovalPolicy.md)

### Query Definitions

- [listApprovalPolicies](../query/ListApprovalPolicies.md)

### Models

- ApprovalPolicy

### Invariants

- `purpose` is a non-empty opaque string and is not validated against an enum
- `name` is required and non-empty
- DRAFT: `activatedAt` is null and the policy and its nested rows are editable
- ACTIVE: `activatedAt` is set to the moment of activation and the policy and its nested rows are immutable
- INACTIVE: `activatedAt` and `deactivatedAt` are both set; all fields remain immutable; row is retained indefinitely (no hard delete)
- At most one ACTIVE policy exists per `(purpose, name)` pair at any time
- Multiple DRAFT policies under the same `(purpose, name)` may coexist; only one may be activated
- Activation requires at least one `ApprovalPolicyStep` and every step must have at least one `ApprovalPolicyStepAssignee`

### Relationships

- **Has Many ApprovalPolicySteps**: A policy owns an ordered list of `ApprovalPolicyStep` rows that define the routing chain
- **Used As Template By ApprovalRequest**: When a request is created in policy mode, the policy's structure is copied into the request's runtime tables (`ApprovalRequest` / `ApprovalStep` / `ApprovalStepAssignee`); the request retains `sourcePolicyId` for traceability and joins back to `name` and `activatedAt` for reporting
