|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Hugo documentation website for Cozystack (Kubernetes-based cloud platform) using the Google Docsy theme. **Production is served by GitHub Pages** — Netlify is only used for deploy previews on PRs. Do not rely on Netlify-specific features (`netlify.toml` redirects, headers, edge functions) for production behavior; they only work in deploy previews. For redirects, use Hugo aliases (per-page) or the JS fallback in `layouts/404.html`. |
| 8 | + |
| 9 | +## Build & Development Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Install dependencies |
| 13 | +npm install |
| 14 | + |
| 15 | +# Local dev server (serves at http://localhost:1313/docs; wipes public/ first) |
| 16 | +make serve |
| 17 | + |
| 18 | +# Production build |
| 19 | +./hack/download_openapi.sh && hugo --gc --minify |
| 20 | + |
| 21 | +# Sync app docs from cozystack/cozystack repo. |
| 22 | +# By default targets content/en/docs/next/ (the version-agnostic trunk). |
| 23 | +# With RELEASE_TAG, routing depends on whether the minor version is already released: |
| 24 | +# - patch of an existing released version → updates that vX.Y/ in place |
| 25 | +# - otherwise → updates next/ (upcoming release) |
| 26 | +make update-all # update trunk from upstream main |
| 27 | +make update-all RELEASE_TAG=v1.2.5 # patch release → updates v1.2/ |
| 28 | +make update-all RELEASE_TAG=v1.3.0 # v1.3 not yet released → still updates next/ |
| 29 | +make update-apps # application docs only (also: update-vms, update-networking, update-k8s, update-services) |
| 30 | +make update-oss-health # OSS health metrics (requires Python 3.12+) |
| 31 | + |
| 32 | +# Scaffold front-matter-only stubs into DEST/_include (scaffolding variant of update-*, via hack/fill_templates.sh) |
| 33 | +make template-all # or template-apps / template-vms / template-networking / template-k8s / template-services |
| 34 | + |
| 35 | +# Version lifecycle (requires yq v4+) |
| 36 | +make init-next # (re)create content/en/docs/next/ from latest released version |
| 37 | +make release-next RELEASE_TAG=v1.3.0 # promote next/ → v1.3/, register in hugo.yaml |
| 38 | + |
| 39 | +# Initialize a new docs version directory directly (edge cases / manual backfills) |
| 40 | +make init-version DOC_VERSION=v1.3 |
| 41 | + |
| 42 | +# Override the app list for any update-*/template-* target |
| 43 | +make update-apps APPS="tenant redis" |
| 44 | + |
| 45 | +# Debug routing |
| 46 | +make show-target RELEASE_TAG=v1.3.0 # prints the resolved DOC_VERSION/BRANCH |
| 47 | +``` |
| 48 | + |
| 49 | +Required tools: Hugo extended v0.160.1, Go 1.23+, Node 20+, yq v4+ (for version lifecycle targets). |
| 50 | + |
| 51 | +## Architecture |
| 52 | + |
| 53 | +- **Hugo modules** (not git submodules): Docsy theme v0.12.0 pulled via `go.mod` |
| 54 | +- **Versioned docs**: `content/en/docs/v0/`, `content/en/docs/v1.0/`, `content/en/docs/v1.1/`, `content/en/docs/v1.2/` plus the permanent trunk `content/en/docs/next/`. Version switching handled by `layouts/partials/version-switcher.html` (honours the `hidden: true` flag on version entries). Version derived from RELEASE_TAG (e.g., v1.2.1 → v1.2) |
| 55 | +- **Content sync scripts**: `hack/update_apps.sh` fetches READMEs from the upstream cozystack repo and appends autogenerated notices. Driven by the `make update-*` targets (manual) |
| 56 | +- **OpenAPI specs**: v0/v1.0 api.json stored in git; v1.1+ downloaded at build time from GitHub releases via `hack/download_openapi.sh` |
| 57 | +- **OSS health pipeline**: `hack/update_oss_health.py` collects metrics from GitHub API, OpenSSF, DevStats, OSS Insight → writes JSON to `data/oss-health/` and `static/oss-health-data/`. Monthly GitHub Action |
| 58 | +- **Asset pipeline**: Bootstrap 5.3 + Font Awesome 6.7 mounted from node_modules via Hugo mounts (configured in `hugo.yaml`). SCSS entry point: `assets/scss/main.scss` |
| 59 | +- **Blog**: `content/en/blog/` with permalink pattern `:section/:year/:month/:slug/` |
| 60 | + |
| 61 | +## Versioning |
| 62 | + |
| 63 | +Docs are versioned per Cozystack minor release. Each version is an independent copy of the tree under `content/en/docs/<version>/` and is built into its own URL prefix (`/docs/<version>/`). |
| 64 | + |
| 65 | +**Directory layout** |
| 66 | +- One directory per minor version: `content/en/docs/v0/`, `v1.0/`, `v1.1/`, `v1.2/` |
| 67 | +- Version name derivation: major `0` → `v0` (legacy, covers all 0.x); major ≥ 1 → `v<major>.<minor>` (e.g., `v1.2`). Patch level is not reflected in the directory name |
| 68 | +- Each version directory is self-contained: all pages under `applications/`, `virtualization/`, `networking/`, `operations/`, `storage/`, `install/`, `guides/`, etc. live once per version |
| 69 | +- `content/en/docs/_index.md` is the single version-agnostic landing page |
| 70 | +- `content/en/docs/next/` is the permanent trunk for upcoming/unreleased docs. Internal links use `/docs/next/`; these are rewritten at release time by `hack/release_next.sh`. Excluded from production builds via the `hidden: true` entry in `hugo.yaml` and the content mount exclusion `- '! docs/next/**'` |
| 71 | + |
| 72 | +**Version registration (`hugo.yaml`)** |
| 73 | +- `params.latest_version_id` — id of the current/default version |
| 74 | +- `params.versions[]` — ordered list consumed by the version switcher (`layouts/partials/version-switcher.html`). Newest goes first, `order` highest. **When adding a new version, update both fields.** |
| 75 | +- `hidden: true` on a version entry hides it from the dropdown selector. Combined with the content mount exclusion pattern (`- '! docs/<id>/**'`), the whole version is also excluded from production builds. Used for the `next` trunk; the dev server and Netlify deploy previews still render it at `/docs/next/`. |
| 76 | + |
| 77 | +**Where to add changes** |
| 78 | +- Docs for an upcoming (unreleased) feature → edit `content/en/docs/next/`. These materialize as `v<next-release>/` when `make release-next RELEASE_TAG=vX.Y.Z` runs |
| 79 | +- Bug fix or addition to the current release → edit only `content/en/docs/<latest_version_id>/` (currently `v1.2`) |
| 80 | +- Content that also applies to older supported versions → copy the change into each relevant `v*/` directory (no automatic backport) |
| 81 | +- Cross-version/landing content → `content/en/docs/_index.md` |
| 82 | +- Blog posts are version-independent → `content/en/blog/` |
| 83 | + |
| 84 | +**Autogenerated files — do not edit in-place** |
| 85 | +- App/VM/networking/services pages synced from `cozystack/cozystack` have the footer `Autogenerated content. Don't edit this file directly; edit sources instead.` (injected by `hack/update_apps.sh`) |
| 86 | +- To change the body: edit the upstream README in `cozystack/cozystack` under `packages/apps/<app>/` (or `packages/extra/<svc>/` for services), then re-run the corresponding `make update-*` target |
| 87 | +- To change only front matter (title, weight, aliases) for a specific version: edit the stub at `content/en/docs/<version>/<section>/_include/<app>.md` — `update-*` merges this with the upstream README. `make template-*` scaffolds these stubs |
| 88 | + |
| 89 | +**RELEASE_TAG → routing (Makefile)** |
| 90 | + |
| 91 | +The Makefile routes updates between `next/` and released `vX.Y/` directories. Given a `RELEASE_TAG` like `v1.2.5` the minor version `v1.2` is derived; routing is: |
| 92 | + |
| 93 | +- `make update-all` (no tag) → `DOC_VERSION=next`, `BRANCH=main` |
| 94 | +- `make update-all RELEASE_TAG=v1.2.5` and `content/en/docs/v1.2/` exists and is a non-hidden entry in `hugo.yaml` → `DOC_VERSION=v1.2` (patch release, updates in place) |
| 95 | +- `make update-all RELEASE_TAG=v1.3.0` and `content/en/docs/v1.3/` does not yet exist → `DOC_VERSION=next` (still accumulating in the trunk) |
| 96 | +- `make release-next RELEASE_TAG=v1.3.0` copies `content/en/docs/next/` → `content/en/docs/v1.3/`, rewrites `/docs/next/` links, and registers `v1.3` via `hack/register_version.sh --release v1.3`. `next/` is unchanged |
| 97 | +- After `release-next`, subsequent `make update-all RELEASE_TAG=v1.3.1` routes to `v1.3/` |
| 98 | + |
| 99 | +**Releasing a new minor (`v1.3.0`)** |
| 100 | +1. `make release-next RELEASE_TAG=v1.3.0` — copies `next/` → `v1.3/`, rewrites internal links, registers `v1.3` as the new `latest_version_id`. `next/` stays in place for the next cycle |
| 101 | +2. (optional) `make update-all RELEASE_TAG=v1.3.0` — pulls fresh upstream READMEs pinned to the exact tag into `v1.3/` |
| 102 | + |
| 103 | +**Refreshing the trunk from the latest released version** |
| 104 | +- `make init-next` — removes `content/en/docs/next/` and reinitializes it from the latest `v*/` directory. `hack/init_version.sh` handles the `next/` case specially (sets title to "Cozystack Next (unreleased)", strips aliases, prepends a draft banner shortcode) |
| 105 | + |
| 106 | +**OpenAPI per version** |
| 107 | +- `v0` and `v1.0` ship their `api.json` in git under `static/docs/<version>/cozystack-api/api.json` |
| 108 | +- `v1.1+` are fetched at build time from `https://github.com/cozystack/cozystack/releases/download/<tag>/openapi.json` by `hack/download_openapi.sh` (run before `hugo --gc --minify`). `openapi.json` is produced as a release asset by the upstream tags workflow (cozystack/cozystack#2214) |
| 109 | + |
| 110 | +**How new-version docs arrive** |
| 111 | +- Docs updates are pushed by the upstream `cozystack/cozystack` release workflow (`.github/workflows/tags.yaml`, `update-website-docs` job). On every `vX.Y.Z` tag it checks out this repo at `main` and opens/updates a PR titled `[docs] Update managed apps reference for v<version>` |
| 112 | +- Upstream workflow contract: |
| 113 | + - Always calls `make update-all RELEASE_TAG=vX.Y.Z` — routing (above) picks the right target directory |
| 114 | + - Additionally calls `make release-next RELEASE_TAG=vX.Y.Z` for new minor/major releases (not patch releases). `release-next` validates preconditions and fails hard if they aren't met — there is no silent no-op. Detection of "new minor vs patch" is owned by the upstream workflow (explicit conditional), not by the website-side Makefile |
| 115 | +- The website-side `make update-*` / `make template-*` / `make release-next` / `make init-next` targets and `hack/update_apps.sh` / `hack/fill_templates.sh` / `hack/download_openapi.sh` / `hack/release_next.sh` are the contract this upstream workflow invokes |
| 116 | +- The previous website-side daily cron (`.github/workflows/update-managed-apps.yaml`) is obsolete (superseded by the upstream flow from cozystack/cozystack#2214) |
| 117 | + |
| 118 | +## Key Config |
| 119 | + |
| 120 | +- `hugo.yaml` — main Hugo config including module mounts, menus, params, multi-version setup |
| 121 | +- `netlify.toml` — Netlify build settings (deploy previews include `--buildFuture`) |
| 122 | +- `package.json` — npm deps (Bootstrap, Font Awesome, PostCSS/autoprefixer) |
| 123 | + |
| 124 | +## Custom Shortcodes |
| 125 | + |
| 126 | +Located in `layouts/shortcodes/`: `tabs`/`tab`, `note`, `warning`, `caution`, `include`, `youtube`, `system-resource-calculator`, `blocks/hero`, `blocks/resource`, `blocks/flux_ui_galleries`. |
| 127 | + |
| 128 | +## Content Conventions |
| 129 | + |
| 130 | +- Docs synced from upstream have autogenerated notices — don't manually edit those files; update the source in cozystack/cozystack instead |
| 131 | +- Hugo frontmatter uses YAML |
| 132 | +- OSS health app pages use custom layout (`layouts/_default/oss-health-app.html`) with frontmatter keys: `oss_health_key`, `oss_health_kind`, `lede`, `source_url` |
| 133 | +- Goldmark rendering has `unsafe: true` enabled (raw HTML allowed in markdown) |
0 commit comments