docs: initialize project
This commit is contained in:
142
.planning/PROJECT.md
Normal file
142
.planning/PROJECT.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# SummerCMS (Go)
|
||||
|
||||
## What This Is
|
||||
|
||||
SummerCMS is a Go rewrite of the WinterCMS/OctoberCMS content management framework for the Golem15 stack. It keeps what makes WinterCMS productive for us (plugins that extend each other, YAML-driven admin forms and lists, models/controllers/components, scaffolding commands, a headless API layer) and drops the parts that do not survive a compiled language (runtime plugin autoloading, PHP-style mutable magic). It is built by Golem15 developers and AI agents, for Golem15 projects that today run on the WinterCMS starter.
|
||||
|
||||
v1 is a headless backend that runs one real project, Płytarium (`fonoteka`), with its existing Nuxt 4 app and MCP server unchanged.
|
||||
|
||||
## Core Value
|
||||
|
||||
An existing WinterCMS-shaped app can be ported plugin by plugin to a single Go binary without its frontend noticing: the PHP version's API contract is the acceptance test.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Validated
|
||||
|
||||
(None yet — ship to validate)
|
||||
|
||||
### Active
|
||||
|
||||
Framework kernel
|
||||
|
||||
- [ ] A single `summer` binary boots an application from HOCON-style layered config (base + env overlays + plugin namespaces), the design carried over from summer-compass
|
||||
- [ ] Plugins are Go modules registered at build time through a generated import list; `summer make:plugin` scaffolds one and `summer build` rebuilds the binary; a dev watch loop rebuilds on change
|
||||
- [ ] Plugins declare models, migrations, routes, console commands, jobs, event listeners, admin controllers and navigation through one plugin descriptor, and can extend other plugins' models through ordinary Go interfaces and events
|
||||
- [ ] A typed in-process event bus lets plugins subscribe to each other's events
|
||||
- [ ] Console command framework with registration, dispatch and rich output (spinners, progress, tables, prompts), the design carried over from summer-bonfire; scaffolding commands for plugin, model, controller, migration, command, job
|
||||
- [ ] i18n with CLDR plurals and namespaced keys (`vendor.plugin::group.key`), pl and en, the design carried over from summer-phrasebook
|
||||
- [ ] YAML `rules:` validation mapped onto go-playground/validator with translated messages
|
||||
|
||||
Data layer
|
||||
|
||||
- [ ] GORM models with Eloquent-like flows on Postgres; per-plugin migrations runnable up and down, with a "drop the last migration and fix it" workflow
|
||||
- [ ] All 25 Płytarium models ported (Album, Artist, Collection, Genre, Style, AlbumRating, AlbumReservation, ApiToken, CollectionEditor, CollectionInvitation, CsvImport, CsvImportRow, Notification, OAuthAuthCode, OAuthClient, OAuthRefreshToken, OrgAiCredential, OrgDiscogsCredential, PendingInvitationRegistration, Settings, UserAiCredential, UserCollectionContext, UserDiscogsCredential, WishlistDigestQueue, WishlistSubscription) and its 27 migrations
|
||||
- [ ] Pagination, soft deletes, timestamps, relations (has-many, belongs-to, many-to-many) and JSON columns behave like the PHP originals for the API responses
|
||||
|
||||
HTTP and auth
|
||||
|
||||
- [ ] net/http ServeMux routing with middleware for auth, org context, locale and CORS; plugins register their routes
|
||||
- [ ] User plugin port: accounts, registration, login, password reset, JWT for the SPA, organizations and org-scoped permissions
|
||||
- [ ] OAuth2/OIDC provider (zitadel/oidc) that the MCP server and the ChatGPT connector use with the same flows as today (auth code + PKCE, refresh tokens, client management, `IssueOAuthClient` command)
|
||||
- [ ] All 154 Płytarium API routes ported with byte-compatible request and response shapes (collections, albums, artists, genres, styles, ratings, reservations, wishlist, sharing and invitations, notifications, realtime channel auth, CSV import/export, locale, user context, credentials)
|
||||
|
||||
Background and integrations
|
||||
|
||||
- [ ] Queued jobs on River (Postgres): CSV import and wishlist digest, plus the `PruneNotifications` and `ReindexAlbums` commands
|
||||
- [ ] Realtime notifications published to the existing Centrifugo server with the same channel names and token issuing, so the Nuxt client keeps working
|
||||
- [ ] Typesense indexing and search for albums with the same query semantics as the Scout-based PHP version
|
||||
- [ ] File uploads and cover images through gocloud.dev/blob with the same public URL shape
|
||||
- [ ] Discogs client and AI cover recognition (Anthropic and OpenAI) with per-user and per-org credentials
|
||||
- [ ] Feedback submissions and sitemap output as in the PHP stack plugins
|
||||
|
||||
Admin
|
||||
|
||||
- [ ] Backend admin users with roles, separate from frontend users, as in WinterCMS
|
||||
- [ ] `fields.yaml` and `columns.yaml` parsed into a JSON form and list schema served per controller, with the WinterCMS field types Płytarium uses (text, textarea, number, switch, dropdown, relation, repeater, fileupload, datepicker)
|
||||
- [ ] A minimal Vue 3 + TypeScript admin SPA that renders those schemas as lists and forms for the five Płytarium controllers (Albums, Artists, Collections, Genres, Styles), with types generated from the API's OpenAPI document
|
||||
|
||||
Quality
|
||||
|
||||
- [ ] `go vet` and `go test ./...` green at every commit; each phase ends with a unit-test plan bringing its code to full coverage
|
||||
- [ ] An API parity test suite replays the Nuxt app's and MCP server's requests against both backends and diffs responses
|
||||
- [ ] Definition of done: `vue-fonoteka-app` and `fonoteka-mcp` run unchanged against the Go backend, in daily use
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Server-rendered themes and components — second port target keios.eu (`.planning/seeds/keios-port-themes-payments.md`); Płytarium is headless
|
||||
- Payments (paymentgateway, pgstripe) — same second target
|
||||
- Chat, forum, video — wavepath.org territory, later
|
||||
- WASM sandboxed extension API — only after the compiled plugin API is stable for a full milestone (`.planning/seeds/wasm-extension-api.md`)
|
||||
- Runtime plugin loading (stdlib `plugin`, yaegi, RPC plugins) — rejected in `why-go-not-scala.md`; compiled plugins only
|
||||
- MySQL and multi-database support — Postgres only in v1; River needs it and one migration target keeps the port simple
|
||||
- Porting Illuminate module by module — the target app pulls what is needed; unneeded WinterCMS subsystems stay unported
|
||||
- "Improving" API response shapes during the port — parity is the acceptance test; improvements come after cutover
|
||||
- Porting the JVM/Scala modules as code — their designs carry over, their code does not
|
||||
|
||||
## Context
|
||||
|
||||
**History.** SummerCMS started in February 2026 as a Scala 3 rewrite (Tapir, Ox, Magnum, Jig). Three infrastructure modules shipped as sbt projects in the meta repo (`../modules/summer-compass`, `summer-phrasebook`, `summer-bonfire`) before the effort stalled: it was building Illuminate-shaped infrastructure bottom-up with no real app pulling requirements, and the deciding test (an OAuth2/OIDC server) found no reusable Scala library. Go passed the same test with zitadel/oidc. The decision is recorded in `.planning/notes/why-go-not-scala.md` and is not to be relitigated.
|
||||
|
||||
**Prior research.** `.planning/research/go-ecosystem.md` is a verified (2026-09-16, GitHub API) ecosystem report with picks per concern and a plugin-architecture comparison. It is the starting point for stack decisions; phase research should extend it, not redo it.
|
||||
|
||||
**Reference implementations.**
|
||||
|
||||
- WinterCMS starter (the Golem15 stack): `../examples/golem15-wintercms-starter`, with 19 Golem15 plugins as nested submodules and its own CLAUDE.md
|
||||
- Płytarium, the v1 target: `/media/nvme/dev/golem15/fonoteka`. Domain plugin at `plugins/golem15/fonoteka` (25 models, 5 admin controllers, 154 routes in `routes.php`, 27 migrations, 3 commands, 2 jobs, 143 test files, ~57k PHP lines). Nuxt app at `vue-fonoteka-app`, MCP server at `fonoteka-mcp`. Its own GSD history lives in `fonoteka/.planning/`, including `STARTER-LINEAGE.md`
|
||||
- Stack plugins Płytarium uses: user, backend, apparatus, golem (AI), translate, websockets (Centrifugo), userfriends, journal, feedback, sitemap
|
||||
- OAuth2 behavioral reference: `/media/nvme/dev/golem15/wavepath.org/plugins/golem15/oauthserver` (11k lines, tests, `INTEGRATING.md`)
|
||||
- Płytarium's environment today: Centrifugo for realtime (WS URL, API key, proxy secret), Typesense for search, a queue connection, SQLite as the config default with the real connection set in `.env`
|
||||
|
||||
**Design carry-overs from Scala.** Module names from `../IDEA_LIB_NAMES.md` (backpack, compass, festival, surf, lagoon, bouncer, lifeguard, cooler, conga, postcard, bonfire, sandcastle, phrasebook, sunset, party) become Go package names. Compass's config layering and plugin namespaces, phrasebook's CLDR plurals and namespaced keys, and bonfire's command registry and rich output are language-neutral designs to port.
|
||||
|
||||
**Go 1.27 notes.** Generic methods, json/v2-backed `encoding/json` (stricter: rejects duplicate keys and invalid UTF-8, relevant to YAML/JSON form definitions), stable iterators and ServeMux patterns. `plugin` package limitations unchanged.
|
||||
|
||||
**Who works on this.** Golem15 developers and AI agents using the GSD workflow. The repo's `CLAUDE.md` carries lean-mode rules that every phase must follow.
|
||||
|
||||
## Constraints
|
||||
|
||||
- **Tech stack**: Go 1.27, standard library first (net/http ServeMux, html/template, encoding/json); a dependency is added only when the research doc or a phase decision names it — keeps the binary boring and the dependency tree auditable
|
||||
- **Data**: GORM on Postgres only — chosen for Eloquent-like DX and a line-by-line model port; River needs Postgres
|
||||
- **Compatibility**: `vue-fonoteka-app` and `fonoteka-mcp` must run unchanged; the Nuxt app's requests define the contract and response shapes are not improved during the port
|
||||
- **Realtime**: keep the Centrifugo server and port only the publisher and token issuing — the Nuxt client connects to Centrifugo directly
|
||||
- **Plugins**: compiled at build time; no runtime plugin loading without a decision note
|
||||
- **Workflow**: lean planning (few, large plans per phase), a plan-count checkpoint before PLAN.md files are written, unit tests as the last plan of every phase, `go vet` and `go test ./...` green at every commit
|
||||
- **Commits**: no co-author tags; one logical change per commit; planning docs and code in separate commits
|
||||
- **Core plugin contracts**: the PHP user, blog, pages and payment plugins are shared across many projects; the Go ports must preserve their contracts and the PHP originals are not changed as part of this project
|
||||
|
||||
## Key Decisions
|
||||
|
||||
| Decision | Rationale | Outcome |
|
||||
|----------|-----------|---------|
|
||||
| Go instead of Scala 3 | Ecosystem depth: the OAuth2/OIDC test had a maintained Go answer (zitadel/oidc) and no Scala one; a CMS is glue over solved problems | ✓ Good (2026-09-16, `notes/why-go-not-scala.md`) |
|
||||
| v1 target is the Płytarium port | Headless, actively used, forces every ecosystem claim at once, three times the size of the `inventory` alternative but finishable | — Pending |
|
||||
| Compiled plugins, Caddy/xcaddy model | Full type safety, plugins extend each other through Go interfaces, `go test` works; rebuild cost is seconds | — Pending |
|
||||
| Headless first; admin is a schema-driven SPA | Płytarium needs no theme engine; PocketBase-style schema-driven admin is the best-fit reference | — Pending |
|
||||
| GORM over ent | Closest to Eloquent's mutable-model DX, simplest line-by-line port of 25 PHP models; ent's codegen deferred | — Pending (chosen at init, 2026-09-16) |
|
||||
| Postgres only for v1 | One migration target; River requires it; Płytarium cuts over as part of go-live | — Pending |
|
||||
| Minimal admin SPA in v1 | Five YAML-driven controllers are part of what Płytarium needs day to day; proves the fields.yaml to JSON schema pipeline | — Pending |
|
||||
| Keep Centrifugo, port the publisher | Nuxt client stays unchanged, which is the definition of done | — Pending |
|
||||
| Reuse IDEA_LIB_NAMES module names as Go packages | Continuity with the Scala work and its docs | — Pending |
|
||||
| WASM extension API deferred | Plugin surface too wide to marshal until the compiled API settles | — Pending (seed) |
|
||||
| Themes and payments deferred to keios.eu port | Smallest Golem15 project with both a Twig theme and a payment flow | — Pending (seed) |
|
||||
|
||||
## Evolution
|
||||
|
||||
This document evolves at phase transitions and milestone boundaries.
|
||||
|
||||
**After each phase transition** (via `/gsd-transition`):
|
||||
1. Requirements invalidated? → Move to Out of Scope with reason
|
||||
2. Requirements validated? → Move to Validated with phase reference
|
||||
3. New requirements emerged? → Add to Active
|
||||
4. Decisions to log? → Add to Key Decisions
|
||||
5. "What This Is" still accurate? → Update if drifted
|
||||
|
||||
**After each milestone** (via `/gsd:complete-milestone`):
|
||||
1. Full review of all sections
|
||||
2. Core Value check — still the right priority?
|
||||
3. Audit Out of Scope — reasons still valid?
|
||||
4. Update Context with current state
|
||||
|
||||
---
|
||||
*Last updated: 2026-09-16 after initialization*
|
||||
Reference in New Issue
Block a user