"""Vult de lege website-checklist-template in voor Helvoirt Gevelreiniging. Leest de template uit de bovenliggende map (ongemoeid) en schrijft een ingevulde kopie in de helvoirt-map. Kolommen: B=Uitgevoerd, C=Wie, D=Wanneer, E=Opmerking. """ import openpyxl from collections import Counter SRC = r"C:/projects/dewebsmid/Checklist - Websites (template, leeg).xlsx" DST = r"C:/projects/dewebsmid/helvoirt/Checklist - Websites - helvoirt (ingevuld).xlsx" D = "17-06-2026" WS_ = "De Websmid" KL = "Klant" CO = "Collega" # row -> (Uitgevoerd, Wie, Wanneer, Opmerking) F = { 5: ("Deels", KL, D, "Livegang akkoord (klant heeft de nameservers omgezet). Definitieve content (reviews, FAQ, echte foto's) nog te bevestigen/aanleveren."), 6: ("Ja", KL, D, "Klant heeft de nameservers omgezet = akkoord op livegang."), 7: ("Deels", KL, D, "Binnen: telefoon (085 060 4956) + adres. Nog open: e-mail, KvK, BTW, logo, echte foto's, reviews, mailbox-gegevens."), 9: ("Ja", WS_, D, "Alle pagina's 200; nav + Diensten-dropdown + CTA's (header/sticky/drawer naar /contact, in-page naar #contact) werken; onbekende route naar 404."), 10: ("Deels", WS_, D, "Telefoon correct en in JSON-LD/Instellingen. E-mail nog placeholder (info@helvoirtgevelreiniging.nl) tot de mailbox er is."), 11: ("Deels", WS_, D, "Adres Stationsplein 1, 6131 AS Sittard correct. KvK/BTW nog niet ingevuld in Instellingen."), 12: ("Actie", KL, "", "Reviews (Familie Jansen e.a.), FAQ-teksten en de AI-foto's zijn placeholder; via het CMS vervangen door echte data."), 13: ("Deels", KL, "", "Teksten gecontroleerd, geen bekende spelfouten; definitief klant-akkoord op de teksten nog te bevestigen."), 14: ("Ja", WS_, D, "Geen horizontale overflow (1440/768/390), axe-core 0 violations, visueel gecontroleerd via screenshots."), 15: ("Ja", WS_, D, "Alle beelden WebP en gecomprimeerd; responsive varianten (768/1280/1920); CMS-media op R2."), 16: ("Ja", WS_, D, "Geen title-attributen op afbeeldingen; CMS-beelden via media-URL."), 17: ("Ja", WS_, D, "favicon.svg + apple-touch-icon.png aanwezig; merkmark + iconen als (inline) SVG."), 18: ("Ja", WS_, D, "Gebrande 1200x630 og-default.webp + Twitter-cards; live geverifieerd (200)."), 20: ("Ja", WS_, D, "SSL actief (edge-certificaat), https geeft 200. Workers custom domain: SSL-modus n.v.t. voor de worker-route."), 21: ("Ja", WS_, D, "301 via middleware (geverifieerd). Dashboard 'Always Use HTTPS' optioneel als extra."), 22: ("Actie", WS_, "", "Nog niet gezet (geen Strict-Transport-Security header). Via dashboard zetten na bevestigd HTTPS (OAuth-token mag geen zone-settings, gaf 403)."), 23: ("Ja", WS_, D, "www naar apex 301; canonical naar apex; live geverifieerd."), 24: ("Ja", WS_, D, "CMS op /_emdash/admin (geen wp-admin), afgeschermd met magic-link login."), 25: ("Ja", WS_, D, "Admin-accounts (role 50): mike@dewebsmid.nl + ries@rsonlinemarketing.nl (SEO-partij). Inloggen via 'Sign in with email link' (magic-link werkt, live getest)."), 26: ("N.v.t.", WS_, D, "Nog geen users aangemaakt; ingebouwde defaults (pages/posts) zijn al verwijderd."), 27: ("Ja", WS_, D, "Live geverifieerd: X-Content-Type-Options nosniff, X-Frame-Options SAMEORIGIN, Referrer-Policy, Permissions-Policy."), 28: ("Ja", WS_, D, "Honeypot (website_url) + time-trap (2s tot 6u) server-side; geen reCAPTCHA."), 29: ("Ja", WS_, D, "public/_headers: /images + /fonts immutable (CF-Cache-Status HIT geverifieerd); HTML niet gecached (SSR)."), 30: ("Ja", WS_, D, "astro check 0 errors; productie-build schoon."), 31: ("Ja", WS_, D, "compatibility_date 2026-03-29 + nodejs_compat."), 32: ("Ja", WS_, D, "CONTACT_SMTP_PASS gezet (via bash printf). CONTACT_SMTP_HOST=srv8.dewebsmid.nl in wrangler.jsonc vars. Secrets blijven behouden over deploys."), 33: ("Ja", WS_, D, "wrangler.jsonc observability.enabled = true; logs via wrangler tail."), 34: ("Ja", WS_, D, "*.workers.dev uitgeschakeld bij de custom-domain-deploy (geverifieerd; alleen het echte domein is live)."), 36: ("Ja", WS_, D, "Live getest: 'mail-sent melding-klant'. Aan-adres info@helvoirtgevelreiniging.nl; lokaal afgeleverd op srv8. Bevestig ontvangst in de inbox."), 37: ("Ja", WS_, D, "From = 'Helvoirt Gevelreiniging ', envelope = info@ (geauthenticeerde mailbox). House-style website@ optioneel via env."), 38: ("Ja", WS_, D, "Melding: onderwerp 'Nieuwe aanvraag van ...' + Reply-To = bezoeker. Autoreply: Reply-To = info@. Live getest."), 39: ("Ja", WS_, D, "Live getest: 'mail-sent bevestiging-aanvrager'. Ondertekend 'Team Helvoirt Gevelreiniging' + T/E. Contactpersoon nog te bevestigen."), 40: ("Ja", WS_, D, "Tabel contact_submissions; live geverifieerd (rij opgeslagen en opgeruimd)."), 41: ("Ja", WS_, D, "Alle paden live getest: valid (200 + D1 + 2 mails), ongeldig (422 + veldfouten), honeypot (200 stil), time-trap (200 stil). Geen testrijen achtergebleven."), 42: ("Ja", WS_, D, "AJAX-succesmelding direct in beeld; mobiel design gecontroleerd."), 43: ("Ja", WS_, D, "Consistente labels/marges; een herbruikbaar formuliercomponent."), 44: ("N.v.t.", "", "", "Geen bijlage-veld in het formulier."), 45: ("Ja", WS_, D, "Sentinel-testrijen verwijderd (tabel leeg geverifieerd)."), 47: ("Ja", CO, D, "Zone actief op Cloudflare; nameservers cesar/priscilla.ns.cloudflare.com (collega heeft NS omgezet)."), 48: ("Ja", WS_, D, "Apex + www gekoppeld via wrangler routes (custom_domain); live geverifieerd."), 49: ("Ja", CO, D, "Mailbox info@helvoirtgevelreiniging.nl aangemaakt op srv8.dewebsmid.nl (DirectAdmin)."), 50: ("Ja", CO, D, "MX @ -> srv8.dewebsmid.nl (prio 0) staat live, DNS-only. NB: A-record mail.helvoirtgevelreiniging.nl ontbreekt nog (NXDOMAIN) - alleen nodig als het mailprogramma die hostname gebruikt; gebruik anders srv8.dewebsmid.nl."), 51: ("Ja", CO, D, "SPF live: v=spf1 a mx include:_spf.dewebsmid.nl ~all."), 52: ("Ja", CO, D, "DKIM live: selector x (x._domainkey.helvoirtgevelreiniging.nl, v=DKIM1...)."), 53: ("Deels", CO, D, "DMARC live (p=none), MAAR de rua wijst naar info@behangerbrabant.nl (copy-paste uit het zusterproject). Corrigeren naar rua=mailto:info@helvoirtgevelreiniging.nl."), 54: ("Actie", WS_, "", "Spamscore op mail-tester.com meten (SPF/DKIM/DMARC staan nu, dus zinvol)."), 55: ("Actie", CO, "", "Operationeel; hosting + mailhosting in abonnementen + livegang melden, door de collega."), 56: ("N.v.t.", "", "", "Nieuwe site; geen migratie van een bestaande site/mail."), 57: ("Actie", WS_, "", "Periodieke back-up van content + leads inregelen (wrangler d1 export)."), 59: ("Actie", WS_, "", "Nog niet gemeten (keyless PageSpeed = 429). Meten met een eigen PSI API-key."), 60: ("Actie", WS_, "", "Nog niet gemeten; zie de Lighthouse-meting."), 61: ("Ja", WS_, D, "Hero-cards: fetchpriority/eager op de eerste, rest lazy; eerste-fold-beelden eager. LCP = de koptekst."), 62: ("Ja", WS_, D, "axe-core 0 violations; zichtbare focus; alt-teksten; contrast ruim AA; tap-doelen groter of gelijk aan 44px."), 63: ("Ja", WS_, D, "prefers-reduced-motion overal gerespecteerd (reveals, tijdlijn, hero-gloed, formulier-spinner)."), 64: ("Ja", WS_, D, "Branded 404 met CTA via [...slug].astro; 404-status live geverifieerd."), 66: ("Deels", WS_, D, "Gerenderd/getest in Chromium (Playwright); standaard CSS. Handmatige check in Safari/Firefox/Edge nog aan te raden."), 67: ("Deels", WS_, D, "Responsive geverifieerd op 390/768/1440 (geen overflow) + mobiele screenshots; echte-device-test nog aan te raden."), 68: ("Ja", WS_, D, "Verse, sessie- en cacheloze fetches (incognito-equivalent) werken; publieke SSR zonder bezoeker-login."), 70: ("Ja", WS_, D, "Per-pagina meta-titel/description (CMS-gestuurd) + code-defaults; homepage heeft een goede titel."), 71: ("Ja", WS_, D, "Canonical naar apex; index,follow behalve waar noindex bewust is gezet."), 72: ("Ja", WS_, D, "Allow /, Disallow /_emdash/ + /api/, sitemap-pointer; geen Disallow /. Live geverifieerd."), 73: ("Deels", WS_, D, "sitemap.xml live (vaste routes + CMS-paginas/locaties). Indienen in Search Console nog te doen."), 74: ("Ja", WS_, D, "LocalBusiness (site-breed) + Service/Breadcrumb (dienstpagina's). Formele Rich Results-validatie aan te raden."), 75: ("Ja", WS_, D, "Admin (/_emdash/) + /api op Disallow in robots.txt."), 76: ("Actie", WS_, "", "Search Console-property toevoegen + sitemap indienen na livegang."), 77: ("Actie", KL, "", "GTM-veld klaar in Instellingen; klant levert container-ID. Nog geen analytics actief."), 78: ("N.v.t.", "", "", "Nieuwe site; geen oude URL's om te redirecten."), 79: ("Actie", WS_, "", "Volledige crawl (ScreamingFrog) nog te doen; steekproef: alle interne pagina's 200, geen gebroken links waargenomen."), 81: ("Actie", WS_, "", "Monitoring (Uptime Robot) nog in te stellen."), 82: ("Actie", WS_, "", "Handover: leads komen binnen in D1 + per mail (na de mailbox). Klant hierover informeren."), 83: ("Ja", WS_, D, "/privacy + /voorwaarden live + footer-links. Voorwaarden = algemene basistekst, klant laten controleren."), 84: ("Actie", WS_, "", "Tweede-persoons-eindcontrole nog uit te voeren."), } wb = openpyxl.load_workbook(SRC) ws = wb["Checklist"] for r, (u, wie, wan, opm) in F.items(): ws.cell(row=r, column=2, value=u) ws.cell(row=r, column=3, value=wie) ws.cell(row=r, column=4, value=wan) ws.cell(row=r, column=5, value=opm) wb.save(DST) c = Counter(v[0] for v in F.values()) print("Opgeslagen:", DST) print("Ingevuld:", len(F), "punten") print("Verdeling:", dict(c))