4.7 KiB
Mizan
An Application Framework Interface (AFI) — one decorator on a server function, a typed client generated, invalidation automatic, caching protocol-driven. Any backend, any frontend, one wire protocol.
For the wire protocol, package layout, and codegen state, see CLAUDE.md.
Architecture deep-dives live in docs/. Open work is tracked in
ROADMAP.md and ISSUES.md.
Backend Adapter Parity
Django is the maximal rubric — it implements the full AFI surface. Every other adapter is measured against it. A cell is marked supported only when that adapter wires the capability into its own dispatch surface (not merely that a shared core primitive exists).
Legend: ✅ full · ◑ partial · ❌ absent · — not applicable to this transport
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
RPC call dispatch ({result, invalidate}) |
✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Named-context bundle fetch | ✅ | ✅ | ✅ | ✅ | ✅ |
| Invalidation — JSON body | ✅ | ✅ | ✅ | ✅ | ✅ |
Invalidation — X-Mizan-Invalidate header |
✅ | ❌ | ❌ | — ¹ | ✅ |
| Invalidation auto-scoping (three-tier) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Origin-side HMAC cache | ✅ | ❌ | ❌ | ❌ | ✅ |
| WebSocket channels | ✅ | ❌ | ◑ ² | ❌ | ❌ |
| Forms (schema / validate / submit) | ✅ | ❌ | ◑ ³ | ❌ | ❌ |
| Formsets | ✅ | ❌ | ❌ | ❌ | ❌ |
| API shapes (ORM query projection) ⁴ | ✅ | — | — | — | — |
Auth guards (auth=True/'staff'/'superuser'/callable) |
✅ | ✅ | ❌ | ◑ ⁵ | ❌ |
| JWT auth (access / refresh, session validation) | ✅ | ❌ | ❌ | ❌ | ❌ |
| MWT (edge identity token) | ✅ | ❌ | ❌ | — | ❌ |
| SSR bridge | ✅ | ❌ | ❌ | — | ❌ |
PSR (render_strategy in manifest) |
✅ | ❌ | ❌ | — | ✅ |
| Edge manifest export | ✅ | ❌ | ❌ | — | ✅ |
| Codegen IR export (KDL) | ✅ | ✅ | ✅ ⁶ | ✅ ⁶ | ❌ |
| Session / CSRF init endpoint | ✅ | ◑ ⁷ | ◑ ⁷ | — | ❌ |
| Function discovery / registration | ✅ | ✅ | ✅ | ✅ | ✅ |
| Auth-provider integration (allauth) | ✅ | ❌ | ❌ | ❌ | ❌ |
Notes
- Tauri's transport is Tauri IPC (a single
#[tauri::command]envelope), not HTTP. Invalidation rides in the JSON response body; there is no header channel, so the header row is N/A. - Rust/Axum declares
Transport::Websocketin the IR/macro but routes no Axum WebSocket handler yet. - Rust/Axum carries
is_form/form_roletrait stubs but no validate/submit endpoint. - "API shapes" is Django's django-readers queryset projection — ORM-coupled. Every adapter carries typed input/output through the KDL IR; the projection primitive itself is Django-only.
- Tauri's
FunctionSpeccarriesauth/privatefields, but the dispatch path does not enforce them. - Rust/Axum and Tauri are the IR authority via the
#[mizan::client]macro + linkme registry; the codegen links the crate directly (build_ir()/ theexport-irbin) rather than fetching over HTTP. - FastAPI and Rust/Axum expose
GET /session/returning a null CSRF token for wire parity; real CSRF is Django-only.
Reading the columns
- FastAPI — the AFI-common HTTP subset: dispatch, contexts, body invalidation, auth guards, IR export. Channels / forms / SSR / cache are deliberately delegated to native FastAPI equivalents.
- Rust / Axum — core dispatch + context bundling + compile-time registry, and the server-side IR authority. No HTTP-layer cache, auth enforcement, or edge surface yet.
- Tauri — the same Rust core over IPC for desktop/mobile. Edge, SSR, MWT, and CSRF are structurally inapplicable to a local app.
- TypeScript — the edge/protocol reference: HMAC cache, edge manifest, and PSR strategy, proving the cache + invalidation protocol is language-agnostic. It is not a codegen IR source.
Keeping this honest
This table is a snapshot, and a hand-maintained snapshot drifts the moment an
adapter gains or loses a target. The enforcing layer is the AFI conformance suite at
tests/afi/, which today gates IR-shape parity — the same fixture
through Django, FastAPI, and the Rust adapter must emit byte-identical KDL
(test_codegen_parity.py). It does not yet assert runtime capability parity
(e.g. "every adapter that claims the header transport actually emits
X-Mizan-Invalidate," "every adapter that claims auth= actually rejects an
unauthorized call"). Extending tests/afi/ with per-capability assertions — one row of
this table per asserted behavior — is what turns the table from documentation into a
red-on-regression contract.