- Proxy notification image_url server-side (GET /api/v1/notifications/:id/image) instead of loading it directly in the browser, so LAN-only image sources (e.g. Frigate snapshots) still load for clients off that network - Tighten CSP img-src to 'self' now that images are same-origin - Update threat model / architecture docs to match the new image-fetch design - Expand README: Home Assistant quick-start, Pocket ID/OIDC walkthrough, Pangolin note, backup automation, new troubleshooting entries - Fix docker-compose.yml: document that --env-file .env must be passed explicitly (Compose's implicit .env lookup was unreliable with -f from a different directory) - Fix image-proxy tests to build a real session cookie (AUTH_MODE=oidc applies inside the test container too, so requireAuth needs one)
35 lines
3.8 KiB
Markdown
35 lines
3.8 KiB
Markdown
# Notizarr — Phase 1 Design Package
|
||
|
||
This is the Phase 1 deliverable: architecture, threat model, data model, API
|
||
design, PWA/Web Push design, Docker/Unraid design, folder structure, and the
|
||
phased implementation plan. **No application code is written in this phase.**
|
||
Per the project's own process rules, implementation (Phase 2+) does not start
|
||
until this package is reviewed and the open decisions below are confirmed.
|
||
|
||
## Documents
|
||
|
||
1. [01-architecture.md](01-architecture.md) — components, containers, data flow
|
||
2. [02-threat-model.md](02-threat-model.md) — trust boundaries, STRIDE notes, mitigations
|
||
3. [03-database-model.md](03-database-model.md) — full Postgres schema
|
||
4. [04-api-design.md](04-api-design.md) — public app API + LAN ingestion API
|
||
5. [05-pwa-web-push-design.md](05-pwa-web-push-design.md) — manifest, service worker, push flow, iOS notes
|
||
6. [06-docker-unraid-design.md](06-docker-unraid-design.md) — compose design, volumes, networking
|
||
7. [07-folder-structure.md](07-folder-structure.md) — repo layout vs. deployment layout
|
||
8. [08-implementation-plan.md](08-implementation-plan.md) — Phase 2–10 task breakdown, mapped to MVP acceptance criteria
|
||
|
||
## Open decisions that need your sign-off before Phase 2
|
||
|
||
These are the "major implementation decisions" the process asks to pause on:
|
||
|
||
| # | Decision | Recommendation | Why |
|
||
|---|---|---|---|
|
||
| 1 | Backend language/framework | **Node.js 22 + TypeScript, Fastify** | One language across front+back end for a solo-maintained homelab app; `web-push` and `openid-client` are the most mature libraries for the two hardest requirements (Web Push, OIDC); Fastify has first-class schema validation and low overhead. |
|
||
| 2 | ORM / migrations | **Drizzle ORM + drizzle-kit** | Typesafe, SQL-first, no native binary/engine (unlike Prisma) — simpler in a small Alpine container, plain-SQL migration files you can read and back up. |
|
||
| 3 | Realtime "instant in UI" delivery | **Server-Sent Events (SSE)**, in-process pub/sub, no Redis | Single-instance app; SSE is one-way (all we need), works over plain HTTP through a reverse proxy, avoids the complexity of a WebSocket + no new infra. |
|
||
| 4 | VAPID key storage | **Postgres `system_settings` table**, generated on first boot if absent | Already-durable volume; no separate key file to remember to back up — `pg_dump` covers it automatically. |
|
||
| 5 | Attachments / image handling | `external_url` is stored as a plain URL and rendered as `<a href>`, never fetched server-side. `image_url` **is** fetched server-side and proxied (`GET /api/v1/notifications/:id/image`) so a LAN-only image source still loads for a client off that LAN — narrowly scoped (no client-supplied URL, requires a scoped token to have set it, timeout + size cap), not a general-purpose fetch proxy. See `02-threat-model.md`'s SSRF section. | A homelab client (phone on cellular) still needs to see camera snapshots from LAN-only sources like Frigate; a pure direct-browser-load design can't do that. Doesn't support arbitrary file uploads in v1 (can be added later as an explicit, scoped feature). |
|
||
| 6 | Webhook mapping | MVP ships a **fixed simple mapping** (`{topic, title, message, url?}` JSON body, or ntfy-style headers), not a configurable templating engine | Spec says "goal is easy migration, not full protocol cloning"; a mapping UI is called out as a later enhancement. |
|
||
| 7 | Topic access control | Topics are **visible to all authenticated users by default**; an admin can mark a topic `restricted` and grant per-user access | Matches "single/small household" simplicity principle while still satisfying "users can browse allowed topics." |
|
||
|
||
If any of these should go differently, say so and I'll adjust the design before Phase 2 starts. Otherwise, confirming this package moves us into Phase 2 (repo bootstrap + Docker Compose skeleton).
|