Systemkarta / Coop / intern översikt

Veckohandlingen,
från behov till korg.

En styrd kedja av läsning, katalogsökning, beslut och exakt verifierade korgklick. Inte ett automatiskt köp.

01 / TOPOLOGI

Två spår. En varukorg.

Heldragna pilar visar veckojobbets data- eller styrflöde. Den fristående lila rutan är en offlinefångst och matar inte korgjobbet.

Arkitekturkarta för Coops veckohandlingCron startar en Python-kontroller som läser basvaror och Livsmedel, söker i Coops produktkatalog, frågar Jev om lämplighet och val, verifierar exakt EAN i Coops användargränssnitt och skriver checkpoint samt Telegramrapport. En separat offlinefångst med 270 kort är inte kopplad till korgflödet. Inget checkout-steg finns. INMATNINGEN KONTROLLERBESLUT & JOURNALEXTERNA GRÄNSSNITT Hermes cron08 måndag · PAUSAD21 BASVARORlästa ur äldre skriptLivsmedelöppna påminnelser Start & autentiseringlås · CDP · BankID-grindPython-kontrollerbehov · preflight · iterationKatalog /search/productsträffar + onlinePromotions Filter → JevNoul → ≥0,5 → Choicekan välja noneCheckpointatomisk JSON · före klickdagnyckel Stockholm Coop produktkatalogpublik sökning · butik frånaktiv butik · medlemsscopeChrome / Coop UIexakt EAN-länk · korgsvarVarukorg & rapportEAN/antal efter varje klickslutläsning → cron → Telegramingen checkout SEPARAT OFFLINEFÅNGST · EJ RUNTIME-INDATA270 renderade primärkort · aktiv onlinebutik 255700Fryst DOM/fixture för revision; ingen pil till korgflödet.Äldre deals-script finns men är inte Python-jobbets indata.
Gränsen är avsiktlig: produktkatalogens onlinePromotions följer sökträffarna; arkiverade 270 erbjudandekort gör det inte. Pilen från journalen mot korgområdet markerar återupptagning och verifiering, inte en separat korgskrivare.
IMPLEMENTERAT · kod finnsPAUSAT · cron avstängdRISK · behöver granskningOFFLINEFÅNGST · ej livekälla
02 / SCHEMA

Klockan styr bara starten.

07:45
Daglig sessions-keepaliveKontrollerar inloggning i befintlig Coop-flik; tyst vid verifierad session, annars BankID-varning.
AKTIV
08:00
Måndag · veckokorgcoop-weekly-cart.sh → coop_weekly_jev.py weekly. Pausad; inget automatiskt korgjobb körs enligt aktuell cron.
PAUSAD
09:00
Måndag · erbjudandesammanfattningSeparat äldre deals-jobb, inte en föregående runtimefas i Python-korgflödet.
PAUSAD

Tiderna är cron-uttryck i schemaläggarens lokala tidszon; cron-jobben anger ingen egen tidszon och config.yaml har tomt timezone-fält. Checkpointens datum beräknas däremot uttryckligen i Europe/Stockholm.

03 / FÖRLOPP

Relativ sekvens, inte stopptider.

Ordningen nedan är implementerad kontrollordning. Bredder och avstånd är inte uppmätta körtider; varje behov kan ge flera sökningar, Jev-anrop och UI-mappningar.

Lås & start

Exklusivt Coop-lås, Chrome/CDP och verifierad användarsession. BankID sker manuellt vid behov.

Läs behov

21 hårdkodade BASVAROR + öppna Livsmedel. Läsfel markeras otillgängligt; basvaror fortsätter.

Granska korg

Preflight av alla befintliga SKU:er mot exakt EAN, katalog och UI. Blockera på oklarheter.

Sök & välj

Sök behov + första ordet; förena träffar per EAN. Mekaniska spärrar, sedan oberoende Noul och Choice.

Mappa & lägg till

Exakt EAN i produktkort; journal före klick. Verifiera antal och EAN i Coops korgsvar.

Avsluta

Läs korgen igen, spara slutstatus och skriv sammanfattning för cron/Telegram. Ingen checkout.

10 sper Reminders-läsare: AppleScript, därefter fallback-CLI vid fel eller timeout
25 / 30 scurl --max-time / Python subprocess för publik HTTP-läsning
take: 20antal katalogträffar per sökfråga, inte sekunder
45 / 55 sJev CLI-timeout / väntetid i Python
75 sPython väntar högst på varje browser-hjälpanrop
14 / 18 skorgsvar efter klick / korgsvar vid navigation
12 försökChrome-CDP-start: 1 s paus per försök, plus anslutningskontroll
1 800 saktuell cron.script_timeout_seconds; veckokorg kräver minst detta

