diff --git a/DECISIONS.md b/DECISIONS.md index 5798e51..4870990 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1219,6 +1219,54 @@ stops scraping; the app is unaffected. No schema change. --- +## ADR-031 — SPA-like reader: inline-expand summary + Q&A in the list (HTMX, no framework) + +**Status:** Proposed (2026-06-12). Issue #16. **Draft for review — no code yet.** + +**Context / requirements.** The reader is multi-page: a list of compact cards (`/`), then a +navigation to a separate detail page (`/v/{id}`) for the full summary + the docked chat (ADR-027). +It feels less fluid than a single integrated view. We want the full summary AND the per-video +Q&A to open **in place in the list**, no page hop. Requirements: +- R1: clicking a summarized card expands it in place to the full summary (summary/highlights/ + takeaways) + the chat dock; a collapse returns it to the compact card. +- R2: **no SPA framework** — stay HTMX + Templ (ADR-003); reuse existing fragments, not a rewrite. +- R3: **progressive enhancement** — with JS off, the card link still navigates to `/v/{id}` + (the detail page stays as the no-JS + deep-link surface). Nothing becomes JS-only. +- R4: only **summarized** cards expand; pending/rate-limited/no-caption cards keep their current + footer behaviour (Summarize button, waiting/none states). +- R5: chat inside an expanded card works exactly as on the detail page (reuse `chatReveal`/ + `chatSection` + the existing `/v/{id}/chat` endpoints, unchanged). + +**Decision / architecture.** +1. **Reuse the existing fragments.** `summaryBody(r)` and `chatReveal(videoID)` already exist and + render the detail page; a new `expandedCard(r, chatEnabled)` composes the compact header + a + collapse control + `summaryBody` + `chatReveal`. `DetailPage` is refactored to also compose + `summaryBody` so the two never drift (DRY). +2. **Two fragment endpoints** (mirroring the existing list/status HTMX fragment pattern): + `GET /v/{videoId}/expand` → `expandedCard`; collapse reuses the existing compact `VideoCard` + via `GET /v/{videoId}/card`. Both are list-card `