TEN-WP-0002 T01-T03: service skeleton, domain model, storage layer
Python 3.12 + FastAPI, pyproject.toml + Makefile mirroring
qonto-assistant's exactly. src/tenant_engine/{domain,store,app,main}.py:
- domain.py: Tenant, CapabilityRole (PLTF/IAM/VEN/CUS), RoleGrant,
PlanAssignment, create_role_grant() enforcing ADR-0014's invariants.
Refinement made while implementing: platform_default grants are valid
for trial-grouped tenants OR the reserved tenant:platform/tenant:coulomb
tenants (their baseline roles were never purchased either) -- the task
spec only named the trial case.
- store.py: TenantStore Protocol + InMemoryTenantStore, every mutation
emits a DomainEvent per the boundary contract's Audit Correlation
Contract.
- app.py/main.py: FastAPI factory + /health endpoint, verified live on
127.0.0.1:8090.
29 tests passing, including non-exclusive role coexistence (CUS+VEN
simultaneously) and append-only revoke semantics.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
7eb21c05b8
commit
0770ce82d9
11 changed files with 774 additions and 3 deletions
|
|
@ -34,7 +34,7 @@ enforcement.
|
|||
|
||||
```task
|
||||
id: TEN-WP-0002-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d22b0ce8-3f25-4c8d-b54f-ba44c65159c1"
|
||||
```
|
||||
|
|
@ -47,11 +47,19 @@ routers), from day one — not refactored in later.
|
|||
Done when: `make test` runs an empty/smoke suite; `make run` starts a bare
|
||||
FastAPI app with a `/health` endpoint.
|
||||
|
||||
**Done 2026-07-23:** `pyproject.toml` + `Makefile` land, mirroring
|
||||
`qonto-assistant`'s exactly (`install-dev`/`test`/`lint`/`run`).
|
||||
`src/tenant_engine/{domain,store,app,main}.py` scaffolded per the planned
|
||||
layering (`domain.py` pure, `store.py` the persistence seam, `app.py` the
|
||||
FastAPI factory). Verified live: `python -m tenant_engine.main` starts on
|
||||
`127.0.0.1:8090`, `GET /health` returns
|
||||
`{"status": "ok", "service": "tenant-engine", "version": "0.1.0"}`.
|
||||
|
||||
## Task: Domain model — tenant, grouping, capability role, plan grant
|
||||
|
||||
```task
|
||||
id: TEN-WP-0002-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "cfceea30-f383-4781-a7e4-226653aafca9"
|
||||
```
|
||||
|
|
@ -84,11 +92,23 @@ Validation rules encoded as domain invariants, not just API-layer checks:
|
|||
Done when: unit tests cover valid/invalid grouping values, the trial/
|
||||
no-plan-required exception, and grant/revoke as append-only operations.
|
||||
|
||||
**Done 2026-07-23:** `domain.py` implements `Tenant`, `CapabilityRole`,
|
||||
`RoleGrant`, `PlanAssignment`, and `create_role_grant()` exactly as
|
||||
specified. One refinement made while implementing, not pre-specified in the
|
||||
task text: `platform_default` is valid for `trial`-grouped tenants **or**
|
||||
the reserved, ungrouped `tenant:platform`/`tenant:coulomb` tenants (their
|
||||
baseline roles were never purchased either) — the task only mentioned the
|
||||
`trial` case. Also enforced `platform_default` grants must not carry a
|
||||
`plan_id` (implied by "no `plan_id`" in the task text, made an explicit
|
||||
invariant). `tests/test_domain.py` covers all listed cases plus the
|
||||
reserved-tenant extension and double-revoke rejection. `pytest` →
|
||||
29 passed (whole-repo total, includes T03's tests below).
|
||||
|
||||
## Task: Storage layer
|
||||
|
||||
```task
|
||||
id: TEN-WP-0002-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ade9374a-ed26-45da-a424-a0d21effe520"
|
||||
```
|
||||
|
|
@ -103,6 +123,14 @@ Contract — the event bus itself can be a simple in-process list for now.
|
|||
Done when: unit tests cover create/read/grant/revoke/assign-plan through the
|
||||
store interface, plus event emission for each mutation.
|
||||
|
||||
**Done 2026-07-23:** `store.py`'s `TenantStore` Protocol +
|
||||
`InMemoryTenantStore` implement create/get/grant/revoke/active_roles/
|
||||
assign_plan, each emitting a `DomainEvent`. `tests/test_store.py` covers
|
||||
the full lifecycle, non-exclusive role coexistence (`CUS` + `VEN`
|
||||
simultaneously, proving ADR-0014's non-exclusivity isn't just a comment),
|
||||
revoke-keeps-record-but-clears-active-set, and asserts the exact event
|
||||
sequence for a full mutation chain. `python -m compileall src tests` clean.
|
||||
|
||||
## Task: Cache-read API (for key-cape)
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue