Files
minerops/docs/design/COMPONENT_DOMAIN_MODEL.md
T

458 lines
13 KiB
Markdown

# MinerOps Component Domain Model
## Status
Proposed design baseline for tracked physical components. The generalized
component model, tables, routes, permissions, lifecycles, and events described
here are not currently implemented. Task 004's implemented control-board
replacement structures and behavior remain authoritative.
## Purpose
MinerOps should represent important physical parts as durable entities with their own identity, installation history, condition, location, and repair relationships.
A miner remains the durable parent asset. Replacing a control board, hashboard, PSU, fan, or other component must not create a new miner or erase prior history.
## Design Principles
- Model meaningful physical objects when tracking them creates operational value.
- Give every individually tracked component an immutable UUID.
- Separate internal UUID, human Asset ID, and manufacturer identifiers.
- Preserve installation, movement, repair, and disposition history.
- Keep current-state projections fast without treating them as historical truth.
- Add complexity progressively rather than requiring full warehouse management.
## Core Model
### Component
The base durable identity for an individually tracked physical part.
Conceptual fields:
- immutable UUID
- optional human Asset ID
- component type
- manufacturer
- model
- manufacturer serial
- lifecycle
- condition
- notes
- creation and retirement metadata
A component type should not change after meaningful operational history exists.
### Specialized Components
Use type-specific tables only where structured attributes or rules justify them.
The following names are conceptual and do not reserve future table names:
```text
components
├── control_boards
├── hashboards
├── power_supplies
├── fans
└── cables
```
Examples:
- Control board: model, hardware revision, firmware, and relationships to the
implemented Task 004 installation and MAC history. A specialization must not
create competing MAC history.
- Hashboard: serial, revision, nominal hashrate, chip count.
- PSU: serial, model, rated power, voltage range.
- Fan: model, dimensions, connector, rated RPM.
Many simple parts may remain quantity-based rather than individually tracked.
## Identity
Every tracked component may have:
1. **Internal UUID**: immutable database and API identity.
2. **Human Asset ID**: operator-facing label such as `CB-00183`.
3. **Manufacturer identity**: serial, MAC, QR code, PCB identifier, or firmware-reported value.
Manufacturer values help identify a component but do not define its durable identity.
## Component Installation
A Component Installation records where a component was installed over time.
Conceptual fields:
- installation UUID
- component UUID
- miner UUID
- component slot
- installed timestamp and actor
- related repair
- removed timestamp and actor
- removal disposition
- notes
A current installation has no removal timestamp.
### Invariants
- A component has at most one current installation.
- It cannot be installed in two miners simultaneously.
- A miner cannot have conflicting components in an exclusive slot.
- Removal occurs after installation.
- Unknown legacy actor or timestamp values remain unknown.
- Historical installations are not physically deleted.
## Component Slots
Examples:
```text
control_board
hashboard_1
hashboard_2
hashboard_3
power_supply
front_fan_1
rear_fan_1
```
Slots may later be constrained by miner model or hardware profile.
## Lifecycle and Condition
Lifecycle and condition are different concepts.
Candidate lifecycle values:
- available
- installed
- under_repair
- quarantined
- sent_for_rma
- retired
- scrapped
- lost
- unknown
Candidate condition values:
- new
- working
- used
- repaired
- untested
- failed
- damaged
- unknown
Only introduce values when the corresponding workflows exist.
## Locations
A component may be:
- installed in a miner
- stored at a site, room, rack, shelf, or bin
- on a repair bench
- in transit
- with a vendor
- in RMA
Installed components normally inherit physical location from the miner. Uninstalled components require location history.
A component must not simultaneously have an incompatible current installation and current storage location.
## Events
Component history is append-only.
Candidate events:
- component created
- Asset ID changed
- installed
- removed
- moved
- condition changed
- repair started
- repair completed
- sent for RMA
- returned from RMA
- retired
- scrapped
The implemented `CONTROL_BOARD_REPLACED` event remains valid. It does not
currently contain a generalized component UUID. A later migration may add
component or installation references only when those identities exist
authoritatively; it must not reconstruct or invent them for older events.
Do not duplicate the same authoritative event across unrelated streams. One event may appear in several read models.
## Current Projections
Implemented Task 004 current-state projections are:
```text
miners.current_mac
miners.control_board_sn
```
`miners.firmware_version` is an existing miner field, but Task 004 records the
replacement firmware on the installation and does not update that miner field.
Possible generalized component projections include:
```text
components.lifecycle_status
components.current_location_id
```
Projection updates must occur in the same transaction as authoritative history. Constraints or deferred checks should prevent drift.
## Repairs and Components
Repairs and components are related but distinct.
- A repair belongs to one miner.
- A component may move through several miners.
- A component may appear in many repair histories.
- A repair event may reference a component or installation.
- The repair timeline explains what happened in that repair.
- The component history explains the component's lifetime.
## Parts Versus Components
Not every part needs an individual UUID.
### Individually tracked
Appropriate for:
- control boards
- hashboards
- PSUs
- expensive or serialized fans
- specialty harnesses
- tagged network hardware
### Quantity-based
Appropriate for:
- screws
- thermal pads
- connectors
- common cables
- cleaning supplies
- untracked fans
Task 005 remains a focused quantity-based repair record and does not require a
generalized component inventory. Whether it may optionally reference an
existing tracked component is an open decision for its implementation; it must
not create or infer component identity automatically.
## Donor Components
A component moved from Miner A to Miner B retains the same UUID.
```text
Installed in Miner A
Removed from Miner A
Stored or repaired
Installed in Miner B
```
Never clone the component record merely because ownership or location changes.
## Unknown Components
A component may be tracked without a known serial, Asset ID, exact installation date, or complete history. Unknown values remain null or explicitly unknown. Do not fabricate identifiers or dates.
## MAC Identity
A control board MAC is a mutable manufacturer/network identifier.
- It does not define the miner.
- It does not define the component UUID.
- Current and historical ownership remain searchable.
- Automatic transfer between durable miners is prohibited.
- Conflict resolution is explicit.
- Ownership, network association, and installation history must not drift.
Implemented Task 004 structures remain authoritative until an explicit,
history-preserving migration generalizes them:
- `miners.current_mac` and `miners.control_board_sn` are current projections.
- `miner_network_identities` stores current and historical network associations.
- `miner_mac_ownerships` prevents normalized MAC ownership from silently moving
between durable miners.
- `miner_control_board_installations` preserves installation and removal
history and enforces one current board per miner.
- `repair_events` stores the immutable, sequenced `CONTROL_BOARD_REPLACED` fact.
Task 004 requires the miner to be `in_repair`, requires one active repair, and
updates these records in one transaction. Deferred database checks keep the
current miner, installation, and network-identity projections aligned. Legacy
unknown actors and installation timestamps remain null.
## Permissions
Candidate capabilities:
```text
components.read
components.create
components.update_metadata
components.install
components.remove
components.move
components.change_condition
components.retire
components.scrap
components.rma.manage
```
`miners.replace_control_board` is implemented for Task 004 and is granted to
Admin, Manager, and Technician, but not Read Only. Task 005 proposes
`repairs.parts.manage`; it is not implemented. The candidate component
capabilities above remain future concepts.
## Transactions
Every future generalized component operation must own one transaction. Task 004
already performs its control-board replacement as one transaction.
### Install
- lock miner and component
- validate lifecycle and slot
- close prior installation only through an explicit replacement
- create installation
- update projections
- append event
### Remove
- lock component and current installation
- close installation
- update projections and location/lifecycle
- append event
### Move
- close current location
- create new location
- update projection
- append event
## Lock Ordering
Implemented repair and control-board workflows use:
```text
Miner -> Repair -> related component, network-identity, and ownership rows
```
Before generalized component workflows are implemented, define one global order across Miner, Component, Repair, Installation, and Location. No task should introduce a conflicting lock order without review.
## Database Invariants
Where practical, enforce:
- an explicitly decided Asset ID uniqueness scope when Asset IDs are introduced
- one current installation per component
- one component per exclusive miner slot
- installation chronology
- no incompatible installation and storage location
- constrained lifecycle and condition values
- immutable MAC ownership across durable miners
- actor and timestamp requirements for new rows
- history-preserving foreign keys
Use legacy-safe constraints where historical truth is incomplete.
## API Principles
Implemented Task 004 operation:
```http
POST /api/miners/{miner_id}/replace-control-board
```
The legacy `POST /api/miners/{miner_id}/change-mac` route is a compatibility
alias that uses the same permission and Task 004 service workflow.
Possible future explicit operations include:
```http
POST /api/miners/{miner_id}/components/{component_id}/install
POST /api/components/{component_id}/remove
POST /api/components/{component_id}/move
POST /api/components/{component_id}/retire
```
Avoid generic ownership or lifecycle patches for meaningful operations.
## Relationship to Task 004
Task 004 is the first implemented component-history workflow. Its route requires
`miners.replace_control_board`, an active repair, and miner lifecycle
`in_repair`.
Do not immediately rewrite it into a generic framework. Generalize only when Task 005 or later work proves a shared abstraction and a safe migration path.
## Relationship to Task 005
Task 005 should:
- record repair parts
- support quantity-based consumables
- remain usable without generalized component inventory
- reference an existing tracked component only if that optional relationship is
explicitly approved during Task 005 implementation
- preserve explicit void/correction history
- leave control-board identity changes under Task 004
- avoid warehouse, purchasing, vendor, and supplier scope
## Future Directions
This model can later support:
- spare-parts inventory
- vendors and purchasing
- warranty and RMA
- donor units
- test benches and results
- QR/barcode labels
- costs
- failure analytics
- predictive maintenance
These are future directions, not present commitments.
## Open Product Decisions
Before generalized component inventory is implemented, decide:
1. Which component types require individual tracking?
2. Are human Asset IDs required for each type?
3. Can technicians create components during repair work?
4. Can installation occur before a formal inventory record exists?
5. Which types require serial numbers?
6. How are donor miners represented?
7. What is the global lock order?
8. How does a removed component move to available, under repair, or scrapped?
9. Are component repairs separate records or work orders?
10. How will Task 004 history migrate into generalized components?
11. Do component Asset IDs share the miner Asset ID namespace or use a separate
uniqueness scope?
12. Should Task 005 accept an optional tracked-component UUID, or remain limited
to its approved quantity, type, and serial fields?
## Decision Test
A component feature should help identify, locate, repair, install, move, preserve history for, or prevent conflicting ownership of a physical part. Interesting data alone is not enough.