docs(standards): mirror doc-forge wiki style; mermaid + copyable build prompt

- move templates into src/templates; renumber wiki pages; add app-components page

- embed agentic build prompt as a copyable markdown block; add mermaid diagrams

- build.py writes <name>/mcp; config static bundle -> standards/mcp

- registry reads libraries.json as bytes (committed file was UTF-16LE); normalize to UTF-8

- Dockerfile: drop stale blog copy; per-repo <name>/mcp copies

- drop nested standards/mcp/standards duplicate and empty root mcp/
This commit is contained in:
2026-10-12 00:21:41 +05:30
parent 9929f05334
commit 06ff5bce6e
80 changed files with 2009 additions and 829 deletions

View File

@@ -1,54 +1,99 @@
# Overview
## Summary
The blueprint is a **hexagonal (ports and adapters) application** with a
The blueprint is a **hexagonal (ports & adapters) application** with a
**spec-first** web edge and a **single composition root**. It favors explicit
wiring over implicit magic, and it prefers existing internal libraries over
hand-written infrastructure.
wiring over implicit magic and existing internal libraries over hand-written
infrastructure. Start here to build the mental model; the enforceable details
live in the reference pages.
---
## The three layers
## 🏗️ Architecture
```
interfaces/ ← HTTP edge: thin handlers bound to an OpenAPI operationId
domain/ ← business core: models, ports (interfaces), services, orchestrators
infra/ ← adapters: databases, caches, external clients, hardware
```mermaid
flowchart LR
subgraph EDGE["interfaces/ — HTTP edge"]
OAS["openapi.yaml<br/>operationId contract"]
RT["<resource>/routes.py<br/>thin handlers"]
end
subgraph CORE["domain/ — pure business core"]
MD["models"]
PT["ports (abstract)"]
SV["services"]
end
subgraph INFRA["infra/ — adapters"]
RP["mongo repos (mongo-ops)"]
AD["cache · stores · llm · mail"]
DB[("MongoDB")]
end
CR["init.py<br/>composition root"]
OAS --> RT
RT --> SV
SV --> PT
SV --> RP
PT -. depends on .- RP
CR --- RT
CR --- SV
CR --- RP
RP --> DB
AD --- CR
```
Plus two optional layers:
The rule holds at every edge: code in an outer ring may depend on a ring closer
to the core, never the reverse. `domain/` never imports a web framework or a
database driver.
```
pipelines/ ← data-driven transformation graphs (extraction, enrichment)
scripts/ ← operator scripts that reuse the composition root
```
> **Legend** — solid arrows are compile-time calls; dotted arrows are the
> port/adapter contract, resolved by the composition root at startup.
## Core principles
---
1. **One-way dependencies.** `interfaces -> domain -> infra` is allowed;
the reverse is forbidden. The domain never imports a framework it does not
own.
2. **Ports in the domain, adapters in infra.** A service depends on an
abstract port; the composition root injects a concrete adapter.
## 🔄 The one-way dependency rule
| Ring | May import | Never imports |
|-------------|------------------------------------|----------------------------------|
| `interfaces/` | `domain`, framework glue (glue only) | business logic, `infra` directly |
| `domain/` | nothing but its own ports | web frameworks, drivers, `infra` |
| `infra/` | `domain` ports, drivers, libraries | — |
| `init.py` | everything (the wiring point) | — |
---
## 🧭 Core principles
1. **One-way dependencies.** `interfaces -> domain -> infra` is allowed; the
reverse is forbidden.
2. **Ports in the domain, adapters in infra.** A service depends on an abstract
port; the composition root injects a concrete adapter.
3. **One composition root.** Nothing constructs its own dependencies. All
wiring lives in one module (`init.py`) and is exposed as a flat resource
registry.
4. **Spec-first.** The HTTP contract is declared in an OpenAPI document. Route
wiring lives in one module (`init.py`) exposed as a flat resource registry.
4. **Spec-first.** The HTTP contract is declared in `openapi.yaml`; route
handlers are looked up by `operationId`. There are no decorator routers.
5. **Reuse the libraries.** Pipeline orchestration, DI, Mongo repositories,
ingestion, auth, and docs are provided by internal libraries. Do not
reimplement them — see the library registry.
5. **Reuse the libraries.** Orchestration, DI, Mongo repositories, ingestion,
auth, and docs come from internal libraries — see the [Library
Registry](../lib/13_library_registry/).
6. **Explicit state machines.** Long-running work moves through explicit,
durable statuses and can pause for human input.
## Runtime processes
---
A standard app may run as up to three processes that share the same
composition root:
## ⚙️ Runtime processes
| Process | Entry point | Responsibility |
|---|---|---|
| API | `main.py` | serve HTTP; start/stop resources via lifespan |
| Worker | `worker.py` | poll durable jobs, run pipelines, publish progress |
| Scripts | `python -m scripts.<name>` | one-shot operator tasks |
A standard app may run as up to three processes that share the same composition
root:
| Process | Entry point | Responsibility |
|---------|------------------------|-------------------------------------------|
| API | `main.py` | serve HTTP; start/stop resources via lifespan |
| Worker | `worker.py` | poll durable jobs, run pipelines, publish progress |
| Scripts | `python -m scripts.<name>` | one-shot operator tasks |
---
## ➡️ Read Next
- [02 – App Components](02_components.md) · [03 – Build Recipe](03_build_recipe.md)

View File

@@ -0,0 +1,137 @@
# App Components
What ships in every standard app, and how the pieces relate. This is the
blueprint's component model — `templates/app/` is a runnable instance of it.
---
## 🗂️ Component model
```mermaid
flowchart LR
subgraph EDGE["interfaces/ — HTTP edge"]
OAS["openapi.yaml"]
RU["resource routes"]
JU["job routes"]
end
subgraph CORE["domain/ — business core"]
RI["<resource> · models · ports · services"]
JI["<job/worker> · models · ports · services"]
PI["pipelines/<family>"]
end
subgraph INFRA["infra/ — adapters"]
DB[("MongoDB repos")]
CA["redis cache"]
ST["stores · progress bus"]
LL["llm clients"]
end
W["worker.py"]
CR["init.py — composition root"]
OAS --> RU
OAS --> JU
RU --> RI
JU --> JI
JI --> PI
PI --> DB
PI --> LL
RI --> CA
RI --> DB
JI --> ST
W --> JI
W --> PI
CR === RU
CR === JU
CR === RI
CR === JI
CR === PI
CR === W
CR === DB
CR === CA
CR === ST
```
> **Legend** — solid arrows are direct calls; thick links are wires created by
> the composition root. Every component is injected, never self-constructed.
---
## 📦 Component roles
### 1. `interfaces/` — the edge
Thin handlers bound to `openapi.yaml` `operationId`s. They parse the request,
call a service, and shape the response. No business rules, no I/O.
- `interfaces/openapi.py` re-exports every route module so the OpenAPI-first
app can resolve handlers.
- Routes may mount the `cache` decorator on read endpoints.
### 2. `domain/` — the core
Pure models, **ports** (abstract contracts), and services (use cases). No
framework imports, no drivers.
- `<aggregate>/models.py` — dataclasses, enums, document shapes.
- `<aggregate>/ports/db.py` — repo contract; `<aggregate>/ports/service.py` —
service contract.
- Services compose ports and enforce the business rules; the composition root
injects the implementations.
### 3. `infra/` — the adapters
Concrete implementations of the domain ports plus cross-cutting infrastructure:
- `db/` — mongo-ops repositories and the connection lifecycle.
- `adapters/` — cache store, progress bus, storages, fetchers (library-backed).
- Anything else the domain needs, implemented against its ports.
### 4. `pipelines/` — data-driven families *(optional)*
Extraction and enrichment families, each a deterministic step chain
(`abc.py` / `impl.py` / `pipeline.yaml` / `resources/`). Roots are registered
in the pattern registry and driven either by a worker job or a CLI.
### 5. `worker.py` — the job worker *(optional)*
A separate process that polls durable job collections, runs pipeline roots, and
publishes progress to the progress bus. It shares the same composition root as
the API.
### 6. `init.py` — the composition root
The only place anything is constructed: leaf repositories → dependent
repositories → services → adapters. Exposes `get_svc` overloads and starts /
stops resources on the app lifespan.
---
## 🔗 How the request flows
```mermaid
sequenceDiagram
participant C as Client
participant R as route (interfaces)
participant S as service (domain)
participant P as repo (infra)
participant DB as MongoDB
C->>R: POST /items (operationId)
R->>S: svc.create(payload)
S->>P: repo.insert(doc)
P->>DB: insert
DB-->>P: ack
P-->>S: doc
S-->>R: result
R-->>C: 200 JSON
```
---
## Related
- [01 – Overview](01_overview.md) · [03 – Build Recipe](03_build_recipe.md) · [04 – Testing & Quality](04_development/01_testing.md)

View File

@@ -0,0 +1,124 @@
# Build Recipe
The ordered, deterministic checklist for generating a new application of the
standard shape. Every step is fixed; only steps 2 and 3 need app-specific
authoring. Give an AI agent the copyable prompt below (or read it from the
`standards` MCP bundle as `doc://modules/build_recipe`) and it can produce a
complete app in one pass.
---
## 🚀 Quick start
```bash
# Copy the runnable skeleton (from the standards docs checkout)
cp -r <docs>/standards/src/templates/app apps/<your-app>
cd apps/<your-app>
```
Then follow the numbered steps in the prompt.
---
## 📋 Agent prompt (copyable)
````markdown
# Build a new application from the Aetos Standards blueprint
You are coding a complete new backend application conforming to the Aetos
standard app blueprint. Execute every step in order. Only steps 2 and 3 use the
app-specific details provided by the user; everything else is deterministic.
Before writing any code, connect to the `standards` MCP server and read:
- `doc://nav` (the module list)
- `doc://modules/layering_rules` (the dependency rules)
- `doc://modules/genericity_matrix` (what is generic vs app-specific)
Then call `find_library` with capabilities like `db`, `di`, `routing`,
`ingestion`, `auth`, `docs`, `pipeline`, and note the libraries that already
exist. Never reimplement one.
1. **Scaffold** — copy `src/templates/app/` into `apps/<your-app>/`. Keep the
package tree: `domain/`, `infra/`, `interfaces/`, `pipelines/`, `tests/`,
`scripts/`, plus `pyproject.toml`, `openapi.yaml`, `config.py`, `init.py`,
`main.py`, `worker.py`, `Dockerfile`, `docker-compose.yaml`, `.env.example`.
2. **Author the spec (app-specific)** — write `openapi.yaml`: resources,
schemas, `operationId`s, security, and extension metadata. This is the
contract and drives all routing.
3. **Write each CRUD slice (app-specific)** — per resource create the
four-file slice: `models.py`, `ports/db.py`, `ports/service.py`, and
optional `converters.py`. Follow the CRUD template.
4. **Wire the composition root** — in `init.py`, build leaf repositories, then
dependent repositories, then services; add infra adapters (db, cache,
stores, progress bus, fetchers). Expose `get_svc` overloads.
5. **Add routes** — create `interfaces/<resource>/routes.py` thin handlers
bound to `operationId`s and re-export them in `interfaces/openapi.py`. Add
the cache decorator to read endpoints.
6. **Bootstrap app and worker** — confirm `main.py` runs the OpenAPI-first app
with its lifespan. If the app has long-running jobs, adapt `worker.py` to
poll the job collection, run the pipeline, and publish progress.
7. **Add pipeline families (only if data-driven)** — create
`pipelines/<family>/` with `abc.py`, `impl.py`, `pipeline.yaml`,
`resources/`, and register the root. Add fixtures and a parity test.
8. **Add infrastructure only where needed** — prefer a library-backed adapter.
Never hand-write what an internal library already provides.
9. **Tests** — integration tests with fakes at the HTTP edge; unit tests for
domain and pipeline logic; a config-consistency test for rule-driven
pipelines.
10. **Scripts and seeds** — operator scripts under `scripts/` using
`init()` / `get_svc()` / `shutdown()`.
11. **Docs** — author GSDFC docstrings, generate `.pyi` stubs, mark the package
`py.typed`, and build the docs.
**Definition of done:**
- `python -c "import main"` succeeds.
- `pytest` passes.
- The app serves every operation in the spec; the worker drains its queue.
- No domain module imports a web framework.
- No infrastructure was reimplemented that a library already provides.
````
---
## 🧭 Where the steps land
The steps map onto the layers as follows:
| Step | Package / file | Depends on |
|---------------------|-----------------------------------|---------------------------------------------|
| 1 · Scaffold | whole `templates/app/` | — |
| 2 · Spec | `openapi.yaml` | — |
| 3 · CRUD slices | `domain/<resource>/` | spec, CRUD template |
| 4 · Wiring | `init.py` | every slice |
| 5 · Routes | `interfaces/<resource>/` | services, openapi route registry |
| 6 · Bootstrap | `main.py`, `worker.py` | composition root |
| 7 · Pipelines | `pipelines/<family>/` | library pipeline engine |
| 8 · Infra | `infra/` | domain ports |
| 9 · Tests | `tests/` | app + fixtures |
| 10 · Scripts | `scripts/` | composition root |
| 11 · Docs | docstrings + docs build | code, Doc Forge |
---
## ⚠️ Definition of done
- `python -c "import main"` succeeds.
- `pytest` passes.
- The app serves the spec's operations; the worker drains its queue.
- No domain module imports a web framework.
- No infrastructure was reimplemented that a library already provides.
---
## Related
- [01 – Overview](01_overview.md) · [02 – App Components](02_components.md) · [04 – Testing & Quality](04_development/01_testing.md)

