Files
Notizarr/docs/phase1/08-implementation-plan.md
2026-09-07 09:54:30 +00:00

6.3 KiB
Raw Permalink Blame History

08 — Implementation Plan (Phases 2–10)

Each phase ends with: run tests, run lint, build, fix all errors, verify docker compose up -d still works end-to-end for whatever exists so far. No phase starts until the previous one is green.

Phase 2 — Bootstrap project & Docker Compose

  • npm/pnpm workspace scaffold (apps/server, apps/web, packages/shared)
  • Fastify skeleton with the two listeners (8080/8081), /health, /ready
  • Vite + React + Tailwind skeleton, dark theme tokens, empty shell page
  • Drizzle configured against Postgres; docker-compose.yml (dev) brings up notizarr (hot-reload) + notizarr-postgres
  • Dockerfile (multi-stage: build web → build server → copy web dist into server's static dir → slim runtime image), non-root user, healthcheck script
  • Exit criteria: docker compose up -d succeeds, notizarr-postgres is healthy, GET :8080/health returns 200, empty React shell loads.

Phase 3 — Database + backend API skeleton

  • All tables from 03-database-model.md as Drizzle schema + migrations
  • CRUD-level modules for topics, notifications (insert, list, get) with no auth yet (stubbed), so the data layer can be exercised
  • OpenAPI schema generation wired up, /docs serving it
  • Unit tests for schema constraints (unique slugs, FK cascades, retention math)
  • Exit criteria: migrations run clean on a fresh DB; can insert/list a topic and a notification via the API without auth.

Phase 4 — Authentication + API tokens

  • OIDC module (openid-client): login/callback/logout, PKCE, state/nonce validation, session cookie issuance, bootstrap-first-admin logic
  • Proxy-auth module: trusted-CIDR check, header parsing, session creation
  • AUTH_MODE=disabled (local dev convenience: single implicit admin user)
  • API token module: create/list/revoke/rotate, hashing, scoping (topics/source/CIDR/expiry), last-used tracking
  • CSRF protection (Origin check + custom header) on listener A mutations
  • Tests: each auth mode, token scope enforcement, revoked/expired token rejection, CSRF rejection on cross-origin mutation attempts
  • Exit criteria: MVP criteria #5–7 (auth works, admin can create a topic, admin can create a scoped token) pass manually and via tests.

Phase 5 — Notification ingestion + history

  • Listener B: canonical publish endpoint, /api/v1/topics/:slug alias, ntfy-compat endpoint, webhook endpoint
  • Rate limiter (per-token, per-IP), INGESTION_ALLOWED_CIDRS enforcement
  • Deduplication logic, occurrence_count increment
  • SSE stream on listener A (notification.created/updated events)
  • Read/unread + starred state, unread-count aggregation per topic
  • Retention cleanup interval job
  • Tests: ingestion auth/scoping, rate limiting (burst + sustained), dedup window behavior, SSE fan-out, retention deletion
  • Exit criteria: MVP criteria #8–10 (LAN client can publish, appears instantly via SSE, persisted) pass.

Phase 6 — Frontend UI

  • Navigation shells: mobile bottom nav (Inbox/Topics/Search/Starred/ Settings), desktop sidebar + stream + optional detail panel
  • Topic list (unread/total/latest, bell state), topic settings screen (push ON/OFF toggle)
  • Notification list (cards per spec), notification detail (/topics/:slug/messages/:id), search + filters
  • Empty states, loading skeletons, dark-first theme, responsive breakpoints
  • Manual + automated visual smoke checks in the Browser tool (mobile and desktop viewport)
  • Exit criteria: MVP criteria #22 (polished on iPhone and desktop) — judged by hand in the browser tool at this stage, refined further in Phase 7/8.

Phase 7 — PWA + Web Push

  • vite-plugin-pwa with injectManifest, manifest.webmanifest, icon set (incl. maskable + apple-touch-icon), safe-area CSS
  • Service worker: precache, runtime caching, push/notificationclick handlers
  • VAPID generation/storage in system_settings, web-push send integration wired into the Phase 5 fan-out step (previously a no-op stub)
  • Subscribe/unsubscribe flow, devices screen, diagnostics screen
  • Manual iPhone test pass (install to Home Screen, enable notifications, trigger a real push, confirm deep link opens the right message)
  • Exit criteria: MVP criteria #11–18 (PWA installable, push permission, subscription stored, push ON sends / OFF doesn't, arrives on iPhone, tapping opens exact notification) pass.

Phase 8 — Admin UI + rate limiting polish + diagnostics

  • Admin dashboard widgets (04-api-design.md's /admin/stats/dashboard)
  • Noisy-source detection thresholds + admin warnings
  • Tokens/Users/Devices/Push/Security/System admin screens
  • Audit log viewer
  • Settings screens (user + admin) per 01-architecture.md
  • Exit criteria: full admin IA from the spec is navigable and functional; rate-limit rejections are visible end-to-end (trigger one, see it flagged).

Phase 9 — Migration helpers + ntfy compatibility hardening

  • docs/migration-ntfy.md: side-by-side ntfy → Notizarr endpoint mapping
  • docs/home-assistant.md: rest_command example replacing ntfy.publish (as given in the spec), plus one example per currently-used service (Seerr, Uptime Kuma, generic webhook)
  • Compatibility test matrix: header-based, JSON-based, query-param-based ntfy-style requests all produce equivalent stored notifications
  • Exit criteria: MVP criteria #8 re-verified using an ntfy-style request shape, not just the canonical API.

Phase 10 — Testing + hardening + documentation

  • Fill any remaining gaps in the automated test list from the original spec (stale push subscription cleanup, device removal, authorization matrix across roles, retention cleanup edge cases)
  • Security pass: CSP, HSTS, frame-ancestors, request size limits, dependency audit
  • Top-level README.md: install, configure .env, deploy on Unraid, backup/restore, troubleshooting (linking the diagnostics screen)
  • Full MVP acceptance checklist run end-to-end, including container restart persistence checks (#19–21)
  • Exit criteria: all 22 MVP acceptance criteria pass.

Cross-cutting, done incrementally rather than as a separate phase

  • Structured logging + secret redaction: introduced in Phase 2, extended as new modules land
  • Metrics: introduced alongside the ingestion endpoints in Phase 5
  • Lint/typecheck/test/build as CI-equivalent local commands: set up in Phase 2, run at the end of every subsequent phase