de Website van Je-Ma ICT Beheer
  • Nunjucks 33.2%
  • HTML 28.4%
  • CSS 18.8%
  • PHP 13.4%
  • JavaScript 3.1%
  • Andere 3.1%
Zoek een bestand
Jesse van Mullem eb59b759cc OTAP-branchmodel met promotie vanuit de CMS
- promote.php: server-side endpoint dat via de Gitea-API een PR van de ene
  omgevingsbranch naar de volgende aanmaakt en merget (dev -> test -> acc -> prod)
- admin/promote.html: promotiepaneel in de CMS met wachtwoord-guard en confirm op productie
- Decap CMS commit nu naar de dev-branch
- config.local.example en docker-compose: JEMA_GITEA_TOKEN en JEMA_PROMOTE_SECRET
- README: OTAP-sectie met Coolify-, Gitea- en promotie-instructies
- promote.php meegekopieerd in de Eleventy-build

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:49:01 +02:00
docker add Docker build for Coolify deployment 2026-06-01 22:47:17 +02:00
src OTAP-branchmodel met promotie vanuit de CMS 2026-07-14 19:49:01 +02:00
.dockerignore add Docker build for Coolify deployment 2026-06-01 22:47:17 +02:00
.eleventy.js OTAP-branchmodel met promotie vanuit de CMS 2026-07-14 19:49:01 +02:00
.gitignore introduce Eleventy build pipeline and Decap CMS foundation 2026-06-01 22:24:40 +02:00
docker-compose.yml OTAP-branchmodel met promotie vanuit de CMS 2026-07-14 19:49:01 +02:00
Dockerfile fix Coolify build by using npm install instead of npm ci 2026-06-02 08:37:29 +02:00
package.json self-host Decap CMS bundle instead of loading from jsDelivr 2026-06-06 19:56:53 +02:00
README.md OTAP-branchmodel met promotie vanuit de CMS 2026-07-14 19:49:01 +02:00

Je-Ma ICT Beheer website

Statische site gebouwd met Eleventy, met content beheerd via Decap CMS. Source-bestanden staan in src/, de gebouwde site komt in _site/.

Structuur

.
├── .eleventy.js              Eleventy-configuratie
├── package.json              Node-dependencies en build-scripts
├── src/
│   ├── _data/                YAML data-files (site-config, navigatie, footer)
│   ├── _includes/            Layouts en partials
│   │   ├── base.njk          Basis-HTML met head + header + footer
│   │   ├── article.njk       Layout voor een nieuws-artikel
│   │   └── partials/         Header en footer partials
│   ├── _news/                Markdown-bestanden, één per nieuwsbericht
│   ├── admin/                Decap CMS (index.html + config.yml)
│   ├── assets/               Afbeeldingen, fonts, logos, badges
│   ├── css/                  Stylesheet
│   ├── js/                   JS (inclusief vendored captcha-widget)
│   ├── *.html                Pagina-templates (gebruiken base.njk via frontmatter)
│   ├── *.php                 Server-side endpoints (contact + altcha)
│   ├── .htaccess             Apache-config (security-headers + CSP)
│   ├── robots.txt
│   └── sitemap.xml
└── _site/                    Build-output (gitignored)

Lokaal werken

Eenmalig:

npm install

Daarna voor lokaal ontwikkelen:

npm run serve

Eleventy serveert op http://localhost:8080 en watcht wijzigingen in src/.

Voor een productie-build:

npm run build

De gebouwde site staat in _site/.

Deployment

De aanbevolen route is Docker via Coolify. De Dockerfile in de repo-root bouwt Eleventy en zet daarna een PHP 8.3 + Apache image klaar met _site/ als document-root, msmtp voor mail-relay en een volume-mount voor rate-limit state.

