No description
  • CSS 86.9%
  • php 9%
  • SCSS 2.4%
  • Twig 1.3%
  • JavaScript 0.2%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
bdu 3d5d03d259
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
upgrades and lockfilemaintenance by renovate bot
2026-11-05 17:16:52 +01:00
.ddev fix: drop and recreate local DB before import in pull-prod-db 2026-05-15 22:31:24 +02:00
config/sync fix: clear status report warnings 2026-10-21 19:42:55 +02:00
deploy chore: remove unused deploy/docker-compose.yml 2026-05-15 22:52:16 +02:00
docker fix: clear status report warnings 2026-10-21 19:42:55 +02:00
docs afwezigheden: documentatie en API-contract voor Sint-Lukas Admin 2026-07-06 21:17:33 +02:00
private private files 2026-07-21 10:08:02 +02:00
web chore(deps): update dependency autoprefixer to v10.6.2 2026-10-30 03:00:36 +00:00
.dockerignore more cleanup 2026-03-07 22:23:49 +01:00
.editorconfig initial setup 2025-06-19 13:24:24 +02:00
.gitattributes upgrade drupal to 11.2 2025-06-19 14:28:34 +02:00
.gitignore Merge branch 'staging' into afwezigheden 2026-07-21 11:55:02 +02:00
.woodpecker.yml build: php 8.4 on trixie, pull base image on build 2026-10-21 19:34:37 +02:00
BACKUP.md backup 2026-03-16 21:11:30 +01:00
CLAUDE.md Merge branch 'main' into afwezigheden 2026-09-08 20:20:44 +02:00
composer.json fix(deps): update dependency cweagans/composer-patches to v2 2026-10-16 12:23:49 +00:00
composer.lock upgrades and lockfilemaintenance by renovate bot 2026-11-05 17:16:52 +01:00
Dockerfile fix: clear status report warnings 2026-10-21 19:42:55 +02:00
license.md license 2025-09-17 14:19:38 +02:00
patches.lock.json upgrade 2026-10-21 14:59:04 +02:00
PRODUCT.md feat: page headers, gallery grid, calendar styling, prose layout 2026-05-08 21:33:44 +02:00
readme.md docs: add settings, config sync, splits, and DB pull sections to readme 2026-05-15 23:04:19 +02:00
renovate.json upgrades and lockfilemaintenance by renovate bot 2026-11-05 17:16:52 +01:00

SLB website

Drupal 11 website for SLB, built with the Bootstrap 5 base theme and a custom subtheme. Local development runs on DDEV with Nginx, PHP 8.3, and MariaDB 10.11.

Staging: status-badge

Production: status-badge

Prerequisites

  • DDEV
  • Node.js (managed via Corepack inside DDEV)

Getting started

ddev start
ddev composer install
ddev launch

Theme development

The custom theme lives in web/themes/custom/b5_slb and uses Gulp with BrowserSync for live reload during development.

ddev ssh
cd web/themes/custom/b5_slb
npm install
npx gulp

This compiles SCSS to CSS (with Autoprefixer) and opens a BrowserSync proxy at the DDEV site URL. Changes to .scss, .php, and .twig files trigger automatic reloads.

Deployment

Production runs on Docker via Woodpecker CI (.woodpecker.yml). Pushing to main builds and deploys the prod image; pushing to staging builds and deploys the staging image.

Docker image

The Dockerfile produces a self-contained image with Nginx, PHP-FPM, and Supervisor. Runtime configuration is injected via environment variables:

Variable Description
DRUPAL_ENV prod or staging — controls config split activation
DB_HOST MariaDB hostname
DB_NAME Database name
DB_USER Database user
DB_PASSWORD Database password
DRUPAL_HASH_SALT Drupal hash salt
TRUSTED_HOSTS Trusted host regex (e.g. ^sintlukasbasisschool\\.be$)

Generating a hash salt

openssl rand -base64 55

Store the result as a Woodpecker secret (SLB_PROD_HASH_SALT / SLB_STAGING_HASH_SALT).

Woodpecker secrets

The following secrets must be configured in the Woodpecker repository settings:

  • SLB_PROD_DB_NAME, SLB_PROD_DB_USER, SLB_PROD_DB_PASSWORD, SLB_PROD_HASH_SALT
  • SLB_STAGING_DB_NAME, SLB_STAGING_DB_USER, SLB_STAGING_DB_PASSWORD, SLB_STAGING_HASH_SALT

Trusted hosts

The TRUSTED_HOSTS env var is passed to Drupal's trusted_host_patterns setting. It must be a valid PHP regex anchored with ^ and $, with dots escaped as \\.:

  • Production: ^sintlukasbasisschool\\.be$
  • Staging: ^staging\\.sintlukasbasisschool\\.be$

Environment management

Settings files

Each environment loads a different settings file:

