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

131 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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