Initial commit

This commit is contained in:
siliconsolder committed 2026-09-07 09:54:30 +00:00
commit 38c24fc9dc
166 files changed
+22002

No files matched your search

+130
View File
@@ -0,0 +1,130 @@
# 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