← Tilbage til The Vault
PoC⚡ AI-augmentedlive

ArchiveSALE

Personligt arkiv over danske butikkers tilbudsaviser via Tjek's API, med DeepSeek-chat til at spørge om aktuelle tilbud og prishistorik. Katalogbevidst synk hver 3. time, SQLite-arkiv over prisændringer, indkøbsliste og watchlist med semantisk matching, og notifikationer ved fejl — på dansk og engelsk.

#python#deepseek-api#tjek-api#sqlite#fastapi
ArchiveSALE

Selvinitieret, selvhostet projekt. Bygget og drevet af mig som arkitekt, product owner og reviewer, med AI som en overvåget "lærling" i udviklingsprocessen og i dele af selve produktet.

DEL 1: Resume

ArchiveSALE arkiverer danske butikkers ugentlige tilbudsaviser og gør dem til en søgbar prishistorik, en indkøbsliste og en overvågningsliste, med en AI-chat, der besvarer spørgsmål om aktuelle tilbud. Det erstatter at bladre i aviser og huske, hvad noget kostede sidste måned, med ét sted, der gør det for dig.

Tech stack

  • Backend: Python 3.12, FastAPI/uvicorn, Pydantic v2, SQLite, SMTP til mail (ca. 7.700 linjer inklusive single-page-UI'et)
  • Frontend: single-page-UI med dansk/engelsk ordbog, uden build-trin
  • Datakilde: Tjeks åbne JSON-API (ca. 300 danske butikker), planlagt synkronisering hver tredje time
  • AI: DeepSeek-chat med afgrænset kontekst og skrivebeskyttede værktøjskald ind i prisarkivet; semantisk matchning af overvågningsliste
  • Identitet: Cloudflare Access-bevidste brugere, med en fælles LAN-bruger til lokal adgang
  • Drift: systemd user service, install-/opdateringsscripts, TOML-konfiguration

Største bedrift At lade en AI arbejde på rigtige data uden at give den databasen i hænde. Chatten kan slå op i prishistorikken og redigere en brugers egne lister, men hvert værktøjsargument valideres og begrænses, forespørgsler er parametriseret SQL bygget af min kode, modellen kan ikke udvide sit butiksomfang, og en anmodning, der burde have ændret en liste, men ikke gjorde det, markeres i stedet for at blive meldt som udført.

DEL 2: Dybdegående baggrund

Problemet

Tilbud skifter ugentligt, aviser udgives parallelt af dusinvis af butikker, og tilbudspriser er ikke altid reelle tilbud. En forbruger skal sammenligne pakkestørrelser, tjekke om varen var billigere før og huske, hvad der skulle holdes øje med. Det er manuelt, gentaget og let at gøre forkert. Samme mønster findes i virksomheders indkøb: priser ændrer sig, historik gemmes ikke, og beslutninger bygger på hukommelse.

Arkitektur og løsning

Tjek API ──(hver 3. time: katalogtjek af metadata; fuld hentning kun for nye kataloger)──▶ sync
   │                                                                              │
   └──────────────────────────────────────────────────────────▶ SQLite (tilbud + prishistorik)
                                                                                  │
Browser-UI ◀── FastAPI ◀── DeepSeek (chat med værktøjer, matchning af overvågning) ◀┘
                      └── SMTP (indkøbsliste, mail om overvågning)

Designvalg, der er værd at fremhæve

  • Synkronisér kun det, nogen følger, og kun det, der er ændret. Brugere følger op til 15 butikker hver; kun fulgte butikker synkroniseres. Et billigt metadatatjek af udgivne kataloger kører hver tredje time, og den fulde tilbudsliste hentes kun, når et nyt katalog dukker op, hvilket fanger næste uges avis, før den er i salg, uden en blind genindlæsning.
  • Prishistorik, der betyder noget. En historikrække skrives kun, når et tilbud er nyt, eller prisen er ændret, så tabellen er en ægte pris-over-tid-registrering frem for gentagne øjebliksbilleder.
  • Rolig fejlrapportering. Gentagne fejl af samme vedvarende problem samles i én notifikation med et antal forsøg og alarmerer først igen, når hentningen har virket og så fejler påny.
  • Troværdighedspanel. Et lille mærke markerer tilbud, hvis pris ser vildledende ud: reelt billigere før, en større pakke billigere lige nu i samme butik, eller samme vare billigere i en anden butik, brugeren følger. Den slags funktion gør data nyttige frem for blot vist.
  • Kontekst afpasset til spørgsmålet. Ved et lille omfang ser chatten alle live-tilbud; ved et stort får den antal pr. butik og søger med et værktøj, hvilket holder pris og svartid nede.
  • Værktøjer med faste grænser. Skrivebeskyttede prisværktøjer plus listeredigeringsværktøjer begrænset til den loggede brugers egne lister, med et loft på ti ændringer pr. anmodning.
  • Internationalisering gjort ordentligt. Alt, serveren skriver (notifikationer, mails, chatbekræftelser, fejl), følger brugerens sprog, og dansk prisformatering anvendes konsekvent.
  • Kendte mangler er dokumenteret. Projektnoterne lister bevidste udeladelser (fx hvordan sprog gemmes for den fælles LAN-bruger), så de ikke forveksles med fejl.
  • Ingen automatisk testsuite. Adfærd er verificeret med engangsscripts: stubbet Tjek og DeepSeek, en lokal SMTP-sink, sidens rigtige JavaScript kørt i Node og kørsler med den rigtige model mod en kopi af databasen. Commit-beskederne siger, hvad hver ændring blev kontrolleret mod. En teamversion ville gøre scriptene til en rigtig suite.

AI som lærling

AI i selve produktet. Chatassistenten er afgrænset til en butik, en kategori eller brugerens samlede udvalg. Den kan søge i prisarkivet (prishistorik, statistik, kommende tilbud) og, når den bliver bedt om det, tilføje eller fjerne varer på brugerens indkøbs- og overvågningsliste. Overvågningslisten bruger semantisk matchning: en fri tekstbeskrivelse som et produktnavn matches mod aktuelle og kommende tilbud, straks ved tilføjelse. Butikskategorier gættes af en LLM, hvor Tjek ingen har, og kan tilsidesættes i konfigurationen.

AI i udviklingsprocessen (human-in-the-loop). Jeg ejer scope og accept; en AI-kodeassistent implementerer. En projektnotefil registrerer aktuel status, bevidste udeladelser og hvad hver ændring blev verificeret mod. Jeg betragter "modellen sagde, det virkede" som utilstrækkeligt: chattens påmindelse om listeændringer findes netop, fordi modellen kan påstå en handling, den ikke har udført.

Lederens refleksion

  1. Giv AI værktøjer, ikke adgang. Smalle, validerede værktøjer med grænser er sikrere og lettere at gennemgå end at lade en model nærme sig en database.
  2. Opdag "påstået men ikke gjort". Ethvert system, hvor en AI melder handlinger, har brug for et tjek af, at handlingen faktisk skete.
  3. Lav historik af ændring, ikke af tid. At skrive en række kun ved ændring holder data små og meningsfulde.
  4. Reducér støj. At samle gentagne alarmer er en lille designbeslutning, der afgør, om nogen bliver ved med at læse notifikationer.
  5. Skriv ned, hvad du valgte ikke at gøre. En liste over kendte mangler sparer teamet for at undersøge ikke-fejl igen.

Ærlige begrænsninger. Lille personligt værktøj med én fælles LAN-bruger, ingen automatiske tests og ingen CI. Bygget fra september til oktober 2026. Data er kun så komplette som det offentlige Tjek-API.