docs: add component domain model
This commit is contained in:
1 parent
bcf1b4e3cf
commit
73f98685ce
1 file changed
+457
@@ -0,0 +1,457 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user