Work through TODO follow-ups: analytics, admin sort/filter, search facets, double opt-in, tests

Work through TODO follow-ups: analytics, admin sort/filter, search facets, double opt-in, tests

#1 in tonybierman/dx-blog — merged 2026-05-29

Summary

Builds out the dx-blog feature backlog on top of the initial scaffold. The branch carries two batches of TODO follow-ups plus housekeeping.

Batch 1 (187d0e1)

  • Account/MFA: /account wrapping arium's AccountSettings + MfaSetup; MfaChallenge handling LoginOutcome::MfaRequired in the login flow.
  • Feeds: pagination for tag / author / archive feeds.
  • Authoring: per-post edit affordance from the post detail page via ResourceGate; author-facing draft preview.
  • Reader: real featured-posts (most-viewed) + recent-comments home sidebar; loading skeletons.
  • Ops: server-side error boundary routing runtime errors to /500.

Batch 2 (398ac67)

  • Analytics: top referrers + 30-day views-over-time chart on /admin/analytics (top_referrers/views_over_time server fns; ReferrerStat/DailyViews types).
  • Admin post table: status filter + sortable Title/Status/Published headers (admin_list_posts is now #[post] with whitelisted sort + status_filter).
  • Search facets: category/tag/date filters in the sidebar (search_posts gains optional category_slug/tag_slug/date_range, bound-param WHERE fragment).
  • Subscriber double opt-in: subscribe issues a randomblob token (new idempotent subscriber_tokens table) + emails a confirm link; /subscribe/confirm flips the confirmed flag.
  • Tests: markdown render/sanitize, slug uniqueness, comment auto-approve rule (src/server/tests.rs, in-memory SQLite + #[tokio::test]).

Housekeeping (65bffcd)

  • Gitignore local planning notes (TODO*.md).

Test plan

  • cargo check --no-default-features --features server,sqlite — server target ✓
  • cargo check --no-default-features --features web --target wasm32-unknown-unknown — wasm client ✓
  • cargo test --no-default-features --features server,sqlite — 7 passing ✓

🤖 Generated with Claude Code

Last updated 2026-05-30