Replace the ansible container-run plus copy publish with a proper compose
build service deployed via the role's own stack. The one-shot writes the
npm mirror straight into the node-local served CDN root that openresty
reads, so there is no DiND bind-layer mismatch and no separate publish step.
- meta/volumes.yml: build mounts (served root rw, staged manifests ro,
build script as a docker config)
- templates/compose.yml.j2 + env.j2: one-shot build service (restart no,
swarm condition none), CDN_WEB_ROOT and ROLES_DIR from the mount targets
- meta/services.yml: placement manager, replicas 1, resources, deploy modes
- meta/networks.yml: local subnet (the role now ships a stack)
- meta/variants.yml: internal and external flavor variants
- meta/tests.yml + test.env.j2 + files/test/test.sh: flavor-branching e2e
- tasks: internal flavor deploys the stack via sys-stk-full; drop the
container-run and ansible-copy publish; remove the unused dev-git include
- vars: pin CDN_FLAVOR to the role id (scope-safe) and compute host paths
directly (avoid the volume-lookup double-template)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add lookup('asset', app, pkg, path) and lookup('asset_host'): both resolve
the asset origin through one shared resolve_host, returning the internal
CDN domain when web-svc-cdn is deployed with flavor internal and
cdn.jsdelivr.net otherwise, so template URLs and CSP origins can never
diverge. Versions come from the role's committed files/package-lock.json.
Roles declare frontend dependencies in files/package.json; web-svc-cdn
aggregates every role lockfile, runs one npm ci per role in a node
container and mirrors the packages under /npm/<pkg>@<version>/ following
jsdelivr's path scheme, so internal and external URLs differ only by host.
Convert web-app-dashboard (keycloak-js 24.0.5 UMD) and web-app-littlejs
(bootstrap, fontawesome) to the asset lookup, drop the vendored keycloak
blob, and add a repository lint forbidding hardcoded external CDN hosts
in templates and CSP metas; pre-existing external CDN entries are checked
out with nocheck markers and a migration TODO.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* scripts/lint/autoformat.sh:
- rename run_sort_claude_settings worker to run_claude (matches the
renamed scripts/lint/claude.sh).
- drop the EXIT trap that wiped status_dir; cleanup happens explicitly
after `wait` returns, so a parallel worker that interrupts the
parent never races a vanished status dir.
- each worker now captures its tool's exit code and writes one of
OK / SKIP / FAIL. Tolerated `expected violations remain`-style exits
(markdownlint-cli2 rc≤1, ansible-lint rc≤2) still count as OK; only
real failures count as FAIL.
- all workers run to completion regardless of individual tool failures
(so the user always sees the full picture); after the summary, the
script exits 1 if any worker reported FAIL.
* scripts/lint/sort_claude_settings.sh -> scripts/lint/claude.sh
(history preserved via git mv); update test_claude_settings_sorted.py
fix-hint accordingly.
Plus working-tree drift across roles/, group_vars/, inventories/,
requirements/, and .pre-commit-config.yaml accumulated from the
make-test setup phase regenerating generated artefacts during recent
test runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Unify reverse proxy handling across apps via sys-stk-front-proxy and cleanly separate internal docker nginx configs from external vhosts.
Changes:
- docker-compose: use with_first_found for optional env and docker-compose.override files so roles can provide either a template or a static file without noisy 'Could not find or access' failures.
- sys-stk-front-proxy: remove front_proxy_domain_conf_src and switch nginx vhost rendering to with_first_found over app-specific proxy.conf.j2 and the generic roles/sys-svc-proxy vhost flavour; keep health-check and handler logic unchanged.
- web-app-nextcloud: migrate to sys-stk-full-stateful (front proxy + DB + docker), move internal nginx config to docker.conf.j2 under the volume path, and rename host.conf.j2 to proxy.conf.j2 for the external vhost.
- web-app-magento: rename nginx.conf.j2 to docker.conf.j2 and update the runtime template task accordingly to make the intent (internal nginx) explicit.
- web-app-matrix: rename nginx.conf.j2 to synapse.conf.j2 and adjust the webserver task to use the new template name for the synapse vhost.
- web-app-bridgy-fed & web-app-flowise: pass domain and http_port explicitly when including sys-stk-front-proxy so the front stack has all required context.
- web-svc-cdn/file/html: replace direct sys-stk-front-base + sys-util-csp-cert + nginx.conf.j2 handling with sys-stk-front-proxy and proxy.conf.j2, relying on the shared front-stack for TLS/CSP/vHost wiring.
- web-svc-collabora: drop the direct nginx.conf.j2 vhost generation and rename it to proxy.conf.j2 so it is picked up by sys-stk-front-proxy like other services.
- web-opt-rdr-domains: rename redirect.domain.nginx.conf.j2 to redirect-domain.conf.j2 and adjust the task for clearer and more consistent naming.
Context: see ChatGPT refactor discussion on 2025-11-30 (proxy unification, Collabora/Nextcloud/CDN stacks, CSP/header handling): https://chatgpt.com/share/692c64ea-a488-800f-ad42-7f7692a3742f