# Spec Delta

## Purpose

Provide a predictable JSON contract for CMMS clients, preserving English technical identifiers and Indonesian business content across API modules.

## ADDED Requirements

### Requirement: Success envelope
JSON success responses under `/api/v1` SHALL contain `success: true`, `data`, and `meta.requestId`, and SHALL omit `error`. Single-resource data SHALL be an object; collection data SHALL be an array. HTTP 204, HEAD, downloads, and documentation assets SHALL retain their native body semantics.

#### Scenario: Authenticated user response
- **WHEN** an authenticated client requests `/api/v1/auth/me`
- **THEN** the API returns 200 with the public user at `data.user`, `success: true`, and a request ID
- **AND** no password hash or token is present in the body

#### Scenario: Logout response
- **WHEN** a permitted logout request succeeds
- **THEN** the API clears the existing authentication cookie and returns 204 with no body

### Requirement: Error envelope
JSON failures SHALL contain `success: false`, `error.code`, `error.message`, and `meta.requestId`, and SHALL omit `data`. Optional `error.details` SHALL be an array of safe items with `code`, `message`, and an optional `field` matching the request path. Clients SHALL use codes rather than message text for control flow.

#### Scenario: Invalid quantity
- **WHEN** a request field `quantity` fails its positive-integer constraint
- **THEN** the response has status 422, code `VALIDATION_ERROR`, and a detail identifying `quantity`

### Requirement: HTTP status semantics
The API SHALL use 200 for successful reads/updates, 201 with Location for created resources, and 204 for bodyless success. Failures SHALL use 400 for malformed syntax, 401 for unauthenticated access, 403 for forbidden access, 404 for missing targets/routes, 409 for state conflicts, 422 for input constraint failures, 429 for rate limits, 500 for unknown failures, and 503 for recognized temporary unavailability.

#### Scenario: Distinguish malformed and invalid input
- **WHEN** a login request contains malformed JSON
- **THEN** the API returns 400
- **WHEN** valid JSON fails login field constraints
- **THEN** the API returns 422

#### Scenario: Duplicate resource identifier
- **WHEN** creation conflicts with a documented unique resource identifier
- **THEN** the API returns 409 with a stable domain error code

### Requirement: Paginated collections
Paginated collection endpoints SHALL accept positive integer `page` and `pageSize`, defaulting to 1 and 20, with pageSize limited to 100. Responses SHALL include `meta.pagination` with page, pageSize, totalItems, and totalPages. Counts SHALL use the same filters as the list. Sorting SHALL be deterministic, with an ID tie-breaker.

#### Scenario: Empty result
- **WHEN** no records match a paginated query
- **THEN** data is an empty array, totalItems is 0, and totalPages is 0

#### Scenario: Invalid or out-of-range page
- **WHEN** pageSize exceeds 100 or either pagination input is not a positive integer
- **THEN** the API returns 422 with field details
- **WHEN** a valid page exceeds the last page
- **THEN** the API returns 200 with an empty array and the requested page metadata

### Requirement: Language separation
Routes, JSON keys, machine codes, and enum values SHALL use English. User-entered content SHALL be preserved without automatic translation. User-facing API error messages SHALL use Indonesian sentences while retaining familiar technical terms. Clients SHALL map enum values to presentation labels independently.

#### Scenario: Indonesian content and English enum
- **WHEN** a work order is represented with an Indonesian description and status `IN_PROGRESS`
- **THEN** the response preserves the description and status identifier without translating either

### Requirement: Stable value serialization
Resource IDs SHALL be strings. Instant timestamps SHALL be ISO 8601 UTC strings; date-only schedule values SHALL be `YYYY-MM-DD` interpreted in the configured facility timezone. Monetary decimals SHALL be decimal strings and whole-unit quantities SHALL be JSON integers. Locale-specific formatting SHALL remain a client responsibility.

#### Scenario: Money and time representation
- **WHEN** a resource has a monetary value of 125000.00 and an instant timestamp
- **THEN** the response represents money as `"125000.00"` and the instant with a UTC `Z` suffix

### Requirement: Coordinated client compatibility
The API, shared public DTOs, frontend consumers, and OpenAPI descriptions SHALL agree on the envelope at release. Authentication cookies, account-state checks, origin protection, and logout semantics SHALL remain unchanged by the envelope migration.

#### Scenario: Frontend login after migration
- **WHEN** the frontend receives a successful login response
- **THEN** it obtains the public user from `data.user` inside the JSON envelope and continues using the existing cookie authentication
- **AND** failure handling reads `error.code` and `error.message`
