Files
summercms/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md
Jakub Zych bd0a27f59f docs(14.2.1): lock Go tables to golem15_translate_*
Execute-phase Task 2 chose golem15-prefix over the researched winter_translate_* names so the plugin ships vendor tables; PHP winter names stay a later import mapping.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 11:36:28 +02:00

143 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 14.2.1: Translate plugin - Context
**Gathered:** 2026-10-06
**Status:** Ready for planning
<domain>
## Phase Boundary
`Golem15.Translate` is ported to Go as `sm-translate-plugin` so Journal (Phase 15) and later blogs can keep translatable fields. This phase ships the lean core Journal needs: the Locale model and its admin screen, the TranslatableModel behavior, cabana ML field types, and PHP's request-locale resolution.
The proof host is `sm-grzybyfunkcjonalne-app`, booted with `sm-user-plugin` + `sm-translate-plugin` (Journal mounts in Phase 15). Proof: the app boots, Locales admin works, and a fixture model can save and read `en`+`pl` through ML fields and `WithLocale`.
`summercms.go` is touched for the ML field types (`mltext`, `mlmarkdown`) and any Translator/request-locale seam the plugin cannot own alone.
Out of scope: the Messages catalogue and `manage_messages` admin, locale-picker / hreflang / suggestion-banner CMS components, AI and theme console commands, message import/export, and any edit to `wn-translate-plugin`. Those wait for a later translate follow-up if a site needs them.
</domain>
<decisions>
## Implementation Decisions
### PHP source of truth
- **D-01:** The port contract is `github.com/golem15com/wn-translate-plugin` at git SHA `725d547` (2026-08-26), the pin currently checked out in Płytarium. That tree is newer than grzybyfunkcjonalne.pl (`6e0c146`). — **Reversibility:** costly — Locale tables, attribute storage and Translator behaviour are copied from this tree.
- **D-02:** Freeze at `725d547`. 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/translate` (already at that SHA). Do not clone a second copy unless that path is missing or the SHA does not match.
- **D-04:** This phase does not edit or PR `wn-translate-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.
### What ships this phase
- **D-05:** Lean only: Locale model + Locales admin (`golem15.translate.manage_locales`), and a TranslatableModel behavior Journal can implement. Messages catalogue, locale-picker components, AI/theme commands and message import/export are deferred. — **Reversibility:** reversible — later plans can add the rest without rewriting Locale.
- **D-06:** Cabana gains ML field types (`mltext`, `mlmarkdown`) matching PHP's `ml*` widgets, so a Journal form stays one screen with a locale switch. Phase 15's markdown field (15 D-11) and these ML types must compose (`mlmarkdown` is markdown plus locale). — **Reversibility:** costly — new field types in the typed admin schema and generated TS types.
- **D-07:** Port PHP `Translator` locale resolution: URL prefix / session / cookie / default. Do not reduce this phase to `Accept-Language` or a query param only. — **Reversibility:** costly — public blog URLs and the Journal API will depend on this order.
- **D-08:** The plugin seeds English and Polish locales, matching Journal 15 D-06.
### Model API
- **D-09:** A Go model declares translatable attributes with a `Translatable() []string` (or equivalent tagged list) the way PHP uses `$translatable`. Journal copies the PHP Post/Category lists. — **Reversibility:** costly — every translatable model in shared plugins will call this.
- **D-10:** Go storage tables are `golem15_translate_locales`, `golem15_translate_attributes`, `golem15_translate_indexes`, and `golem15_translate_messages`, with the PHP pin's columns and indexes. No JSON-column alternative. PHP at SHA `725d547` uses `winter_translate_*`; do not copy those names into Go DDL. Winter import needs a later mapping. Locked at execute-phase Task 2 (2026-10-06) as `golem15-prefix`. — **Reversibility:** one-way — Journal and every host migrate against these names.
- **D-11:** A missing translation falls back to the default locale, as PHP does.
- **D-12:** The exported API other plugins call this phase is the minimum: `WithLocale` on queries, get/set an attribute in a locale, and current locale from Translator. Do not 1:1 every PHP `TranslatableModel` / `Translator` method name unless research shows Journal needs it.
### Where it boots
- **D-13:** The host is `sm-grzybyfunkcjonalne-app` (same as Phase 15 D-18). This phase mounts `sm-user-plugin` + `sm-translate-plugin`; Journal is added in Phase 15. — **Reversibility:** one-way — submodule layout lands in that app.
- **D-14:** Local app checkout: `/media/nvme/dev/golem15/summercms.io/summercms/sm-grzybyfunkcjonalne-app/` (sibling of `summercms.go`).
- **D-15:** The public Gitea remote is `git@git.golem15.com:golem15/sm-translate-plugin.git` (created 2026-10-06). Module path `git.golem15.com/golem15/sm-translate-plugin`, package `translate`, plugin ID `golem15.translate`.
- **D-16:** Local plugin checkout: `/media/nvme/dev/golem15/summercms.io/summercms/sm-translate-plugin/` (sibling of `summercms.go`). The host mounts it as a submodule at `plugins/golem15/translate` with a `go.work` replace.
- **D-17:** Phase proof: the app boots with user+translate; Locales admin works; a fixture model can save and read `en`+`pl` through ML fields and `WithLocale`.
### Claude's Discretion
- Exact `golem15_translate_*` Go table names (D-10 execute lock); column/index shapes still come from the frozen PHP updates, not invented.
- ML field YAML type names and SPA locale-switcher chrome, provided they follow cabana fail-loud rules and update the module README, `docs/`, admin OpenAPI, generated TS types and committed `dist/` in the same change.
- How `mlmarkdown` shares implementation with Phase 15's markdown field (land the shared primitive here if Journal is otherwise blocked).
- Plan count and split, subject to the plan-count checkpoint and "unit tests are the last plan".
- Run the security-review agent: locale switching on public requests and admin ML writes are authorization-adjacent.
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Roadmap and prior decisions
- `.planning/ROADMAP.md` § Phase 14.2.1 — stub goal; this file is the real scope
- `.planning/ROADMAP.md` § Phase 15 — Journal depends on this plugin
- `.planning/phases/15-journal-plugin/15-CONTEXT.md` — D-09/D-10 (Journal requires translate; translatable title/slug/content), D-06 (`en`+`pl`), D-11 (markdown field), D-18–D-21 (grzyby host)
- `.planning/notes/core-plugins-own-repos.md` — `sm-<name>-plugin` layout, module path, submodule mount
- `.planning/phases/12.1-user-plugin-admin-screens/12.1-CONTEXT.md` — YAML admin screens, framework-first field types
- `.planning/phases/04-cli-scaffolding-i18n-and-mail/04-CONTEXT.md` — phrasebook; this plugin is model-level translation, not UI strings
- `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md` — typed schema, fail-loud YAML
### PHP contract (read-only) — `/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate` at SHA `725d547`
- `Plugin.php` — permissions (`manage_locales`, `manage_messages`), navigation, components (components are out of scope)
- `models/Locale.php`, `models/Attribute.php`, `models/Message.php` (Message is out of scope except as a table that must not be broken)
- `behaviors/` — TranslatableModel (or equivalent) and how `$translatable` is applied
- `classes/Translator.php` — URL prefix / session / cookie / default (D-07)
- `controllers/Locales.php` and YAML under `controllers/locales/`, `models/locale/`
- `formwidgets/` — PHP `ml*` widgets that D-06 replaces
- `updates/` — Locale / attributes / indexes table names and migration IDs (D-10)
- `README.md`, `UPGRADE.md`
- `tests/` — use as landmines; lean scope means not every PHP test maps 1:1
### Go references
- `../fonoteka.go/plugins/golem15/user/` — mount pattern for the sibling plugin
- `modules/cabana/` — field registry; `mltext` / `mlmarkdown` land here
- `modules/phrasebook/` — UI strings; do not conflate with model translations
- `docs/backend/forms.md`, `docs/backend/admin-controllers.md`
### Remotes
- `git@git.golem15.com:golem15/sm-translate-plugin.git` — public, created; local sibling checkout on `main`
- `git@git.golem15.com:golem15/sm-grzybyfunkcjonalne-app.git` — empty proof host, already created
- `git@git.golem15.com:golem15/sm-journal-plugin.git` — public, empty; mounted in Phase 15
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `sm-user-plugin` mount pattern: `summer.yaml`, submodule at `plugins/golem15/user`, `go.work` replace, `pact.HasAdminControllers`.
- cabana field registry (Phase 12.1 `permissioneditor`, Phase 12.2 `fileupload` / `datepicker`): the pattern for `mltext` / `mlmarkdown`.
- phrasebook `en`/`pl` for plugin UI strings — separate from Locale rows and attribute translations.
- `sm-grzybyfunkcjonalne-app` remote already exists; local directory may not.
### Established Patterns
- Shared plugins: module `git.golem15.com/golem15/sm-<name>-plugin`, package plain (`translate`), plugin ID `golem15.translate`.
- Unknown YAML keys fail boot. Framework field types update README, `docs/`, OpenAPI, TS types and `boardwalk` `dist/` in the same change.
- PHP originals are not changed. Migrations are append-only. Unit tests are the last plan.
### Integration Points
- New repo `sm-translate-plugin`: Locale model, updates, Locales admin, Translatable behavior, Translator.
- `summercms.go` cabana + admin SPA: `mltext`, `mlmarkdown`, locale switcher on forms.
- `sm-grzybyfunkcjonalne-app`: first mount of user + translate.
- Phase 15 Journal: `Requires` translate; Post/Category `Translatable()` lists; `mltext`/`mlmarkdown` on YAML forms.
</code_context>
<specifics>
## Specific Ideas
- Same freeze/read-only/re-pin rules as Journal, applied to Translate.
- "Start fast" on `sm-grzybyfunkcjonalne-app` still holds; this phase boots that app without Journal.
- Messages, CMS locale components and AI/theme commands were explicitly left out so Journal is not blocked.
</specifics>
<deferred>
## Deferred Ideas
- Messages catalogue and `golem15.translate.manage_messages` admin.
- Locale picker, alternate hreflang, and locale-suggestion-banner CMS components (Phase 16 views may need a successor).
- AI/theme console commands and message import/export.
- Remaining PHP locales beyond the `en`+`pl` seed (D-08 is seed rows, not phrasebook files).
- Phase 15 should list **Depends on: Phase 14.2.1** in ROADMAP (`$gsd-phase --edit 15`); not done in this discussion.
### Reviewed Todos (not folded)
- `sitemap-plugin-port.md`, `mailblocker-with-mailing.md`, and the other keyword matches from `todo.match-phase 14.2.1`: unrelated housekeeping.
</deferred>
---
*Phase: 14.2.1-translate-plugin*
*Context gathered: 2026-10-06*