458 lines
13 KiB
Markdown
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.
|