Geen omschrijving
  • Astro 75%
  • TypeScript 18.4%
  • CSS 4.8%
  • Dockerfile 0.7%
  • JavaScript 0.7%
  • Andere 0.4%
Zoek een bestand
Riesewijk Tweewielers ee3f470fd6 PageSpeed en toegankelijkheid: contrast, fonts, beeld-cache, tekst opschonen
- Groene tekstkleur naar #557519 (WCAG AA, 5.3:1 op wit, was 3.77)
- Poppins laadt alleen de latin-subset, kleinere fontdownload
- Hero krijgt srcset/sizes zodat mobiel een kleiner beeld laadt
- /img: schijf-cache voor webp zodat conversies bewaard blijven over herstarts
- Lange streepjes uit alle teksten gehaald

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 23:52:45 +02:00
public Integraties (CMS-schakelbaar): WhatsApp, consent, analytics, GSC, reviews, Instagram 2026-06-07 14:02:32 +02:00
src PageSpeed en toegankelijkheid: contrast, fonts, beeld-cache, tekst opschonen 2026-06-07 23:52:45 +02:00
.dockerignore Bouw moderne Riesewijk-website (Astro + DecapCMS + assortiment-API) 2026-06-06 21:14:48 +02:00
.env.example Afstemmen op testomgeving (SITE_URL, OAuth, dynamische robots) 2026-06-07 13:06:54 +02:00
.gitignore PageSpeed en toegankelijkheid: contrast, fonts, beeld-cache, tekst opschonen 2026-06-07 23:52:45 +02:00
astro.config.mjs Afstemmen op testomgeving (SITE_URL, OAuth, dynamische robots) 2026-06-07 13:06:54 +02:00
docker-compose.yml Bouw moderne Riesewijk-website (Astro + DecapCMS + assortiment-API) 2026-06-06 21:14:48 +02:00
Dockerfile Afbeeldingen: WebP + cache via /img-endpoint, instelbaar in CMS 2026-06-07 13:22:06 +02:00
package-lock.json Afbeeldingen: WebP + cache via /img-endpoint, instelbaar in CMS 2026-06-07 13:22:06 +02:00
package.json Afbeeldingen: WebP + cache via /img-endpoint, instelbaar in CMS 2026-06-07 13:22:06 +02:00
README.md Integraties (CMS-schakelbaar): WhatsApp, consent, analytics, GSC, reviews, Instagram 2026-06-07 14:02:32 +02:00
tsconfig.json Bouw moderne Riesewijk-website (Astro + DecapCMS + assortiment-API) 2026-06-06 21:14:48 +02:00

Riesewijk Tweewielers — website

Moderne herbouw van riesewijk.nl met Astro + DecapCMS (self-hosted), gekoppeld aan de bestaande RiesewijkAPI voor het fietsassortiment. Deploybaar op Coolify via Docker, met login/contentbeheer via Forgejo/Gitea (PKCE OAuth).

Stack

Onderdeel Keuze
Framework Astro 5 (SSR via @astrojs/node, standalone)
Styling Eigen design-tokens (CSS), font Poppins (self-host)
CMS DecapCMS — Gitea/Forgejo-backend met PKCE
Assortiment RiesewijkAPI /api/fietsen (server-side, gecachet)
Formulieren Brevo (transactionele e-mail + nieuwsbrief)
Deploy Docker → Coolify (poort 4321)

Het hele site draait server-side (on-demand): één Node-server serveert alle pagina's én de statische assets. Assortiment en tweedehands halen live data uit de API; alle teksten, nieuws, FAQ, merken en pagina's komen uit Git via DecapCMS.

Lokaal ontwikkelen

npm install
npm run dev            # http://localhost:4321

Productiebuild lokaal draaien:

npm run build
npm run start          # node ./dist/server/entry.mjs

Maak een .env op basis van .env.example voor live API/mail. Zonder ASSORTIMENT_API_URL tonen de assortimentspagina's een nette "tijdelijk niet beschikbaar"-melding.

Omgevingsvariabelen

