# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What this is SummerCMS in Go: a content management framework modelled on WinterCMS/OctoberCMS, for the Golem15 stack. An application built on it compiles into one binary: framework modules, the application's plugins, the embedded admin SPA and console commands. Read `README.md` first (module table, quick start, development commands), then `.planning/PROJECT.md` and `.planning/notes/` for decisions. The core value: a WinterCMS-shaped app is ported plugin by plugin to a single Go binary without its frontend noticing. When porting endpoints, the existing frontend's requests (Nuxt app, MCP server) define the contract; response shapes are not "improved" during a port. References: the WinterCMS starter at `../examples/golem15-wintercms-starter`, the first port target Płytarium at `/media/nvme/dev/golem15/fonoteka`. ## Commands ```sh go vet ./... go test -short ./... # fast loop, no Docker go test ./... # also the testcontainers Postgres/Mailpit tests (needs Docker) go test -short ./modules/cabana -run TestName # one test cd examples/hello && go test ./... # separate workspace module, not covered by the root ./... go install ./cmd/summer # the CLI go test ./cmd/summer -run TestDocsTree # docs checker summer docs:build --check # docs checker (identifiers, links, anchors, src= snippets, command names) summer docs:sync # refresh src= code copies in docs/ after changing their source npm --prefix admin ci npm --prefix admin run test | typecheck | build | dev scripts/check-admin-openapi.sh [--check] # swag annotations in cabana -> admin/openapi/admin.json -> admin/src/api/schema.d.ts scripts/check-admin-dist.sh # committed modules/boardwalk/dist must match a fresh admin build scripts/check-phaseN.sh # per-phase verification gates ``` Docker-backed tests skip themselves under `testing.Short()`. Keep `go vet` and `go test ./...` green at every commit. ## Architecture - **One Go module**, `git.golem15.com/golem15/summercms`; each package is imported as `.../modules/`. Module names follow a beach theme, and each README carries a `**Name:**` mnemonic; a new module gets a fitting beach name, a README in the standard structure and a row in the root `README.md` table. - **Compiled plugins.** A plugin implements capability interfaces from `pact` (routes, config, migrations, middleware, commands, admin screens, translations, mail, jobs). `summer build` reads the application's `summer.yaml`, generates `plugins.gen.go` and `main.go` (`internal/build`) and builds the binary. `party` orders plugins by `Requires()` and runs `Register(app)` then `Boot(app)`; `backpack.App` is the per-instance container (config, typed service registry via `app.Lookup[T]()`, event bus, activated plugins). No runtime plugin loading (stdlib `plugin`, yaegi) without a decision note. - **Request path.** `surf` assembles plugin routes and named middleware onto a stdlib `net/http` ServeMux; `bouncer` authenticates (JWT, and personal API tokens resolved via cabana); `towel` carries actor/locale through `context.Context`; `wire` keeps JSON byte-compatible with the PHP (Laravel) backend. - **Admin.** Plugins describe lists, forms, filters and relations in WinterCMS-style YAML (`columns.yaml`, `fields.yaml`). `cabana` compiles them at boot and serves a JSON admin API (swag-annotated, see `admin_openapi.go`); `boardwalk` embeds the Vue 3 SPA from `admin/`, whose build output is committed in `modules/boardwalk/dist`. Before tagging a release that changes `admin/`, rebuild, commit the dist and pass `check-admin-dist.sh` (`.planning/notes/2026-10-07-embedded-admin-release-gate.md`). - **Data.** `lagoon`: GORM on Postgres only, per-plugin gormigrate migrations, model helpers, attachments (`lagoon/attach`). `conga`: River jobs on the same pool plus the `summer_jobs` record. YAML is parsed with `goccy/go-yaml`, never `gopkg.in/yaml.v3` (archived). - **Dependencies.** Standard library first. A new dependency needs a research doc or a phase/decision note naming it (`.planning/research/STACK.md` has the decided set and versions). ## Sibling repositories The meta repo (`..`) holds the framework and its consumers side by side. Consumers `require` a tagged framework version (`vX.Y.Z` tags on `master`) and `replace` it with `../summercms.go` during development: - `fonoteka.go`: Płytarium application (go.work workspace; app-specific plugins stay in-repo). - `sm-*-app`: other applications (`sm-grzybyfunkcjonalne-app`, `sm-summercmsio-app`, `sm-bm-app`). - `sm-*-plugin`: shared core plugins in their own repos, module path = repo path, mounted in apps as git submodules at `plugins//` (`.planning/notes/core-plugins-own-repos.md`). Commit and push the plugin first, then the pointer bump in the app as a separate commit. - `vue-journal-layer`: public Nuxt layer consumed by site apps as a pnpm git dependency pinned by tag. Framework code never names a consuming application (READMEs, docs, examples use neutral names like `blog` or `acme`). ## Documentation rules - A change to a module's exported API, config keys, CLI commands or dependencies updates that module's `README.md` and the affected `docs/` pages in the same commit. - Module README structure: H1 name, one-sentence summary, import line, `**Name:**` mnemonic, then Overview, Features, Usage, API reference, optional Configuration and CLI commands, Dependencies, Testing. The root table's purpose text reuses the summary sentence. - Every identifier in a README or docs page must exist in the package (the docs checker enforces it). Config keys are not checked automatically; review them by hand. ## MSD workflow Work goes through MSD (`/msd-*` commands; the older GSD tooling is retired): `/msd-quick` for small tasks (`.planning/quick/`), `/msd-fast` for trivial edits, `/msd-debug`, and `/msd-discuss-phase` → `/msd-plan-phase` → `/msd-execute-phase` for roadmap phases (`.planning/ROADMAP.md`, `.planning/phases/`). Urgent work is inserted as decimal phases (`/msd-phase --insert`). Don't edit the repo outside an MSD workflow unless the user says so. Project rules that override MSD defaults: 1. **Lean planning.** Few, large plans per phase. Before writing PLAN.md files, present the suggested plan count with a one-line scope each and wait for confirmation. 2. **Unit tests are the last plan of every phase.** Earlier plans may carry smoke tests but are not blocked on coverage. 3. **State through handlers.** Update `.planning/STATE.md` with `msd_run query state.*` handlers, not raw edits. 4. **g15office sync.** Todos and phase milestone tasks are mirrored in g15office (`.planning/G15OFFICE.md`); post a short comment when a phase advances. ## Commits and concurrency - No co-author tags. One logical change per commit; planning docs and code in separate commits. - Several Claude sessions often work in this repo at once (different phases, quick tasks). Stage files explicitly by path (never `git add -A`), leave other sessions' uncommitted edits (often `STATE.md`, `state.json`) alone, and check for in-flight edits before touching shared files such as cabana. - Don't push, tag or deploy without the user's go-ahead; deploys are documented per application (for example `../sm-grzybyfunkcjonalne-app/DEPLOY.md`).