From 98b615b6fcfc13711e3719be005b982e55d63832 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Thu, 20 Aug 2026 12:42:23 +0330 Subject: [PATCH] docs: approve modular monolith architecture --- docs/DATA-FOUNDATION-SPEC.md | 16 +++++++++------- docs/decisions/0001-modular-monolith.md | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 docs/decisions/0001-modular-monolith.md diff --git a/docs/DATA-FOUNDATION-SPEC.md b/docs/DATA-FOUNDATION-SPEC.md index d11a25c..2133dcd 100644 --- a/docs/DATA-FOUNDATION-SPEC.md +++ b/docs/DATA-FOUNDATION-SPEC.md @@ -146,11 +146,13 @@ This ERD is a logical baseline, not an approved physical schema. In particular, ## Approval gates / unresolved decisions -1. Go architecture style: vertical-slice/modular monolith, hexagonal, clean architecture, or another preference. -2. Dependency injection: manual constructor injection, compile-time/runtime DI library, or none. -3. PostgreSQL access stack: ORM choice plus a bulk-ingest path suitable for 2.2M+ rows. -4. Source timestamp timezone and daylight-saving assumptions. -5. Whether `payer_card_key` must be retained, irreversibly transformed, or omitted after derived analytics. -6. Minimum cohort size and suppression policy for peer benchmarks. -7. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone. +Resolved: use a capability-oriented modular monolith, with lightweight ports/adapters at external boundaries such as PostgreSQL and AvalAI. See ADR 0001. +Remaining approval gates: + +1. Dependency injection: manual constructor injection, compile-time/runtime DI library, or none. +2. PostgreSQL access stack: ORM choice plus a bulk-ingest path suitable for 2.2M+ rows. +3. Source timestamp timezone and daylight-saving assumptions. +4. Whether `payer_card_key` must be retained, irreversibly transformed, or omitted after derived analytics. +5. Minimum cohort size and suppression policy for peer benchmarks. +6. Physical partitioning/materialization strategy, which must follow measured query needs rather than the logical ERD alone. diff --git a/docs/decisions/0001-modular-monolith.md b/docs/decisions/0001-modular-monolith.md new file mode 100644 index 0000000..3701d2f --- /dev/null +++ b/docs/decisions/0001-modular-monolith.md @@ -0,0 +1,23 @@ +# ADR 0001: Capability-oriented modular monolith + +- Status: Accepted +- Date: 2026-08-20 + +## Context + +The backend must support ingestion, merchant identity, deterministic analytics, authenticated APIs, and a later AvalAI integration. The hackathon needs fast delivery, while a production continuation needs explicit boundaries and independent testability. A distributed service architecture would add deployment and consistency costs before traffic or ownership evidence justifies them. + +## Decision + +Build one Go modular monolith organized by business capability. Identity, data foundation, analytics, merchant API, and later AI assistance own their internal models and behavior. Cross-capability calls use explicit package contracts. Lightweight ports/adapters isolate external systems such as PostgreSQL, AvalAI, clocks, and credential/session infrastructure where substitution or deterministic testing provides concrete value. + +Runnable concerns such as the HTTP API, importer, migrations, and optional analytics jobs may have separate thin commands under `cmd/` while sharing the same internal modules and release artifact lineage. + +## Consequences + +- One repository, database boundary, and release train keep development and operations simple. +- Capability boundaries remain visible and can be extracted later if measured scaling or ownership needs justify it. +- Packages must not bypass module contracts through shared mutable state or an unrestricted generic `utils`/`models` layer. +- Ports are introduced at real external or volatile boundaries, not around every function. +- This decision does not choose dependency injection, HTTP routing, ORM/database access, or background-job libraries; those remain separate approval decisions. +