Online documentation and public showcase
The documentation and showcase are independent static sites. Both use Docker Bake and non-root NGINX behind Coolify’s Traefik proxy, following Publica Negotia’s Docker jobs, Harbor publication, Bake configuration, and service restart conventions. The documentation uses the existing Ātrium icon and canonical repository Markdown. The demo packages the production showcase and its demonstration adapters.
Sites and environments
| GitLab environment | Public URL | Required source |
|---|---|---|
playground/documentation | https://atrium-documentation.playground.agon-partners-innovation.ch | Verified protected-branch commit, including unreleased work. |
production/documentation | https://atrium-documentation.agon-partners-innovation.ch | Stable GitLab release and its verified immutable image digest. |
playground/demo | https://atrium.playground.agon-partners-innovation.ch | Verified protected-branch commit, including unreleased work. |
production/demo | https://atrium.agon-partners-innovation.ch | Stable GitLab release and its verified immutable image digest. |
These are deployment destinations. Creating the configuration does not provision DNS, Coolify resources, credentials, or public sites. Playground and production must use separate Coolify resources. The demo’s fixture sessions and API simulations are demonstrations, not production authentication.
The showcase’s final Documentation sidebar group links to the production documentation site. The documentation sidebar ends with a Live demo link to the production showcase, also shown at the top of its home page. Both remain ordinary external links during local previews. Their destinations require the hosted sites, and local browser checks use substituted responses instead of contacting those destinations.
Author documentation
Keep maintained prose in its existing location. docs/publication/registry.json explicitly classifies maintained Markdown as a guide, a linked reference page, or excluded content. Each guide and reference record selects a source path and stable route. Section and record order define navigation. Root and package READMEs and the changelog have dedicated destinations. The references list gives linked agent guidance, skills, and verification records local reading pages without adding them to the main navigation or search. Explicit reference records take precedence over broad exclusion patterns. Unreferenced audits, ledgers, and CI internals remain excluded.
The root README badge block is discarded during collection. Its repository source remains intact. The collector reads Markdown syntax, so example code is preserved. It rewrites both relative links and full GitLab source URLs for this repository to the published document, source viewer, or local media destination. Branch and revision URLs resolve against the current documentation build, preserving heading fragments. Directory links use a published README when available. This lets package READMEs keep their standalone repository URLs while their published copies stay within the documentation site. Every repository reference must have a local destination. Collection fails for unregistered references, and final artifact verification rejects any link to the repository host. There is no GitLab fallback. Missing references, symlinks, unsupported URL schemes, and executable raw HTML are rejected. Remote images from other sites become text, avoiding third-party runtime requests.
The registry also explicitly lists the approved sourceFiles. Referenced HTML, JavaScript, JSON, Python, and text files in that list are captured from the build checkout, once per file. Their links open a local dialog with syntax highlighting, copy, and download controls. Modified clicks and browsers without JavaScript open the same highlighted source as a regular local page. The build generates highlighting, so reading code needs no GitLab access or external runtime service. Source pages remain outside documentation search. Raw downloads preserve the original bytes and use .txt URLs so HTML examples are served as text. Add a reviewed source path to sourceFiles when introducing a new example link. The sourceDirectories list selects folders to bundle with local indexes under /files/. Indexes include maintained files and child folders from Git’s inventory, excluding ignored caches and build output. Code uses the existing source viewer, and media links serve bundled assets. Unsupported files, symlinks, missing files, and empty folder inventories fail the build. Approve a new file, reference document, or directory in the registry when introducing its link.
docs/publication/metadata.json records source fingerprints and stable heading IDs. After reviewing a documentation edit or a new registry entry, run:
yarn docs:refreshyarn docs:buildReview the metadata diff together with the prose. Ordinary builds refuse stale metadata instead of silently approving it. Existing heading keys preserve their approved IDs. When renaming a heading, retain its old id in the corresponding refreshed metadata record if inbound links must survive. Do not change published routes casually. Rendered internal links, local assets, and fragment targets are checked after Astro rendering.
English is the only published locale because it is the only complete maintained documentation set. Add real reviewed translations before enabling another locale. No current published document contains Mermaid. Mermaid fences fail clearly until a reviewed local static renderer, accessible alternatives, and light/dark checks are added.
The English UI overrides live in src/documentation/src/content/i18n/en.json. Keep this collection populated so Starlight can load the site’s navigation label and fall back to its built-in English messages. The maintained src/documentation/src/pages/404.astro renders the missing-page response and return link. Starlight’s generated 404 route is disabled because that page is supplied explicitly, avoiding a lookup for an absent docs collection entry.
Build and preview
Use the root’s supported Node range, pinned Yarn version, and immutable installation from setup. The private src/documentation/ workspace owns Astro/Starlight and never enters the four distributable packages. Its dependencies use exact stable versions. The optional Astro compiler WASI binding needs the two exact @emnapi dependencies recorded in .yarnrc.yml because its published dependency metadata omits them.
yarn docs:buildyarn docs:previewOpen the documentation preview. Stop it with Ctrl+C. When Astro detects an agent and starts preview in the background, stop that owned server with yarn workspace @agon/atrium-documentation astro preview stop. Preview serves the latest promoted build. It does not apply NGINX headers. For production acceptance, use the container tests below.
yarn docs:verifyyarn sites:prepareyarn sites:imagesyarn sites:testdocs:verify builds two independent candidates and requires identical artifact inventories and bytes. Candidates stay under .build/documentation/work/ for diagnosis. Only successful candidates replace .build/documentation/release/. Failed qualification preserves the previous complete release. The showcase receives the same revision-bound treatment under .build/showcase/release/. Build artifacts record the Git revision, so qualify the final committed revision again in CI before delivery.
Each artifact includes its site/ tree, source revision, per-file SHA-256 inventory, checksum file, and generated security headers. Documentation validates a 1.2 MB page budget, a 1.5 MB JavaScript-file budget, and a 150 MB total budget. Source maps, package archives, and dependency trees are forbidden in static output. Documentation programs are extracted to local files, and Pagefind’s local WebAssembly search uses the narrow wasm-unsafe-eval permission. Both sites exclude inline scripts and JavaScript unsafe-eval. Their current styles require style-src 'unsafe-inline'.
The search build uses Pagefind’s Node API to retrieve complete files in memory and await every filesystem write before closing the native process. This avoids the empty output files observed with the default write-and-close sequence during reproducibility checks. Empty or unsafe search output fails qualification.
Runtime package inventory comes from emitted browser chunks plus copied Pagefind resources. The checked-in docs/publication/THIRD_PARTY_NOTICES.txt contains full upstream license and notice text. Builds verify it against installed packages and publish it at /legal/THIRD_PARTY_NOTICES.txt, alongside /legal/documentation.cdx.json, a CycloneDX dependency graph distinguishing redistributed runtime packages from build dependencies. After an intentional documentation dependency update, run yarn docs:legal, review the notice diff, then run yarn docs:verify. The exact Pagefind UI license fallback is checked against the matching Pagefind version and license.
sites:images verifies both artifact inventories before calling resources/infrastructure/.docker/docker-bake.hcl. Its named artifact contexts and small infrastructure context exclude developer files and credentials. The local command explicitly overrides Bake with Docker-only output, the native platform, disabled attestations, and the tags agon-atrium-documentation:local and agon-atrium-demo:local. No registry write occurs. The shared Bake file defaults to the sibling’s Docker and registry outputs, so use yarn sites:images for a local build. A direct Bake invocation without these overrides publishes to Harbor. Images run as UID/GID 101, listen on 8080, and support a read-only filesystem with writable /tmp. sites:test starts temporary containers on loopback ports 4180 and 4181, then stops them. Reports and screenshots remain under .reports/sites/.
NGINX serves /healthz and /revision.json, compresses text, caches hashed assets immutably, and serves documents without stale-cache assumptions. Documentation has true 404 responses. The demo supports extensionless application route refresh while missing assets and /api/ requests stay 404. PDF workers use the correct .mjs MIME type. PDF and media byte-range requests remain available.
CI artifact and image chain
The CI guide owns the complete pipeline. Jobs follow the sibling stage-based includes: preparation in prepare.gitlab-ci.yml, browser checks in test.gitlab-ci.yml, Docker image jobs in build.gitlab-ci.yml, release downloads in publish.gitlab-ci.yml, and manual environments in deploy.gitlab-ci.yml. Shared runtime and delivery rules stay in base.gitlab-ci.yml. prepare:sites requires the application build, qualifies documentation twice, and prepares the showcase artifact. test:sites:browser tests those exact files with production headers in an ordinary container. build:docker:images:verify independently builds and smoke-tests both NGINX images. Image publication requires these checks and the independent four-package consumer gate.
Hosted build:docker:images:sites can run on protected-branch push and GitLab UI pipelines. Like publica-negotia, it uses .base:docker:login, creates a Docker-container builder, and calls docker buildx bake directly. The Docker jobs use the runner’s existing Docker, Buildx, and Compose tools. They declare no Node image, Yarn installation, downloaded Docker client, or Docker-in-Docker service. Builders and verification containers use job-specific names and are removed after execution. Configure Harbor trust and network access on the runner and its Docker daemon.
resources/infrastructure/.docker/docker-bake.hcl owns image names, tags, outputs, platforms, and OCI metadata. It uses the sibling’s GitLab and Harbor variables, project-title expression, shared base target, and site targets. Images are ${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAME}-documentation and ${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAME}-demo. Each receives its commit SHA tag and a branch tag outside main. The base declares linux/amd64 and linux/arm64, while hosted jobs explicitly select linux/amd64, matching the sibling’s infrastructure. SBOM and SLSA v1 maximum provenance attestations are enabled on main and explicitly disabled elsewhere. Source, revision, creation date, author, vendor, license, version, title, and description metadata follow the sibling’s OCI conventions, using the packages’ LicenseRef-LICENSE declaration. Annotations target image manifests so the same metadata also works with single-platform local exports.
The publication job retains native Bake metadata in .build/images/bake.json together with both qualified artifact.json files. Release and deployment helpers read those artifacts, require both commit-tagged image names and matching site revisions and versions, and derive immutable digest references. Release downloads retain the resulting images.json. Deployment always uses a digest. No Node helper performs Docker login, image building, or image publication.
Local CI allows prepare:sites and test:sites:browser through yarn ci:local sites. yarn ci:local full runs the site and package-consumer graph together so shared prerequisites execute once. Local site browser jobs use a static fixture server because ordinary verification containers have no Docker daemon. Run yarn sites:images && yarn sites:test on the workstation to exercise actual NGINX. Hosted release, publication, tagging, upload, and deployment jobs are never local verification commands.
Configure GitLab and Coolify
Create four Coolify Docker Compose services. Use resources/infrastructure/.deploy/documentation/continuum.yml for each documentation environment and resources/infrastructure/.deploy/demo/continuum.yml for each demo environment. Keep the selected ATRIUM_IMAGE value as a complete immutable reference from images.json. Grant Coolify read access to the Harbor repositories. The Compose files deliberately expose container port 8080 without publishing host ports. Configure each service’s approved hostname, route Traefik to port 8080, and let Coolify manage TLS. Point the four DNS records at the appropriate ingress.
Configure the following GitLab settings without committing their values:
| Variable | Scope and meaning |
|---|---|
HARBOR_HOST | Registry hostname supplied by the GitLab Harbor integration. Bake defaults to hub.agon-partners-innovation.ch outside CI. |
HARBOR_URL | Registry login URL supplied by the Harbor integration, as in publica-negotia. |
HARBOR_PROJECT | Harbor integration project containing both image repositories. Bake defaults to CI_PROJECT_NAME outside CI. |
HARBOR_USERNAME, HARBOR_PASSWORD | Harbor integration credentials with push access. Protect and mask manually configured equivalents. |
CONTINUUM_API_URL | HTTPS Coolify API base, including its API prefix, such as https://coolify.example/api/v1. |
CONTINUUM_API_TOKEN | Protected masked Coolify token authorized to update and restart the selected services. Prefer environment-scoped values. |
CONTINUUM_PLAYGROUND_DOCUMENTATION_UUID | Coolify service UUID for playground/documentation. |
CONTINUUM_PRODUCTION_DOCUMENTATION_UUID | Coolify service UUID for production/documentation. |
CONTINUUM_PLAYGROUND_DEMO_UUID | Coolify service UUID for playground/demo. |
CONTINUUM_PRODUCTION_DEMO_UUID | Coolify service UUID for production/demo. |
Deployment jobs are absent until their corresponding UUID is configured. Keep the non-secret UUID selection variables visible during pipeline creation, as in publica-negotia. Scope the API token to its environment. Each deployment job maps its UUID to the sibling-compatible CONTINUUM_SERVICE_UUID contract. Protect the production GitLab environments and restrict deployment access to the appropriate operators. Protect release branches and version tags as described in CI setup. The current-project CI_JOB_TOKEN supplies GitLab release and registry access. Confirm the project’s job-token permissions allow the Generic Package Registry and Release Links API.
The manual jobs deploy:playground:documentation, deploy:playground:demo, deploy:production:documentation, and deploy:production:demo are independent and locked per Coolify service UUID. Each validates its environment name, hostname, service UUID, source revision, and immutable image reference before changing Coolify. The helper updates only ATRIUM_IMAGE, then restarts the service with pulling enabled using the sibling’s service API contract. It polls health and revision identity for at most 60 bounded attempts. An API-accepted restart alone is not deployment success.
Release downloads and production
The existing manual release:creation gate remains on protected-main release candidates. After it succeeds, npm publication retains its existing restrictions. publish:release:assets requires successful npm publication, verified archives, qualified site artifacts, and published image evidence. It stores nine durable files in the current project’s Generic Package Registry under atrium-release/<version>:
- The exact tested core, publisher, starter, and showcase
.tgzarchives. - Documentation and demo
.tar.gzstatic distributions with their source and integrity metadata. images.jsonwith both immutable registry references and supported platforms.release-manifest.jsonwith revision, version, image references, artifact URLs, sizes, and SHA-512 digests.SHA512SUMScovering the other eight downloads.
Release-page links point to those durable files rather than expiring CI job artifacts. Identical upload retries reuse matching bytes and links. Conflicting bytes or link destinations fail before writes. The Generic Package Registry and Harbor retention policies must preserve released artifacts. Their access permissions govern whether anonymous visitors can download release assets.
Both production jobs require the successful release-asset job. At execution time they independently query the actual stable GitLab release, verify its commit, require the attached release manifest, and compare the selected image with the release’s digest. A version-shaped tag, a manual job, or an unreleased image does not satisfy production eligibility. Playground skips the release requirement while retaining verification and immutable image checks.
Rollback and operational checks
For a deliberate rollback, retry the appropriate deployment job in the prior successfully verified pipeline while its image evidence remains available. This selects the previous digest without rebuilding. Production rechecks that older pipeline’s stable release and attached manifest. Bake metadata and both site identities are retained for one year in CI. Release downloads retain the derived image evidence durably. If required CI artifacts have expired, use a separately reviewed recovery procedure based on the durable released digest and manifest instead of overriding the helper’s revision guards. Never rebuild a release under the same version to manufacture rollback evidence.
After platform setup, verify each public /healthz, /revision.json, a documentation deep link, a demo deep link, PDF rendering, and a real missing-asset response. Confirm served revision and version match the selected release or playground pipeline. Local passing tests do not prove hosted credentials, DNS, TLS, runner privileges, Harbor permissions, or compatibility with a particular installed Coolify version. The first hosted run is the acceptance check for that external configuration.
Author
Laurent Declercq l.declercq@agon-innovation.ch
Version
Version: 20260921