Files
mizan/docs/AFI_ARCHITECTURE.md
Ryth Azhur e00b3a177e Docs carry the shape of the system, not its status
MIZAN.md's phase-numbered implementation order, PRODUCT_ARCHITECTURE's
"Deferred until Render revenue funds it" and "Shipped in", PSR_VS_EDGE's
current-state section, and the READMEs' passing-test counts were all reporting
where the work stood rather than what the system is. OWED_SURFACE keeps its
subject — surface that is specified but unbuilt — stated as the shape each unit
owes.

The channel sections follow the renamed slots: Params / ClientMessage /
ServerMessage, and Channel as the base class on both backends.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:03:29 -04:00

116 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AFI Architecture
Mizan is an **Application Framework Interface (AFI)** — the
server-client unification layer.
## Package layout
Tree organized by role.
```
backends/ server protocol adapters
mizan-django/ Django adapter
mizan-fastapi/ FastAPI adapter (AFI-common scope)
mizan-rust-axum/ Rust/Axum adapter (handlers, errors, IR export)
mizan-tauri/ Tauri adapter — Mizan calls served in-process
mizan-ts/ TypeScript adapter (proves the protocol is language-agnostic)
frontends/ client kernel + per-framework adapters + transports
mizan-base/ framework-agnostic kernel (@mizan/base); owns data, status,
error; adapters subscribe through the MizanTransport interface
mizan-react/ React contexts + hooks over the kernel
mizan-vue/ Vue composables over the kernel
mizan-svelte/ Svelte stores/runes over the kernel
mizan-rust/ Rust client kernel
mizan-tauri-transport/ MizanTransport over Tauri IPC
mizan-webview-transport/ MizanTransport over a webview message channel
mizan-webview-channels/ channel transport over a webview bridge
cores/ shared language-level primitives
mizan-python/ @client decorator, registry, MWT, HMAC cache keys
mizan-rust/ Rust core — IR build (build_ir()), registry
mizan-rust-macros/ #[derive(Mizan)] / #[mizan::client] / #[mizan::context] /
#[mizan::channel] proc-macros
mizan-rust-ssr/ embedded-V8 SSR engine (deno_core + deno_web); evals the
build-time bundle, renders per request; no_rsc guard
protocol/ protocol-level tooling
mizan-codegen/ codegen — Rust binary (crate `mizan-codegen`); reads KDL IR,
emits typed clients. Targets: stage1, react, vue, svelte,
channels, python, rust. Askama templates under templates/.
mizan-generate/ thin npm-package launcher (bin/launcher.mjs) dispatching to
the compiled mizan-codegen binary per platform
```
## Two orthogonal products
- **RPC** — typed client generation via codegen
- **SSR** — server rendering via the embedded-V8 engine in the Rust
binary (see `docs/SSR_ARCHITECTURE.md`)
Independent and composable. Either ships standalone; together they
compose.
## Kernel model
The client kernel (`@mizan/base`) is the one hard thing. It owns
`ContextState<T> = {data, status, error}`, the context registry
(`registerContext`), `mizanCall` / `mizanFetch`, server-driven `merge`
and `invalidate`, and `initSession`. It reaches the backend through a
pluggable `MizanTransport` (`call` / `fetch`); the default is the
HTTP `httpTransport()`, swapped via `configure({ transport })` for
Tauri / webview hosts. Per-framework adapters are thin idiomatic
wrappers that subscribe to the kernel. Codegen emits typed bindings
against the framework adapter's surface — a React developer gets
`useEcho()` hooks, a Vue developer gets `useEcho()` composables, a
Svelte developer gets readable stores. Same kernel underneath.
## KDL is the IR
The Mizan IR is **KDL** — the LLVM-IR-equivalent of the system. Every
backend adapter produces KDL describing its registered functions,
contexts, types, channels, and invalidation graph. Every codegen target
consumes KDL. KDL is the contract; everything else (REST envelopes,
OpenAPI documents, framework idioms) is sediment around it.
The IR is validated against multiple adapters — single-adapter
validation hides assumptions, and divergence between adapters is what
the IR exists to prevent.
Forward-direction primitives:
- Each backend adapter emits KDL on stdout from an IR-export command:
FastAPI `python -m mizan_fastapi.ir <module>`, Django
`python manage.py export_mizan_ir`, Rust a consumer-side cargo bin
that calls `mizan_core::build_ir()`. Python's `build_ir()` walks
`mizan_core.registry`; the Rust emitter walks the linkme slices the
proc-macros populate. The IR grammar (`type` / `function` /
`context` / `channel` nodes) is parsed by `mizan-codegen`'s
`src/ir.rs`; fixtures live at
`protocol/mizan-codegen/tests/fixtures/*.kdl`.
- `protocol/mizan-codegen/src/fetch.rs` spawns the configured source
command and parses the KDL it writes.
- Codegen reads KDL directly — no OpenAPI envelope, no
`openapi-typescript`, no per-backend converter divergence; codegen
is a single Rust binary.
- Edge manifest, MWT claims, and other protocol artifacts derive from
the same registry/IR.
## Authoring surface
Python (Django) + React is the reference stack. Vue and Svelte are
co-equal codegen targets over the same kernel. The TypeScript backend
(`mizan-ts`) proves the protocol is portable.
## Why the AFI shape
Quadratic ecosystem growth (N server adapters × M client adapters)
collapses to linear (one adapter per stack) when both sides
communicate through a shared protocol.
## Invariants
- All cross-package communication goes through the protocol. No
direct cross-package dependencies.
- New adapters land as new packages, not as modifications to existing
ones.
- Framework adapters wrap the kernel in framework idioms — they
don't bypass it. Codegen targets the adapter, not the raw kernel.