diff --git a/docs/architecture/architecture.md b/docs/architecture/architecture.md
index 022f64e..e4ba02d 100644
--- a/docs/architecture/architecture.md
+++ b/docs/architecture/architecture.md
@@ -45,7 +45,7 @@ adapter behind an interface (Clean Architecture ports & adapters).
```mermaid
graph TB
subgraph tapir["Tapir (Go)"]
- http["HTTP server
OAuth callbacks +
user-facing API"]
+ http["tapir serve
(HTMX+Templ web surface:
read summaries, connect,
account, summarize)"]
watcher["Watcher
detects new videos
(WebSub + poll)"]
engine["Summarization engine
(use-case core)"]
resolver["Transcript resolver
(captions-first)"]
@@ -95,6 +95,66 @@ two codebases (ADR-003).
---
+## Web surface — `tapir serve` (Stage 1, ADR-011 → ADR-012)
+
+A later transport added over the **unchanged** engine/ports/sinks core (ADR-003): `tapir serve`
+is an HTMX+Templ reader/writer (`internal/web`) over the existing `store`. It added no business
+logic to the engine — it reads the store and, for one action, kicks the existing engine. ADR-011
+shipped it single-user; ADR-012 opened multi-user with DB-enforced (RLS) isolation.
+
+```mermaid
+graph TB
+ browser["Browser
(Dex-authenticated user)"]
+ subgraph web["internal/web (tapir serve)"]
+ oidc["oidc
Dex OIDC session
(authenticate-only)"]
+ gate["registration gate
new subject -> /register"]
+ pages["summary list + detail
(read) + actions"]
+ connect["/oauth/youtube/callback
per-user token connect"]
+ account["account
(disconnect, delete)"]
+ summarize["Summarize button
-> background goroutine"]
+ end
+ store[("store
(Postgres, RLS per user)")]
+ engine["Summarization engine
(unchanged core)"]
+ secrets["SecretStore
(per-user token refs)"]
+
+ browser --> oidc
+ oidc --> gate
+ gate --> pages
+ pages --> store
+ connect --> secrets
+ connect --> store
+ account --> store
+ account --> secrets
+ summarize -->|background| engine
+ summarize -->|HTMX status poll| store
+ engine --> store
+```
+
+- **Dex OIDC session layer** (`internal/web/oidc`) — **authenticate-only** (ADR-012). It proves
+ *who*; authorization/isolation is the DB's job (RLS), not the session's.
+- **Registration gate** — a Dex subject with no `users` row is routed to `/register`, which
+ creates the `users` row + the `user_identities` mapping (migration 004). Returning subjects
+ pass straight through.
+- **Web-initiated YouTube connect** — `/oauth/youtube/connect` → `/oauth/youtube/callback`
+ persists a **per-user** refresh-token ref (`youtube//refresh_token`) via `SecretStore`
+ and a `video_connections` row (ADR-006, migration 005). Distinct from the CLI `tapir auth`.
+- **Account management** — `/account` offers disconnect and **delete account**. Delete removes
+ only Tapir-side state (cascade across the user's tables + secret refs); the shared Dex identity
+ is left intact (ADR-013).
+- **Immediate summarization** — the web "Summarize" button (`POST /v/{id}/summarize`) fires the
+ engine in a **background goroutine** inside `serve`; the page HTMX-polls `/v/{id}/status`,
+ showing a Charmbracelet spinner while in-flight (and an honest "queued/waiting" state under
+ rate-limiting — ADR-014).
+- **Summarization mode** — `users.auto_summarize` (migration 006). Auto: every new video is
+ summarized. Manual (default): new videos appear unsummarized; the button sets
+ `videos.summarize_requested`, which the next `tapir run` processes and clears. Both the click
+ path and the batch `tapir run` drive the same unchanged engine.
+
+The engine, ports, and sink adapters are **untouched** by all of the above — the web surface only
+reads the store and triggers the existing engine. Adding it changed wiring, not the core (ADR-003).
+
+---
+
## Sequence — core use case: new video summarized
```mermaid
@@ -191,6 +251,8 @@ Gherkin features in `docs/use-cases/`).
- Audio-download + speech-to-text resolver (ADR-007) — would be an additional `VideoSource`
fallback path, drawn when built.
-- Multi-tenant isolation primitives (per-tenant Postgres role, NetworkPolicy, tenant label)
- — activate at Stage 1 (ADR-002); single-user Stage 0 doesn't exercise them.
+- Per-user isolation is **live, not deferred**: Postgres RLS `FORCE`d on every user-owned table
+ (ADR-012, migration 003), realising ADR-002's per-tenant intent at the DB layer. The coarser
+ multi-tenant primitives (per-namespace NetworkPolicy, Kyverno, tenant label) remain a
+ Stage-2 hardening item, not exercised yet.
- Public SaaS surface (sign-up, billing) — Future C, not built (ADR-008).