15 KiB
Phase 15: Journal plugin - Context
Gathered: 2026-10-06 Status: Ready for planning
## Phase BoundaryThe Golem15 Journal plugin is ported to Go as sm-journal-plugin and mounted in sm-grzybyfunkcjonalne-app the same way sm-user-plugin is mounted in a host application. A blog can run on SummerCMS without the PHP plugin: models, migrations, YAML-driven admin screens, permissions, import/export, and /_journal/api/v1 (public reads and backend-Bearer writes) match the frozen PHP tree.
The first real site (HTML, reusable blog views, live grzybyfunkcjonalne.pl pages) is Phase 16. This phase only has to prove the plugin mounts, migrates, the admin screens work, and the API answers.
summercms.go is touched only when a framework feature is missing. The one named framework addition is a cabana markdown field (and preview). Apparatus is already dissolved into the framework.
Out of scope: sm-translate-plugin itself (insert as its own phase before this one; Journal depends on it), Winter.Pages menu item types, the dashboard report widget, Apparatus backend personal API tokens (g15_), sitemap, and any edit to wn-journal-plugin.
PHP source of truth
- D-01: The port contract is
github.com/golem15com/wn-journal-pluginat git SHA02110eb(2026-08-27), the pin currently checked out in Płytarium. That tree is newer than grzybyfunkcjonalne.pl (2ad25e0) and the Winter starter (7237ed0); it includes tags,/_journal/api/v1, Typesense, and the security fixes. — Reversibility: costly — every model, table, YAML key and route in the Go plugin is copied from this tree. - D-02: Freeze at
02110eb. Planner and researcher must not silently pick a newermaster. — Reversibility: reversible — a later discussion can re-pin. - D-03: Downstream agents read the frozen source from
/media/nvme/dev/golem15/fonoteka/plugins/golem15/journal(already at that SHA). Do not clone a second copy unless that path is missing or the SHA does not match. - D-04: Binding from that tree: models, tables, YAML forms/lists/filters, permission codes, console commands, and
/_journal/api/v1request/response shapes. Same bar as the user plugin port. - D-05: PHPUnit under
tests/(security access/XSS/mass-assignment plusPostRedactor) is a behavioral spec. Researcher maps each test to a Go case; the phase's last plan covers them. - D-06: The Go plugin ships English and Polish phrasebook files only. The other 19 PHP locales stay in PHP until a later request.
- D-07: This phase does not edit or PR
wn-journal-plugin. An urgent PHP upgrade on a live Winter site before that site migrates is allowed as operations. If it lands before plan or execute, re-pin the SHA rather than mixing trees. - D-08: Embed the same admin nav SVG (
assets/images/journal-icon.svg) in the Go plugin.
What ships this phase
- D-09: Do not port
Golem15.Translateinside Phase 15. Insertsm-translate-pluginas its own roadmap phase before Phase 15 ($gsd-phaseafter this discussion). — Reversibility: one-way — Journal's translatable fields and Phase 16 blogs assume that plugin exists first. - D-10: Once that translate phase exists, Journal depends on it. Title, slug, content and the other PHP
$translatableattributes stay translatable, so Phase 16 blogs work. — Reversibility: costly — the storage shape and admin fields couple to the translate plugin's contract. - D-11: Add a cabana markdown field (and preview) in
summercms.gothis phase, the same "framework first" pattern as Phase 12.1. Journal's post content uses it instead of a textarea stub. — Reversibility: costly — a new field type in the typed admin schema and generated TS types. - D-12: Port
search_use_typesense, keep it off by default, and wire it to the Phase 11 search stack when enabled. A fresh install never contacts Typesense. — Reversibility: reversible — the setting and the hook can sit unused. - D-13: CSV import/export and the
journal:export-posts/journal:import-postscommands ship now (admin + CLI). Winter.Pages menu item types and the dashboard report widget are deferred (no pages plugin, no dashboard widgets in the admin SPA).
Public HTTP
- D-14: Ship the full
/_journal/api/v1surface this phase: anonymous GETposts,posts/{slug},categories,tags,rss; backend-authenticated POST/PUT/DELETE posts, featured-image and media upload. Shapes followAPI.mdandroutes.phpin the frozen tree. — Reversibility: one-way — Phase 16 views and any importer will call this contract. - D-15: Write routes authenticate with the Phase 9 backend Bearer guard (admin session). They do not use frontend
sm-user-pluginuser.api_token(wrong identity) and they do not fold ApparatusPersonalApiToken/g15_tokens (still.planning/todos/pending/backend-admin-api-tokens.md). — Reversibility: costly — clients that later expectg15_tokens would need a second guard. - D-16: Proof is
API.mdplus the mapped PHPUnit tests. Journal is not added to the Płytarium tide 154-route harness. - D-17: Keep PHP's two limiter buckets (
journal-public-apiandjournal-api, 120/min) and the CORS path_journal/api/*.
Where it boots
- D-18: The proof host is the empty repo
git@git.golem15.com:golem15/sm-grzybyfunkcjonalne-app.git(already created). Not an in-module testhost and notfonoteka.go/sm-summercmsio-app. — Reversibility: one-way — the Go module path and submodule layout land in that app. - D-19: Phase 15 proof on that host: Journal mounts, migrations run, admin screens work,
/_journal/api/v1answers. Live site HTML and reusable blog views stay Phase 16. - D-20: Local checkout:
/media/nvme/dev/golem15/summercms.io/summercms/sm-grzybyfunkcjonalne-app/(sibling ofsummercms.go, same asfonoteka.goandsm-summercmsio-app). - D-21: The app mounts
sm-journal-plugin,sm-translate-pluginandsm-user-plugin(submodules atplugins/golem15/{journal,translate,user}), following.planning/notes/core-plugins-own-repos.md. - D-22: The plugin remote
git@git.golem15.com:golem15/sm-journal-plugin.gitalready exists and is public. Module pathgit.golem15.com/golem15/sm-journal-plugin, packagejournal, plugin IDgolem15.journal. - D-23: Local plugin checkout:
/media/nvme/dev/golem15/summercms.io/summercms/sm-journal-plugin/(sibling ofsummercms.go). The host mounts it as a submodule atplugins/golem15/journalwith ago.workreplace, same assm-user-plugininfonoteka.go.
Claude's Discretion
- Markdown field YAML type name, Go identifiers and SPA registry keys, provided they follow existing cabana fail-loud rules and update the module README,
docs/, admin OpenAPI, generated TS types and committeddist/in the same change. - Plan count and split, subject to the plan-count checkpoint and "unit tests are the last plan". Framework markdown work may land in an early plan and be tagged if a framework version bump is needed.
- Exact app wiring (
summer.yaml,go.work, embed vs not) insidesm-grzybyfunkcjonalne-app, as long as D-18 to D-21 hold. - How Winter component pages (
journalPost,journalPosts, …) are documented as a Phase 16 successor — they are not implemented here. - Run the security-review agent: the phase touches the plugin API (
pact), authorization (golem15.journal.*, draft visibility) and public HTTP.
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Roadmap and prior decisions
.planning/ROADMAP.md§ Phase 15 — goal, repos, success criteria.planning/ROADMAP.md§ Phase 16 — site HTML and reusable views stay there.planning/PROJECT.md— core plugin contracts; PHP originals are not changed.planning/notes/core-plugins-own-repos.md—sm-<name>-pluginlayout, module path, submodule mount.planning/notes/apparatus-dissolved-into-framework.md— why Journal does not depend on an Apparatus plugin.planning/phases/12.1-user-plugin-admin-screens/12.1-CONTEXT.md— YAML admin screens, permissions, framework-first extras.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md— typed schema, filters (D-12 already used Journal'sconfig_filter.yaml), backend Bearer.planning/phases/11-jobs-realtime-and-search-infrastructure/11-CONTEXT.md— search stack Journal wires when Typesense is enabled.planning/todos/pending/backend-admin-api-tokens.md— ApparatusPersonalApiTokenstays deferred (D-15).planning/todos/pending/sitemap-plugin-port.md— sitemap is Phase 16 / its own plugin
PHP contract (read-only) — /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal at SHA 02110eb
Plugin.php— requires Translate + Apparatus, permissions, navigation, settings, Scout/Typesense guard, Pages menu eventsroutes.php— public and token-auth/_journal/api/v1groups, limiter namesAPI.md— request/response contract for the JSON APIUPGRADE.md— breaking-change notes already in this pinREADME.md— feature list and Winter components (components are Phase 16)models/Post.php,Category.php,Tag.php,Settings.php,PostImport.php,PostExport.phpcontrollers/Posts.php,Categories.php,Tags.php,controllers/api/controllers/posts/config_filter.yamland sibling YAML undercontrollers/andmodels/console/ExportPosts.php,console/ImportPosts.phpformwidgets/JournalMarkdown.php,MLJournalMarkdown.phptests/security/,tests/unit/models/PostRedactorTest.phpassets/images/journal-icon.svglang/en/,lang/pl/
Go references
../fonoteka.go/plugins/golem15/user/(sm-user-plugin) — mount pattern,plugin.go, admin controllers, READMEmodules/cabana/— list/form/filter schema, field registry; markdown field lands heremodules/pact/capabilities.go—HasAdminControllers, permissions, navigationdocs/backend/admin-controllers.md,docs/backend/forms.md,docs/backend/lists-and-filters.mddocs/examples/blog/— in-root toy blog only; not the Journal port and not the host../sm-summercmsio-app/— sibling host wiring precedent (go.work,summer.yaml, submodules)
New remotes (already created)
git@git.golem15.com:golem15/sm-journal-plugin.git— public, emptygit@git.golem15.com:golem15/sm-grzybyfunkcjonalne-app.git— empty proof host
First blog PHP site (Phase 16; do not port the theme here)
/media/nvme/dev/golem15/grzybyfunkcjonalne.pl— living Winter site; its Journal submodule is an older ancestor of02110eb
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
sm-user-plugin(../fonoteka.go/plugins/golem15/user/): compiled plugininit,summer.yamllisting, submodule +go.workreplace,pact.HasAdminControllers, permission codes, phrasebooken/pl, README that never names a consuming application.- cabana: list, form, filters (
switch,daterange, model scopes — Journal'sconfig_filter.yamlwas a Phase 9 reference),relation,fileupload,datepicker, bulk/record actions, preview, row state. No markdown field yet (D-11). - Phase 11 search / Typesense client: Journal's optional
search_use_typesensehook (D-12). - Phase 9 backend Bearer guard: Journal write API (D-15).
docs/examples/blog: scaffold layout only. Do not treat it asGolem15.Journal.
Established Patterns
- Shared core plugins live in
git.golem15.com/golem15/sm-<name>-plugin, package name plain (journal), plugin IDgolem15.journal, mounted atplugins/golem15/journal. - Unknown YAML keys and unregistered actions fail boot. Writes use
requireAjaxunder the backend guard withRequiredPermissions. - Framework changes update module README,
docs/, admin OpenAPI, generated TS types and committedboardwalkdist/in the same change. Neutral names only (acme,blog). - PHP originals are not changed. Shipped migrations are append-only. Unit tests are the last plan.
go vetandgo test ./...stay green in every repo this phase writes.
Integration Points
- New repo
sm-journal-plugin: models, updates, admin YAML,/_journal/api/v1, commands, lang, embedded icon. - New host
sm-grzybyfunkcjonalne-app:summer.yaml+go.workrequiring framework (local replace to../summercms.go), submodules for journal, translate and user. summercms.gomodules/cabana+ admin SPA: markdown field type (D-11).- Translate plugin (future phase before this one): Journal
Requiresit; translatable attributes (D-10). - Phase 16 consumes the API and admin; it does not redefine them.
</code_context>
## Specific Ideas- "We'll start fast" — use the empty
sm-grzybyfunkcjonalne-apprepo as the proof that Journal is migrated, rather than a disposable testhost. - Both remotes already exist:
sm-journal-plugin(public) andsm-grzybyfunkcjonalne-app. - Urgent PHP Journal upgrades on a live Winter site before migration are allowed; re-pin the SHA if that happens before we plan or execute.
- Frontend
user.api_tokenwas considered for Journal writes and rejected after clarifying it is not ApparatusPersonalApiToken.
- Insert
sm-translate-pluginas a new phase before Phase 15 ($gsd-phase). Journal will depend on it (D-09, D-10). - Phase 16: grzybyfunkcjonalne.pl HTML, reusable blog views, Winter component successors (
journalPost,journalPosts, RSS page, author/tags pages). - Winter.Pages menu item types (
journal-category,journal-post, …) until a pages plugin exists. - Admin dashboard report widget until the SPA has dashboard widgets.
- Apparatus backend personal API tokens (
g15_) — todobackend-admin-api-tokens.md. - Remaining 19 PHP locales beyond
enandpl. - WYSIWYG / redactor as a second editor mode, unless research shows the markdown field must cover PHP's switch this phase.
Reviewed Todos (not folded)
sitemap-plugin-port.md: next blog / Phase 16; user chose leave on backlog.2026-10-01-benchmark-the-application-on-wintercms-vs-summercms.md,nest-framework-packages-under-modules.md,bonfire-duplicate-command-names.md,lagoon-readme-after-commit-callback-order.md,mailblocker-with-mailing.md,per-module-readmes-after-nest.md,readme-go-fences-src.md,refresh-fonoteka-readme.md,rewrite-summercms-readme.md,scaffold-admin-controller-incomplete.md,scaffold-same-second-migration-order.md,wristband-neutral-resource-default.md,scaffold-generated-header-and-command-deps.md,backend-admin-api-tokens.md: keyword matches only, not this phase.
Phase: 15-journal-plugin Context gathered: 2026-10-06