Environment Loads Notes
Local DDEV web/sites/default/settings.php → settings.ddev.php → settings.local.php All gitignored
Staging / Prod docker/settings.docker.php (copied to settings.php in the image) Reads env vars
  • settings.php — Drupal's stock file, gitignored, generated by DDEV.
  • settings.ddev.php — DDEV-managed local DB credentials and Mailpit config.
  • settings.local.php — local-only dev overrides (cache off, no aggregation, verbose errors, stage_file_proxy origin, activates both config splits). Never deployed.
  • settings.docker.php — runtime config for staging/prod. Reads DB creds and DRUPAL_ENV from container env vars. Activates the non_prod split when DRUPAL_ENV != prod.

The Dockerfile copies settings.docker.php over settings.php at build time, so dev settings never reach the cloud.

Config sync

All exported Drupal config lives in config/sync/ (in the repo root, outside the webroot). The Docker image and local DDEV both point there:

  • Local DDEV: settings.local.php sets $settings['config_sync_directory'] = $app_root . '/../config/sync'
  • Docker: settings.docker.php sets it to /var/www/html/config/sync

Export → commit → deploy flow:

ddev drush cex -y               # export DB config to config/sync/
git add config/sync/ && git commit && git push   # to staging, then merge to main

Woodpecker runs drush cim -y on every deploy.

Config splits (per-environment modules)

The config_split module manages modules that should only be enabled in some environments. Two splits exist:

Split Modules Active on
local browsersync, yaml_editor local only
non_prod stage_file_proxy local + staging

Activation:

  • Local: settings.local.php sets status = TRUE on both splits.
  • Staging: settings.docker.php activates non_prod based on DRUPAL_ENV=staging (set in docker-compose.staging.yml).
  • Prod: neither split active.

When a split is active, drush cex removes its modules from the main core.extension.yml, keeping prod config clean. drush cim on each environment then enables/disables modules according to which splits are active.

Adding a module to a split:

ddev drush config-set config_split.config_split.local module.MY_MODULE 0 -y
ddev drush cex -y
git add config/sync/ && git commit

Database sync from prod

Files are pulled on-demand via Stage File Proxy (no local copy needed). The database is pulled manually:

  1. Export DB from prod via phpMyAdmin (use gzip compression) or drush sql:dump on the server.
  2. Save to .backup/prod-db.sql (or .sql.gz) — gitignored.
  3. Run:
    ddev pull-prod-db
    
    This drops the local DB, imports the dump, runs drush updatedb and drush cr.

For staging DB syncs, copy the dump to the server and pipe into the container:

scp .backup/prod-db.sql.gz user@server:/tmp/
ssh user@server
gunzip -c /tmp/prod-db.sql.gz | docker exec -i slb-drupal-staging sh -c \
  'mysql -h mariadb -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME"'
docker exec slb-drupal-staging drush updatedb -y
docker exec slb-drupal-staging drush cim -y
docker exec slb-drupal-staging drush cr

Content management

Bulk calendar import (Feeds)

The feeds module is installed to allow bulk importing of gebeurtenis (event) nodes from a CSV file via the Drupal admin UI.

First-time setup (run once after a fresh install or database restore):

  1. Go to /nl/admin/structure/feeds → Add feed type

  2. Configure:

    • Label: Gebeurtenis import
    • Fetcher: Upload form
    • Parser: CSV
    • Processor: Node — Content type: Gebeurtenis
  3. Under Mapping, add:

    CSV column Drupal target Note
    title Title ✓ Mark as unique key
    start Datum en tijd → Start Format: Y-m-d H:i or Y-m-d
    end Datum en tijd → End Same format
    description Beschrijving
  4. Save, then export config: ddev drush cex -y

Annual import workflow (for the school admin):

  1. Prepare a CSV file — one row per event occurrence:
    title,start,end,description
    Herfstvakantie,2026-10-27,2026-10-31,
    Oudercontacten,2026-11-12 18:00,2026-11-12 20:00,Info avond klassen 1 en 6
    Zwemmen klas 1,2026-10-07 14:00,2026-10-07 15:00,
    Zwemmen klas 1,2026-10-14 14:00,2026-10-14 15:00,
    
  2. Go to /nl/admin/content/feed → Add feed → choose Gebeurtenis import
  3. Upload the CSV → click Import
  4. Re-importing the same file updates existing events (matched by title) instead of creating duplicates

Note: recurring events with multiple sessions (e.g. Zwemmen) should be flattened to one row per session in the CSV. Truly multi-date single nodes (e.g. a week-long holiday) can be entered manually via the smartdate recurring UI.

Tech stack

  • CMS: Drupal 11
  • Base theme: Bootstrap 5 (bootstrap5)
  • Custom subtheme: b5_slb
  • Admin theme: Gin
  • Local environment: DDEV (Nginx, PHP 8.3, MariaDB 10.11)
  • Build tools: Gulp, Sass (embedded), PostCSS, BrowserSync
  • Dependency management: Composer, Drush