UI-navigation har dessutom egna gränser: page.goto 30 s och väntan på första produktlänk 10 s (den senare får misslyckas utan att ett tomt resultat i sig bevisar produktfrånvaro). Dessa är kapslade väntetider, inte poster som ska summeras till en uppmätt total.

04 / BESLUT & GRINDAR

Modellen väljer. Koden spärrar.

01 · Läsning

Behoven bildas

Python läser exakt 21 unika namn ur coop-weekly.sh (det äldre skriptet körs inte i denna kedja). Öppna Livsmedel-påminnelser läses med AppleScript och fallback till reminder-tool, båda med 10 s gräns. Resultaten avdubbletteras i ordning.

Misslyckas båda: remindersStatus: unavailable, listan utelämnas uttryckligen; den framställs inte som verifierat tom.

02 · Katalog

Live sökning, inte arkiv

Konfiguration läses från Coops publika sidinställningar; /search/products ger sökträffar med bland annat varumärke, kategori, ursprung, pris och onlinePromotions. Sökningarna är behovets hela text och dess första ord; katalog-ID/EAN förenar träffarna.

Den separata fångsten med 270 kort används inte som lista över varor eller kampanjer av veckokörningen.

03 · Jev

Två olika frågor

För varje kvarvarande kandidat ställs oberoende noul-frågor. Kandidater med numeriskt värde ≥ 0,5 och inte uttryckligen otillgängliga online går vidare. En choice väljer bästa EAN eller none; ingen lämplig match blir ett redovisat ouppfyllt behov.

Jev får nuvarande korg, familjekontext, storlek/pris och kandidatens onlinePromotions men kan inte upphäva hårda spärrar.

FÖRE OCH EFTER VAL

Identitet, kategori & exklusion

  • Begärda namnord måste kunna matchas i produkttiteln; exakt EAN ska också finnas som UI-länk med separat produktidentitet. Motsägande exakta kategoriankare stoppar valet.
  • Exakt märke Xtra utesluts skiftlägesokänsligt. Kött med ursprung Danmark eller Irland utesluts; okänt ursprung för kött kräver kontroll och får inte läggas till. Ett varumärke räknas inte som ursprungsbevis.
  • Vald produkt kontrolleras åter mot UI-etikett, kategori, identitet och märke innan klick. Om EAN inte kan UI-mappas prövas bredare sökning och vid behov nytt Noul + Choice över mappade alternativ; inget tyst SKU-byte.
FÖRE OCH EFTER KLICK

Preflight, journal & stopp

  • Befintlig korg revideras mot exakt EAN och oberoende katalog/UI-data. Felaktig eller tvetydig SKU blockerar hela körningen utan att ändra korgen.
  • adderar och cartBefore skrivs atomiskt innan klick. Browsern kontrollerar att korgen inte ändrats av annan aktör och att exakt EAN inte redan finns.
  • Efter klick krävs EAN med antal 1 och totalUnitCount ökat med ett. Vid osäker förändring hämtas korgen om och flödet stoppas för att undvika dublett.
KVARSTÅENDE OSÄKERHET

När flera exakta namnträffar har olika kategori, eller någon saknar verifierad UI-kategori, stoppar kodens kategorigrind valet i stället för att gissa. En enda namnträff utan kategoridata kan fortfarande väljas efter övriga identitets- och exklusionsspärrar; det är inte samma sak som att kategorin är bevisad. Veckocron är pausad även under den separata manuella livekörningen.

05 / DATAMODELLER

Vad som faktiskt färdas.

Illustrativa, sanerade formexempel – inte verkliga varor, giltiga EAN, priser, sparade korgdata eller ett körningsresultat. Fältnamn speglar kodens JSON-nycklar; Need är ett begreppsnamn för en sträng, inte en egen runtime-klass.

Need · sträng i needs[]

Basvara eller öppet påminnelsenamn. Listan avdubbletteras; en återupptagen checkpoint kan slå ihop gamla och nya behov.

"Illustrativ vara"

Candidate · kompakt katalogträff

Priser och erbjudanden är katalogfält och kan saknas; UI-berikning lägger till fält som uiLabel, uiTitle, uiCategory efter exakt EAN-match.

