- Astro 45.2%
- TypeScript 39.6%
- JavaScript 10.6%
- CSS 3.2%
- Shell 1%
- Other 0.4%
Het hele blok was naar /about verhuisd en daarmee raakte de homepage
haar hardste argument kwijt. Dat argument is het getal, niet de drie
alinea's eronder.
Dus hier het getal, de conclusie erbij ("niet een revolutie, een grotere
kaart") en een link naar de cijfers erachter. De onderbouwing en de bron
blijven op /about, want dezelfde zinnen op twee pagina's is precies wat
we niet doen. De slotregel over de grotere kaart staat nu alleen nog
hier, niet meer daar.
432px in plaats van de 729px die het blok eerst was.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014d9igBWXLHnf4tgYJ5cuFw
|
||
|---|---|---|
| .forgejo/workflows | ||
| public | ||
| scripts | ||
| src | ||
| .dockerignore | ||
| .gitignore | ||
| astro.config.mjs | ||
| BEELD.md | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
edano.eu
De website van edano (European Digital Autonomy Network), een Europese IT-cooperatie in oprichting.
Doel van de site: leden werven. Daarnaast drie nevenpaden: klanten, partners en investeerders. Alles wat niet bijdraagt aan een ingevulde inschrijving is bijzaak.
Meedoen
Je hebt Node 22 nodig. Verder niets: geen database, geen externe dienst.
git clone https://forgejo.bb-open.com/bb-open/edano-web.git
cd edano-web
npm install
npm run dev # http://localhost:4321
Dat is genoeg om de hele site te zien, in beide talen, inclusief het
inschrijfformulier. Zonder Odoo-configuratie komt een inschrijving in
.dev-leads.jsonl in de projectmap terecht; die staat in .gitignore.
Voordat je iets voorstelt
npm run check # types in .astro EN .ts, plus de contrastcontrole
npm run build # dezelfde build als de CI draait
npm run check-promises # tegen een draaiende server; zie hieronder
npm run check is geen formaliteit. npm run build compileert .astro-
bestanden wel maar rendert ze niet, en tsc kijkt alleen in .ts. Een
verwijzing naar een contentveld dat niet meer bestaat viel daardoor door beide
mazen heen en gaf pas in de browser een serverfout. astro check kijkt wel in
de expressies binnen .astro en vangt dat. De CI draait het en blokkeert de
build erop.
Een wijziging voorstellen
- Vertak van
dev, niet vanmain. - Push je branch en open een pull request naar
dev. - Bekijk het lokaal met
npm run dev. Dat is de plek waar we ernaar kijken. - Van
devnaarmaingaat naaredano.eu. Dat is een aparte, bewuste stap.
main krijgt nooit rechtstreeks een commit. Alles gaat eerst naar dev;
pas als het daar goed is gaat het via een merge naar main en dus naar
productie. Ook kleine wijzigingen, ook als het duidelijk klopt: een
uitzondering maken haalt de hele reden weg dat die scheiding er is.
De volgorde bij een uitrol:
git switch dev
# werken, committen, lokaal nakijken
git push origin dev
git switch main && git merge --ff-only dev && git push origin main
# scripts/release.sh <versie>, image bumpen in de platform-repo
Er stond een ontwikkelomgeving op demo.website.edano.eu. Die is weggehaald:
iedereen draait de site lokaal, dus hij voegde niets toe en kostte wel een pod.
De controlestap is daarmee npm run dev op je eigen machine.
Kleine tekstwijzigingen hoeven geen uitleg. Voor alles wat kleur, contrast of
opmaak raakt: lees eerst de kop van src/styles/global.css. Daar staat per
kleur waarvoor hij is en wat hij meet, en die afspraken worden bewaakt door
scripts/check-contrast.mjs.
De omgeving
edano.eu is de enige draaiende omgeving; hij volgt main. Wat hij doet hangt
volledig aan een handvol variabelen, en dat is bewust: zo kan er een tweede
omgeving naast zonder dat er een regel code verandert.
SITE_URL waar de site zichzelf canoniek verklaart
SITE_INDEXABLE noindex-meta, robots.txt en X-Robots-Tag tegelijk
PLAUSIBLE_SCRIPT_URL meting; niet gezet is niet meten
LEADS_DIR waar inschrijvingen worden weggeschreven
ODOO_URL/DB/USER/API_KEY
Zo hoort het te gaan: een push bouwt een image
(.forgejo/workflows/build.yml), Flux ziet de nieuwe tag en zet hem in de
platform-repo. main levert main-<run>, dev levert dev-<run>; twee
prefixen zodat een dev-image nooit op productie kan belanden.
Dat werkt nu nog niet, maar anders dan hier eerder stond. Er IS een runner
met het label nixos: op 21 augustus 2026 zijn zestien runs opgepakt. De job
check slaagde elke keer, dus de runner haalt de repo op, draait nix en voert
npm run check uit. De job image faalde elke keer.
Gemeten aan de registry: er staat geen enkele tag met de prefix main- of
dev-. Alle zeventien tags zijn met de hand gepusht via scripts/release.sh.
Hetzelfde geldt voor bb-open/sextantfleet.com, waar deze workflow vandaan komt:
ook daar nul CI-tags. Deze workflow heeft dus in geen enkele repo ooit een image
gepusht.
De waarschijnlijke oorzaak staat in de kop van het workflowbestand zelf:
inloggen op de registry gaat met het token dat Forgejo per run meegeeft, en dat
token mag daar kennelijk niet pushen. De uitweg die er ook al staat is
REGISTRY_USER en REGISTRY_TOKEN als repo-secrets zetten; die krijgen
voorrang. Zonder de logs van een run is dat een vermoeden en geen diagnose.
Sinds 21 augustus 16:17 is er niets meer gedraaid, terwijl er daarna tientallen keren is gepusht. Ook de job die het wel deed staat dus stil.
Tot dit klopt gaat uitrollen met de hand, en dat werkt.
Tot er een runner is, gaat uitrollen met de hand:
scripts/release.sh 0.5.2
Dat draait de controle, bouwt, doet een rooktest over alle routes, pusht, en drukt de regel af die in de platform-repo moet. De digest komt daarbij uit de registry en niet uit podman: die twee wijken van elkaar af, en met de verkeerde waarde blijft de pod in ImagePullBackOff hangen zonder dat er iets mis lijkt.
Wat waar staat
src/content/ teksten. en.ts en nl.ts, met de gedeelde vorm in types.ts
src/lib/nav.ts de navigatie, gedeeld door kop en voet
src/lib/site.ts SITE_URL en de indexeringsschakelaar
src/lib/analytics.ts Plausible via onze eigen herkomst
src/lib/leads.ts waar een inschrijving landt: eerst schijf, dan Odoo
src/lib/signup.ts validatie en verwerking van de POST
src/lib/odoo.ts JSON-RPC-client voor Odoo CRM
src/components/ Header, Footer, HomePage, InfoPage, TrackPage, Logo
src/middleware.js CSP, securityheaders, rem op POST, canonieke host
src/styles/global.css de kleurtokens, met de gemeten contrasten erbij
scripts/check-contrast.mjs rekent elke kleurcombinatie na
scripts/check-promises.mjs toetst wat de site over zichzelf belooft
scripts/check-style.mjs meet de stijlgids na op de gerenderde pagina's
scripts/release.sh bouwen, testen, pushen zolang er geen CI-runner is
scripts/replay-leads.mjs inschrijvingen die Odoo niet haalden alsnog aanbieden
scripts/build-press-logos.mjs de logobestanden voor de persmap
scripts/build-images.mjs de beeldvarianten: drie formaten, vijf breedtes
scripts/build-stats.mjs haalt het Plausible-script op naar public/js
BEELD.md welk beeld er nog ontbreekt, met de opdracht erbij
Vier sporen
members, partners, customers en investors. De sleutels staan in
TRACK_KEYS (src/content/types.ts) en sturen de routes, de navigatie, de
kaarten op de homepage en het formulier tegelijk. Eén sleutel toevoegen raakt
dus alle vier.
Daarnaast vier uitlegpagina's: /why, /how-it-works, /governance,
/about. Die hergebruiken inhoud die ook op de homepage staat; er wordt daar
niets nieuws beweerd.
Een inschrijving raakt nooit kwijt
De volgorde is: eerst naar schijf, dan pas naar Odoo.
Lukt het wegschrijven niet, dan ziet de bezoeker een fout. Dat is de enige
situatie waarin we niets kunnen garanderen. Lukt Odoo niet, dan ziet de
bezoeker gewoon de bedankpagina, want zijn inschrijving staat veilig. De fout
gaat naar het log en scripts/replay-leads.mjs biedt die regels later opnieuw
aan.
Andersom was het eerst, en toen betekende een Odoo-storing van vijf minuten dat elke inschrijving in die vijf minuten weg was.
Weringen tegen misbruik: een honeypot-veld, een ondertekende tijdstempel en een teller per IP in het geheugen. Geen captcha, want dat kost een externe bron en botst met het hele uitgangspunt van de site.
Geen externe bronnen
De CSP staat op 'self'. Geen CDN, geen webfont van een ander domein, geen
tracker, geen captcha. Dat is niet alleen hygiene: een site over Europese
digitale onafhankelijkheid die scripts van derden inlaadt, weerlegt zichzelf.
Daarom zijn ook de lettertypen zelf gehost, en loopt Plausible via eigen routes
(/js/stats.js, /api/event) in plaats van rechtstreeks vanuit de browser.
Er is wel JavaScript, en het staat allemaal in losse bestanden omdat inline script door de CSP wordt geblokkeerd:
public/js/counters.js telt de cijfers op de homepage omhoog
public/js/menu.js sluit de menu's bij een klik ernaast en bij Escape
src/pages/js/stats* Plausible, alleen als PLAUSIBLE_SCRIPT_URL gezet is
De site werkt zonder al deze bestanden. Ze voegen gedrag toe, geen inhoud.
npm run check-promises toetst dit tegen een draaiende server: geen enkele
route zet een cookie, geen enkele pagina haalt een subresource van een ander
domein, en de CSP noemt geen externe herkomst. Dat zijn geen stijlregels maar
uitspraken die in de privacyverklaring staan, en een juridische uitspraak die
stilletjes onwaar wordt is erger dan geen uitspraak. scripts/release.sh
draait het tegen het gebouwde image, dus tegen wat er echt op edano.eu komt.
Merk
Merkgids v3.0 is leidend, behalve de kleuren: die waren toen nog niet
bepaald. Het palet staat in src/styles/global.css, met per kleur waar hij
voor is en de gemeten contrastwaarde erbij. /styleguide zet alle
merkbeslissingen naast elkaar; die pagina staat niet in de navigatie en blijft
ook na livegang uit de index.
Twee regels die niet ter discussie staan, allebei bewaakt door
npm run check-contrast:
- Op donker is alle tekst vol wit. Gedempt wit haalt het op de lichte kant van het verloop niet (3.76).
- Bij een verloop telt de slechtste tussenstop, niet de uiteinden.
Het logo is vector, geen tekst. Als tekst zou het afhangen van of het font
laadt. Het vlak heeft de gehaakte e UIT GESTANST met een masker, dus er is
geen apart bestand voor een lichte variant: het vlak krijgt currentColor en
door de uitsparing schijnt de ondergrond. In de kop loopt dat vlak tot de
bovenrand van de pagina (flushTop), zoals op rijksoverheid.nl.
Nog te doen
- Odoo is nog niet gekoppeld. Zonder de vier
ODOO_*-variabelen schrijft de site elke inschrijving naarLEADS_DIRen logt[lead][ODOO-FAILED]; de bezoeker ziet gewoon de bedankpagina, er gaat niets verloren. Zodra de koppeling staat haaltnpm run replay-leadsde wachtrij op. Draait Odoo buiten het cluster, dan moet dat adres bij de egressregel innamespace.yaml, anders faalt de koppeling stil. my.edano.euserveert nog de standaard Odoo-pagina. De ledeningang in de voet wijst er al naartoe.- Cookies, Terms en Security ontbreken nog naast
/privacy. - De cijfers 13+, 10+ en 4 zijn door de eigenaar bevestigd als "vooralsnog prima", maar staan wel op een geïndexeerde site.
- Er is geen CI-runner met het label
nixos. Tot die er is gaat uitrollen met de hand viascripts/release.sh.
Afgedaan sinds de eerste versie: de privacyverklaring is ingevuld en
SITE_INDEXABLE staat aan, het beeld staat op de site, en het echte logo heeft
de gegenereerde plaatsvervanger vervangen.