# SSR Architecture

*Decided 2026-04-07.*

Mizan's SSR adapter is a **Django template backend**. It plugs into
Django's existing `TEMPLATES` setting, replacing the template
rendering engine.

```python
TEMPLATES = [
    {
        'BACKEND': 'mizan.ssr.MizanTemplates',
        'DIRS': [BASE_DIR / 'frontend'],
        'OPTIONS': {
            'worker': 'path/to/mizan-ssr/src/worker.tsx',
            'timeout': 5,
        },
    }
]
```

Then `render(request, 'components/Hello.tsx', context)` calls the Bun
subprocess bridge instead of rendering a Django/Jinja2 template.
**The template name IS a `.tsx`/`.jsx` file path**, resolved against
`DIRS`; `get_template` returns a `MizanTemplate` wrapping the absolute
file path. The context dict becomes the component's props (`request`
and `csrf_token` stripped). Rendered output is wrapped in
`<div id="mizan-root">…</div>` plus a
`<script>window.__MIZAN_SSR_DATA__=…</script>` hydration payload.

## AFI boundary

| Side | Responsibility |
|---|---|
| Backend adapter (`SSRBridge`) | Manages the Bun subprocess lifecycle; gathers props |
| Bun worker (`worker.tsx`) | `import()`s the file path, `renderToString(createElement(Component, props))` |
| stdin/stdout JSON-RPC | Newline-delimited; `{id, method:"render", params:{file, props}}` → `{id, html}` / `{id, error}`; `ping` → `{id, pong:true}` |

## Why template backend

- Django's template system is swappable by design (batteries
  included, but replaceable).
- Django developers already use `render(request, template, context)`
  — no new API to learn.
- URL routing, views, middleware, auth — all unchanged.

> A `templatetags/` package exists for a future `{% mizan_render %}`
> convenience tag (base.html shell with Mizan components inside), but
> it is currently empty — no tag is implemented yet.

## Implementation surface

The SSR backend (`mizan/ssr/backend.py`) implements Django's template
backend interface:

- `MizanTemplates(BaseEngine)` — requires `OPTIONS['worker']` (path to
  `worker.tsx`); `get_template(name)` resolves a file under `DIRS`
- `MizanTemplate` with `.render(context, request)` → calls the bridge
- `SSRBridge` (`bridge.py`) — spawns `bun run <worker>`, holds the
  persistent subprocess, correlates requests by message id, thread-safe,
  auto-restarts on crash, waits for the worker's ready signal

Everything Django expects from a template backend, but the actual
rendering routes to Bun.
