Files
KNELContracts/docs/branch-previews.md
T
tsgstaff-coo-svpknel 2bd0eea138
lint / markdownlint (blocking) (pull_request) Canceled after 0s
lint / typos spell-check (blocking) (pull_request) Canceled after 0s
lint / vale prose (advisory) (pull_request) Canceled after 0s
lint / lychee link-check (advisory) (pull_request) Canceled after 0s
v0.1: Grav-only repo + CI lint + branch-preview architecture
Pipeline fully retired: src/, contract-inputs/, service-csv/ deleted;
their content is fully superseded by grav/user/pages (verified section
by section). New: gitea actions lint workflow (markdownlint + typos
blocking, vale prose + lychee links advisory), lint configs, README
documents the branch/PR model, docs/branch-previews.md is the LAMP +
wildcard + Git Sync runbook for <branch>.contract.knownelement.com.
Blocking checks verified green before push (pinned containers).

Ticket: https://projects.knownelement.com/issues/924
2026-09-09 12:46:07 -05:00

3.1 KiB

Branch preview sites — <branch>.contract.knownelement.com

Goal: every branch of this repo gets a browsable Grav rendering of the contract at https://<branch>.contract.knownelement.com, with https://contract.knownelement.com serving the release branch. Reviewers get a URL instead of a diff.

Architecture

One Cloudron LAMP app with a wildcard alias:

  • App location: contract.knownelement.com
  • Wildcard alias: *.contract.knownelement.com (Cloudron provisions the wildcard Let's Encrypt certificate via DNS-01)
  • Apache maps the Host header to a per-branch docroot under /app/data/branches/<host>/ (mass virtual hosting via mod_rewrite)
  • The root docroot /app/data/public/ serves the release site

Each branch site is a complete, standalone Grav install whose user/pages and user/themes come from the repo branch via the Grav Git Sync plugin:

  • Per-site Git Sync config: same repository, per-site branch
  • Auto-pull on a cron schedule (every 5 minutes is plenty); gitea webhooks can replace cron later
  • Theme config (including e-sign endpoints) lives in the repo, so branch sites inherit the right e-sign wiring automatically

Branch name → hostname

Branch names are not DNS-safe in general, so the mapping is mechanical: lowercase, every run of characters outside [a-z0-9-] becomes -. Examples: feature/grav-native-cifeature-grav-native-ci; v0.1v0-1. The wildcard covers every mapping — no per-branch DNS or certificate work.

Provisioning a new branch site (one-time per branch)

  1. composer create-project getgrav/grav /app/data/branches/<host>
  2. Copy user/pages and user/themes/knel-contract from the branch checkout into the new install
  3. Install + configure the Git Sync plugin (repository URL, the branch, cron pull)
  4. Reload Apache — the rewrite rule picks the site up by Host header

Deprovisioning is the reverse: delete the site directory when the branch is deleted. Provisioning/deprovisioning is agent work (docker exec into the LAMP app container is a permitted access path); the procedure is scriptable and should be automated in CI once proven by hand.

Migration runbook (production change — GLPI CR required first)

  1. File the GLPI CR + Uptime Kuma maintenance window (evening, low traffic)
  2. Back up the current Grav app (app id 757c60ba) appdata off-box
  3. Uninstall the Grav app; install the LAMP app at the same location and add the *.contract.knownelement.com wildcard alias
  4. Restore the Grav content as the release site in /app/data/public/ (full Grav install; Git Sync → release branch)
  5. Lay down the Apache branch-rewrite config in /app/data/apache-app.conf
  6. Smoke test: home/services/terms/sign/execution all 200 on the root host; e-sign flow still POSTs through apigw.knownelement.com/contract-sign (unchanged — endpoints are in the theme config); provision one test branch site and confirm <host>.contract.knownelement.com serves that branch
  7. Post verification evidence on the CR and the Redmine ticket

Rollback: reinstall the Grav app at the same location from the backup taken in step 2.