Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 0 additions & 152 deletions .github/workflows/docs.yml

This file was deleted.

66 changes: 33 additions & 33 deletions apps/docs-site/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

The QAuth documentation site (Astro + Starlight), published at
[docs.qauth.dev](https://docs.qauth.dev). Source lives here; deployment is
handled by `.github/workflows/docs.yml` at the repo root.
handled by Netlify's own git-based continuous deployment, configured in
`netlify.toml` at the repo root.

## Local development

Expand Down Expand Up @@ -60,38 +61,37 @@ so a guard failure blocks the deploy — it does not publish a broken site.

## Deployment

`.github/workflows/docs.yml`:

- **Pull requests** get a Netlify **preview deploy** (draft, with its own
URL, printed in the job log).
- **Pushes to `main`** get a **production deploy**.
- A `workflow_dispatch` run is available as a manual escape hatch — useful
after a change the path filter doesn't watch (e.g. a root dependency bump
in `package.json`/`pnpm-lock.yaml`), since it isn't a change under
`apps/docs-site/**`, `docs/adr/**`, or `docs/security/**`.

Both triggers run the same steps: install, `nx test docs-site`,
`nx build docs-site`, then upload `dist/apps/docs-site` with the Netlify CLI
(`netlify deploy` / `netlify deploy --prod`). The workflow builds the site
itself in GitHub Actions (using this repo's normal pnpm/Nx setup and cache)
and uploads the prebuilt output — it does not rely on Netlify's own
git-connected build servers.

This requires two repository secrets, **currently unset**:

- `NETLIFY_AUTH_TOKEN` — a personal or CI access token
(Netlify dashboard → User settings → Applications → Personal access
tokens).
- `NETLIFY_SITE_ID` — the target site's Project ID (Netlify dashboard →
Site configuration → General → Project ID).

If a Netlify site doesn't exist yet for this project, create one (a manual
`netlify init --manual` or `netlify deploy` from a one-off local build is
enough — Git-based continuous deployment is not needed here, since this
workflow uploads a prebuilt artifact instead) and copy its Project ID
into `NETLIFY_SITE_ID`. Without both secrets set, the workflow fails
immediately with a named "missing secret" error rather than silently
skipping the deploy.
Netlify's own git-connected build, configured by `netlify.toml` at the repo
root. Netlify clones the repository, installs the pnpm workspace, runs
`pnpm exec nx build docs-site`, and publishes `dist/apps/docs-site`. Pushes to
`main` produce a production deploy and pull requests produce a deploy preview,
both on Netlify's side — no repository secrets and no GitHub Actions step are
involved.

There used to be one: `.github/workflows/docs.yml` built the site in Actions and
uploaded the prebuilt output through the Netlify CLI, which needed a
`NETLIFY_AUTH_TOKEN` and a `NETLIFY_SITE_ID`. It was removed in favour of
Netlify's own CD. The site's checks did not go with it — `ci.yml` runs
`nx affected -t lint typecheck test build`, which covers `docs-site` (its drift
invariants included) whenever the diff touches it or anything it reads.

Two settings in `netlify.toml` are load-bearing, and both are documented at the
lines that set them:

- **`PNPM_VERSION`.** The root `package.json` declares
`engines.pnpm: ">=11.0.0"` but pins the exact version only inside each
workflow's `pnpm/action-setup` input, so an external builder has nothing to
read it from. Unset, Netlify activates its bundled pnpm and the install fails
with `ERR_PNPM_UNSUPPORTED_ENGINE` before anything is built. Keep it in step
with `.github/workflows/*.yml`.
- **`publish`.** `dist/apps/docs-site`, not `apps/docs-site/dist` — see
[Build](#build) for why `outDir` points at the workspace root. A publish path
aimed at Astro's default location deploys an empty directory and reports
success.

Because `netlify.toml` overrides the equivalent fields in the Netlify UI, the
build is reproducible from the repository rather than from dashboard settings
nobody can review.

## DNS and TLS for docs.qauth.dev

Expand Down
52 changes: 52 additions & 0 deletions netlify.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Netlify build configuration for docs.qauth.dev (#347).
#
# Deployment is Netlify's OWN git-based continuous deployment. There is
# deliberately no GitHub Actions deploy workflow: `.github/workflows/docs.yml`
# built the site and pushed a prebuilt artifact through the Netlify CLI, and it
# was deleted when this file landed. The site's lint/typecheck/test/build
# coverage did not go with it — `ci.yml` runs `nx affected -t lint typecheck
# test build`, which picks up `docs-site` whenever the diff touches it or
# anything it reads.
#
# Settings here OVERRIDE the equivalents in the Netlify UI, which is the point:
# the build is reproducible from the repository rather than from a dashboard
# nobody can review.

[build]
# The repository root. This is a pnpm WORKSPACE — the lockfile and the
# packages `docs-site` depends on live here, so the install has to happen at
# the root. Pointing `base` at `apps/docs-site` would leave Netlify installing
# from a package with no lockfile of its own.
base = "."

command = "pnpm exec nx build docs-site"

# `dist/apps/docs-site`, NOT `apps/docs-site/dist`.
#
# `astro.config.mjs` redirects `outDir` to the workspace-level output so it
# matches the Nx `build` target's declared `outputs` — a declared output that
# does not match reality breaks Nx caching silently. Astro's default location
# is therefore empty, and a publish path pointing at it deploys nothing while
# reporting success.
publish = "dist/apps/docs-site"

[build.environment]
# Pinned to what the root `package.json` demands (`engines.pnpm: ">=11.0.0"`)
# and to what every workflow in `.github/workflows/` installs.
#
# Without this the build image activates its own bundled pnpm — 10.30.3 at the
# time of writing — and the install dies with ERR_PNPM_UNSUPPORTED_ENGINE
# before a single file is built. The repo pins the version in each workflow's
# `pnpm/action-setup` input rather than in a `packageManager` field, so an
# external builder has nothing to read it from; this is that pin for Netlify.
# Keep it in step with `.github/workflows/*.yml`.
PNPM_VERSION = "11.4.0"

# `engines.node` is `>=24.7.0`. Naming the major lets Netlify take the current
# 24.x rather than freezing a patch release nobody will remember to bump.
NODE_VERSION = "24"

# No Nx daemon in an ephemeral builder: it exists to keep a project graph warm
# across repeated invocations, and there is exactly one here. Left on, it also
# spawns a background process that can outlive the build.
NX_DAEMON = "false"