docs(arch): update hypermedia architecture blueprint and AGENTS.md with SSE adapter, mid-stream resilience, and AI-optimized coding principles
This commit is contained in:
parent
f6b5dd3992
commit
70542c2dc2
59
AGENTS.md
59
AGENTS.md
@ -65,7 +65,64 @@ Management (IAM) fabric and WebAuthn Passkey authority.
|
||||
`tasks/GUIDELINES.md`) by reference rather than copy-pasting operational
|
||||
rules into prompts.
|
||||
|
||||
## 4. History & Context Link
|
||||
## 4. Hypermedia, Datastar & Vertical Feature Slicing Rules
|
||||
|
||||
1. **Locality of Behavior (Vertical Slicing):**
|
||||
- Co-locate all domain routes, queries, and UI view fragments in
|
||||
`src/features/<domain>/`.
|
||||
- Name template files `fragments.tsx` or `views.tsx` to reinforce the
|
||||
server-side hypermedia model.
|
||||
2. **Right-Sized Transport Selection:**
|
||||
- Standard point-to-point user actions MUST return standard `text/html` JSX
|
||||
fragments.
|
||||
- SSE streams (`text/event-stream`) are STRICTLY reserved for multi-user
|
||||
broadcasts and live pub/sub updates.
|
||||
- Abstract SSE protocol strings behind a typed Datastar adapter/SDK. Never
|
||||
hand-roll raw SSE strings in route handlers.
|
||||
3. **Hypermedia Error Invariant & Mid-Stream Resilience:**
|
||||
- Never return raw JSON error payloads to browser/Datastar callers.
|
||||
- All 4xx validation errors and 5xx server faults MUST return an HTML error
|
||||
fragment targeting `#status-banner` or `.field-error`.
|
||||
- If an error occurs mid-stream after an SSE connection is open (HTTP 200),
|
||||
the handler must yield an error toast fragment before closing cleanly.
|
||||
4. **Durable State vs. Transient Signals:**
|
||||
- Database (PostgreSQL) and Cache (Valkey) are the SOLE authoritative sources
|
||||
of state.
|
||||
- Datastar `data-signals` must ONLY be used for transient presentation
|
||||
toggles (e.g. dropdown open/close). Never cache domain data or store auth
|
||||
secrets in client signals.
|
||||
5. **Vanilla JS Subtree Protection:**
|
||||
- Any DOM element manipulated by native browser APIs (WebAuthn passkeys,
|
||||
clipboard copy feedback) MUST include `data-ignore` or `data-ignore-morph`
|
||||
to prevent Datastar reconciliation conflicts.
|
||||
6. **Payload & Rate Guardrails:**
|
||||
- All interactive action endpoints must be bounded by rate-limiting and a
|
||||
strict 16KB request body ceiling.
|
||||
|
||||
## 5. AI-Optimized Code Organization & Engineering Principles
|
||||
|
||||
1. **Bounded Files & Concise Functions:**
|
||||
- Target small, focused functions (4–20 lines) and keep files bounded (under
|
||||
300–500 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 1–2 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. History & Context Link
|
||||
|
||||
This repository was cleanly extracted from `ed-droid`.
|
||||
|
||||
|
||||
212
docs/HYPERMEDIA_ARCHITECTURE_BLUEPRINT.md
Normal file
212
docs/HYPERMEDIA_ARCHITECTURE_BLUEPRINT.md
Normal file
@ -0,0 +1,212 @@
|
||||
# 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
|
||||
(`<script>`).
|
||||
|
||||
---
|
||||
|
||||
## 5. AI-Optimized Code Organization & Engineering Principles
|
||||
|
||||
1. **Bounded Files & Concise Functions:**
|
||||
- Target small, focused functions (4–20 lines) and keep files bounded (under
|
||||
300–500 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 1–2 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.
|
||||
Loading…
x
Reference in New Issue
Block a user