Coolify

  1. Nieuw project in Coolify, Type "Dockerfile". Koppel deze repo (Gitea-source). Branch: main.
  2. Build settings: geen extra build args nodig; Coolify pakt het Dockerfile automatisch.
  3. Environment variables (zie docker-compose.yml voor het complete overzicht):
    • JEMA_ALTCHA_KEY (secret, vereist) — genereer met openssl rand -hex 32
    • JEMA_MAIL_TO — geadresseerde, default support@je-ma.com
    • JEMA_MAIL_FROM — afzender, default no-reply@je-ma.com
    • SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM — SMTP-relay voor uitgaande mail (verplicht voor werkende contactformulier)
  4. Persistent storage: mount een volume op /var/lib/jema-state zodat rate-limit- en replay-cache een container-restart overleven.
  5. Domain: je-ma.com, met automatische HTTPS via Coolify (Caddy of Traefik labels).
  6. Health-check zit al in het image (HEALTHCHECK ... curl /), Coolify pakt die automatisch op.
  7. Deploy. Coolify bouwt het image, start de container en koppelt het domein. Bij elke push naar main herbouwt Coolify automatisch (mits Auto Deploy aan staat).

Lokaal testen

# Bouw en draai in één:
docker compose up --build

# Of zonder compose:
docker build -t jema-web .
docker run --rm -p 8080:80 \
    -e JEMA_ALTCHA_KEY=$(openssl rand -hex 32) \
    -e SMTP_HOST=smtp.example.com -e SMTP_PORT=587 \
    -e SMTP_USER=u -e SMTP_PASS=p \
    -v jema-state:/var/lib/jema-state \
    jema-web

De site is dan beschikbaar op http://localhost:8080.

Build buiten Docker (legacy / handmatig)

Als je liever zonder Docker werkt, draait de oude flow ook nog:

npm install
npm run build      # output in _site/
rsync -a --delete _site/ /var/www/jema-html/

Documentroot = _site/. Mail-config via src/config.local.php.

OTAP (dev, test, acc, prod)

De site gebruikt een OTAP-branchmodel. Content en code stromen door de keten van laag naar hoog:

dev  ->  test  ->  acc  ->  prod
  • dev: de werkbranch. Decap CMS commit hier naartoe (zie backend.branch: dev in src/admin/config.yml).
  • test: interne verificatie.
  • acc: acceptatie/klant-review.
  • prod: productie, gekoppeld aan je-ma.com.

