Architecture Decisions

evergreenLast update on Sep 1, 2026
Download .md

Architecture Decisions

Record major decisions here. Keep entries short and update them when the decision changes.

ADR-001: Contract-First Development

  • Status: accepted
  • Decision: packages/contracts/openapi.yaml is the API source of truth.
  • Why: backend, web, and mobile must stay synchronized.
  • Consequence: generated clients are required; handwritten duplicate API types are forbidden.

ADR-002: Modular Monorepo

  • Status: accepted
  • Decision: keep backend, web, mobile, contracts, infra, and docs in one repository.
  • Why: vertical slices often span all platforms.
  • Consequence: ownership boundaries must be directory-based and enforced in review.

ADR-003: Append-Only Asset Events

  • Status: accepted
  • Decision: asset history is stored as immutable events.
  • Why: receiving, correction, handoff, and audit flows need traceability.
  • Consequence: current state is derived; corrections are new events.

ADR-004: Idempotent Event Sync

  • Status: accepted
  • Decision: event ingest deduplicates by client-minted event_id.
  • Why: mobile writes must tolerate offline retry and network timeouts.
  • Consequence: backend insert uses conflict-safe behavior.

ADR-005: Backend Enforces Authorization

  • Status: accepted
  • Decision: backend is the final authorization boundary.
  • Why: web and mobile controls can be bypassed.
  • Consequence: every protected endpoint needs authorization tests.

ADR-006: Generated API Clients

  • Status: accepted
  • Decision: generate TypeScript and Dart clients from OpenAPI.
  • Why: shared API types must not drift.
  • Consequence: generated output is checked in or generated consistently by CI, but never hand-edited.

ADR-007: POC Is Reference, Not Product Architecture

  • Status: accepted
  • Decision: reference/mobile_app_demo documents proven workflow behavior, not final module structure.
  • Why: the POC has useful domain learning but lacks production architecture.
  • Consequence: port behavior intentionally into apps/mobile instead of copying limitations.