4.9 KiB
Task 002: Repair Timeline
Objective
Add read-only APIs for viewing one repair and its immutable timeline.
Scope
Add exactly these two endpoints:
GET /api/repairs/{repair_id}
GET /api/repairs/{repair_id}/events
Do not add any other repair endpoints.
Permissions
Add:
repairs.read
Grant it to Admin, Manager, Technician, and Read Only. Existing repairs.create access remains unchanged.
Architecture
Preserve:
Router -> Service -> Repository -> PostgreSQL
Routers contain no SQL or transaction logic. Services contain no FastAPI dependencies. Repositories contain no FastAPI imports. Reads must not modify data.
GET /api/repairs/{repair_id}
Return:
{
"repair_id": "uuid",
"miner_id": "uuid",
"miner_asset_id": "string",
"status": "OPEN",
"reason": "INSPECTION",
"opened_at": "timestamp",
"opened_by": {
"user_id": "uuid",
"display_name": "string"
},
"closed_at": null,
"closed_by": null,
"miner_lifecycle": "in_repair",
"latest_event_sequence": 2
}
Requirements:
- Return 404 when the repair does not exist.
- Return the current miner lifecycle.
- Resolve actor identity using existing user conventions.
- Obtain
latest_event_sequencefrom authoritative event data. - Do not infer missing history or expose internal-only fields.
GET /api/repairs/{repair_id}/events
Return:
{
"repair_id": "uuid",
"events": [
{
"event_id": "uuid",
"sequence": 1,
"event_type": "REPAIR_STARTED",
"actor": {
"user_id": "uuid",
"display_name": "string"
},
"occurred_at": "timestamp",
"payload": {
"reason": "INSPECTION",
"from_lifecycle": "active",
"to_lifecycle": "in_repair"
}
}
]
}
Requirements:
- Return 404 when the repair does not exist.
- Return all events ordered strictly by database sequence ascending.
- Do not order only by timestamp.
- Preserve payload as structured JSON.
- Avoid N+1 actor lookups.
Timeline Invariants
Events are immutable. This task must not add support for editing, deleting, replacing, or reordering timeline events. Corrections must be represented by new events.
Models and Validation
- Use UUID types for identifiers.
- Use timezone-aware datetime types.
- Reuse existing constrained status, reason, lifecycle, and event types where practical.
- Represent payloads as structured JSON, not serialized strings.
- Avoid exposing unexpected internal fields.
Repository Requirements
Add focused read methods for repair detail and ordered repair events. Queries should include miner asset ID, current lifecycle, actor display data, and latest event sequence. Do not add broad list or search methods.
Service Requirements
The service must validate existence, coordinate repository reads, map missing repairs to the domain-standard not-found exception, and contain no SQL or FastAPI dependencies.
Router Requirements
Expose exactly the two routes in this specification, require repairs.read, follow existing exception patterns, and contain no SQL, commits, or transaction management.
Migration
Create the next Alembic revision only if required to add repairs.read and role assignments. Preserve existing permissions and provide a complete downgrade. Do not alter repair tables unless a material incompatibility is found; report that conflict before deviating.
Tests
Cover at least:
- 401 unauthenticated
- 403 unauthorized
- Read Only can read detail and events
- Admin, Manager, and Technician can read
repairs.createbehavior remains unchanged- existing repair detail
- missing repair 404
- asset ID, lifecycle, actor, nullable closed fields, and latest sequence
- sequence ordering even when timestamps are equal or non-monotonic
- structured JSON payload
- actor data
- explicit empty-timeline behavior
- Begin Repair regression
- Inventory regression
- migration upgrade, downgrade, re-upgrade, and empty database through head
- exactly two new routes
- architecture audits
Validation
Run:
- Python compilation
- shell syntax validation
- focused timeline tests
- existing Begin Repair tests
- inventory regression tests
- migration validation
- disposable development baseline
- router SQL/driver/transaction audit
- service/repository FastAPI audit
- exact route-count audit
git diff --check
Documentation
Update docs/ROADMAP.md only after implementation and validation pass. Do not add an ADR unless a genuinely new architectural decision is required.
Explicitly Out of Scope
Do not implement repair listing, search, pagination, adding or editing notes, deleting events, completion, return to service, cancellation, assignment, diagnostics, parts, photos, control-board replacement, generic CRUD, or UI changes.
Completion Report
Report files created and modified, migration revision if any, routes, permission changes, tests and validation, and final git status --short.
Do not commit. Do not push.