26 KiB
Helvoirt Gevelreiniging — Bouwplan (todo)
Stack: Astro 6 + Emdash 0.1.0 + Cloudflare Workers (D1 + R2 + KV). Register: conversiegerichte lokale dienstensite, familie van onderhoudsbedrijfvanhelvoirt.nl. Zie architecture.md (technisch) en CLAUDE.md (regels/workarounds). Alleen wijzigen in dewebsmid\helvoirt.
Status (16-06-2026): marketing-pagina's LIVE + CMS-migratie loopt — morgen verder met LIVE ZETTEN. Alle pagina's live op https://helvoirt-gevelreiniging.mike-197.workers.dev (deploy version f576e989). CMS geseed + ingericht (zie §3); de SEO-partij kan pagina's + locatiepagina's beheren/maken/SEO-optimaliseren (CMS-SEO-handleiding.md). Werkgebied-pills = Helvoirt + Limburgse steden. Bestaande pagina's worden "volledig naar CMS" gemigreerd (klantopdracht), met fallback-veiligheid + sentinel-verificatie: Over ons, Homepage(-tekst), Contact KLAAR; Maastricht-locatiepagina live.
← VOLGENDE STAP: De code-side go-live-laag is af + live (17-06-2026, deploy ed137121): robots, sitemap (incl. CMS), JSON-LD (LocalBusiness + Service/Breadcrumb), GTM-render, OG-image + apple-touch-icon, middleware, privacy/voorwaarden, mail-code + D1-opslag (contact_submissions) + magic-link-plugin. CMS = 100% van de pagina's (Wave 3 Diensten klaar → ook de 5 dienstpagina's + overzicht + homepage-accordion + nav-menu uit de diensten-collectie). Wat nu nog rest is (1) externe input — mailbox-wachtwoord/host → secret CONTACT_SMTP_PASS (bash printf), SEO-partij-e-mail → users-rij, klantcontent (NAW/reviews/FAQ/foto's/GTM-ID), domein-DNS → zone+nameservers+routes(rebuild)+mail-DNS+HTTPS (zie GO-LIVE.md) — en (2) optioneel self-hosted fonts, Lighthouse-meting, checklist .xlsx. CMS-migratie is 100% klaar (alle pagina's + alle beelden, tekst én media, in het CMS — deploy 57651519). Schema op live D1 = via migrations/*.sql. Herdeploy: astro build + wrangler deploy.
⏳ Open punten (afstemmen met klant)
- Telefoon + adres aangeleverd:
085 060 4956,Stationsplein 1, 6131 AS Sittard(inBase.astro+contact.astrofallbacks; staat live). - Werkgebied-copy blijft "Helvoirt en omgeving" (16-06-2026): kop + alle SEO-copy ongewijzigd ("Helvoirt en omgeving"). Alleen de pills vernieuwd: Helvoirt blijft vooraan, daarna de nieuwe steden. Eerdere reverteerde poging om naar "Sittard en omgeving" te gaan is teruggedraaid op klantverzoek.
- NAW resterend: e-mail (nu placeholder
info@helvoirtgevelreiniging.nl), KvK, BTW, WhatsApp, openingstijden bevestigen, Google-reviews-URL + score. - Echte reviews (i.p.v. de 3 placeholders) — liefst met de Google-link.
- Echte foto's: hero + per dienst (resultaat-galerijen) — nu AI-placeholders + de 6 echte
werk-*-foto's. (Before/after-paren niet meer nodig: projecten geschrapt.) - Werkgebied-plaatsen (pills) vastgesteld: Helvoirt, Maastricht, Echt, Roermond, Weert, Sittard, Heerlen, Brunssum, Kerkrade, Landgraaf. Bron: klant 16-06-2026. (Kop blijft "Helvoirt en omgeving".)
- FAQ-teksten "Goed om te weten" bevestigen.
- Logo: levert klant een eigen logo aan? (nu tekst-wordmark "Helvoirt / Gevelreiniging" + H-monogram-merkmark; druppel verwijderd.)
Kleuren samplen→ uit Elementor-kit zusterbedrijf.Fonts→ Archivo Expanded + Open Sans.Worker/D1/R2-naamgeving→helvoirt-gevelreiniging/helvoirt-db/helvoirt-media.Hero-fotografie→ nano-banana placeholders (klantkeuze).Blog→ buiten launch-scope.
§1 — Scaffold (mirror exterios) ✅ GEDAAN
package.json/tsconfig/astro.config.mjs/worker.ts/live.config.ts/wrangler.jsonc/.gitignore/.env+ scripts +lib/img.ts.npm install --ignore-scripts(721 packages) ·astro sync/check/buildslagen.- Geleerd:
NODE_OPTIONS=--use-system-cavoor elke astro/wrangler-call; placeholder-database_id(miniflare eist niet-leeg).
§2 — Design tokens ✅ GEDAAN (DESIGN.md = optioneel, nog niet geschreven)
tokens.css: committed blauw/petrol palette (cyaan#4ebfd9, actie#0069ff/#0055ce, petrol#1d4852/#15363d, off-white#f6fafb), getinte neutralen, status/ster-tokens.- Fonts Archivo Expanded (kop) + Open Sans (body). Géén Poppins/Fraunces.
.btn-cta/.btn-outline/.btn-text, section-helpers,.reveal.- (optioneel)
DESIGN.mdschrijven via/impeccable document.
§3 — Emdash schema (seed/seed.json) + CMS voor SEO-partij 🟢 GESEED + LIVE (volledige migratie loopt, §3b)
Doel (klant 16-06-2026): de SEO-partij moet zelf gewone pagina's én locatiepagina's kunnen aanmaken en optimaliseren voor SEO. Bewust SEO-vriendelijk + simpel ingericht (3 onderdelen i.p.v. het volledige sectie-model).
seed/seed.jsongeschreven — collecties:site_settings(NAW +address_street/address_city+ KvK/BTW/WhatsApp + social + SEO-standaard meta_title/description + GTM + logo/favicon/og_image),paginas(gewone pagina's: title/intro/portableText-content + SEO-groep),locaties(locatiepagina's: plaats/H1/intro/portableText-content + SEO-groep). SEO-groep = expliciete velden met nette NL-labels:meta_title,meta_description,canonical,og_image,noindex. Demo-content:site_settings/main(echte NAW, werkgebied "Helvoirt en omgeving", score 4,9) + 1 concept-sjabloon per type (Voorbeeldpagina + locatie Maastricht).- Routes gebouwd (lezen CMS met try/catch + fallback → nette 404 vóór seed):
src/pages/[...slug].astro— root-router: zoekt de slug op inlocaties(lokale pagina, petrol-hero + content) énpaginas(gewone pagina); beide op de root (/maastricht,/onderhoudstips). Locatie wint bij botsing. Laagste prioriteit, PortableText, eigen branded 404. (Klantkeuze 16-06: locatiepagina's op/URL, niet/werkgebied/URL.)src/pages/werkgebied/index.astro— werkgebied-hub die gepubliceerde locaties oplijst (linkt naar/<plaats>); anders statische pills.
src/lib/images.ts=resolveCmsImage(uit behangerbrabant) voor image-velden;Base.astrouitgebreid metnoindex-prop + absolute OG-URL; gedeelde.proseintokens.css.astro check0/0/0 + build OK.CMS-SEO-handleiding.mdgeschreven voor de SEO-partij (inloggen, pagina/locatie aanmaken, SEO-velden, do's/don'ts, wat nog in code zit).- Geseed (16-06-2026): setup-wizard gedraaid met "Include sample content" →
site_settings/paginas/locaties+ demo in remote D1. - Ingebouwde
pages/postsverwijderd (emdash-defaults, leeg/ongebruikt) viascripts/cleanup-default-collections.sql. Blijven weg (defaults worden alléén bij setup aangemaakt). CMS toont nu alleen relevante onderdelen. Base.astroleest nusite_settings.meta_title/meta_description/og_image(per-pagina prop > Instellingen > code-default) → SEO-partij kan site-brede SEO in Instellingen zetten.- CMS-login: e-mail-provider-plugin (magic-link, newsite.md §6b) + SEO-partij-gebruiker(s) in
users. (nog te doen)
§3b — Volledige CMS-migratie bestaande pagina's (klant: "Volledig naar CMS") ✅ KLAAR (17-06-2026) — alle pagina's + álle beelden in het CMS (tekst + media)
Aanpak (bewezen, risico-arm): per pagina (a) model in scripts/cms-models/<x>.mjs, (b) scripts/gen-cms-sql.mjs genereert D1-SQL die emdash's eigen tabelstructuur spiegelt (overgenomen uit de echte ec_paginas-DDL; géén search/FTS op nieuwe collecties), (c) toepassen op remote D1 via wrangler d1 execute --file migrations/*.sql, (d) .astro herschrijven om uit CMS te lezen met de huidige tekst als fallback (site blijft identiek), (e) deploy + verifiëren.
- Machinerie gebouwd:
scripts/gen-cms-sql.mjs(generator: type→column_type, systeemkolommen, ULID viaulidx) +scripts/cms-models/. UTF-8 (·, —) blijft intact door de round-trip (geverifieerd). - Wave 1 — Over ons KLAAR + LIVE-GEVERIFIEERD (version
3ce0ce32). Singletonover_ons(hero/verhaal/waarden-koppen + SEO; verhaal = portableText) +waardenals inline repeater-veld op over_ons.over-ons.astroleest uit CMS met fallback. Sentinel-test bewees CMS-aansturing; 4/4 repeater-rijen + icoon-SVG renderen live. Visueel identiek. - Klantfeedback Over ons verwerkt (
0003_*.sql): "Waarden" van losse collectie → inline repeater (rijen toevoegen/verwijderen/verslepen binnen de pagina, WP-Bakery-achtig); kern-inhoudvelden verplicht zodat "(optional)" daar weg is. Native emdash: pagina's dupliceren (kopieer-icoon in lijst,POST .../duplicate), collectie-rijen add/delete. "(optional)" is niet globaal uitschakelbaar (geen branding/CSS-hook); alleen via velden verplicht maken. Repeater-velddef =validation.subFields(ziescripts/gen-over-ons-repeater.mjs). - Beeldvelden toegevoegd aan Over ons (
0004_*.sql):hero_image(banner) +story_image(verhaalfoto), viaresolveCmsImagemet de huidige statische foto's als fallback (leeg veld = standaardfoto). Sentinel-test bewees dat het veld de pagina aanstuurt; leeg → fallback. Les voor volgende waves: beeldvelden meenemen (hero/galerij/dienst-foto's) — niet alleen tekst. - Labels opgeschoond (
0005_*.sql): "(~N tekens)" uit alle SEO-labels (site_settings/paginas/locaties/over_ons) — ook inseed.json+ model. NB: "(optional)" blijft (emdash-standaard, niet uitzetbaar). - Foto's in de mediabibliotheek gezet (
0006_*.sql+ R2-upload,scripts/gen-over-ons-media.mjs):hero-after-1280.webp+werk-3.webpnaar R2 (helvoirt-media, key=<ulid>.webp) +media-rijen + veld-JSON (local provider). De Over ons-beeldvelden tonen nu de echte foto in het CMS (niet leeg). Geverifieerd: media serveert via/_emdash/api/media/file/<key>(200, image/webp) en de pagina gebruikt de CMS-afbeeldingen. Patroon voor volgende waves: zo ook de echte foto's voor homepage/diensten in de library zetten. - Maastricht-locatiepagina LIVE (
/maastricht, gepubliceerd, 200, H1 correct). - Wave 2a — Homepage TEKST KLAAR + LIVE-GEVERIFIEERD (version
1223ddda). Singletonhomepage(0007_*.sql): hero (titel/sub/vinkjes-repeater), intro, diensten-koppen, werkwijze-repeater (4), bewijs-kop, reviews (uitgelicht + kleine-reviews-repeater), werkgebied-koppen, FAQ-repeater (4).Hero.astro(props) +index.astrolezen uit CMS met fallback. Sentinel-test bewees CMS-aansturing; alle repeaters renderen live. Generator uitgebreid met repeater-validation/subFields. - Wave 2b — Homepage BEELD KLAAR + LIVE-GEVERIFIEERD (17-06-2026,
0011_homepage_media.sql). Collectieshero_cards(3) +galerij(6) als image-rijen (image+tekst);Hero.astro(viacards-prop uitindex.astro) + de bewijs-sectie lezen eruit met fallback. Foto's in de mediabibliotheek (galerij hergebruikt de werk-foto's uit Wave-3-media; hero gebruikt kleine -768-varianten voor perf → 2 nieuwe media). Live: 3/3 hero + 6/6 galerij = CMS-media; screenshot bevestigt visueel identiek. - Diensten-BEELD in de mediabibliotheek (
0010_diensten_media.sql,gen-diensten-media.mjs). 13 unieke foto's naar R2 +media-rijen, gekoppeld aan alle 25 beeldvelden (nav/hero + 3 resultaat-slots × 5 diensten). Live: detailpagina 4/4, overzicht 5/5, accordion 5/5 = CMS-media. CMS serveert één formaat → -1280 voor hero/cards, werk-basis voor galerij;srcsetForgeeftundefinedvoor CMS-paden (geen kapotte srcset). - Wave 3 — Diensten KLAAR + LIVE-GEVERIFIEERD (17-06-2026,
0009_diensten.sql). Collectiediensten(5 entries, 36 velden) gedeeld door: homepage-accordion (nav_*),/diensten-overzicht (title+nav_*),/diensten/[slug]-detail (alle velden: hero/points/intro/included/resultaat-galerij/aanpak/faq/seo/noindex) én het nav-dropdownmenu (Base.astro, opnav_order). Alles leest uit CMS met de hardcoded data als fallback. Beeldvelden leeg = code-fallback naar de huidige foto's (nav_image/hero_image/result_N_imageper dienst; media-library-populatie = optionele vervolgstap zoals over-ons). Resultaat-galerij = 3 vaste image-slots (repeater kan geen image-subveld). Sentinel-test bewees dat de CMS-waarden zowel de detailpagina als de homepage-accordion aansturen. Onbekende slug → 404.astro check0. - Wave 4 — Contact KLAAR + LIVE-GEVERIFIEERD (version
f576e989,0008_*.sql). Singletoncontact_page(kicker/H1/intro + SEO).contact.astroleest uit CMS met fallback (NAW blijft uitsite_settings). Sentinel-test OK. Generator is nu argument-gedreven:node scripts/gen-cms-sql.mjs <model> <out.sql>.
§4 — Base layout + kerncomponenten ✅ GEDAAN
Base.astro(donkere petrol header met telefoon + CTA + dropdown, drawer, prefooter-form#contact, footer, sticky-CTA, reveal-IO, SEO-head, site_settings try/catch).ContactForm.astro(naam [placeholder "Naam"], e-mail, telefoon, bericht + honeypot + time-trap).api/contact.ts(spam-bescherming + validatie + D1-opslagcontact_submissions+ 2 mails viasrc/lib/smtp.ts; secret = §12).CtaBand.astroextraheren wanneer subpagina's het nodig hebben.
§5 — Homepage (index.astro) ✅ GEDAAN + GEPOLISHED
- Hero = tekst links + werkfoto-collage rechts (Tailark hero-6 nagebouwd): Archivo-kop "Je gevel weer als nieuw." (800) + dominante blauwe CTA + vinkjes + prominente 4,9-Google-regel; rechts 3 staande werkfoto-cards die links overlopen in het tekstblok (
.hero__fade), mobiel swipebaar. Doorlopen: craft → bolder (verworpen) → quieter → split (verworpen) → collage → audit 20/20 → critique 33/40 + fixes. Géén before/after-slider in hero (→ planning/projecten, §7).hero-after/before/gevel.webp+degrade-before.pynu ongebruikt op de homepage (de 3 hero-cards gebruikenwerk-1/3/5; was 4 incl.werk-6/Metselwerk, op klantverzoek terug naar 3 + cards verbreed). - Intro (statement + inline meta), Diensten = uitklappende beeld-accordion (5 panelen, "+"-indicator, blijft open om te lezen, mobiel gestapeld), Werkwijze-tijdlijn (licht), Bewijs-galerij (echte foto's), Reviews (uitgelicht + 2 klein), Werkgebied-pills, FAQ "Goed om te weten".
- Impeccable: craft ("het verschil zien") → bolder (donkere header) → overdrive (accordion) → audit 19/20 (tapdoelen ≥44px, fetchpriority, tokens) → critique 32/40 (accordion klikbaar, FAQ, scaffold-cleanup, hero→
#contact+ adresveld). animate-pass: samenhangende motion-laag — consistente scroll-reveals over álle secties, werkwijze-tijdlijn tekent zich in (.flow__line+.reveal--draw), gestaggerde werkgebied-pills + FAQ (.reveal--stagger/--i),:active-indruk op.btn-cta/.btn-outline, offerteformulier-spinner (aria-busy) + geanimeerde succesmelding, trage hero-gloed. Nieuwe token-primitives.reveal--draw/.reveal--staggerintokens.css. Alles achterprefers-reduced-motion.- Eerdere diensten-iteraties (verworpen): zig-zag-banden → index+preview → foto-mozaïek → typografisch menu → accordion (definitief).
- Inline secties later extraheren naar herbruikbare componenten.
§6 — Diensten ✅ KLAAR (overzicht + 5 detailpagina's)
pages/diensten/[slug].astro= herbruikbaar SSR-sjabloon met alle 5 slugs gevuld (zie onder); per pagina dienst-hero (+4,9-regel) + intro/checklist + resultaat-galerij + mid-page CTA-band + aanpak-stappen + dienst-FAQ → CTA's#contact. Onbekende slug → 404 (getest).astro check0 errors, axe-core 0 violations, geen overflow (1440/768/390), mobiel stapelt netjes.- Resultaat-galerij i.p.v. een voor/na-slider op de dienstpagina (klantkeuze): 3 losse resultaatfoto's met bijschrift per stap (aanslag weg, voegwerk hersteld, strak/verzorgd). Reden: een echte voor/na-slider eist twee exact uitgelijnde foto's van dezelfde gevel, wat de klant zelden heeft. Werkt met losse werkfoto's.
components/BeforeAfter.astro= herbruikbare voor/na-sleepvergelijker (range-input → sleep + toetsenbord,:has()-focusring, "voor"/"na"-labels). Nergens geïmporteerd (projecten geschrapt, §7); bewaard als herbruikbaar component.- Alle 5 slugs ingevuld in
DIENSTEN:gevelreiniging,voegwerk,dakreiniging-coating,schoorsteen-voegwerk,algemeen-reinigen. Elk: dienst-hero (+4,9-regel) + intro/checklist + resultaat-galerij + mid-page CTA-band + aanpak-stappen + dienst-FAQ. Dak gebruikt de 3 echte dakfoto's als narratief (mos → reinigen op hoogte → schoon, kop "Van mos tot een schoon dak"). Galerijen mixen de echtewerk-*-foto's met dienst/hero-placeholders. - Smoke-test: alle 5 slugs → 200 (juiste H1), onbekend → 404. Per nieuwe pagina: axe clean, geen overflow (1440/768/390).
astro check0 errors, build OK. pages/diensten/index.astro(overzicht, 5 dienstkaarten met "Bekijk" → detail) gebouwd; nav-link "Diensten" werkt nu, breadcrumb-crumb "Diensten" hersteld op de detailpagina's. 200, axe clean, geen overflow.- Image-fallback per slug bestaat al (
/images/dienst-<slug>.webp). Echte projectfoto's vervangen de placeholders zodra de klant ze levert. /impeccable critiqueop/diensten/gevelreiniging→ 33/40 (sterk), detector[](0 slop-patronen), cognitive load laag. Fixes doorgevoerd: P0 alle CTA-knoppen (header/sticky/drawer) →#contacti.p.v./contact-404 (globaal inBase.astro); P1 4,9-Google-trust-regel in de dienst-hero + mid-page CTA-band ("Klaar om je gevel weer als nieuw te zien?") na de galerij als desktop-snelkoppeling naar het formulier; P2 dode breadcrumb-crumb "Diensten" verwijderd tot/dienstenbestaat; contrast-fix stap-nummers cyaan → diep blauw (--c-action-deep, cyaan op--softzakte onder WCAG). Galerij bewust gelaten (klantkeuze, foto's later). FAQ bewust plat gehouden (homepage-FAQ is óók plat; accordion zou juist inconsistent zijn). Na de fixes: axe 0, geen overflow (1440/768/390), build OK.
§7 — Projecten (before/after) ❌ GESCHRAPT (klantverzoek)
- Projecten-pagina geschrapt op klantverzoek: uit de nav (
Base.astro) en de homepage-link ("Alle projecten") verwijderd.BeforeAfter.astroblijft als ongebruikt herbruikbaar component staan (nergens geimporteerd, dus niet in de build).
§8 — Contact / Over-ons / Werkgebied 🟡 DEELS (contact + over-ons af)
pages/contact.astro(hidePrefooter+ NAW + formulier, sectieid="contact"). Contactblok = Bel ons / Mail ons / Adres (Werkgebied + Bereikbaar op klantverzoek verwijderd) + 4,9-regel links, formulier-kaart rechts; e-mail op één regel (1-koloms). 200, axe clean, geen overflow.pages/over-ons.astro(hero + 4,9-regel + verhaal met werkfoto + 4 waarden + werkgebied-pills). 200, axe clean, geen overflow.- Hoofd-CTA's (header/sticky/drawer) →
/contact(was interim#contact); sticky-CTA verborgen wanneerhidePrefooter(dus op /contact). Naam-veld-placeholder in alle formulieren: "Naam" (was "Voor- en achternaam"). - Form end-to-end testen (valid / honeypot / time-trap / 422) — na Mailtrap (§12).
pages/werkgebied.astro(optioneel, lokale SEO) — nog te bepalen.
§9 — Footer-pagina's + SEO 🟢 GROTENDEELS KLAAR (17-06-2026, deploy 15e076ff)
- Branded 404 bestaat nu via de catch-all
[...slug].astro(onbekende route → nette 404-pagina met CTA i.p.v. blanco). Losse404.astrodaardoor optioneel. public/robots.txt(Allow /, Disallow /_emdash/ + /api/, Sitemap-regel). Live geverifieerd.src/pages/sitemap.xml.ts= vaste code-routes + gepubliceerdepaginas+locaties(live query, noindex uitgesloten; CMS-fout → vaste routes blijven). Overschrijft emdash's eigen/sitemap.xml(die gebruikt/collectie/slug, fout voor ons root-URL-model) — user-route insrc/pages/wint (build-warning is verwacht/onschadelijk). Live geverifieerd: bevat/maastrichtuit CMS +/privacy//voorwaarden.site: "https://helvoirtgevelreiniging.nl"inastro.config.mjs→ canonical + sitemap-base wijzen naar het echte domein (ook vóór koppeling).voorwaarden.astro= Algemene voorwaarden (17-06-2026: herschreven o.b.v. zusterbedrijf onderhoudsbedrijfvanhelvoirt.nl, 10 artikelen; klant juridisch laten controleren) + in het CMS (singletonvoorwaarden, artikelen-repeater,0012_voorwaarden.sql, sentinel-geverifieerd). Privacyverklaring op klantverzoek VERWIJDERD (pagina + footer-link + sitemap; /privacy → 404). NB: voor de AVG is een privacyverklaring bij een contactformulier doorgaans wél aan te raden.- JSON-LD
HomeAndConstructionBusiness(LocalBusiness-subtype) site-breed inBase.astro: naam/desc/url/image/telefoon/e-mail/adres (gesplitst) + areaServed + aggregateRating (4,9) + optioneel kvk/btw/sameAs uitsite_settings. Live geverifieerd (rendert met CMS-data). - GTM-renderblok in
Base.astro(head-script + body-noscript), leestsite_settings.gtm; leeg = niets geïnjecteerd (geverifieerd). + theme-color + twitter-cards + og:image-default. - Gebrande 1200×630 OG-image (
public/images/og-default.webpviascripts/make-og.py: schone gevel + petrol-gradient + wordmark + 4,9-Google) +og:image:width/height/typeinBase.astro. Live (200, image/webp). +apple-touch-icon.png(180×180 H-monogram) +<link>. Service+BreadcrumbListJSON-LD op de 5 dienst-detailpagina's (diensten/[slug].astro, matcht het zichtbare kruimelpad). 3 ld+json-blokken per dienstpagina (LocalBusiness + Service + Breadcrumb). Live geverifieerd.- Resterend (optioneel):
FAQPageJSON-LD (wacht op echte FAQ-teksten — placeholder nu, schema zou dun zijn), self-hosted fonts (Archivo Expanded niet via css2, zie §10/notitie), Lighthouse/CWV-meting (keyless PSI = 429, eigen PSI-key nodig).
§10 — Beeld-pipeline 🟡 DEELS
- nano-banana placeholders:
hero-after/before.webp,hero-gevel.webp, 5×dienst-*.webp; echte input →werk-1..6.webp; 768/1280/1920-varianten +IMG_WIDTHS/srcsetForbedraad. In gebruik: dienst-hero's (dienst-*), homepage-hero + galerijen (werk-*), dienst-resultaat-galerijen + over-ons (hero-after/gevel). Ongebruikt:hero-before.webp(alleen via het geparkeerdeBeforeAfter.astro). - Echte foto's van klant verwerken → placeholders vervangen;
IMG_WIDTHSbijwerken.
§11 — Cloudflare provisioning + deploy ✅ GEDAAN (preview)
wrangler d1 create helvoirt-db→database_id0fb83f17-f91d-4910-ac8c-80f00569ce35inwrangler.jsonc;r2 bucket create helvoirt-media; KVSESSIONauto-provisioned.astro build+wrangler deploy→https://helvoirt-gevelreiniging.mike-197.workers.dev(alle marketing-pagina's 200 op fallbacks; onbekend → 404;/_emdash/admin→ setup). Laatste deploy: versionff725970.- Remote D1 seeden (dump/restore per tabel, NIET hele DB) + setup-wizard remote — hangt af van §3 (
seed.json).
§12 — Domein + Mail + CMS-login 🟡 CODE KLAAR, EXTERNE STAPPEN OPEN (17-06-2026)
- Mail-code af (patroon uit exterios/behangerbrabant):
src/lib/smtp.ts(authenticated SMTP overcloudflare:sockets, poort 465) +api/contact.tsslaat nu op in D1contact_submissions(migratie0001, toegepast op remote D1) + stuurt 2 mails (melding-klant + autoreply) viaPromise.allSettled. Mailtrap geschrapt → eigen mailbox-SMTP (besluit conform newsite.md §6). Live geverifieerd: POST → 200, D1-rij opgeslagen (sentinel getest + opgeruimd). Mail is no-op tot secret gezet is. - CMS-login-code af:
src/plugins/smtp-email.ts(email:deliver-provider voor magic-link) + geregistreerd inastro.config.mjs(plugins:[…], absoluut pad/forward-slashes). +src/cloudflare-env.d.ts(env/sockets types) +src/middleware.ts(http→https + www→apex 301, no-op op *.workers.dev). - MAIL WERKT (17-06-2026, deploy
cb425dc4).CONTACT_SMTP_PASSsecret gezet (bash printf).CONTACT_SMTP_HOST=srv8.dewebsmid.nlinwrangler.jsoncvars — mailbox draait op srv8 (ontdekt via/webmail→roundcube-redirect);mail.helvoirtgevelreiniging.nlis NXDOMAIN in Cloudflare-DNS. Live getest: beide mails verstuurd, alle paden (valid/422/honeypot/time-trap) OK, testrijen opgeruimd. Magic-link werkt nu ook (zelfde SMTP). - Mail-DNS in Cloudflare (collega; mijn token mag geen DNS, 403): A
mail→srv8-IP (185.84.143.157, DNS-only), MX@→mail.helvoirtgevelreiniging.nl, SPF, DKIM (key uit DirectAdmin), DMARC. Nodig voor INKOMENDE mail naar info@ van externen + afleverbaarheid autoreply. Outbound form-mail werkt al zonder. - CMS-gebruiker(s) SEO-partij in
usersaanmaken (SQL, §6b newsite.md) — e-mailadres(sen) opvragen. - DOMEIN LIVE (17-06-2026, deploy
7ed8f33b). Zonehelvoirtgevelreiniging.nlactief op Cloudflare (NScesar/priscilla.ns.cloudflare.com). Custom domain (apex +www) gekoppeld viawrangler.jsoncroutes+ rebuild. Site live ophttps://helvoirtgevelreiniging.nl(alle pagina's 200, canonical/sitemap = echte domein, 404 werkt). www→apex + http→https = 301 (middleware).*.workers.devis uitgeschakeld (custom-domain-only; geen duplicate content). NS-blokkade was: registrar wees nog naar hosted.nl i.p.v. Cloudflare → collega heeft NS omgezet. - Mail-DNS (MX/SPF/DKIM/DMARC) — wacht op mailbox (collega) + DNS-edit-token/dashboard (OAuth-token mag geen zone-settings/DNS, gaf 403). HTTPS-hardening (Always Use HTTPS + HSTS) = optioneel via dashboard; redirects werken al via middleware, SSL-cert actief (Workers custom domain → SSL-modus n.v.t.).
- Echte NAW/reviews/werkgebied/FAQ + GTM-ID in
site_settings; echte foto's.
§13 — QA & oplevering 🟡 DEELS
/impeccable audit(hele site) = 17/20 (Good). Fixes doorgevoerd + live (versionff725970): tap-doelen ≥44px (telefoon/e-mail prefooter+contact, logo, skip-link), scrim-kleuren → tokens, dienst-kaarttitels →<h3>, eerste-fold-beelden eager+fetchpriority, accordion-reflowcontain: layout. axe 0 op alle 9 pagina's, geen overflow (1440/768/390),astro check0, detector[].- Lighthouse/CWV (mobile+desktop) meten, formulier end-to-end (na Mailtrap §12), git-remote + eerste commit/push.
Gedaan (referentie)
- Input gelezen (Content.docx + 6 werkfoto's), referentiesite geanalyseerd,
architecture.md/todo.md/CLAUDE.mdopgesteld en bijgehouden.