From 1bfe4fd794e6f351718a16f52d40ca7305e15b4b Mon Sep 17 00:00:00 2001 From: Sjoerd de Vries Date: Sat, 5 Sep 2026 14:30:28 +0200 Subject: [PATCH] Add design spec for korting prijstracker Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz --- .../2026-09-05-korting-prijstracker-design.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-05-korting-prijstracker-design.md diff --git a/docs/superpowers/specs/2026-09-05-korting-prijstracker-design.md b/docs/superpowers/specs/2026-09-05-korting-prijstracker-design.md new file mode 100644 index 0000000..ef8516b --- /dev/null +++ b/docs/superpowers/specs/2026-09-05-korting-prijstracker-design.md @@ -0,0 +1,115 @@ +# Korting — prijstracker design + +**Datum:** 2026-09-05 +**Status:** Approved + +## Doel + +Een webdienst die dagelijks een lijst productpagina's bezoekt, de huidige +prijs extraheert, en een email stuurt wanneer de prijs is veranderd +sinds de vorige check. Gehost op Coolify, bereikbaar op +`korting.sjoerd.app`, repo in Gitea (`git.pietpiraat.online`). + +## Architectuur + +Eén Node.js/Express monoliet in één Docker-container: + +- `server.js` — Express app, basic-auth middleware, web-UI routes +- `db.js` — SQLite setup + queries (`better-sqlite3`) +- `scraper.js` — haalt een pagina op (`fetch`) en extraheert de prijs (`cheerio`) +- `mailer.js` — verstuurt email via `nodemailer` (SMTP) +- `scheduler.js` — `node-cron` job, dagelijks, doorloopt alle producten +- `views/` — server-rendered HTML (geen frontend-framework) + +Geen aparte services: scheduler draait in-process in dezelfde container +als de webserver. SQLite-bestand staat op een persistent Coolify volume +zodat data een redeploy overleeft. + +## Data model + +Tabel `products`: + +| kolom | type | omschrijving | +|---|---|---| +| id | integer PK | | +| name | text | leesbare naam | +| url | text | productpagina-URL | +| last_price | real, nullable | laatst bekende prijs | +| last_checked_at | datetime, nullable | tijdstip laatste (succesvolle) check | +| last_check_status | text, nullable | bijv. `ok` / `not_found` / `fetch_error` | +| created_at | datetime | | + +Geen aparte prijshistorie-tabel (YAGNI) — kan later toegevoegd worden als +er behoefte is aan een grafiek. + +## Prijs-extractie (`scraper.js`) + +Volgorde van pogingen per pagina: + +1. JSON-LD (`