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

6.0 KiB

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:

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

{
  "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.