Each policy now has exactly one copy: docs/PRIVACY.md in the app's own
repository. The pages keep their URLs and chrome and render that file
through a content collection, so the published page and the app's own
documentation cannot drift.
scripts/sync-external.mjs shallow-clones both repos into external/ from
prebuild and predev — not from CI: Coolify builds the site from the repo,
so a checkout that only ran in a Gitea job would never reach the deploy.
It falls back to the raw file if git is unavailable, and takes <APP>_REF
or <APP>_LOCAL for work against a branch or an unpushed working copy.
A missing, empty or malformed policy fails the build, verified against the
real image: the deploy stops rather than publishing an empty privacy page.
Personal site & blog for jeanlucmakiola.de.
- Astro 7 static output; self-hosted Inter + JetBrains Mono (Fontsource)
- Material 3 Expressive design tokens (red accent over neutral surfaces)
- Home (hero + about + selected work + latest writing)
- /work index + per-app pages (Calendula, Agendula, floret-kit) with
build-time Gitea release tags, brand-icon link rows, features grid,
and an at-a-glance facts panel
- Blog via Markdown content collection; RSS, sitemap, robots, OG/SEO
- Privacy-respecting Umami analytics, env-gated (off in dev)
- Dockerfile (build -> Caddy) + Caddyfile for Coolify deploy
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>