Files
minerops/docs/CODING_STANDARDS.md

5.8 KiB

MinerOps Coding Standards

Purpose

This document defines the engineering conventions for MinerOps. Task specifications may add feature-specific requirements, but they should not weaken these standards without an explicit architectural decision.

Core Principles

  1. Prefer explicit domain operations over generic CRUD.
  2. Preserve operational history.
  3. Enforce critical invariants in PostgreSQL.
  4. Keep operations atomic.
  5. Separate network identity from durable asset identity.
  6. Use server-controlled timestamps and authenticated actor identities.
  7. Design for self-hosted deployment and safe recovery.
  8. Prefer clear, maintainable code over clever abstractions.
  9. Keep each implementation task focused and reviewable.
  10. Treat safety as more important than convenience for actions affecting miners.

Layered Architecture

Router
  -> Service
    -> Repository
      -> PostgreSQL

Router

Routers may define HTTP routes, validate requests, enforce authentication and permissions, and serialize responses.

Routers must not contain SQL, manage transactions, implement domain decisions, import database drivers directly, or bypass the service layer.

Service

Services implement domain workflows, coordinate repositories, enforce domain rules, and raise domain exceptions.

Services must not import FastAPI, raise HTTP-specific exceptions, contain raw SQL, or trust actor identity supplied in request bodies.

Repository

Repositories own database queries, row locking, persistence details, and PostgreSQL-specific integrity behavior.

Repositories must not import FastAPI, make permission decisions, define HTTP behavior, or commit independently inside a larger service transaction.

Domain Operations

Use explicit operations such as:

POST /api/repairs
POST /api/repairs/{repair_id}/complete
POST /api/miners/{miner_id}/move
POST /api/miners/{miner_id}/replace-control-board

Only POST /api/repairs is implemented by the modular Repairs domain today. The other routes are illustrative names for possible future explicit workflows, not existing API contracts.

Avoid broad mutable CRUD endpoints when the request represents a meaningful operational event.

Transactions and Concurrency

Any workflow that changes multiple authoritative records must execute atomically.

Use row locks and database constraints when concurrent requests could violate an invariant. Do not rely only on pre-insert application checks when PostgreSQL can enforce the rule.

Database Integrity

Use constraints for uniqueness, valid state combinations, referential integrity, one-active-record rules, event-sequence integrity, and actor/timestamp requirements.

Operational history should generally use RESTRICT rather than disappearing through cascades.

Every migration must support upgrade, safe downgrade or explicit refusal, previous-head testing, re-upgrade, and empty-database-through-head validation. A downgrade must never invent historical values.

Identity

A miner's durable identity must not depend on its current IP address, MAC address, control board, hostname, or location.

Network identifiers are observations or replaceable hardware attributes and must retain history.

Actor identity must come from the authenticated principal, never an authoritative request-body field.

Time

Use timezone-aware timestamps. Authoritative operational timestamps are server- or database-controlled. Never use timestamp order as a substitute for an explicit event sequence.

Immutable Operational History

Timeline and audit events are append-only. Once written, an event is never edited, deleted, reordered, or silently replaced. Corrections are new events.

Sequenced domain timeline events should include an event UUID, parent UUID, sequence, event type, actor UUID, timestamp, and structured JSON payload.

API Design

  • Use UUID types for UUID fields.
  • Use constrained domain values.
  • Use 404 for missing resources, 409 for state conflicts, 422 for invalid input, and established project behavior for 401 and 403.
  • Do not expose internal fields without a product requirement.
  • Keep routes focused.
  • Protect existing static routes when introducing parameter routes.

Permissions

Permissions describe capabilities, not roles. Implemented examples include repairs.read and repairs.create. Names such as repairs.complete and miners.move illustrate possible future capabilities and are not currently registered permissions.

Every protected route requires unauthenticated, unauthorized, and authorized-role tests. Read-only roles may view history but may not perform actions.

Testing and Validation

Feature work should cover happy paths, validation, permissions, missing records, conflicts, rollback, concurrency where relevant, constraints, migrations, route compatibility, and architecture boundaries.

Unless a task says otherwise, run:

  • Python compilation
  • shell syntax validation
  • focused tests
  • relevant regression suites
  • migration upgrade, downgrade, re-upgrade, and empty database
  • disposable development baseline
  • router SQL/driver/transaction audit
  • service/repository FastAPI audit
  • route-count audit
  • git diff --check

Security

Never commit credentials, tokens, environment files, dumps, private configuration, caches, or local database data. Do not log secrets. Apply least privilege and preserve audit history for sensitive actions.

Documentation

Every implementation task should have a version-controlled specification under docs/tasks/. Update roadmaps only after validation passes. Add an ADR only for a genuinely new architectural principle.

Review Checklist

Before approval, confirm scope, transaction boundaries, database invariants, actor attribution, timestamps, immutable history, permissions, migrations, regressions, route behavior, performance risks, and the reviewed file set.