docs: add architecture decision records
This commit is contained in:
1 parent
7280f1dfea
commit
93e034ea07
1 file changed
+372
@@ -0,0 +1,372 @@
|
||||
# MinerOps Architecture & Product Decisions
|
||||
|
||||
This document records long-lived engineering and product decisions for
|
||||
MinerOps. Each record explains the context, the chosen approach, and its
|
||||
consequences so future work can preserve intent rather than infer it from code.
|
||||
|
||||
Decisions may evolve as operational evidence changes. Replacing or reversing a
|
||||
decision should be deliberate and documented in a later record. Existing
|
||||
records should remain available as history rather than being silently rewritten.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0001
|
||||
|
||||
**Title:** MinerOps is self-hosted first.
|
||||
|
||||
## Context
|
||||
|
||||
Mining operations depend on local equipment, segmented networks, and
|
||||
operational records that may need to remain under direct organizational control.
|
||||
Requiring a hosted service would make availability, data access, and subscription
|
||||
terms dependencies of core operations.
|
||||
|
||||
External services can still provide useful integrations. The question is
|
||||
whether they are optional participants or mandatory owners of the operational
|
||||
record.
|
||||
|
||||
## Decision
|
||||
|
||||
MinerOps is self-hosted first. Operators control the deployment and retain
|
||||
ownership of their operational data. Core use must not require a mandatory SaaS
|
||||
subscription or transfer the authoritative record to a hosted provider.
|
||||
|
||||
Remote access and integrations are allowed when the operator chooses them. They
|
||||
must not change the self-hosted deployment into a secondary cache of a required
|
||||
external service.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Operators can place MinerOps near local mining networks, retain
|
||||
control of data and availability, and use it in restricted environments.
|
||||
|
||||
**Tradeoffs:** Operators are responsible for deployment, updates, backups, and
|
||||
recovery. Optional hosted integrations must be designed so loss of the
|
||||
integration does not remove ownership of the core record.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0002
|
||||
|
||||
**Title:** Assets use durable internal identity.
|
||||
|
||||
## Context
|
||||
|
||||
A miner's observable properties change during normal operations. IP addresses
|
||||
change, network interfaces and control boards are replaced, equipment moves,
|
||||
and operator-facing labels may be corrected. None of those changes should make
|
||||
the asset appear to be a different historical object by default.
|
||||
|
||||
Operators also need a practical label that can be printed, scanned, and used in
|
||||
conversation without exposing an internal database key.
|
||||
|
||||
## Decision
|
||||
|
||||
Every miner asset has an immutable internal UUID. That UUID is the durable
|
||||
identity used for relationships and history.
|
||||
|
||||
The Asset ID is the operator-facing identifier. It is unique within a MinerOps
|
||||
installation and can be managed independently of mutable network values. IP
|
||||
addresses, MAC addresses, hardware serials, and location are attributes or
|
||||
associations of the asset, not substitutes for its internal identity.
|
||||
|
||||
Hardware replacement does not automatically create a new asset identity. The
|
||||
correct outcome depends on whether the operation represents repair of the same
|
||||
asset or introduction of a genuinely different asset, and that distinction must
|
||||
be explicit.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Records can remain connected through network changes, movement,
|
||||
and component replacement. Internal relationships do not depend on a mutable or
|
||||
human-entered value.
|
||||
|
||||
**Tradeoffs:** Imports, discovery, and repair workflows must resolve observations
|
||||
to an existing UUID or deliberately create a new asset. Duplicate resolution
|
||||
cannot safely rely on IP or MAC alone.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0003
|
||||
|
||||
**Title:** Network identity is not asset identity.
|
||||
|
||||
## Context
|
||||
|
||||
Discovery observes devices through IP addresses, MAC addresses, hostnames, and
|
||||
protocol responses. These values are useful for finding and communicating with
|
||||
a miner, but they can change because of DHCP, network reconfiguration, control
|
||||
board replacement, or data correction.
|
||||
|
||||
Treating the latest network observation as the asset identity loses continuity
|
||||
and can attach history to the wrong equipment.
|
||||
|
||||
## Decision
|
||||
|
||||
Network identities are associated with durable assets. Current IP and MAC values
|
||||
represent the latest known network state, while meaningful prior associations
|
||||
should remain available as history.
|
||||
|
||||
Discovery proposes or updates associations; it does not redefine the asset
|
||||
solely because an address changed. Ambiguous matches require a deliberate
|
||||
identity workflow rather than silent merging or replacement.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Discovery can remain useful without erasing asset continuity.
|
||||
Operators can understand address changes and component replacement in historical
|
||||
context.
|
||||
|
||||
**Tradeoffs:** Matching requires more information and explicit conflict handling.
|
||||
Some observations cannot be attached automatically, and network history adds
|
||||
records that must be maintained and presented clearly.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0004
|
||||
|
||||
**Title:** Business logic belongs in services.
|
||||
|
||||
## Context
|
||||
|
||||
When business rules are implemented in HTTP handlers, they become coupled to a
|
||||
transport and are difficult to reuse or test. When they are placed in database
|
||||
code, persistence concerns become mixed with product decisions.
|
||||
|
||||
MinerOps has existing integrated routes that predate the current domain
|
||||
boundaries. Copying that structure would continue the coupling.
|
||||
|
||||
## Decision
|
||||
|
||||
Domain services own normalization, business validation, decisions, state-change
|
||||
rules, and use-case orchestration. Routers handle HTTP concerns and call
|
||||
services. Repositories persist the outcomes requested by services.
|
||||
|
||||
Services raise domain errors and return domain results. They do not depend on
|
||||
FastAPI requests, responses, decorators, or status codes. The Inventory service
|
||||
is the current reference for this separation.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Business behavior can be tested without HTTP or a real database,
|
||||
used by more than one adapter, and maintained in one explicit location.
|
||||
|
||||
**Tradeoffs:** Features require an additional boundary and clear input and output
|
||||
contracts. Poorly chosen service responsibilities can become overly broad, so
|
||||
service ownership must follow domain use cases rather than convenience.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0005
|
||||
|
||||
**Title:** Persistence is isolated behind repositories.
|
||||
|
||||
## Context
|
||||
|
||||
SQL embedded in routes or services couples product behavior to schema details,
|
||||
connection handling, and a specific database driver. Repeated queries also make
|
||||
ownership unclear and allow filtering or transaction behavior to diverge.
|
||||
|
||||
Tests need a boundary where service behavior can substitute persistence and
|
||||
where database behavior can be verified independently.
|
||||
|
||||
## Decision
|
||||
|
||||
Each domain isolates its database access behind repositories. Repositories own
|
||||
SQL, database-facing filtering and ordering, connection and transaction
|
||||
mechanics, and persistence mapping.
|
||||
|
||||
Routers and services do not issue SQL. A domain owns persistence for its records,
|
||||
and another domain does not bypass that ownership by importing its repository
|
||||
to perform unrelated writes.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** SQL has explicit ownership, service tests can use substitutes,
|
||||
repository tests can target real database behavior, and persistence changes have
|
||||
a defined boundary.
|
||||
|
||||
**Tradeoffs:** Repository interfaces must be maintained, and cross-domain read
|
||||
requirements need deliberate query ownership. A repository is not an excuse to
|
||||
hide business rules in database code.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0006
|
||||
|
||||
**Title:** Database schema changes use Alembic.
|
||||
|
||||
## Context
|
||||
|
||||
Persistent schema must be reproducible across new installations, existing
|
||||
deployments, tests, and recovery environments. Runtime table creation makes
|
||||
schema state depend on which application paths have executed and is difficult
|
||||
to review or reverse.
|
||||
|
||||
The existing application contains legacy runtime schema creation for
|
||||
compatibility, but the repository now has a versioned Alembic migration chain
|
||||
and focused migration tests.
|
||||
|
||||
## Decision
|
||||
|
||||
New persistent schema changes are made through explicit, versioned Alembic
|
||||
migrations. A migration documents upgrade behavior, treatment of existing data,
|
||||
constraints and indexes, and a downgrade path where it is safe and meaningful.
|
||||
|
||||
New code must not create or alter persistent tables at application runtime.
|
||||
Legacy runtime schema behavior is an existing compatibility condition, not a
|
||||
pattern for new work.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Schema state is reviewable, reproducible, testable, and ordered.
|
||||
Deployments and disposable tests can reach the same known schema from an empty
|
||||
or existing database.
|
||||
|
||||
**Tradeoffs:** Schema work requires migration design and validation before the
|
||||
application can use it. Some destructive downgrades cannot preserve all data and
|
||||
must be documented explicitly.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0007
|
||||
|
||||
**Title:** Operational history is preserved.
|
||||
|
||||
## Context
|
||||
|
||||
The current value of an asset does not explain how it arrived there. Repairs,
|
||||
movement, lifecycle changes, network identity changes, component replacement,
|
||||
and operator actions all affect operational understanding.
|
||||
|
||||
Overwriting important changes may simplify the current record but removes the
|
||||
context technicians and managers need to diagnose problems and trust the
|
||||
system.
|
||||
|
||||
## Decision
|
||||
|
||||
MinerOps preserves meaningful operational history. Current state remains easy
|
||||
to identify, while important repairs, movement, lifecycle events, identity
|
||||
associations, and audited actions remain traceable with time and context.
|
||||
|
||||
Corrections must not silently destroy history that remains operationally
|
||||
relevant. Retention policy may summarize high-volume observations, but durable
|
||||
asset, repair, movement, lifecycle, and audit meaning is preserved.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Operators can understand an asset across its lifecycle, technicians
|
||||
can review prior work, and changes can be audited and explained.
|
||||
|
||||
**Tradeoffs:** Historical data requires storage, retention policy, and interfaces
|
||||
that distinguish current state from prior state. Corrections and privacy or
|
||||
retention requirements need deliberate handling.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0008
|
||||
|
||||
**Title:** Safety takes precedence over convenience.
|
||||
|
||||
## Context
|
||||
|
||||
MinerOps can coordinate actions that interrupt individual miners or affect a
|
||||
large part of a fleet. A fast or convenient action can create substantial
|
||||
operational impact when its target, scope, timing, or authorization is wrong.
|
||||
|
||||
Bulk operations and automation increase this risk because one request may affect
|
||||
many devices without individual review.
|
||||
|
||||
## Decision
|
||||
|
||||
Potentially disruptive actions favor safety over minimum interaction. Product
|
||||
workflows enforce permissions, communicate target and scope, require clear
|
||||
confirmation where appropriate, and leave an audit trail.
|
||||
|
||||
Broad actions should support safeguards such as preview or dry-run behavior,
|
||||
staggering, limits, expiry, and awareness of maintenance or intentionally
|
||||
offline state when those safeguards apply. Development and new installations
|
||||
use safe defaults.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Operators receive clearer intent and accountability, accidental
|
||||
fleet-wide disruption is less likely, and actions can be investigated after the
|
||||
fact.
|
||||
|
||||
**Tradeoffs:** Some operations require more steps and may complete more slowly.
|
||||
Safety behavior adds product and test complexity and must be maintained rather
|
||||
than bypassed for convenience.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0009
|
||||
|
||||
**Title:** Progressive complexity.
|
||||
|
||||
## Context
|
||||
|
||||
Mining operations vary from small fleets with simple inventory needs to
|
||||
multi-site organizations with detailed infrastructure, automation, and role
|
||||
requirements. Requiring every installation to configure the largest possible
|
||||
model would make basic workflows difficult to adopt and maintain.
|
||||
|
||||
At the same time, limiting the product to the smallest deployment would prevent
|
||||
larger operators from representing their real work.
|
||||
|
||||
## Decision
|
||||
|
||||
MinerOps exposes useful basic workflows without requiring every advanced
|
||||
capability. Operators can begin with the records and structure they need, then
|
||||
adopt additional location depth, monitoring, automation, integrations, and
|
||||
organizational controls as their operation requires them.
|
||||
|
||||
Advanced features remain coherent extensions of the same operational record.
|
||||
They do not create a separate product mode or make basic asset and repair work
|
||||
dependent on unrelated configuration.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Small deployments can gain value with less setup, while larger
|
||||
deployments have room to model additional complexity without abandoning the
|
||||
same system of record.
|
||||
|
||||
**Tradeoffs:** Defaults and optional states must be designed carefully. Features
|
||||
must work when advanced context is absent, which increases the number of valid
|
||||
configurations that testing must cover.
|
||||
|
||||
---
|
||||
|
||||
# ADR-0010
|
||||
|
||||
**Title:** Architecture evolves incrementally.
|
||||
|
||||
## Context
|
||||
|
||||
MinerOps contains working early-stage software alongside newer domain
|
||||
boundaries. Replacing the application in one rewrite would put existing
|
||||
workflows, data compatibility, and validation at unnecessary risk.
|
||||
|
||||
Leaving all existing responsibilities in integrated modules would also make new
|
||||
features harder to test and maintain.
|
||||
|
||||
## Decision
|
||||
|
||||
Architecture improves incrementally. New domain code follows the established
|
||||
router, service, and repository boundaries. Existing behavior moves behind
|
||||
those boundaries in small, reviewable changes that preserve working software
|
||||
and include compatibility validation.
|
||||
|
||||
A new boundary is introduced when it clarifies ownership or testability, not
|
||||
merely to rename or relocate code. Existing integrated code is context to
|
||||
preserve, not a template to duplicate.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Benefits:** Architectural quality improves while the application remains
|
||||
usable. Smaller changes are easier to review, test, diagnose, and reverse.
|
||||
|
||||
**Tradeoffs:** The repository will contain transitional patterns for a period of
|
||||
time. Contributors must understand which code represents current rules and
|
||||
which code remains for compatibility, and some temporary duplication may need
|
||||
careful removal after migration.
|
||||
Reference in new issue
Block a user