main blijft bestaan als de repo-default (waar code-PR's op landen), maar de deploys draaien op de OTAP-branches. Wil je main niet meer gebruiken, dan kun je de default-branch in Gitea op dev zetten.

Deploy-topologie (Coolify)

Maak in Coolify vier deploys van dit Dockerfile, elk gekoppeld aan een branch met een eigen subdomein:

Branch Coolify-app Domein
dev jema-dev dev.je-ma.com
test jema-test test.je-ma.com
acc jema-acc acc.je-ma.com
prod jema-prod je-ma.com

Zet op elke app dezelfde env-vars als de bestaande productie-app (zie docker-compose.yml). Elke omgeving heeft eigen state en eigen secrets. Zet dev, test en acc bij voorkeur achter HTTP Basic Auth of een IP-allowlist, zodat alleen productie publiek is.

Promoveren vanuit de CMS

In de CMS-omgeving zit een promotiepaneel op /admin/promote.html met drie knoppen: dev -> test, test -> acc en acc -> prod. Een klik roept het server-side endpoint promote.php aan, dat via de Gitea-API een pull request van de ene branch naar de volgende aanmaakt en direct merget.

Benodigde server-config (per omgeving van waaruit je wilt promoveren, dus minimaal dev, test en acc):

  1. Gitea PAT: maak in Gitea onder Settings -> Applications -> Generate New Token een token met schrijfrechten op de repo. Zet die als env-var JEMA_GITEA_TOKEN (of in config.local.php als gitea_token).
  2. Promotie-wachtwoord: kies een geheim en zet dat als JEMA_PROMOTE_SECRET (of promote_secret). Dit wachtwoord vul je in op /admin/promote.html; zonder juist wachtwoord weigert het endpoint.
  3. Zonder beide waarden is promote.php fail-closed (weigert alles).

Omdat promote.php naar productie kan mergen: geef het Gitea-token alleen aan vertrouwde beheerders, en stel branch-protection in op acc en prod (in Gitea onder Settings -> Branches), zodat er geen directe push buiten deze flow om plaatsvindt.

Promoveren zonder de CMS (handmatig)

Promotie is gewoon een merge, dus het kan ook via git of via de Gitea-UI (open een PR van bijvoorbeeld test naar acc en merge die). Het CMS-paneel is enkel een gemak bovenop diezelfde merges.

Decap CMS opzetten

Decap CMS authentiseert via Gitea OAuth. Setup-stappen:

1. OAuth-app aanmaken in Gitea

  1. Log in op code.securityasaservice.org met een admin-account.
  2. Ga naar Settings → Applications → Manage OAuth2 Applications.
  3. Klik op Create a new OAuth2 Application en vul in:
    • Application Name: Je-Ma CMS
    • Redirect URI: https://je-ma.com/admin/
    • Confidential Client: uitvinken (Decap gebruikt implicit grant)
  4. Klik op Create Application. Kopieer de Client ID.

2. Client ID invullen in config.yml

Open src/admin/config.yml en vervang PLAK_HIER_DE_CLIENT_ID_VAN_DE_GITEA_OAUTH_APP door je Client ID.

3. CSP toestaan

De .htaccess zet een strikte Content-Security-Policy. Decap CMS heeft toegang nodig tot Gitea en jsDelivr. Pas de policy aan in src/.htaccess:

Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data: blob: https://code.securityasaservice.org; connect-src 'self' https://code.securityasaservice.org; worker-src 'self' blob:; frame-ancestors 'none'; form-action 'self' https://code.securityasaservice.org; base-uri 'self'; object-src 'none'"

Of beperk dit alleen tot /admin/ via een aparte <Location> block, zodat de rest van de site een strikte CSP houdt.

4. Inloggen

Ga naar https://je-ma.com/admin/. Decap stuurt je naar Gitea voor autorisatie. Na akkoord land je in de CMS-omgeving met:

  • Site-instellingen — bedrijfsnaam, contact, navigatie, footer
  • Nieuws — alle persberichten, nieuwe artikelen aanmaken

Elke wijziging wordt als commit naar main gepusht.

5. Lokaal CMS testen (zonder Gitea)

npm run cms      # Decap proxy server op poort 8081
npm run serve    # in een tweede terminal

local_backend: true in config.yml zorgt dat Decap met de lokale proxy praat en wijzigingen direct op je filesystem schrijft.

Een nieuwsbericht aanmaken (handmatig, zonder CMS)

Maak een bestand in src/_news/ met YYYY-MM-DD-slug.md als naam:

---
layout: article.njk
title: 'Titel <span class="gradient-text">met accent</span>'
intro: "Korte inleiding."
date: 2026-06-15
category: "Persbericht"
heroImage: "/assets/badges/example.svg"
heroImageAlt: "Beschrijving"
---

Hier komt de inhoud. **Markdown** of HTML mag.

Eleventy bouwt automatisch /nieuws/2026-06-15-slug.html en neemt het bericht op in de lijst op /nieuws.html.

Pagina-content uitbreiden naar CMS

De fundering staat. Site-instellingen, navigatie, footer en nieuws zijn volledig CMS-bewerkbaar. Pagina-content (home, diensten, etc.) zit nu nog hard in de HTML-templates onder src/.

Om een specifiek veld bewerkbaar te maken:

  1. Verplaats de hard-gecodeerde tekst naar een data-bestand (bv. src/_data/pages/home.yml).
  2. Vervang in de template de tekst door {{ pages.home.veld_naam }}.
  3. Voeg een collection-entry toe in src/admin/config.yml (de stub staat onderaan, uncomment en pas aan).

Doe dit incrementeel per veld of per pagina.

Wat niet via Eleventy gaat

  • contact.php en challenge.php worden 1:1 mee gekopieerd vanuit src/. Inhoud bewerken doe je door het PHP-bestand zelf aan te passen.
  • config.local.php staat op je server (gitignored).
  • De security-headers in .htaccess worden 1:1 mee gekopieerd.

Veiligheidsaandachtspunten

  • Geheimen (zoals de Altcha HMAC-key) blijven in config.local.php, buiten git.
  • Decap CMS commit als de ingelogde gebruiker. Geef alleen vertrouwde gebruikers schrijfrechten op de repo.
  • Overweeg een aparte branch (bv. cms-edits) waar Decap naartoe pusht, met code review voor merges naar main.