Commit Graph
6 Commits
Author SHA1 Message Date
mathiasandClaude Opus 4.8 5d029a2823 feat(store): default auto_summarize ON for new users (ADR-018)
Migration 011 flips the auto_summarize column default to TRUE and brings
existing rows (maintainer + current registrations) along. Onboarded friends
now get zero-friction discovery: scheduled discovery (ADR-018) both discovers
AND summarizes new videos, so a user's list fills and summarizes itself
instead of presenting an empty list of manual Summarize buttons.

Safe only because the process-wide caption-fetch rate gate (ADR-014 item 2,
prior commit) now exists — auto + scheduled + multi-user would otherwise
self-inflict 429s every cycle. The down migration reverts the default but
intentionally leaves existing rows as-is (no surprise manual regression on
rollback). RegisterUser already lets the column default drive the value, so
no app change is needed; the account-page manual toggle still works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 23:42:23 +02:00
mathiasandClaude Opus 4.8 b070347597 feat(store): add append-only login_events table with forced RLS
Stage-0 usage measurement (VISION/ADR-016): summary_actions captures acts
(watch/skip/save) but not reads. A reader who logs in weekly and clicks
nothing is invisible — for a reading product that return is the signal the
gate ("usage in >=2 distinct weeks") is defined on. login_events records
THAT a user was active, append-only, one row per user per active day.

Per-user isolation via the same GUC-keyed FORCE RLS policy as migration 003.
No FK to users (mirrors summary_actions) — the cascade footgun is handled by
DeleteUser in a later commit. Adds an up/down reversibility test and registers
the table in both truncate helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 23:46:03 +02:00
mathiasandClaude Opus 4.8 3014ee0d60 feat(web): summarization-mode UI — all-videos list, Summarize queue, mode toggle
CI / Lint / Test / Vet (push) Successful in 10s
CI / Build & Import (push) Successful in 10s
CI / Mirror to GitHub (push) Has been skipped
The list now shows ALL videos (ListVideos), not just summaries. Summarized cards
are unchanged; discovered-but-unsummarized videos render with a muted "pending"
treatment and either a "Summarize" button or a "Queued" chip.

- POST /v/{videoId}/summarize queues a video (RequestSummarize) and returns the
  refreshed card — it does NOT run the engine inline; `tapir run` is the single
  summarization driver, which picks up the flag on its next pass.
- Account page gains an Automatic/Manual toggle (POST /account/summarize-mode →
  SetAutoSummarize), shown as the current mode with a one-click switch.
- Both new POSTs degrade without JS (redirect back); HTMX swaps the fragment.

VideoCard and summarizeModeControl are extracted templ fragments reused as the
HTMX swap targets. views_templ.go regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 19:31:29 +02:00
mathiasandClaude Opus 4.8 7b4960e417 feat(web): registration gate + per-request user-id seam (ADR-012)
CI / Lint / Test / Vet (push) Successful in 9s
CI / Build & Import (push) Successful in 10s
CI / Mirror to GitHub (push) Failing after 3s
Multi-user web surface. Two layered middlewares: Auth.Middleware (Dex
session required) wraps registrationGate, which resolves the authenticated
subject -> tapir user_id once per request via the new web.Identity port and
stashes it. A subject with no tapir user is redirected to GET /register
(display name + accept-terms); POST /register calls RegisterUser then
redirects to /. /register is inside the auth guard but exempt from the gate
(/auth/* and /healthz too).

Current-user seam: CurrentUserID(r) (string, bool) returns the resolved id
from the request context. The list/detail/action handlers now scope by it,
replacing the single configured App.UserID (removed). App gains an Identity
field; *store.Store satisfies both Store and Identity. cmd/tapir wires
Identity: st and drops UserID.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:00:30 +02:00
mathias d9b7107ccb feat(web): sleek Stage-0 reader — design system, card list, reader detail
Implements the Top 5 fixes from the Stage-0 UX review (docs/ux-review/UX-REVIEW.md):

1. Dark mode: full light+dark custom-property palette (bg/fg/muted/line/accent/
   card) under :root + @media (prefers-color-scheme: dark), applied to body.
   color-scheme: light dark is now actually honoured — summary text was invisible
   on a dark canvas before.
2. Table -> responsive card list: one card per summary (title link, channel·date
   meta, provider chip, fallback badge, action state). Single-column reflow at
   375px, no horizontal crush.
3. Minimal design system: 4/8px spacing scale, one accent, styled accent links
   (underline-on-hover), real buttons with active/pressed state, consistent
   radius and dividers — applied across list + detail.
4. Detail page as a reader: prose capped at 38rem, title->meta->summary->
   highlights->takeaways hierarchy with section rules, 1.7 line-height. Meta is
   built from non-empty parts (detailMeta) so the no-video edge case no longer
   renders a stray "· — ·".
5. Contrast + a11y: muted bumped to #595959 (~7:1, clears WCAG AA), fallback
   badge gets vertical padding + aria-label/title, friendly first-run empty
   state, hx-indicator on the filter form.

Tests updated for the card markup (table -> cards); missing date is now omitted
rather than em-dashed. task check green; HTMX action toggles verified working.
2026-06-03 00:20:22 +02:00
mathiasandClaude Opus 4.8 71689ced60 feat(web): Stage-0 reader UI — Templ+HTMX pages + tapir serve
Add the lane-C reader surface: list, detail, and an action button-group
fragment over the lane-A store reads/actions, behind the web.Auth seam.

- Templ components (base layout, list+filters, detail, ActionButtons) with
  committed *_templ.go so go build/task check work without the templ binary;
  `task generate` regenerates. Filters and action toggles are HTMX-swapped and
  degrade to plain form GET/POST (POST→303→GET) without JS.
- Handlers (internal/web): GET / (channel+date filters, in-memory),
  GET /v/{videoId}, POST /v/{videoId}/action (re-click clears, else SetAction;
  store enforces watched↔skipped exclusion), GET /healthz (no auth). Store ops
  run as the configured UserID; Auth only gates.
- `tapir serve` wires store + StubAuth{Subject: cfg.UserID} + http.Server on
  TAPIR_HTTP_ADDR (default :8080), graceful shutdown on signal. Handlers depend
  only on web.Auth — Conductor swaps StubAuth → oidc.DexAuth at merge (one line
  in cmdServe).
- Handler tests: real store (embedded-postgres) + StubAuth — list rows+state,
  HTMX fragment vs full page, channel filter, detail highlights/takeaways,
  404, action toggle+clear, no-JS redirect, bad-verb 400.

New dep: github.com/a-h/templ — the house default for typed server-rendered
HTML (CLAUDE.md stack, ui-spec.md §3). Generated code is committed so the
templ binary is build-time-optional.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 23:47:47 +02:00