Files
minerops/docs/tasks/005-repair-parts-tracking.md
T

190 lines
6.0 KiB
Markdown

# Task 005: Repair Parts Tracking
## Status
Design specification. Not yet implemented.
## Objective
Allow authorized operators to record parts installed, removed, or consumed
during a repair while preserving immutable history and leaving room for a later
spare-parts inventory system.
## Product Intent
A technician should be able to determine what parts were installed, removed, or
consumed; their quantity and identifying serial number where relevant; any
concise notes; and the authoritative actor and timestamp.
## Scope
- proposed focused repair-part read and action APIs
- proposed capability-based permissions
- a deliberately small part type and action vocabulary
- part type, action, quantity, optional serial number, and notes
- serialized component identifiers where applicable
- explicit void/correction rather than physical deletion
- immutable repair events
- migration, constraints, tests, and documentation
## Out of Scope
Purchasing, suppliers, pricing, invoices, warehouse transfers, reorder automation, warranties, RMA, full inventory, generalized bill of materials, bulk import, automatic stock deduction, photos, work orders, and control-board identity replacement.
Task 004 remains authoritative for control-board identity and MAC changes.
Task 005 must not accept `control_board` as a generic part type or update
`miners.control_board_sn`, `miners.current_mac`, or
`miner_network_identities`.
## API
Proposed routes:
```http
GET /api/repairs/{repair_id}/parts
POST /api/repairs/{repair_id}/parts
POST /api/repairs/{repair_id}/parts/{repair_part_id}/void
```
Do not physically delete authoritative entries.
## Permissions
The proposed authorization model is:
- use implemented `repairs.read` for the read route
- introduce `repairs.parts.manage` for add and void actions
Grant the proposed write permission to Admin, Manager, and Technician. Do not
grant it to Read Only. `repairs.parts.manage` does not exist yet and must be
introduced by the Task 005 migration. The router checks capabilities rather than
role names.
## Add Request
```json
{
"part_type": "fan",
"action": "installed",
"quantity": 1,
"serial_number": null,
"notes": "Replacement fan installed."
}
```
## Initial Vocabulary
Proposed part types:
- `fan`
- `power_supply`
- `hashboard`
- `cable`
- `consumable`
- `other`
Proposed actions:
- `installed`
- `removed`
- `consumed`
Task 005 does not model source inventory, stock movement, return destination,
condition, or disposition. Those concepts require a later inventory decision
and must not be approximated with overlapping action/value combinations here.
Use notes for concise context that is not authoritative structured inventory
data.
## Quantity Rules
- quantity greater than zero
- integer quantities for this task
- serialized components normally quantity 1
- consumables may exceed 1
- voiding does not create a negative entry or reverse inventory; it marks the
original record void
## Repair State Rules
- add entries only while the repair is active
- void entries only while the repair is active
- read entries and void state after completion
- completed repairs remain read-only
- no unrestricted editing in any repair state
## Data Model
Proposed table: `repair_parts`. No such table currently exists. The legacy
`/api/repairs/parts-summary` route summarizes generic maintenance-event data and
is not an implementation of this model.
Potential fields:
- UUID
- repair UUID
- part type
- action
- quantity
- serial number
- notes
- recorded actor and timestamp
- void actor, timestamp, and reason
- related event UUID
Entries are never physically deleted. A void changes only the one-way void
metadata. It must not edit the original part type, action, quantity, serial
number, notes, recording actor, or recording timestamp. The void reason is
required; void actor and timestamp come from authentication and the server.
## Constraints
- quantity > 0
- void fields all-null or all-present
- void timestamp after recorded timestamp
- actor and recorded timestamp required
- valid constrained values and combinations
- serialized entries with a serial number have quantity 1
## Events
Proposed types:
- `REPAIR_PART_RECORDED`
- `REPAIR_PART_VOIDED`
The events are immutable history; the table is the queryable projection.
## Atomicity
Adding a part and appending its event occur in one transaction. Voiding and appending the void event occur in one transaction.
Voiding must lock the repair-part row and succeed only when its void fields are
still null. Concurrent void requests must produce one success and one conflict,
with exactly one `REPAIR_PART_VOIDED` event.
## Architecture
Preserve `Router -> Service -> Repository -> PostgreSQL`. No generic parts CRUD, router SQL, or physical deletion.
## Tests
Cover:
- authorization
- serialized and consumable entries
- removed part
- list chronology
- read after completion
- explicit void
- invalid quantities and combinations
- control-board part rejection
- add to completed repair
- already-voided conflict
- cross-repair entry conflict
- concurrent void
- rollback on event failure
- direct constraints
- Tasks 001-004 regressions
- migration lifecycle and full backend suite
## Migration
Create the focused table, add permissions and event constraints, add justified indexes, preserve legacy truth, and refuse destructive downgrade when authoritative Task 005 history exists.
## Acceptance Criteria
1. Parts can be recorded against an active repair.
2. Historical entries remain readable.
3. Entries are never physically deleted.
4. Voids are explicit and audited.
5. Actor and timestamps are authoritative.
6. Writes and events are atomic.
7. Values and quantities are constrained.
8. No warehouse or purchasing system is introduced.
9. Task 004 remains authoritative for control-board identity changes.
10. No commit or push is performed.
## Completion Report
Report files, migration, routes, permissions, schema, constraints, events, tests, migration lifecycle, architecture audit, limitations, and final status.
Do not commit.
Do not push.