Files
summercms/CLAUDE.md

78 lines
7.7 KiB
Markdown

# 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 under `-short`; a `TestMain` that starts containers must call `flag.Parse()` and check `testing.Short()` (go test passes `-test.short=true`, so scanning `os.Args` for `-test.short` misses it). If the Docker socket is denied although the user is in the `docker` group, the shell session predates the group; run the tests through `sudo -u golem` to pick up a fresh group list. 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/<name>`. 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/<vendor>/<name>` (`.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`).