Files
mizan/ROADMAP.md
Ryth Azhur b2f990b4e5 Architecture rework: fix protocol bugs, add origin-side cache, document spec
8-expert review identified 3 bugs in shipped code (Vary header hallucination,
fn/function wire key mismatch, max-age=0 defeating PSR) — all fixed with
tests updated across Python and TypeScript.

Added: manifest version field, affects validation, wire format convention,
origin-side cache module (HMAC key derivation, MemoryCache + RedisCache
backends, reverse index for scoped invalidation, executor integration).

16 known issues documented in cache/KNOWN_ISSUES.md from expert review —
critical items (user_id not passed, purge race condition, no Redis error
handling) to be fixed in follow-up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:40:55 -04:00

192 lines
5.9 KiB
Markdown

# Mizan Roadmap
## v1 — Django + React
### Done
- **@client decorator** — `context=`, `affects=`, `auth=`, `websocket=`
- **ReactContext class** — type-safe context/affects references with linting
- **Named contexts** — functions sharing a context name are grouped into one provider and one fetch
- **Context bundling endpoint** — `GET /api/mizan/ctx/<name>/` returns all functions in one response
- **Server-driven invalidation (JSON body)** — mutation responses carry `{"result": ..., "invalidate": [...]}`
- **Scoped invalidation** — runtime supports `invalidate: [{context: "user", params: {user_id: 5}}]`
- **Param elevation** — shared params become required provider props, non-shared become optional
- **Schema export** — `x-mizan-functions` + `x-mizan-contexts` for codegen
- **Auth guards** — `auth=True`, `auth='staff'`, `auth='superuser'`, `auth=callable`
- **JWT + session auth** — auto-detected, CSRF handled
- **Shapes** — Pydantic + django-readers for typed query projections
- **WebSocket channels** — real-time bidirectional communication
- **Codegen** — generates typed React providers, hooks, mutations from schema
- **CDN-ready headers** — `Cache-Control`, deterministic JSON on context GETs, `no-store` on mutations
### Next: X-Mizan-Invalidate Header
Second invalidation transport. For view responses (redirects, HTML), invalidation goes in an HTTP header instead of the JSON body. Both transports are first-class AFI spec.
- Header format: `X-Mizan-Invalidate: user;user_id=5, notifications`
- Comma-separated contexts, semicolon-separated params per context
- Decorator auto-adds header to any HttpResponse with `affects=`
- Edge reads this header to purge cached pages
- Runtime also reads it on XHR/fetch responses (htmx path)
### Next: Return-Type Branching
`@client` serves both RPC developers (React/SPA) and view developers (htmx/templates). Return type determines behavior:
- **Data return** (dict, Shape, BaseModel) → RPC path. Generates typed hooks. Invalidation in JSON body.
- **HttpResponse return** (render, redirect) → View path. No codegen. Invalidation in `X-Mizan-Invalidate` header.
Same decorator. Same `affects=`. Same invalidation graph. Two paths.
### Next: affects_params
Scoped invalidation with a lambda that extracts which params were affected:
```python
@client(affects='user', affects_params=lambda req: {'user_id': req.user.pk})
def update_name(request, name: str) -> dict:
...
```
Produces `invalidate: [{context: "user", params: {user_id: 5}}]` in JSON body or `X-Mizan-Invalidate: user;user_id=5` in header.
### Next: Edge Manifest
`mizan-generate --manifest` compiles the decorator registry + Django URL conf into static JSON for Edge:
```json
{
"contexts": {
"user": {
"endpoints": ["/api/mizan/ctx/user/"],
"views": ["/profile/:user_id/"],
"params": ["user_id"]
}
}
}
```
Edge reads the manifest at deploy time. When it receives `X-Mizan-Invalidate: user;user_id=5`, it resolves URL patterns with params and purges `/profile/5/` and `/api/mizan/ctx/user/?user_id=5`.
Generated alongside React code. Covers both RPC and view-path functions.
### Next: Codegen Rewrite
Generated code uses the runtime directly (`mizanFetch`, `mizanCall`, `registerContext`) instead of the legacy `MizanProvider` pattern. Mutations have zero invalidation knowledge — the runtime reads the server response.
### Next: SSR Bridge
Django renders React components server-side via a persistent Bun subprocess.
- Bun worker: stdin/stdout JSON-RPC, `renderToString`, component registry
- Django bridge: subprocess management, IPC, request synthesis
- Template tag: `{% mizan_render "ProfilePage" user_profile=profile %}`
- Hydration: `window.__MIZAN_SSR_DATA__` consumed by generated providers
- Generated contexts check SSR data before first fetch
---
## Mizan Cloud (closed-source)
### Mizan Edge
Cloudflare Workers for automatic edge caching.
- Reads the Edge manifest to configure cache rules
- Context GETs cached at edge, keyed by context name + params
- Reads `X-Mizan-Invalidate` header from mutation responses to purge caches
- Reads JSON `invalidate` key from RPC responses for the same purpose
- Resolves URL patterns from manifest to purge view pages
- Zero configuration — the manifest IS the cache policy
### Mizan Render
SSR at the edge via Cloudflare Workers.
- The Bun SSR bridge, running on Cloudflare instead of colocated with Django
- Context data fetched from Django (or edge cache), rendered at the edge
- HTML response streamed to the user from the nearest PoP
### Mizan Deploy
One-command deployment for Django + React apps.
- Container orchestration (AWS/Azure)
- Edge + Render auto-configured
- `mizan deploy` from the CLI
- The Vercel experience for Django
---
## Protocol Spec (AFI)
The protocol is the product. Two invalidation transports. Every endpoint CDN-ready.
### Context fetch
```
GET /api/mizan/ctx/<name>/?param=value
200 OK
Cache-Control: public, max-age=0, s-maxage=31536000
{
"function_a": { ... },
"function_b": [ ... ]
}
```
### Mutation call (RPC path — JSON body transport)
```
POST /api/mizan/call/
Cache-Control: no-store
{
"result": { ... },
"invalidate": ["context_name"]
}
```
### Mutation call (View path — header transport)
```
POST /profile/update/
302 Found
Location: /profile/5/
Cache-Control: no-store
X-Mizan-Invalidate: user;user_id=5, notifications
```
### Scoped invalidation (JSON)
```json
{
"result": { ... },
"invalidate": [
"notifications",
{ "context": "user", "params": { "user_id": 5 } }
]
}
```
### Scoped invalidation (Header)
```
X-Mizan-Invalidate: user;user_id=5, notifications
```
### Edge manifest
```json
{
"contexts": {
"user": {
"endpoints": ["/api/mizan/ctx/user/"],
"views": ["/profile/:user_id/"],
"params": ["user_id"]
}
}
}
```