Phase 7: serve the vet sample from the template tools and docs
- build.py: _TEMPLATE_COMPONENTS rewritten around the vet sample (53 kinds —
per-resource slices, jobs, worked appointment_reminder family, tests);
seed tokens dropped from the manifest ('sample: vet' instead)
- registry.py: get_app_component(kind) no longer renames item/example seeds;
prompts and tool docs updated to 'copy a slice and adapt'
- templates/README.md, 01_build_recipe, 40_ui_admin, wiki/03 updated off the
old seed scheme; repo inventory/config now exclude vet (docs move under
standards; react/vet itself is deleted in a later phase)
- regenerated MCP bundle, vendored templates, and site output
This commit is contained in:
@@ -69,8 +69,7 @@ Then:
|
||||
- call `find_library` with `db`, `di`, `routing`, `ingestion`, `pipeline`, `docs`
|
||||
and note the Tier A libraries that already exist — never reimplement one;
|
||||
- call `list_app_components()` and pull each file you need with
|
||||
`get_app_component(kind, resource=..., family=...)` instead of writing it from
|
||||
scratch.
|
||||
`get_app_component(kind)` instead of writing it from scratch.
|
||||
|
||||
## Steps
|
||||
|
||||
@@ -117,10 +116,11 @@ Then:
|
||||
with its lifespan. If the app has long-running jobs, adapt `worker.py` to poll
|
||||
the job collection, run the pipeline, and publish progress.
|
||||
|
||||
8. **Add pipeline families (only if data-driven)** — copy `pipelines/example/`
|
||||
to `pipelines/<family>/` with `abc.py`, `impl.py`, `pipeline.yaml`,
|
||||
`resources/`, and reuse `pipelines/shared/` (loader + registry). Register the
|
||||
root. Add fixtures and a parity test.
|
||||
8. **Add pipeline families (only if data-driven)** — copy the worked family
|
||||
`pipelines/appointment_reminder/` to `pipelines/<family>/` with `abc.py`,
|
||||
`impl.py`, `pipeline.yaml`, `resources/`, and reuse `pipelines/shared/`
|
||||
(loader + registry). Register the root, add the `job.kind` handler in
|
||||
`worker.py`. Add fixtures and a parity test.
|
||||
|
||||
9. **Add infrastructure only where needed** — Tier A capability: use the
|
||||
library. Tier B capability: copy the template. Never hand-write a Tier A
|
||||
|
||||
@@ -57,7 +57,7 @@ docs://modules/react-openapi # module: specExtensions — the full catalo
|
||||
|
||||
The app's own spec carries the per-resource values; the catalog explains what
|
||||
each field does. The template's `openapi.yaml` shows the convention on the
|
||||
example `Item` and `Job` schemas.
|
||||
example `Job` schema.
|
||||
|
||||
---
|
||||
|
||||
@@ -82,5 +82,7 @@ example `Item` and `Job` schemas.
|
||||
- The server template ships authless by default (see
|
||||
[22 – Auth Integration](22_auth_integration.md)); the client template pairs
|
||||
with it and degrades to "no login" until a security scheme is declared.
|
||||
- `react/vet` is the full-stack reference implementation: spec with x-
|
||||
extensions, server, and the consuming client in one tree.
|
||||
- The standards **app + client templates** are the full-stack reference: the
|
||||
server spec carries the x- extensions, and the client renders the admin from
|
||||
it. The wiki's **Reference App** walkthrough (`06_reference_app`) documents
|
||||
the pairing end to end.
|
||||
|
||||
@@ -10,7 +10,7 @@ chosen by what the repository produces:
|
||||
|------|------|----------|-------|
|
||||
| **A — PyPI package** | `templates/drone/python-lib.yaml` | A wheel + sdist on the private index | `dagpipe`, `doc-forge`, `hexa`, `mail-intake`, `mongo-ops`, `omniread`, `openapi-first`, `py-jwt` |
|
||||
| **B — npm package** | `templates/drone/npm-lib.yaml` | A package published to the private npm registry | `doc-weaver`, `react-auth`, `react-openapi` |
|
||||
| **C — Docker deployment** | `templates/drone/service-docker.yaml` | An image pushed to the registry and run as a container | `auth-server`, `vet` |
|
||||
| **C — Docker deployment** | `templates/drone/service-docker.yaml` | An image pushed to the registry and run as a container | `auth-server` |
|
||||
|
||||
All templates run on `platform: linux / arm64` with the workspace at
|
||||
`/drone/src`. Copy the matching template to `<repo>/.drone.yml`; the Type A and
|
||||
|
||||
@@ -45,15 +45,14 @@ source is `package.json`; Drone file is `npm-lib.yaml` (tag-triggered).
|
||||
|
||||
---
|
||||
|
||||
## Services & Apps (Type C)
|
||||
## Services (Type C)
|
||||
|
||||
A container image pushed to the registry and run on the Docker host. Version
|
||||
source is the `VERSION` file; Drone file is `service-docker.yaml`.
|
||||
|
||||
| Repo | Path | Type | Trigger | Docs |
|
||||
|------|------|------|---------|------|
|
||||
| `auth-server` | `auth-server` | service | tag | api, lib, wiki |
|
||||
| `vet` | `react/vet` | app | tag | lib, wiki |
|
||||
| Repo | Path | Trigger | Docs |
|
||||
|------|------|---------|------|
|
||||
| `auth-server` | `auth-server` | tag | api, lib, wiki |
|
||||
|
||||
Tag-triggered and enforces `tag == VERSION`.
|
||||
|
||||
@@ -65,7 +64,7 @@ Tag-triggered and enforces `tag == VERSION`.
|
||||
|------|----------------|-----------|-------|
|
||||
| package (PyPI) | `pyproject.toml` | `CHANGELOG.md` | `python-lib.yaml` |
|
||||
| package (npm) | `package.json` | `CHANGELOG.md` | `npm-lib.yaml` |
|
||||
| service / app | `VERSION` | `CHANGELOG.md` | `service-docker.yaml` |
|
||||
| service | `VERSION` | `CHANGELOG.md` | `service-docker.yaml` |
|
||||
|
||||
Every covered repository must be able to satisfy `tag == version`:
|
||||
the version file (never a commit id) is bumped in the release MR, the MR is
|
||||
|
||||
@@ -122,16 +122,6 @@
|
||||
"trigger": "tag",
|
||||
"docs": ["api", "lib", "wiki"],
|
||||
"mcp": null
|
||||
},
|
||||
{
|
||||
"name": "vet",
|
||||
"type": "app",
|
||||
"path": "react/vet",
|
||||
"version_source": "VERSION",
|
||||
"drone": "service-docker.yaml",
|
||||
"trigger": "tag",
|
||||
"docs": ["lib", "wiki"],
|
||||
"mcp": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
# Application Template
|
||||
|
||||
A minimal, runnable skeleton of the standardized architecture. It demonstrates
|
||||
both axes of the blueprint (see `standards`):
|
||||
A runnable sample of the standardized architecture — the **vet** veterinary
|
||||
clinic domain, kept as the standards' reference sample. It demonstrates both
|
||||
axes of the blueprint (see `standards`):
|
||||
|
||||
1. **Resource axis** — items and jobs, each a Claude-style generic CRUD slice
|
||||
(model → document → repo → service → route), all driven from `openapi.yaml`.
|
||||
2. **Pipeline axis** — a background `worker.py` that polls pending jobs and runs
|
||||
a pipeline; `pipelines/example/` shows the reusable family skeleton and
|
||||
`pipelines/item_sync.py` the simple end-to-end form.
|
||||
1. **Resource axis** — five domain aggregates (parents, pets, treatments,
|
||||
vets, appointments) plus a **jobs** queue, each a CRUD slice
|
||||
(model → document → repo → service → route), all driven from
|
||||
`openapi.yaml`. x- extension fields on the spec drive the admin client.
|
||||
2. **Pipeline axis** — a background `worker.py` that polls pending jobs and
|
||||
dispatches by `job.kind`; `pipelines/appointment_reminder/` is the worked
|
||||
family and `pipelines/shared/` the reusable scaffold.
|
||||
|
||||
Everything here is deliberately small so an agent can rewrite each file rather
|
||||
than delete unused code. The domain is a neutral "item", not an app noun.
|
||||
Copy a slice, replace the domain with your own — the layer structure, wiring
|
||||
patterns and tests stay.
|
||||
|
||||
## Internal dependencies
|
||||
|
||||
@@ -38,11 +41,19 @@ The app depends on the internal Aetos libraries (`openapi-first`, `mongo-ops`,
|
||||
cd apps/<your-app>
|
||||
|
||||
1. `pyproject.toml` — rename the package; keep the internal library pins.
|
||||
2. `config.py` — replace/add settings consumed by your domain.
|
||||
3. `openapi.yaml` — replace the `Item`/`Job` resources with your resources.
|
||||
4. `domain/` — rename `item` and `job` slices to your aggregates.
|
||||
5. `pipelines/` — replace the demo with your pipeline (see below).
|
||||
6. `tests/` — keep the two test files as the pattern for your own.
|
||||
2. `config.py` — replace/add settings consumed by your domain (keep the
|
||||
worker knobs if you run jobs).
|
||||
3. `openapi.yaml` — replace the vet resources with yours; keep the x-
|
||||
extension conventions on schemas and fields.
|
||||
4. `domain/` — replace each aggregate slice with your own; copy
|
||||
`domain/parents/` as the simplest pattern, `domain/appointments/` when you
|
||||
need FK expansion.
|
||||
5. `interfaces/` — one `routes.py` per resource re-exported from
|
||||
`openapi.py`; keep `_common.py` as-is.
|
||||
6. `pipelines/` — replace the appointment_reminder family with yours (see
|
||||
below); keep `pipelines/shared/` as-is.
|
||||
7. `tests/` — keep `test_openapi_app_builds.py`; adapt the unit tests as
|
||||
patterns for your own.
|
||||
|
||||
Install and run:
|
||||
|
||||
@@ -53,8 +64,7 @@ Install and run:
|
||||
|
||||
## Pipeline families
|
||||
|
||||
`pipelines/item_sync.py` is the smallest possible pipeline (plain async steps).
|
||||
When a family needs its own stages, copy `pipelines/example/`:
|
||||
Copy `pipelines/appointment_reminder/` as the family pattern:
|
||||
|
||||
pipelines/<family>/
|
||||
abc.py # port contracts
|
||||
@@ -68,7 +78,8 @@ When a family needs its own stages, copy `pipelines/example/`:
|
||||
|
||||
The shared loader wires the root through the DI library (`hexa.build`) and merges
|
||||
the pattern fragments; the registry resolves a `(kind, variant, mode)` triple to
|
||||
a root class. See standards "50_pipeline_scaffold".
|
||||
a root class. The worker maps `job.kind` to a handler in its `HANDLERS`
|
||||
dispatch table. See standards "50_pipeline_scaffold" and "51_worker_and_progress".
|
||||
|
||||
## What to keep, what to replace
|
||||
|
||||
@@ -79,9 +90,10 @@ a root class. See standards "50_pipeline_scaffold".
|
||||
| openapi-first routing | Paths, schemas, operationIds |
|
||||
| mongo-ops repo factory | Collections, doc models |
|
||||
| generic CRUD adaptor | Nothing (reuse as-is) |
|
||||
| `interfaces/_common.py` | Nothing (reuse as-is) |
|
||||
| `pipelines/shared/` | Nothing (reuse as-is) |
|
||||
| `pipelines/example/` | Family name, stages, patterns |
|
||||
| worker poll + status loop | Job payloads, pipeline steps |
|
||||
| `pipelines/appointment_reminder/` | Family name, stages, patterns |
|
||||
| worker poll + dispatch loop | Job kinds, payloads, pipeline steps |
|
||||
| `scripts/` | Task bodies |
|
||||
|
||||
## Where the internal libraries slot in
|
||||
@@ -95,4 +107,4 @@ a root class. See standards "50_pipeline_scaffold".
|
||||
|
||||
Confirm current endpoints and ownership with the `standards` registry MCP tools:
|
||||
`find_library("pipeline")`, `find_library("auth")`, or
|
||||
`get_app_component("pipeline-abc", family="csv")`.
|
||||
`get_app_component("pipeline-abc")`.
|
||||
|
||||
@@ -40,8 +40,7 @@ From an MCP client connected to the `standards` server:
|
||||
**`start_app`** to intake-and-build in one call.
|
||||
3. The prompt hands off to `docs://modules/build_recipe`; the agent scaffolds
|
||||
with `get_app_template()` and pulls exact files with
|
||||
`get_app_component(kind, resource=..., family=...)`, authoring only the
|
||||
app-specific parts.
|
||||
`get_app_component(kind)`, authoring only the app-specific parts.
|
||||
4. To validate the standard without touching a real app, invoke **`trial`**
|
||||
(`trial(app_name=..., build_path=...)`) to build into a scratch directory,
|
||||
prove it builds, and report findings.
|
||||
|
||||
Reference in New Issue
Block a user