{"ean":"EXEMPEL-EAN","name":"Illustrativ vara",
 "brand":null,"size":"1 st","meat":false,
 "categoryNames":["Livsmedel"],
 "countryOfOriginCodes":[],
 "declarationOfOrigin":null,
 "piecePrice":null,"salesPrice":null,
 "onlinePromotions":[],"availableOnline":true}

UILink · produktlänk

Browserns map extraherar länk och EAN ur UI; kontrollern annoterar query för att återöppna rätt sökvy före klick.

{"ean":"EXEMPEL-EAN",
 "name":"Illustrativ vara, 1 st",
 "title":"Illustrativ vara",
 "href":"/handla/varor/exempel-EXEMPEL-EAN",
 "query":"Illustrativ vara"}

CartEntry · normaliserad korgpost

Kontrollerns cart_entries plattar ut Coops entries[].product och quantity. Namn/märke/storlek kan vara ofullständiga och måste kontrolleras mot katalogen.

{"ean":"EXEMPEL-EAN",
 "name":"Illustrativ vara",
 "brand":null,"size":"1 st","quantity":1}

Checkpoint · atomisk dagjournal

state/coop-weekly/<datum>.json lagrar behov, påminnelsestatus, per-behovsbeslut, före-/efterkorg och slutläsning. Här visas bara ett illustrativt utsnitt; Jev-frågor/svar, försök och korgsvar kan också finnas i posten.

{"date":"ÅÅÅÅ-MM-DD",
 "needs":["Illustrativ vara"],"reminders":[],
 "remindersStatus":"read","remindersError":null,
 "cartPreflight":{"status":"passed","eans":[]},
 "items":{"Illustrativ vara":{"need":"Illustrativ vara",
   "status":"verified","attempts":[],
   "chosenEAN":"EXEMPEL-EAN"}},
 "finalCart":{"totalUnitCount":1,"entries":[
   {"quantity":1,"product":{"ean":"EXEMPEL-EAN",
    "name":"Illustrativ vara"}}]}}
JOURNALENS STATUSORD

started → adderar → verified är tilläggsvägen. Alternativen är bland annat redan_i_korg, ingen_lämplig, fel och redan_i_korg_exkluderad. En tidigare verified-post hoppas inte blint över: den aktuella korgen läses och revideras på nytt vid återupptagning.

06 / DRIFTLÄGE

Status är inte ett säkerhetsbevis.

MANUELL LIVEKÖRNING · 21/23

21 varor verifierade i Coop-korgen; två juicebehov kvar.

En verklig engångskörning efter att användaren tömt korgen verifierade 21 exakta EAN/antal mot Coops korgsvar. Äppeljuice och apelsinjuice stoppades av en alltför strikt kategorigrind och håller på att rättas generellt. Detta är inte ett lyckat 23/23-resultat. Veckokorg och erbjudandesammanfattning är fortfarande pausade som cron-jobb.

Ingen checkout: korgen lämnas för mänsklig granskning.

IMPLEMENTERAT

Lås & BankID

Kontrollern tar icke-blockerande flock på state/coop-chrome.lock och äldre kataloglåset /tmp/hermes-coop-cron.lock. Chrome startas vid behov med dedikerad profil; en ogiltig session ger stopp och lämnar webbläsaren öppen för manuell BankID-inloggning. Ingen ny gästflik för korgåtgärder.

IMPLEMENTERAT

Aktiv onlinebutik

Inloggad Chrome-flik läser butik och medlemsgrupper från sidans egen primära erbjudandeförfrågan. Dessa används i katalogsökningen i stället för defaultStoreId; saknat scope eller kollapsat antal blockerar före korgarbete. Den separata 270-kortsfångsten för onlinebutik 255700 är ett revisionsunderlag, inte en hårdkodad butik i veckojobbet.

OFFLINEFÅNGST

270 kort ≠ 270 runtimeval

En sanerad, renderad DOM med 270 unika primärkort och URL/EAN har granskats separat. Den är ett tidsbundet revisionsunderlag, inte katalogsökningens indata, inte antalet grupperade varianter och inte ett bevis om nuvarande liveerbjudanden.

07 / SPÅRBARHET

Läs implementationen.

Relativa sökvägar från Hermes-arbetsytans rot. Siffror, spärrar och status ovan kommer från dessa lokala filer; inga autentiseringsuppgifter eller privata korgposter återges.