Variabele Verplicht Omschrijving
SITE_URL Publieke URL (canonical/OG/sitemap/robots). Test: https://testomgeving.riesewijk.nl, productie: https://riesewijk.nl.
ASSORTIMENT_API_URL Basis-URL van de RiesewijkAPI (bv. https://api.riesewijk.nl).
ASSORTIMENT_CACHE_TTL Cache in seconden voor API-data (default 300).
BREVO_API_KEY ✓¹ Brevo API-key (SMTP & API → API Keys).
BREVO_SENDER_EMAIL ✓¹ Geverifieerde afzender in Brevo.
BREVO_SENDER_NAME Weergavenaam afzender.
BREVO_CONTACT_TO ✓¹ Ontvanger contactformulier (bv. info@riesewijk.nl).
BREVO_NEWSLETTER_LIST_ID Lijst-ID voor nieuwsbriefinschrijvingen.
HOST / PORT Default 0.0.0.0 / 4321.

¹ Nodig om contact- en nieuwsbriefformulieren werkend te krijgen.

De Forgejo OAuth ClientID staat niet in env maar in public/admin/config.yml (app_id). PKCE heeft geen secret nodig.

DecapCMS + Forgejo/Gitea (PKCE)

Het CMS leeft op /admin en commit content rechtstreeks naar deze repo (Riesewijk/RiesewijkWebsite op code.securityasaservice.org).

1. OAuth-applicatie aanmaken in Forgejo Ga naar Instellingen → Toepassingen → OAuth2-toepassingen (of op org-niveau) en maak een app:

  • Redirect URI: https://testomgeving.riesewijk.nl/admin/ (voeg voor productie óók https://riesewijk.nl/admin/ toe — meerdere redirect-URI's mogen)
  • Confidential Client: UIT (belangrijk — PKCE, geen secret)
  • Kopieer de gegenereerde Client ID.

2. ClientID invullen Zet de Client ID in public/admin/config.yml bij app_id (vervang REPLACE_WITH_FORGEJO_OAUTH_CLIENT_ID).

3. CORS aanzetten in Forgejo (app.ini), zodat de browser tokens mag uitwisselen:

[cors]
ENABLED = true
ALLOW_DOMAIN = testomgeving.riesewijk.nl, riesewijk.nl
METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS

Vereist Forgejo ≥ 1.21.4 / Gitea ≥ 1.20. Inloggen op /admin gaat daarna via je Forgejo-account.

Lokaal CMS testen zonder Forgejo: zet local_backend: true in config.yml en draai in een tweede terminal npx decap-server.

Wat is bewerkbaar?

Collectie Locatie
Nieuws & blog src/content/nieuws/
FAQ src/content/faq/
Merken src/content/merken/
Vacatures src/content/vacatures/
Pagina's src/content/pages/
Homepage src/data/home.json
Site-instellingen src/data/settings.json

De mediabibliotheek toont de hele beeldbank in public/images/; geüploade afbeeldingen komen daar ook terecht.

Brevo (formulieren)

  • ContactPOST /api/contact stuurt een transactionele mail naar BREVO_CONTACT_TO, met de inzender als reply-to. Honeypot + validatie ingebouwd.
  • NieuwsbriefPOST /api/newsletter voegt het adres toe aan BREVO_NEWSLETTER_LIST_ID.

Zet BREVO_API_KEY en een geverifieerde BREVO_SENDER_EMAIL in Brevo. Beide formulieren werken ook zonder JavaScript (native POST met server-side feedback).

Assortiment

src/lib/assortiment.ts bevraagt server-side ${ASSORTIMENT_API_URL}/api/fietsen, cachet het resultaat (TTL) en splitst op state:

  • /assortiment — nieuwe fietsen, met filters (merk, kleur, maat, prijs, sorteren).
  • /tweedehands — tweedehands fietsen.
  • /fiets/[id] — detailpagina per fiets.

Fietsfoto's komen uit de API (via de /img-endpoint, zie hieronder). Valt de API weg, dan tonen de pagina's een vriendelijke fallback in plaats van een fout.

Afbeeldingen (WebP + cache)

Alle inhoudsafbeeldingen lopen via de endpoint /img (component src/components/Img.astro), die ze on-the-fly naar WebP omzet, schaalt en met lange cache-headers serveert (Cache-Control: public, max-age=…, immutable). Werkt voor eigen afbeeldingen én voor assortimentsfoto's uit de API. Instelbaar in DecapCMS onder Site-instellingen → Afbeeldingen:

Instelling Effect
Optimalisatie aan Pijplijn aan/uit (uit = originele bestanden direct).
WebP gebruiken Converteren naar WebP.
Kwaliteit (1100) WebP-kwaliteit (default 78).
Max. breedte (px) Bovengrens voor schaalbreedte.
Cache (dagen) Hoe lang browsers/CDN de afbeelding cachen.

Mislukt de conversie of staat sharp niet aan, dan wordt het origineel geserveerd — nooit een gebroken afbeelding. Conversies worden in het geheugen gecachet voor de serverlevensduur. WebP-conversie gebruikt sharp; daarom draait de Docker-image op node:22-slim (libvips).

Integraties (CMS → Site-instellingen → Integraties)

Allemaal aan/uit te zetten en te configureren zonder code. Externe, cookie-zettende onderdelen laden pas na toestemming via de consent-banner.

  • WhatsApp — zwevende chatknop. Vul een internationaal nummer in (bv. 31570677750), standaardbericht en knoptekst. Uit of leeg nummer = geen knop.
  • Cookie-consent — AVG-banner (titel/tekst/privacy-link); opties "statistieken" en "externe content" apart toonbaar. Bezoekers wijzigen later via Cookie-instellingen in de footer.
  • Statistieken — privacyvriendelijk: Plausible/Umami (cookieloos → geen toestemming nodig) of Matomo/GA4 (cookies → achter consent). Kies aanbieder + script-URL/ID.
  • SEO-verificatie — Google Search Console- en Bing-code (meta-tag in <head>).
  • Reviews — cijfer/sterren-kaart (cijfer, aantal, link) en/of widget-embed van Google/KiyOh/The Feedback Company/Trustpilot (embed achter consent).
  • Instagram — feed via LightWidget/Elfsight/Behold (Widget-ID) of eigen embed (achter consent).

Deployen op Coolify

  1. Nieuwe Application → bron = deze Git-repo → build pack Dockerfile.
  2. Port 4321 (staat in de Dockerfile als EXPOSE/PORT).
  3. Zet de environment variables uit de tabel hierboven (minimaal ASSORTIMENT_API_URL, BREVO_*, en SITE_URL=https://testomgeving.riesewijk.nl (productie: https://riesewijk.nl)).
  4. Koppel het domein (test: testomgeving.riesewijk.nl) en laat Coolify TLS regelen.
  5. Deploy. De healthcheck in de Dockerfile pingt /.

Let op: SITE_URL wordt op build-time ingebakken (canonical/OG/sitemap/robots). De Dockerfile heeft testomgeving.riesewijk.nl als default; voor productie geef je de build-arg mee: --build-arg SITE_URL=https://riesewijk.nl (in Coolify als build-argument). De overige variabelen (ASSORTIMENT_API_URL, BREVO_*) zijn gewone runtime-env.

Lokaal de container testen:

docker compose up --build      # http://localhost:4321

Logo & afbeeldingen

Het originele logo (public/brand/logo_riesewijk_light.svg) en de sfeer-/contentfoto's (public/images/) zijn overgenomen van de huidige site en blijven ongewijzigd. Alleen assortimentsafbeeldingen komen dynamisch uit de API.

Projectstructuur (kort)

public/admin/      DecapCMS (index.html + config.yml)
public/brand/      Logo + favicons (ongewijzigd)
public/images/     Sfeer-/contentfoto's + CMS-uploads
src/components/    Header, Footer, BikeCard, FilterBar, ContactForm, ...
src/content/       Nieuws, FAQ, merken, vacatures, pagina's (Markdown)
src/data/          home.json, settings.json (singletons)
src/lib/           assortiment.ts (API), brevo.ts (mail)
src/pages/         Routes (+ api/contact, api/newsletter)

Aandachtspunten

  • Juridische teksten (voorwaarden, privacy) zijn algemene basisversies — laat ze juridisch controleren vóór livegang.
  • Social-media-URL's in settings.json zijn aannames; controleer/pas ze aan.