Skip to content

ADR-0029: Deployment targets from a single repository

Context

This repository holds three things with different release cadences and different runtime requirements: the documentation site, the BOS Console, and the Ansible tree that provisions everything. "Deploy the repo" is not a coherent instruction — each has a different target, and one of them must be independent of the others by design.

Decision

1. Documentation → Cloudflare Pages, its own project

A single repository can back several Pages projects, each with its own build command, output directory and domain.

Setting Value
Project octopodia-abos-docs
Production branch main
Build command pip install mkdocs-material && mkdocs build
Output directory site
Domain docs.octopodia.com.au (ADR-0022)
Access Cloudflare Access, same identity policy as the Console

Branch pushes produce preview URLs, so a documentation change is reviewable rendered, not only as a diff.

2. The BOS Console → the VPS, deployed by Ansible

Not Cloudflare Pages. Pages serves static assets; the Console is an application that reads and writes the registry, and the registry is a container on the host with no public route (ADR-0025 §2). The Console therefore runs in the core stack, behind Caddy at console.octopodia.com.au, deployed by an Ansible run rather than by a git push.

Its frontend could in principle be served statically with the API on the box, but splitting one surface across two hosting models to save a container introduces a seam for no benefit.

3. Ansible → not deployed at all

infra/ is executed from a control machine (ADR-0024 §4). It is never pushed to a host and never built.

4. The docs site must not depend on the VPS

This is the constraint that makes the first two answers differ, and it is not negotiable: a runbook has to survive the outage it is used in (ADR-0028). Documentation is therefore hosted somewhere with no dependency on the infrastructure it documents. Moving the docs site onto the box "for consistency" would defeat its purpose.

5. Path filters on every deployment trigger

Three release cadences in one repository means a change to one must not deploy the others.

  • The docs build ignores changes outside docs/ and mkdocs.yml.
  • Console deployment ignores changes to docs/ and infra/.

Without this, an Ansible commit triggers a documentation rebuild — burning free-tier build minutes on no-op builds — and a documentation typo can redeploy the Console at an awkward moment.

Consequences

Each surface deploys on its own trigger and its own schedule, from one repository with one review path. Documentation stays readable when the host is down, which is when it is needed most. Console releases stay deliberate: an Ansible run, not a side effect of pushing a branch.

The cost is configuration in three places — two Pages/CI projects plus the Ansible tree — and path filters that must be maintained as directories move. A monorepo makes cross-cutting changes easy to review and easy to over-deploy; the filters are what keep that in check.

Alternatives considered

  • Everything on the VPS, including docs — rejected: the docs site would be unavailable during exactly the incidents its runbooks exist for.
  • Console on Cloudflare Pages with the API on the box — rejected: splits one surface across two hosting models and two deployment paths for no gain.
  • Separate repositories per surface — rejected: three review paths for changes that frequently cross boundaries (an ADR, its runbook, and the role implementing it are one logical change).
  • No path filters — rejected: every commit deploying everything is how an unrelated release goes out during an incident.