diff --git a/.planning/phases/15-journal-plugin/15-CONTEXT.md b/.planning/phases/15-journal-plugin/15-CONTEXT.md
new file mode 100644
index 0000000..8d78421
--- /dev/null
+++ b/.planning/phases/15-journal-plugin/15-CONTEXT.md
@@ -0,0 +1,166 @@
+# Phase 15: Journal plugin - Context
+
+**Gathered:** 2026-10-06
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+The 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`.
+
+
+
+
+## Implementation Decisions
+
+### PHP source of truth
+- **D-01:** The port contract is `github.com/golem15com/wn-journal-plugin` at git SHA `02110eb` (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 newer `master`. — **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/v1` request/response shapes. Same bar as the user plugin port.
+- **D-05:** PHPUnit under `tests/` (security access/XSS/mass-assignment plus `PostRedactor`) 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.Translate` inside Phase 15. Insert `sm-translate-plugin` as its own roadmap phase **before** Phase 15 (`$gsd-phase` after 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 `$translatable` attributes 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.go` this 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-posts` commands 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/v1` surface this phase: anonymous GET `posts`, `posts/{slug}`, `categories`, `tags`, `rss`; backend-authenticated POST/PUT/DELETE posts, featured-image and media upload. Shapes follow `API.md` and `routes.php` in 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-plugin` `user.api_token` (wrong identity) and they do **not** fold Apparatus `PersonalApiToken` / `g15_` tokens (still `.planning/todos/pending/backend-admin-api-tokens.md`). — **Reversibility:** costly — clients that later expect `g15_` tokens would need a second guard.
+- **D-16:** Proof is `API.md` plus 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-api` and `journal-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 not `fonoteka.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/v1` answers. 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 of `summercms.go`, same as `fonoteka.go` and `sm-summercmsio-app`).
+- **D-21:** The app mounts `sm-journal-plugin`, `sm-translate-plugin` and `sm-user-plugin` (submodules at `plugins/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.git` already exists and is public. Module path `git.golem15.com/golem15/sm-journal-plugin`, package `journal`, plugin ID `golem15.journal`.
+- **D-23:** Local plugin checkout: `/media/nvme/dev/golem15/summercms.io/summercms/sm-journal-plugin/` (sibling of `summercms.go`). The host mounts it as a submodule at `plugins/golem15/journal` with a `go.work` replace, same as `sm-user-plugin` in `fonoteka.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 committed `dist/` 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) inside `sm-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 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--plugin` layout, 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's `config_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` — Apparatus `PersonalApiToken` stays 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 events
+- `routes.php` — public and token-auth `/_journal/api/v1` groups, limiter names
+- `API.md` — request/response contract for the JSON API
+- `UPGRADE.md` — breaking-change notes already in this pin
+- `README.md` — feature list and Winter components (components are Phase 16)
+- `models/Post.php`, `Category.php`, `Tag.php`, `Settings.php`, `PostImport.php`, `PostExport.php`
+- `controllers/Posts.php`, `Categories.php`, `Tags.php`, `controllers/api/`
+- `controllers/posts/config_filter.yaml` and sibling YAML under `controllers/` and `models/`
+- `console/ExportPosts.php`, `console/ImportPosts.php`
+- `formwidgets/JournalMarkdown.php`, `MLJournalMarkdown.php`
+- `tests/security/`, `tests/unit/models/PostRedactorTest.php`
+- `assets/images/journal-icon.svg`
+- `lang/en/`, `lang/pl/`
+
+### Go references
+- `../fonoteka.go/plugins/golem15/user/` (`sm-user-plugin`) — mount pattern, `plugin.go`, admin controllers, README
+- `modules/cabana/` — list/form/filter schema, field registry; markdown field lands here
+- `modules/pact/capabilities.go` — `HasAdminControllers`, permissions, navigation
+- `docs/backend/admin-controllers.md`, `docs/backend/forms.md`, `docs/backend/lists-and-filters.md`
+- `docs/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, empty
+- `git@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 of `02110eb`
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `sm-user-plugin` (`../fonoteka.go/plugins/golem15/user/`): compiled plugin `init`, `summer.yaml` listing, submodule + `go.work` replace, `pact.HasAdminControllers`, permission codes, phrasebook `en`/`pl`, README that never names a consuming application.
+- cabana: list, form, filters (`switch`, `daterange`, model scopes — Journal's `config_filter.yaml` was 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_typesense` hook (D-12).
+- Phase 9 backend Bearer guard: Journal write API (D-15).
+- `docs/examples/blog`: scaffold layout only. Do not treat it as `Golem15.Journal`.
+
+### Established Patterns
+- Shared core plugins live in `git.golem15.com/golem15/sm--plugin`, package name plain (`journal`), plugin ID `golem15.journal`, mounted at `plugins/golem15/journal`.
+- Unknown YAML keys and unregistered actions fail boot. Writes use `requireAjax` under the backend guard with `RequiredPermissions`.
+- Framework changes update module README, `docs/`, admin OpenAPI, generated TS types and committed `boardwalk` `dist/` 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 vet` and `go 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.work` requiring framework (local replace to `../summercms.go`), submodules for journal, translate and user.
+- `summercms.go` `modules/cabana` + admin SPA: markdown field type (D-11).
+- Translate plugin (future phase before this one): Journal `Requires` it; translatable attributes (D-10).
+- Phase 16 consumes the API and admin; it does not redefine them.
+
+
+
+
+## Specific Ideas
+
+- "We'll start fast" — use the empty `sm-grzybyfunkcjonalne-app` repo as the proof that Journal is migrated, rather than a disposable testhost.
+- Both remotes already exist: `sm-journal-plugin` (public) and `sm-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_token` was considered for Journal writes and rejected after clarifying it is not Apparatus `PersonalApiToken`.
+
+
+
+
+## Deferred Ideas
+
+- Insert `sm-translate-plugin` as 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_`) — todo `backend-admin-api-tokens.md`.
+- Remaining 19 PHP locales beyond `en` and `pl`.
+- 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*
diff --git a/.planning/phases/15-journal-plugin/15-DISCUSSION-LOG.md b/.planning/phases/15-journal-plugin/15-DISCUSSION-LOG.md
new file mode 100644
index 0000000..60e978d
--- /dev/null
+++ b/.planning/phases/15-journal-plugin/15-DISCUSSION-LOG.md
@@ -0,0 +1,78 @@
+# Phase 15: Journal plugin - Discussion Log
+
+> **Audit trail only.** Do not use as input to planning, research, or execution agents.
+> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
+
+**Date:** 2026-10-06
+**Phase:** 15-journal-plugin
+**Areas discussed:** PHP source of truth, what ships this phase, public HTTP, where it boots
+
+---
+
+## PHP source of truth
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Fonoteka's pin `02110eb` | Newest master; API, tags, search, security fixes | ✓ |
+| grzybyfunkcjonalne.pl pin `2ad25e0` | What the first blog runs today; no API/tags | |
+| GitHub master at plan time | Moving target | |
+
+**User's choice:** Fonoteka's pin, then freeze at `02110eb`, read from the Fonoteka path on disk.
+**Notes:** All three checkouts are `github.com/golem15com/wn-journal-plugin`. Binding surface is the full tree (models, YAML, permissions, commands, API shapes). PHPUnit tests are a behavioral spec. Locales `en`+`pl`. PHP is read-only this phase, but an urgent pre-migration PHP upgrade is allowed and forces a re-pin. Embed the admin SVG.
+
+---
+
+## What ships this phase
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Single-locale now | No translate plugin | |
+| Minimal translate seam in this phase | Extra scope | |
+| Insert `sm-translate-plugin` before Journal | New phase, not extra Journal scope | ✓ |
+
+**User's choice:** Insert translate as its own phase before 15. Journal then depends on it so fields stay translatable.
+**Notes:** Cabana markdown field this phase (not textarea). Typesense setting off by default, wired to Phase 11 when enabled. Import/export CLI+admin in; Pages menu items and report widget deferred.
+
+---
+
+## Public HTTP
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Full `/_journal/api/v1` | Public reads + writes | ✓ |
+| Public reads only | Writes later | |
+| No public HTTP | Admin+models only | |
+
+**User's choice:** Full API. Writes use Phase 9 backend Bearer.
+**Notes:** User first thought `sm-user-plugin` tokens were Apparatus admin tokens. Clarified: frontend `user.api_token` exists; backend `PersonalApiToken` / `g15_` is still a todo. User then confirmed backend Bearer. Proof is API.md + mapped PHPUnit tests, not tide. Same 120/min buckets and `_journal/api/*` CORS.
+
+---
+
+## Where it boots
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| In-module testhost | No new app | (superseded) |
+| `sm-journal-dev-app` | Disposable host | |
+| Mount in an existing app | fonoteka / summercms.io | |
+| `sm-grzybyfunkcjonalne-app` | Empty repo, proof host | ✓ |
+
+**User's choice:** "we'll start fast" — `git@git.golem15.com:golem15/sm-grzybyfunkcjonalne-app.git` is the proof that Journal is migrated.
+**Notes:** Phase 15 proves mount, migrate, admin, API. Site HTML/views stay Phase 16. Local app at `summercms/sm-grzybyfunkcjonalne-app/`. Mounts journal + translate + user. Journal remote already created and public. Checkout-location question was skipped; sibling of `summercms.go` used as default. Testhost-deps question was skipped, then superseded by the grzyby app decision.
+
+---
+
+## Claude's Discretion
+
+- Markdown field identifiers and docs/OpenAPI/`dist/` bundling
+- Plan count and split (unit tests last; plan-count checkpoint)
+- Exact `sm-grzybyfunkcjonalne-app` wiring files
+- How Winter components are pointed at Phase 16
+- Security-review agent (plugin API + public HTTP + permissions)
+- Local `sm-journal-plugin` checkout path (skipped question → sibling of `summercms.go`)
+
+## Deferred Ideas
+
+- Insert `sm-translate-plugin` before Phase 15
+- Phase 16 site/views
+- Pages menu item types, report widget, sitemap plugin, `g15_` admin tokens, extra locales, WYSIWYG/redactor