auth-yes/docs/HYPERMEDIA_ARCHITECTURE_BLUEPRINT.md

213 lines
10 KiB
Markdown
Raw Permalink 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.

# Hypermedia & Vertical Slicing Architecture Blueprint
This document defines the architectural specification and plan of record for
Auth-Yes's transition to a server-driven hypermedia paradigm (Datastar + Deno
2 + Hono SSR JSX) and vertical feature slicing.
---
## 1. System Architecture Overview
```mermaid
graph TD
subgraph Client ["Browser Client (Zero-Build)"]
HTML["DOM (Morph Targets)"]
Ignored["Vanilla Subtree (data-ignore)<br/>[WebAuthn Ceremony & Copy Feedback]"]
DS["Datastar Engine (~12kB Pinned)"]
Sig["data-signals (Transient UI Toggles ONLY)"]
end
subgraph Security ["Ingress & Invariant Guards"]
RL["Rate Limiter & 16KB Payload Cap"]
CSRF["Origin / Sec-Fetch-Site Check"]
CN["Content Negotiator (HTML vs JSON vs Shell)"]
end
subgraph Server ["Deno 2 + Hono SSR Engine"]
subgraph Slices ["Vertical Feature Slices (src/features/)"]
Sess["sessions/ (routes.ts, queries.ts, fragments.tsx)"]
Evt["events/ (routes.ts, queries.ts, fragments.tsx)"]
Adm["admin/ (routes.ts, queries.ts, fragments.tsx)"]
end
end
subgraph Data ["Authoritative Data Layer (Zero Client Cache)"]
PG[(PostgreSQL 18 - Authoritative State)]
VK[(Valkey 8 - Pub/Sub & L1 Cache)]
end
HTML -->|data-on-click / data-on-submit| DS
DS -->|Standard HTTP POST/PATCH with 16KB limit| RL
RL --> CSRF --> CN
CN -->|Browser Context| Slices
Slices --> PG & VK
Slices -->|Success 200: JSX View Fragment| HTML
Slices -->|Failure 400/500: JSX Error Toast Fragment| HTML
VK -.->|Targeted SSE Stream (Live Seats/Killswitch)| DS
DS -.->|Morphs DOM, preserves data-ignore| HTML
```
---
## 2. Core Architectural Standards
#### Standard A: Dual-Transport & Right-Sized Delivery
- **Mutations & User Interactions (`POST` / `PATCH`):** Return standard,
stateless `text/html` JSX fragments. Zero long-lived connection overhead.
- **Live Multi-User Broadcasts:** Targeted Server-Sent Events (SSE) bound to
Valkey Pub/Sub with `X-Accel-Buffering: no` for real-time seat counts and
remote session invalidation.
- **Abstracted Protocol Strings:** SSE event formatting is strictly encapsulated
in a typed adapter/SDK (`core/sse_adapter.ts`) rather than
string-concatenation in route handlers.
- **Headless Terminal & SDK Consumers:** Standard REST / ConnectRPC returning
JSON/shell strings via `Content-Negotiation`.
### Standard B: Hypermedia Unhappy Path & Error Protocol
- **Never return raw JSON errors to Datastar.** If a validation fails, a seat
limit is exceeded, or an internal error occurs:
- The server returns an HTTP 422/400/500 status with an **HTML error
fragment** targeting `#field-error-${name}` or `#status-banner`.
- Datastar morphs the error toast into place seamlessly without breaking the
hypermedia loop.
- **Mid-Stream Error Handling:** Because SSE streams open with `200 OK`, any
error occurring after connection initialization cannot return a 500 status.
The stream handler must yield an error toast fragment before cleanly closing
the connection.
### Standard C: Signal Boundaries & The Durable State Invariant
- **Authoritative Server Rule:** PostgreSQL and Valkey are the _only_ sources of
truth. Datastar `data-signals` are strictly transient (e.g.
`{ isDrawerOpen: false, activeTab: 'single' }`).
- **Zero Secrets in Signals:** Never place session tokens, passkeys, or
permission claims in client signals.
### Standard D: Vanilla DOM Isolation (`data-ignore`)
- Any DOM element touched by browser-native micro-helpers (WebAuthn passkey
ceremony indicators or clipboard feedback) MUST carry `data-ignore` or
`data-ignore-morph`. Datastar will bypass diffing on these nodes.
### Standard E: Rate Limiting & Signal Payload Caps
- All Datastar action endpoints are protected by `core/auth_guards.ts`:
- Max request body size capped at **16KB** (rejecting oversized signal
payloads).
- Sliding-window rate limiting on interactive triggers to prevent
button-mashing denial-of-service.
---
## 3. Directory Taxonomy (Vertical Feature Slicing)
```
src/
├── core/ <-- Core Invariants & Shared Infrastructure
│ ├── db.ts (PostgreSQL 18 pool & DDL)
│ ├── valkey.ts (Valkey 8 connection & Pub/Sub broker)
│ ├── sse_adapter.ts (Typed Datastar SSE streaming helper)
│ ├── auth_guards.ts (Rate limiter, 16KB payload cap, CSRF/Origin check)
│ ├── content_negotiation.ts (Detects Datastar HTML vs CLI/JSON clients)
│ └── spire_ffi.ts (Rust SPIFFE/mTLS FFI bindings)
├── features/ <-- Self-Contained Domain Feature Slices
│ ├── sessions/
│ │ ├── routes.ts (Hono router: /dashboard/sessions, /api/sessions/delegate)
│ │ ├── queries.ts (Session DB/Valkey queries)
│ │ ├── fragments.tsx (Hono JSX: SessionTable, SessionDeck, HandoffCard)
│ │ └── sessions.test.ts
│ │
│ ├── events/
│ │ ├── routes.ts (Hono router: /events, /join, /rotate-pin, /extend)
│ │ ├── queries.ts (Event passes, claimed seats, attendees queries)
│ │ ├── fragments.tsx (Hono JSX: EventCockpit, WorkshopDrawer, GuestDrawer)
│ │ ├── stream.ts (Targeted SSE stream handler for live seat counters)
│ │ └── events.test.ts
│ │
│ ├── admin/
│ │ ├── routes.ts (Hono router: /admin/users, /admin/apps, /admin/audit)
│ │ ├── queries.ts (Admin management SQL)
│ │ └── fragments.tsx (Hono JSX: AdminTables, RoleModals)
│ │
│ └── auth/
│ ├── routes.ts (Hono router: /login, /register, /recovery)
│ ├── webauthn.ts (Isolated ceremony micro-scripts with data-ignore)
│ └── fragments.tsx (Hono JSX: PasskeyLogin, Onboarding)
├── shared/ <-- STRICTLY Domain-Agnostic UI Atoms
│ └── ui/
│ ├── Layout.tsx (Global shell, strict CSP, loads /public/datastar-v1.x.js)
│ ├── Navbar.tsx (Top navigation bar)
│ ├── Toast.tsx (Target fragment for #status-banner error/success morphs)
│ ├── DrawerShell.tsx (Slide-over overlay, backdrop, and header)
│ ├── PillGroup.tsx (Selection button groups for hours, seats)
│ └── Accordion.tsx (Clean <details> wrapper without double-arrow regressions)
└── tests/arch/ <-- Persistent Architectural & Network Test Harness
├── transport_efficiency.test.ts (Asserts routine mutations return text/html in <2ms)
├── sse_lifecycle.test.ts (Asserts Valkey SSE connection limits and drain cleanup)
├── proxy_buffering.test.ts (Asserts Traefik X-Accel-Buffering: no bypass headers)
├── error_fragment.test.ts (Asserts 4xx/5xx responses return valid JSX error fragments)
├── xss_fuzzing.test.ts (Fuzzes fragment rendering with malicious script payloads)
└── content_negotiation.test.ts (Asserts CLI curl vs Datastar browser request isolation)
```
---
## 4. Persistent Architectural & Network Test Suite (`tests/arch/`)
To guarantee efficiency and prevent regressions as the system evolves, we
maintain a dedicated **Architectural Test Harness**:
1. **Transport Efficiency & Latency Tests:**
- Asserts that routine point-to-point actions (`/extend`, `/rotate-pin`, form
submissions) return standard `text/html` in $<2\text{ms}$ without opening
or leaking SSE stream connections.
2. **SSE Stream Lifecycle & Capacity Tests:**
- Simulates 100+ concurrent live cockpit clients listening to Valkey Pub/Sub;
asserts proper connection draining, explicit disconnect cleanup, and memory
ceiling stability.
3. **Reverse Proxy & Buffering Invariant Tests:**
- Validates that SSE stream endpoints emit `X-Accel-Buffering: no` and
`Cache-Control: no-cache` headers to prevent reverse proxies
(Traefik/Nginx) from choking or buffering streams.
4. **Dual-Mode Content Negotiation Tests:**
- Asserts that `curl -sSL ... /join/:slug?format=env` returns a valid shell
string, `Accept: application/json` returns pure JSON DTOs, and browser
requests return clean Datastar HTML fragments.
5. **XSS & Escape Fuzzing Harness:**
- Feeds script injection strings (`<script>alert(1)</script>`,
`"><img src=x onerror=...>`) into event names and attendee usernames and
asserts the rendered JSX fragment outputs properly escaped entities
(`&lt;script&gt;`).
---
## 5. AI-Optimized Code Organization & Engineering Principles
1. **Bounded Files & Concise Functions:**
- Target small, focused functions (420 lines) and keep files bounded (under
300500 lines) so agents can read, reason, and edit full units in a single
turn without context fragmentation.
2. **Strict Single Responsibility Principle (SRP):**
- Every module must do exactly one thing well. Independent modules allow
agents to isolate and modify code without loading unrelated context.
3. **Flat Call Chains Over Clever DRY Abstractions:**
- Prefer a flat, shallow 12 hop call chain over deep, multi-level
abstraction hierarchies. Shallow boilerplate is vastly superior to a 5-file
hop for AI reasoning.
4. **Highly Distinctive, Searchable Naming:**
- Avoid generic identifiers (`Manager`, `DataHandler`, `process()`). Use
explicit, searchable domain names (`SessionPinRotator`,
`streamGuestDrawerTelemetry`, `SessionHandoffCard`).
5. **Deterministic Tooling Enforcement:**
- All code quality standards must be enforced by automated tooling
(`deno fmt`, `deno task lint`, `deno task check`, `deno test`). Agents must
verify passing gates before completing tasks.
6. **Payload & Rate Guardrails:**
- All interactive action endpoints must be bounded by rate-limiting and a
strict 16KB request body ceiling.