This session completed Approach C end-to-end on marcelle (status=COMPLETED,
mkdocs untouched, idempotent on re-run). Four fixes landed:
1. template-engine.ts: dropped nginx/conf.d/*.hbs (default, api, services)
from renderAllTemplates AND renderAllTemplatesInMemory. The new
prod-style docker-compose.yml.hbs does NOT mount conf.d/ into the
nginx container ("Note: conf.d is NOT mounted (configs are generated
at startup from templates)" — nginx confs are baked into the nginx
Docker image). Writing them was a no-op orphan that showed up as 3
"modified" lines in preview unnecessarily.
Same reason removed nginx/nginx.conf from staticFiles.
2. templates/configs/{pangolin/resources.yml,prometheus/prometheus.yml,
grafana/datasources/datasources.yml}.hbs: synced byte-identical to
canonical changemaker.lite/configs/*. These ARE mounted into pangolin
tunnel + prometheus + grafana respectively. Preview now reports
"unchanged" for them on install.sh tenants.
3. templates/docker-compose.yml.hbs: dropped the CCP-tenant header
comment, making the template now BYTE-IDENTICAL (58907 bytes) to
canonical changemaker.lite/docker-compose.prod.yml. Even a 1-byte
comment difference caused docker compose to compute new config hashes
for every service, triggering full-stack recreates (including
ccp-agent — the Phase 6 self-destruct trap from upgrade.sh).
4. upgrade.service.ts:runReleaseUpgrade — composeUp now restricted to
core app services [api, admin, media-api, nginx] (same set as
image-upgrade.sh). Unscoped composeUp would recreate ccp-agent
mid-apply and orphan the runner. Until Approach C inherits the
deferred-ccp-agent-restart pattern from upgrade.sh, this restriction
keeps the apply path safe. Limitation: brand-new services in a
release won't auto-deploy via Approach C alone — operator must
follow with Approach A (full upgrade.sh) to pick them up.
E2E verification on marcelle:
- Apply: status=COMPLETED, duration<10s.
- mkdocs.yml md5 unchanged (38810d9df8b4258ad46a6739232cf88a).
- mkdocs/docs file count unchanged (242).
- docker-compose.yml now byte-identical to canonical (58907 bytes).
- app + api public sites: 200 both.
- Re-preview: ALL 10 files show "unchanged" — true idempotency.
Phase 6 acceptance gate met. Approach C now fully operational on the
install.sh fleet.
Bunker Admin
Closes 12 template drift gaps between the Control Panel templates and
production configs. New instances now provision with full monitoring
(alerts fire properly), correct Gitea DB type (postgres not mysql),
social sharing previews (OG meta bot routes), Excalidraw subdomain
routing, docker-socket-proxy for Homepage, and complete Grafana/
Alertmanager/Prometheus config copying.
Key changes:
- Rewrite Prometheus template: add alerting, rule_files, 5 scrape jobs
- Add cAdvisor, node-exporter, redis-exporter, gotify, docker-socket-proxy
- Fix Gitea env from mysql to postgres to match docker-compose
- Add OG bot detection + rewrite routes for campaigns/pages/gallery
- Add Excalidraw nginx server block + Pangolin draw subdomain
- Add embed port to discovery portConfig + emailTestMode to registration
- Copy alerts.yml, alertmanager.yml, Grafana dashboards to templates
- Add Listmonk proxy port and upgrade volume to API service
Bunker Admin