View File

@@ -1,13 +1,12 @@
# Testing
# Testing & Quality Gates
## Summary
Two test suites: **integration** (the HTTP edge with fakes) and **unit** (pure
domain and pipeline logic). Both run under pytest with asyncio auto mode.
Two suites run under pytest with asyncio auto mode: **integration** (the HTTP
edge against fakes) and **unit** (pure domain and pipeline logic). Finish a
blueprint app only when every gate below passes.
---
## Layout
## 🗂️ Layout
```
tests/
@@ -16,7 +15,9 @@ tests/
conftest.py # fixtures
```
## Integration tests
---
## 🚀 Integration tests
- Build the app with `TestClient`.
- Replace `app.state.resources` with fake repositories/services so no database
@@ -35,22 +36,46 @@ def test_create_item():
assert r.status_code == 200
```
## Unit tests
---
## 🧪 Unit tests
- Domain models and converters: pure, no I/O.
- Pipeline stages: feed a fixture state, assert the transformed state.
- Assembled pipeline roots: **fixture parity** — replay a stored fixture input
and compare against a golden output file.
## Config-consistency tests
---
## 🔐 Config-consistency tests
For rule-driven pipelines, add a test that cross-references rules against the
declared pattern registry: every flag emitted must be defined; every defined
flag must be reachable. This catches drift without running the pipeline.
## Conventions
---
## ✅ Quality gates
A **definition of done** for any standard app:
- `python -c "import main"` succeeds.
- `pytest` passes.
- The app serves the spec's operations; the worker drains its queue.
- No domain module imports a web framework.
- No infrastructure was reimplemented that a library already provides.
---
## 💡 Conventions
- `asyncio_mode = "auto"`; no manual event loops.
- Fixtures are checked into the repo (inputs + golden outputs).
- Tests skip (not fail) when a required fixture is absent.
- Do not mock the domain; mock only the infrastructure edge.
---
## Related
- [02 – App Components](02_components.md) · [03 – Build Recipe](03_build_recipe.md) · [Overview](../01_overview.md)

View File

@@ -1,82 +0,0 @@
# Build Recipe
## Summary
Follow this ordered checklist to generate a new application of the standard
shape. Every step is deterministic; only steps 2 and 7 require app-specific
authoring.
---
## 0. Query the registry
Before writing anything, read the **library registry** and note which internal
libraries provide DB, DI, routing, ingestion, auth, and docs. Do not
reimplement them.
## 1. Scaffold the repository
Copy the `templates/` skeleton. It provides: `pyproject.toml`, `openapi.yaml`,
`main.py`, `init.py`, `worker.py`, `config.py`, `Dockerfile`,
`docker-compose.yaml`, `.env.example`, and the package tree
(`domain/ infra/ interfaces/ pipelines/ tests/ scripts/`).
## 2. Author the spec *(app-specific)*
Write `openapi.yaml`: resources, schemas, `operationId`s, security, and any
extension metadata. This is the contract.
## 3. Write each CRUD slice *(app-specific)*
For each resource, create the four-file slice (see **CRUD Template**):
`models.py`, `ports/db.py`, `ports/service.py`, optional `converters.py`.
## 4. Wire the composition root
In `init.py`: build leaf repositories, then dependent repositories, then
services; add infrastructure adaptors (cache store, progress bus, stores,
fetchers). Add `get_svc` overloads.
## 5. Add routes
Create `interfaces/<resource>/routes.py` (thin handlers) and re-export them in
`interfaces/openapi.py`. Add a cache decorator to read endpoints.
## 6. Bootstrap the app and worker
Confirm `main.py` wires the OpenAPI-first app with the lifespan. If the app has
long-running jobs, adapt `worker.py` to poll the relevant job collection.
## 7. Add a pipeline family *(only if data-driven)*
Create `pipelines/<family>/` with `abc.py`, `impl.py`, `pipeline.yaml`,
`resources/`, and register the root in `registry.py`. Add fixtures and a parity
test.
## 8. Add infrastructure as needed
Only where the standard adaptors do not cover the need. Prefer library-backed
adapters.
## 9. Tests
Add integration tests with fakes and unit tests for domain/pipeline logic; add
a config-consistency test if using rule-driven pipelines.
## 10. Scripts and seeds
Add operator scripts under `scripts/` that use `init()` / `get_svc()` /
`shutdown()`.
## 11. Docs
Author GSDFC docstrings, generate the type stubs (`.pyi`), mark the package
`py.typed`, and build docs.
## Definition of done
- `python -c "import main"` succeeds.
- `pytest` passes.
- The app serves the spec's operations; the worker drains its queue.
- No domain module imports a web framework.
- No infrastructure was reimplemented that a library already provides.

View File

@@ -1,45 +1,68 @@
# The Aetos Standard App Blueprint
# 🧩 Standards — the Aetos App Blueprint
A single, reusable architecture for backend applications in the Aetos ecosystem.
One reusable architecture for every backend application in the Aetos ecosystem:
a spec-first HTTP edge, a pure domain core, a pluggable infrastructure layer,
and a single composition root.
Every application built with this blueprint has the same shape:
Fill in **two axes only** and a new app is done: your **resource model**, and
(if needed) your **pipeline family**. The blueprint itself never names a
business domain — expenses, health metrics, inventory, and analytics are all
the same shape underneath.
- a **spec-first HTTP layer** driven by an OpenAPI document;
- a **domain layer** of pure models, ports, and services;
- an **infrastructure layer** of adapters (MongoDB, cache, workers, LLM, mail);
- a **composition root** that wires everything in exactly one place;
- an optional **pipeline layer** for data-driven extraction/enrichment;
- an optional **background worker** that runs long-running jobs and reports progress.
> **Doc model:** this wiki is written for humans — how-to guides, the build
> recipe, and quality gates. The enforceable rules (layering, composition root,
> CRUD template, pipeline scaffold) and the library registry live in the
> **reference** pages, mirrored by the machine-readable `standards` MCP bundle.
> Query `find_library` before writing any infrastructure.
> This blueprints is deliberately **app-agnostic**. It never names a concrete
> business domain. Any application — expenses, health metrics, inventory,
> analytics — is produced by filling in **two axes only**: the resource model
> and (if needed) the pipeline family.
---
## How to read this
## 🚀 Key Features
| Page | What it covers |
|---|---|
| Overview | The philosophy and the one-way dependency rule |
| Layering Rules | Which package may import which |
| Composition Root | The single wiring point |
| Spec-First Routing | OpenAPI as the source of truth |
| CRUD Template | The canonical resource slice |
| Pipeline Scaffold | Data-driven processing families |
| Worker & Progress | Async jobs, status machine, streaming progress |
| Human-in-the-Loop | Pausing a job to ask a question |
| Infra Adapters | MongoDB, cache, stores, LLM, mail |
| Testing | Integration + unit conventions |
| Build Recipe | The ordered checklist to generate a new app |
| Genericity Matrix | What is reusable vs what you must write |
- 🧭 **Spec-first routing** — the OpenAPI document, not decorator routers, is
the source of truth (operationId lookup)
- 🏗️ **One-way layering** — `interfaces → domain → infra`, enforced
- 🔌 **Single composition root** — every dependency is wired in exactly one place
- 🧩 **Generic, not app-specific** — reusable rules versus two authoring axes
- 📚 **Library-backed** — DB, DI, pipelines, ingestion, auth, and docs come from
internal libraries, never hand-written
- 🚦 **Explicit state machines** — durable job statuses, progress, and
human-in-the-loop pauses
## For AI agents
---
This content is served as MCP resources under `docs://index`, `docs://nav`,
and `docs://modules/{module}`. To build a new app:
## 📁 Documentation Structure
1. Read `build_recipe` first.
2. Read `genericity_matrix` to know what you must author.
3. Query the **library registry** (`find_library`) before writing any
infrastructure yourself.
4. Copy the `templates/` skeleton and fill the two app-specific axes.
| Section | Description |
|-----------------------------------------------------|--------------------------------------------------------|
| [Overview](01_overview.md) | Philosophy, the one-way dependency rule, architecture |
| [App Components](02_components.md) | The component model and how the pieces wire together |
| [Build Recipe](03_build_recipe.md) | The ordered, agentic checklist for a new app |
| [Testing & Quality](04_development/01_testing.md) | Test layout and acceptance gates |
**Reference** (separate site, mirrors the MCP bundle): the enforceable
rules — [Layering](../lib/02_layering_rules/), [Composition
Root](../lib/03_composition_root/), [Spec-First
Routing](../lib/04_spec_first_routing/), [CRUD
Template](../lib/05_crud_template/), [Pipeline
Scaffold](../lib/06_pipeline_scaffold/), [Worker &
Progress](../lib/07_worker_and_progress/), [Human-in-the-Loop](../lib/08_human_in_loop/),
[Infra Adapters](../lib/09_infra_adaptors/), [Genericity
Matrix](../lib/12_genericity_matrix/), [Library
Registry](../lib/13_library_registry/).
---
## 🔗 Related Resources
- **MCP bundle** — `standards` server on `:8009`: read `doc://index`,
`doc://nav`, `doc://modules/{module}`; call `find_library(capability)`
- **Library registry** — the catalog of internal libraries behind every app
(`libraries.json`, served as `registry://libraries`)
- **Template** — the runnable skeleton at `standards/src/templates/app/`
- **Copy the repo's `AGENTS.md`-style build prompt** from
[Build Recipe](03_build_recipe.md)
---
© Aetoskia Internal — `standards`