From bd0a27f59f0ae27b4736265e763c2fa46d442162 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Tue, 6 Oct 2026 11:36:28 +0200 Subject: [PATCH] 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 --- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 1 + .../14.2.1-translate-plugin/14.2.1-01-PLAN.md | 48 +++++++++---------- .../14.2.1-translate-plugin/14.2.1-02-PLAN.md | 20 ++++---- .../14.2.1-translate-plugin/14.2.1-04-PLAN.md | 6 +-- .../14.2.1-translate-plugin/14.2.1-CONTEXT.md | 8 ++-- .../14.2.1-PATTERNS.md | 16 +++---- .../14.2.1-RESEARCH.md | 40 ++++++++-------- .../14.2.1-VALIDATION.md | 2 +- 9 files changed, 73 insertions(+), 72 deletions(-) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 397665e..634f77f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -838,7 +838,7 @@ Plans: **Repos:** `sm-translate-plugin` (new); `sm-grzybyfunkcjonalne-app` (proof host); `summercms.go` for ML field types and the surf locale seam **Success Criteria** (what must be TRUE): - 1. Plugin repo exists with `winter_translate_*` schema (locales, attributes, indexes, empty messages table), Locale model, en/pl seed, and context-safe Translator. + 1. Plugin repo exists with `golem15_translate_*` schema (locales, attributes, indexes, empty messages table), Locale model, en/pl seed, and context-safe Translator. 2. Translatable API (`Translatable()`, `WithLocale`, get/set, default-locale fallback) and permissioned Locales admin work; a fixture model saves and reads `en`+`pl`. 3. Cabana `markdown`/`mltext`/`mlmarkdown` compose; nested locale writes are not dropped; docs, OpenAPI, TS types and `boardwalk` `dist/` update in the same change. 4. Proof host `sm-grzybyfunkcjonalne-app` boots with user+translate; unit tests are the last plan. @@ -848,7 +848,7 @@ Plans: Plans: **Wave 1** -- [ ] 14.2.1-01-PLAN.md — Plugin repo, `winter_translate_*` schema, Locale, en/pl seed, Translator, surf Resolver +- [ ] 14.2.1-01-PLAN.md — Plugin repo, `golem15_translate_*` schema, Locale, en/pl seed, Translator, surf Resolver **Wave 2** *(blocked on Wave 1 completion)* - [ ] 14.2.1-02-PLAN.md — Translatable API, Locales admin, fixture save/read diff --git a/.planning/STATE.md b/.planning/STATE.md index 2bf54c8..4f8c33a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -207,6 +207,7 @@ Progress: [███████░░░] 67% Decisions are logged in PROJECT.md Key Decisions table. Recent decisions affecting current work: +- [Phase 14.2.1]: D-10 Go tables are `golem15_translate_*` (execute Task 2 `golem15-prefix`, 2026-10-06). PHP pin still uses `winter_translate_*`; do not copy those names into Go DDL. - [Phase 14.1]: 14.1-01 Task 1 `ship-shared-full` — create `golem15_user_oauth_identities` in the shared sm-user-plugin with the full PHP column set (locked D-01 and D-07). - [Phase 14.1]: Identity Index/Destroy are host-mounted on the JWT group; the user plugin does not register them under `/_user`. `/me` unrestricted `collection_ids` is JSON null (D-09); `scopes` stay `[]`. - [Phase 14.1]: Corpus is 175/175/0 with zero pending routes. Live Nuxt Connected accounts and fonoteka-mcp `me()` stay Phase 15 UAT. diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md index 1253bff..57b0aba 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md @@ -12,10 +12,10 @@ files_modified: - ../sm-translate-plugin/models/registry.go - ../sm-translate-plugin/models/locale.go - ../sm-translate-plugin/updates/registry.go - - ../sm-translate-plugin/updates/202610060001_create_winter_translate_locales.go - - ../sm-translate-plugin/updates/202610060002_create_winter_translate_attributes.go - - ../sm-translate-plugin/updates/202610060003_create_winter_translate_indexes.go - - ../sm-translate-plugin/updates/202610060004_create_winter_translate_messages.go + - ../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go + - ../sm-translate-plugin/updates/202610060002_create_golem15_translate_attributes.go + - ../sm-translate-plugin/updates/202610060003_create_golem15_translate_indexes.go + - ../sm-translate-plugin/updates/202610060004_create_golem15_translate_messages.go - ../sm-translate-plugin/updates/202610060005_seed_en_pl_locales.go - ../sm-translate-plugin/classes/translator.go - modules/surf/locale_resolver.go @@ -26,7 +26,7 @@ requirements: [D-01, D-02, D-03, D-04, D-07, D-08, D-10, D-12, D-15, D-16] must_haves: truths: - "D-01/D-02/D-03/D-04: implementation is derived only from the read-only PHP tree at SHA 725d547ec839f02b5fdc0f0a6faaed601a414d50; no PHP file changes." - - "D-10: gormigrate creates final `winter_translate_locales`, `winter_translate_attributes`, `winter_translate_indexes`, and empty `winter_translate_messages`; it creates no rainlab-era or `golem15_translate_*` tables." + - "D-10: gormigrate creates final `golem15_translate_locales`, `golem15_translate_attributes`, `golem15_translate_indexes`, and empty `golem15_translate_messages`; it creates no rainlab-era or `winter_translate_*` tables." - "D-08: an idempotent seed creates enabled `en` as default at sort_order 1 and enabled non-default `pl` as Polski at sort_order 2, and never seeds `de`." - "D-07/D-12: a backpack-published resolver selects URL prefix, valid user preferred_locale, remembered `golem15.translate.locale`, cookie-gated Accept-Language, then default, and surf stores only a validated code on context." - "KERN-07: no package-level mutable current locale exists; `Translator.Locale(ctx)` and `towel.WithLocale` carry request state." @@ -35,12 +35,12 @@ must_haves: - path: "../sm-translate-plugin/plugin.go" provides: "compiled Plugin registration, migrations/models/config, Resolver publication" contains: "golem15.translate" - - path: "../sm-translate-plugin/updates/202610060001_create_winter_translate_locales.go" + - path: "../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go" provides: "squashed Locale schema" - contains: "winter_translate_locales" - - path: "../sm-translate-plugin/updates/202610060004_create_winter_translate_messages.go" + contains: "golem15_translate_locales" + - path: "../sm-translate-plugin/updates/202610060004_create_golem15_translate_messages.go" provides: "empty compatibility Messages table without admin" - contains: "winter_translate_messages" + contains: "golem15_translate_messages" - path: "../sm-translate-plugin/classes/translator.go" provides: "context-only Translator and request Resolver" contains: "func (" @@ -93,7 +93,7 @@ Phase 14.2.1 has no mapped REQUIREMENTS.md IDs, so requirement probing is visibl ## Artifacts this phase produces - Module `git.golem15.com/golem15/sm-translate-plugin`, package `translate`, `Plugin.ID() == "golem15.translate"`. -- `models.Locale`, model and migration registries, five gormigrate entries, and exact `winter_translate_*` tables. +- `models.Locale`, model and migration registries, five gormigrate entries, and exact `golem15_translate_*` tables. - `classes.Translator`, `Translator.Locale(context.Context)`, and a request resolver implementing surf's `LocaleResolver`. - Surf optional resolver seam with unchanged fallback behavior when the translate plugin is absent. - Application-neutral plugin and surf README updates for exported contracts. @@ -122,22 +122,22 @@ Phase 14.2.1 has no mapped REQUIREMENTS.md IDs, so requirement probing is visibl - Task 2: Confirm the one-way Winter table contract + Task 2: Confirm the one-way table contract ../sm-translate-plugin/updates/ .planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md (D-10), .planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md (Tables, columns, indexes), /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/updates/version.yaml, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/models/Locale.php - Record the selected schema contract before migrations are implemented. Research resolved D-10's provisional prefix against the frozen source: the only compatible selection is the final `winter_translate_*` table family. This gate records the one-way import/storage choice; it does not reopen the PHP pin or permit a JSON-column alternative. + Record the selected schema contract before migrations are implemented. Execute-phase Task 2 locked `golem15-prefix`: Go tables are `golem15_translate_*` with the PHP pin's columns and indexes. PHP still uses `winter_translate_*`; do not copy those names into Go DDL. This gate does not reopen the PHP pin or permit a JSON-column alternative. Which persistent table contract should this shared plugin publish? - Once released and imported by Journal, renaming these tables requires coordinated data migrations in every host. The frozen PHP pin explicitly reads `winter_translate_*` after its RainLab rename history. + Once released and imported by Journal, renaming these tables requires coordinated data migrations in every host. The frozen PHP pin reads `winter_translate_*`; the Go plugin deliberately uses `golem15_translate_*`. Task 3: Resolve one URL-prefixed request through the plugin, enabled Locale row, surf, and context The four table names and columns become the import target; changing them after release requires data migrations in every host. - Tasks 1 and 2 completed, with schema option `winter-final`. - ../sm-translate-plugin/go.mod, ../sm-translate-plugin/plugin.go, ../sm-translate-plugin/README.md, ../sm-translate-plugin/config/config.yaml, ../sm-translate-plugin/models/registry.go, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/registry.go, ../sm-translate-plugin/updates/202610060001_create_winter_translate_locales.go, ../sm-translate-plugin/updates/202610060002_create_winter_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_winter_translate_indexes.go, ../sm-translate-plugin/updates/202610060004_create_winter_translate_messages.go, ../sm-translate-plugin/updates/202610060005_seed_en_pl_locales.go, ../sm-translate-plugin/classes/translator.go, modules/surf/locale_resolver.go, modules/surf/router.go, modules/surf/README.md + Tasks 1 and 2 completed, with schema option `golem15-prefix`. + ../sm-translate-plugin/go.mod, ../sm-translate-plugin/plugin.go, ../sm-translate-plugin/README.md, ../sm-translate-plugin/config/config.yaml, ../sm-translate-plugin/models/registry.go, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/registry.go, ../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go, ../sm-translate-plugin/updates/202610060002_create_golem15_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_golem15_translate_indexes.go, ../sm-translate-plugin/updates/202610060004_create_golem15_translate_messages.go, ../sm-translate-plugin/updates/202610060005_seed_en_pl_locales.go, ../sm-translate-plugin/classes/translator.go, modules/surf/locale_resolver.go, modules/surf/router.go, modules/surf/README.md ../fonoteka.go/plugins/golem15/user/go.mod, ../fonoteka.go/plugins/golem15/user/plugin.go, ../fonoteka.go/plugins/golem15/user/models/registry.go, ../fonoteka.go/plugins/golem15/user/updates/registry.go, ../fonoteka.go/plugins/golem15/user/updates/00_base.go, modules/backpack/app.go, modules/surf/router.go, modules/surf/locale_from_principal.go, modules/towel/context.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/Translator.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/LocaleMiddleware.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/ApiLocaleMiddleware.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/config/config.php, .planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md Implement the production tracer and the complete Plan 01 scope. Create the Go 1.27 module using only existing GORM/gormigrate/framework dependencies. Register the compiled plugin in `init`, expose config/models/migrations, and publish a framework-owned `surf.LocaleResolver` in Boot. Keep `Requires()` empty so user-preference lookup is optional. -Implement exact squashed DDL for `winter_translate_locales`, `winter_translate_attributes`, `winter_translate_indexes`, and `winter_translate_messages`, including all final columns and PHP-indexed columns from RESEARCH. Messages is DDL only and remains empty. Use explicit gormigrate up/down; never AutoMigrate and never create rainlab or provisional-prefixed tables. Seed only en/pl idempotently with D-08 values. +Implement exact squashed DDL for `golem15_translate_locales`, `golem15_translate_attributes`, `golem15_translate_indexes`, and `golem15_translate_messages`, including all final columns and PHP-indexed columns from RESEARCH. Messages is DDL only and remains empty. Use explicit gormigrate up/down; never AutoMigrate and never create rainlab or `winter_translate_*` tables. Seed only en/pl idempotently with D-08 values. Implement `Locale` with no timestamps, table name, code/name rules, and Fillable limited to code/name/is_enabled. Implement Translator/Resolver with the exact D-07 order: enabled URL first segment; valid principal preferred_locale; remembered `golem15.translate.locale`; Accept-Language only when browser detection is enabled and `locale_manually_set` is absent; enabled default. The manual cookie is a flag with value 1, never a locale. Validate every candidate against enabled rows. URL-prefix handling strips only a valid enabled prefix before routing and sets the manual flag using configured expiry. Provide the API resolver variant preferred → Accept-Language → default without persistence. All current-locale access takes context. @@ -176,7 +176,7 @@ Add the surf interface and optional lookup without importing the plugin. When no Non-zero exit, any package reports build failed, or either test command reports FAIL. - - All four migration files contain their exact `winter_translate_*` table name; no source file contains `golem15_translate_` or `rainlab_translate_`. + - All four migration files contain their exact `golem15_translate_*` table name; no source file contains `winter_translate_` or `rainlab_translate_`. - Seed source contains en and pl with en default/enabled and pl enabled/non-default, and contains no Deutsch seed. - Plugin module/ID/package match D-15 and plugin Boot publishes the framework resolver interface. - Resolver order is URL → principal → remembered locale → cookie-gated Accept-Language → default. @@ -217,7 +217,7 @@ Run the Task 3 command. Confirm `git diff -- /media/nvme/dev/golem15/fonoteka/pl - The plugin and surf packages compile and pass short tests. -- Exact final tables and en/pl seed are implemented through gormigrate. +- Exact final `golem15_translate_*` tables and en/pl seed are implemented through gormigrate. - Full resolver order is implemented without process-wide locale state. - No deferred Messages UI, CMS components, AI/theme commands, import/export, or PHP edits are introduced. diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md index 9ec78c1..0655b49 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md @@ -27,7 +27,7 @@ requirements: [D-05, D-08, D-09, D-10, D-11, D-12, D-17] must_haves: truths: - "D-09/D-12: a host model declares `Translatable() []string`, `TranslatableIndexes() []string`, and `MorphName() string`; callers use exported get/set and `WithLocale` APIs." - - "D-10: default-locale values remain in host columns; each non-default locale is one JSON object row in `winter_translate_attributes`, and indexed values are mirrored to `winter_translate_indexes`." + - "D-10: default-locale values remain in host columns; each non-default locale is one JSON object row in `golem15_translate_attributes`, and indexed values are mirrored to `golem15_translate_indexes`." - "D-11: a missing non-default value reads the host model's default-locale field." - "D-05: Locales is ordinary cabana CRUD, permission-gated by exactly `golem15.translate.manage_locales`; no Messages controller, permission, or navigation exists." - "Locale form writes only code/name/is_enabled; is_default and sort_order cannot be mass-assigned, while a permissioned make-default action preserves disabled/default lifecycle guards." @@ -47,11 +47,11 @@ must_haves: contains: "locale:" key_links: - from: "../sm-translate-plugin/classes/translatable.go" - to: "winter_translate_attributes" + to: "golem15_translate_attributes" via: "non-default SetTranslated upserts one locale/model row" pattern: "attribute_data" - from: "../sm-translate-plugin/classes/translatable.go" - to: "winter_translate_indexes" + to: "golem15_translate_indexes" via: "indexed fields upsert locale/model/item/value" pattern: "TranslatableIndexes" - from: "../sm-translate-plugin/controllers/locales.go" @@ -99,10 +99,10 @@ No REQUIREMENTS.md IDs are mapped to this phase. Probe predicates are intentiona Task 1: Save one fixture title in en and pl, then read pl through the exported API ../sm-translate-plugin/classes/translatable.go, ../sm-translate-plugin/classes/translatable_smoke_test.go, ../sm-translate-plugin/models/attribute.go, ../sm-translate-plugin/models/index.go, ../sm-translate-plugin/models/registry.go - /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/TranslatableBehavior.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/202610060002_create_winter_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_winter_translate_indexes.go, ../fonoteka.go/plugins/golem15/user/models/user.go (MorphName), .planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md (Translatable assignment) - Implement the minimum stable D-09/D-12 API without Eloquent-style magic. Define a host-model contract with `Translatable() []string` and `MorphName() string`, plus an explicit indexed-field contract `TranslatableIndexes() []string`. Reject fields not declared by the model and locale codes not enabled in `winter_translate_locales`. + /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/TranslatableBehavior.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/202610060002_create_golem15_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_golem15_translate_indexes.go, ../fonoteka.go/plugins/golem15/user/models/user.go (MorphName), .planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md (Translatable assignment) + Implement the minimum stable D-09/D-12 API without Eloquent-style magic. Define a host-model contract with `Translatable() []string` and `MorphName() string`, plus an explicit indexed-field contract `TranslatableIndexes() []string`. Reject fields not declared by the model and locale codes not enabled in `golem15_translate_locales`. -`SetTranslated` writes the default locale directly to the host model field/column and writes non-default values to one `(locale, model_id, model_type)` `winter_translate_attributes` row as a JSON object keyed by field. Use explicit model primary-key extraction and explicit exported-field/GORM-column mapping; do not use `reflect.Type.String()` as morph identity. Attribute rows have no public controller. +`SetTranslated` writes the default locale directly to the host model field/column and writes non-default values to one `(locale, model_id, model_type)` `golem15_translate_attributes` row as a JSON object keyed by field. Use explicit model primary-key extraction and explicit exported-field/GORM-column mapping; do not use `reflect.Type.String()` as morph identity. Attribute rows have no public controller. `Translated` returns the host field for default locale; for another enabled locale it reads the JSON key and, when absent, returns the default host field per D-11. Keep an explicit locale argument even when context has a UI locale. @@ -113,7 +113,7 @@ Create a neutral fixture model only in the smoke test, migrate its host table ex - Exported interfaces and functions compile from an external test package. - - The default English value is in the fixture host row, not duplicated into `winter_translate_attributes`. + - The default English value is in the fixture host row, not duplicated into `golem15_translate_attributes`. - The Polish value is present under `attribute_data.title` in exactly one pl/model row. - Undeclared fields and unenabled locale codes return errors without database writes. - Test fixture is test-only and no production fixture plugin is globally registered. @@ -125,7 +125,7 @@ Create a neutral fixture model only in the smoke test, migrate its host table ex Task 2: Add indexed locale lookup, WithLocale query scope, and default fallback ../sm-translate-plugin/classes/translatable.go, ../sm-translate-plugin/classes/translatable_smoke_test.go, ../sm-translate-plugin/README.md ../sm-translate-plugin/classes/translatable.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php (scopeTransWhere and index writes), /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/models/Post.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/models/Category.php, .planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md (Minimum exported Go API) - Expand from the proven save/read path. `WithLocale(ctx, db, locale)` validates the explicit locale and carries it on the GORM statement context; it must not mutate global state. Add an indexed equality helper/scope that joins `winter_translate_indexes` by locale, morph name, model id, and item, while default-locale lookup uses the host column and non-default lookup falls back to that host column only when no translated index match exists, matching the frozen PHP behavior. + Expand from the proven save/read path. `WithLocale(ctx, db, locale)` validates the explicit locale and carries it on the GORM statement context; it must not mutate global state. Add an indexed equality helper/scope that joins `golem15_translate_indexes` by locale, morph name, model id, and item, while default-locale lookup uses the host column and non-default lookup falls back to that host column only when no translated index match exists, matching the frozen PHP behavior. When SetTranslated writes a declared indexed field, upsert the corresponding index row atomically with the attribute JSON update. Rewriting one locale/field must preserve other translated fields in the same JSON object. Empty translated values stay explicit empty values rather than silently borrowing fallback during admin editing; ordinary `Translated` still applies D-11 fallback. @@ -136,7 +136,7 @@ Document only the exported identifiers that exist, MorphName's import-stability - `WithLocale` returns a GORM handle carrying an explicit validated locale on context and has no singleton mutation. - - Setting an indexed Polish slug writes one matching `winter_translate_indexes` row. + - Setting an indexed Polish slug writes one matching `golem15_translate_indexes` row. - Polish indexed lookup finds the fixture; default-locale lookup uses the host slug. - Missing Polish title returns English under normal reads per D-11. - README names every exported API identifier accurately and remains application-neutral. @@ -166,7 +166,7 @@ Port the plugin.* and locale.* UI phrases to `lang/en/lang.yaml` and `lang/pl/la - Unknown/unprivileged admin gets 403; privileged admin gets the Locales schema/list. - A crafted body cannot persist is_default or sort_order. - The permissioned make-default action rejects disabled locales and atomically leaves exactly one enabled default locale. - - English/Polish phrasebook files are independent from `winter_translate_attributes`. + - English/Polish phrasebook files are independent from `golem15_translate_attributes`. Authorized administrators can manage the lean Locale surface while default-state and phrasebook/model-translation boundaries remain enforced. diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-04-PLAN.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-04-PLAN.md index 793f985..955a8f5 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-04-PLAN.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-04-PLAN.md @@ -26,7 +26,7 @@ autonomous: true requirements: [D-01, D-02, D-03, D-04, D-05, D-06, D-07, D-08, D-09, D-10, D-11, D-12, D-13, D-14, D-15, D-16, D-17] must_haves: truths: - - "A real-Postgres integration test migrates all four winter_translate tables, activates user+translate+fixture, saves en/pl through cabana ML fields, reads via WithLocale, and reaches Locales admin." + - "A real-Postgres integration test migrates all four golem15_translate tables, activates user+translate+fixture, saves en/pl through cabana ML fields, reads via WithLocale, and reaches Locales admin." - "Migration up/down verifies every final column/index, empty Messages table, idempotent en/pl seed, absence of de, and complete rollback." - "Translator tests prove URL → preferred_locale → remembered locale → cookie-gated Accept-Language → default, invalid-code rejection, API order, plugin-absent surf behavior, and concurrent request isolation." - "Translatable tests prove default-row storage, non-default JSON, default fallback, indexed lookup, undeclared-field rejection, invalid-locale rejection, and atomic preservation of sibling fields." @@ -38,7 +38,7 @@ must_haves: contains: "TestTranslateEndToEnd" - path: "../sm-translate-plugin/updates/migrations_test.go" provides: "real Postgres migration up/down and seed proof" - contains: "winter_translate_messages" + contains: "golem15_translate_messages" - path: "modules/surf/locale_resolver_test.go" provides: "resolver-present/absent and request-isolation tests" contains: "TestLocaleResolver" @@ -154,7 +154,7 @@ Expand host `TestBootUserTranslate` to prove both actual gitlink plugins activat Task 2: Complete migration, Translator, Translatable, admin, ML, markdown, and SPA test matrices ../sm-translate-plugin/updates/migrations_test.go, ../sm-translate-plugin/classes/translator_test.go, ../sm-translate-plugin/classes/translatable_test.go, ../sm-translate-plugin/locales_admin_test.go, modules/surf/locale_resolver_test.go, modules/cabana/ml_test.go, modules/cabana/markdown_test.go, modules/cabana/openapi_conformance_test.go, admin/tests/form/MLFields.test.ts, admin/tests/form/MarkdownField.test.ts - /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/integration_test.go, ../sm-translate-plugin/updates/202610060001_create_winter_translate_locales.go, ../sm-translate-plugin/classes/translator.go, ../sm-translate-plugin/classes/translatable.go, modules/surf/locale_from_principal_test.go, modules/cabana/form_schema_test.go, modules/cabana/field_permission.go, admin/tests/form/DatepickerField.test.ts, admin/tests/form/registry.test.ts + /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/integration_test.go, ../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go, ../sm-translate-plugin/classes/translator.go, ../sm-translate-plugin/classes/translatable.go, modules/surf/locale_from_principal_test.go, modules/cabana/form_schema_test.go, modules/cabana/field_permission.go, admin/tests/form/DatepickerField.test.ts, admin/tests/form/registry.test.ts Complete the decision and security matrix without adding unrelated PHP-suite surfaces. Migration tests: assert every final table, column type/default, PHP-indexed column, empty Messages row count, no rainlab/provisional tables, idempotent seed, en/pl exact flags/order/names, no de, and rollback removes all four tables in reverse-safe order. Re-migrate after rollback. diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md index 10c4fba..424b33f 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md @@ -33,19 +33,19 @@ Out of scope: the Messages catalogue and `manage_messages` admin, locale-picker ### 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:** Storage uses the same tables and columns as this PHP pin (`golem15_translate_*` attributes/indexes/locales — researcher confirms exact names from the frozen updates). No JSON-column alternative. — **Reversibility:** one-way — Winter import and Journal cutover expect those tables. +- **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 user creates the public Gitea remote `git@git.golem15.com:golem15/sm-translate-plugin.git` as a manual plan step (it does not exist yet). Module path `git.golem15.com/golem15/sm-translate-plugin`, package `translate`, plugin ID `golem15.translate`. +- **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_*` table/column names and migration IDs, taken from the frozen PHP updates (D-10), not invented. +- 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". @@ -85,7 +85,7 @@ Out of scope: the Messages catalogue and `manage_messages` admin, locale-picker - `docs/backend/forms.md`, `docs/backend/admin-controllers.md` ### Remotes -- `git@git.golem15.com:golem15/sm-translate-plugin.git` — **does not exist yet**; user creates it, public +- `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 diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md index af6850a..adbb8a5 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md @@ -15,7 +15,7 @@ Path roots: All analog paths below are git-tracked (`git ls-files` in `summercms.go`, inside the user submodule, inside `sm-bm-app`, and inside the PHP plugin). No gitignored mirror is named. `modules/boardwalk/dist`, `admin/openapi/admin.json` and `admin/src/api/schema.d.ts` are generated outputs: regenerate them, never hand-edit. -**Table names (locked by RESEARCH against the frozen PHP models):** `winter_translate_locales`, `winter_translate_attributes`, `winter_translate_indexes`, `winter_translate_messages`. CONTEXT D-10's `golem15_translate_*` placeholder is wrong. Do not invent `golem15_translate_*`. +**Table names (locked D-10 execute-phase 2026-10-06):** Go tables are `golem15_translate_locales`, `golem15_translate_attributes`, `golem15_translate_indexes`, `golem15_translate_messages`. PHP at SHA 725d547 still uses `winter_translate_*`; copy column/index shape from PHP, not the Winter table names. Do not emit `winter_translate_*` or `rainlab_translate_*` in Go DDL. Suggested plan split from RESEARCH (present at the plan-count checkpoint; unit tests last): **14.2.1-01** plugin repo + squashed schema + Locale + Translator + surf Resolver seam; **14.2.1-02** Translatable API + Locales admin + fixture; **14.2.1-03** cabana `markdown`/`mltext`/`mlmarkdown` + SPA + proof host boot; **14.2.1-04** unit/integration tests last. @@ -37,10 +37,10 @@ Suggested plan split from RESEARCH (present at the plan-count checkpoint; unit t | `TR/models/locale.go` | model | CRUD | `USR/models/user_group.go` (Fillable/Rules/TableName) + `PHP/models/Locale.php` (guards) | exact | | `TR/models/attribute.go` | model | CRUD | `USR/models/api_token.go` shape + `PHP/models/Attribute.php` fillable | exact | | `TR/updates/registry.go` | utility | — | `USR/updates/registry.go` | exact | -| `TR/updates/202610060001_create_winter_translate_locales.go` | migration | CRUD | `USR/updates/00_base.go` + `USR/updates/202610020001_create_user_groups.go` (CREATE + seed style) | exact | -| `TR/updates/202610060002_create_winter_translate_attributes.go` | migration | CRUD | `USR/updates/00_base.go` | exact | -| `TR/updates/202610060003_create_winter_translate_indexes.go` | migration | CRUD | `USR/updates/00_base.go` | exact | -| `TR/updates/202610060004_create_winter_translate_messages.go` | migration | CRUD | `USR/updates/00_base.go` (DDL only; no Message admin) | exact | +| `TR/updates/202610060001_create_golem15_translate_locales.go` | migration | CRUD | `USR/updates/00_base.go` + `USR/updates/202610020001_create_user_groups.go` (CREATE + seed style) | exact | +| `TR/updates/202610060002_create_golem15_translate_attributes.go` | migration | CRUD | `USR/updates/00_base.go` | exact | +| `TR/updates/202610060003_create_golem15_translate_indexes.go` | migration | CRUD | `USR/updates/00_base.go` | exact | +| `TR/updates/202610060004_create_golem15_translate_messages.go` | migration | CRUD | `USR/updates/00_base.go` (DDL only; no Message admin) | exact | | `TR/updates/202610060005_seed_en_pl_locales.go` | migration | CRUD | `USR/updates/202610020001_create_user_groups.go` INSERT + `PHP/updates/v1.3.1/seed_all_tables.php` and `v2.4.0/seed_additional_locales.php` | exact | | `TR/classes/translator.go` | service | request-response | `PHP/classes/Translator.php` + `LocaleMiddleware.php` + `ApiLocaleMiddleware.php` (contract) and `USR/plugin.go` Boot `app.Publish` | role-match | | `TR/classes/translatable.go` | service | CRUD | `PHP/behaviors/TranslatableModel.php` + `classes/TranslatableBehavior.php` (no Go translatable analog) | partial | @@ -221,7 +221,7 @@ public $timestamps = false; // makeDefault: cannot make a disabled locale default ``` -Copy: `TableName() "winter_translate_locales"`, no `CreatedAt`/`UpdatedAt`, Fillable **only** `code`, `name`, `is_enabled`. `is_default` and `sort_order` are **not** fillable (PHP). Rules: `code` required, `name` required. Port delete/unset/disabled-default as `FormBeforeDelete` / `FormBeforeUpdate` returning `&cabana.ValidationError{Details: ...}` (422) — analog `USR/controllers/usergroups_admin_controller.go` 162-175. +Copy: `TableName() "golem15_translate_locales"`, no `CreatedAt`/`UpdatedAt`, Fillable **only** `code`, `name`, `is_enabled`. `is_default` and `sort_order` are **not** fillable (PHP). Rules: `code` required, `name` required. Port delete/unset/disabled-default as `FormBeforeDelete` / `FormBeforeUpdate` returning `&cabana.ValidationError{Details: ...}` (422) — analog `USR/controllers/usergroups_admin_controller.go` 162-175. `isValid` = code in enabled list (`PHP/models/Locale.php` 228-232). Default locale: `is_default` true row; seed `en` as default. @@ -231,7 +231,7 @@ Copy: `TableName() "winter_translate_locales"`, no `CreatedAt`/`UpdatedAt`, Fill **Contract:** `PHP/models/Attribute.php` lines 15-34 — table `winter_translate_attributes`, fillable `locale`, `model_type`, `model_id`, `attribute_data`, `$guarded = ['*']`. -**Go analog:** `USR/models/user_group.go` TableName + Register. No public Attribute controller. Writes only through Translatable helpers (RESEARCH T-SEC). Optional: omit a Message model entirely and only DDL `winter_translate_messages` (RESEARCH §9). If Attribute exists, Fillable matches PHP; never expose an admin controller. +**Go analog:** `USR/models/user_group.go` TableName + Register. No public Attribute controller. Writes only through Translatable helpers (RESEARCH T-SEC). Optional: omit a Message model entirely and only DDL `golem15_translate_messages` (RESEARCH §9). If Attribute exists, Fillable matches PHP; never expose an admin controller. Go `TableName()` is `golem15_translate_attributes` even though PHP's `$table` is `winter_translate_attributes`. --- @@ -269,7 +269,7 @@ func init() { Register(migrations...) } | `winter_translate_indexes` | `id`, `locale` indexed, `model_id` indexed nullable, `model_type` indexed nullable, `item` indexed nullable, `value TEXT` nullable | | `winter_translate_messages` | `id`, `code` indexed nullable, `message_data TEXT` nullable, `found BOOLEAN DEFAULT TRUE`, `code_pre_2_1_0 TEXT` indexed nullable — create empty; no Messages admin | -Suggested IDs (planner may adjust date prefix, not table names): `202610060001_create_winter_translate_locales` … `202610060005_seed_en_pl_locales`. +Suggested IDs (planner may adjust date prefix, not table names): `202610060001_create_golem15_translate_locales` … `202610060005_seed_en_pl_locales`. **Seed contract:** `PHP/updates/v1.3.1/seed_all_tables.php` 16-22 (`en` / English / default / enabled) and `PHP/updates/v2.4.0/seed_additional_locales.php` 13-20 (`pl` / Polski / not default / enabled / `sort_order` 2). Set `en.sort_order = 1`. **Do not seed `de`.** Idempotent: insert by `code` if missing (`$exists` check lines 33-36). diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md index 3da09dc..bccae4e 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md @@ -71,9 +71,9 @@ Phase 14.2.1 ports the lean core of `Golem15.Translate` at SHA `725d547ec839f02b5fdc0f0a6faaed601a414d50` so Journal (Phase 15) can keep translatable fields. The frozen tree is present at `/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate` and matches the pin. Do not clone a second copy. -**Primary recommendation:** Create `sm-translate-plugin` on the user-plugin mount pattern; squash PHP's rainlab→winter rename history into four final Postgres tables named `winter_translate_*` (not `golem15_translate_*`); export `Translatable() []string`, `WithLocale`, get/set-in-locale, and Translator current locale; land cabana `markdown` plus `mltext`/`mlmarkdown` in this phase so Phase 15 is not blocked; replace surf's Accept-Language-only house locale middleware with a backpack-published Translator when the plugin is mounted. +**Primary recommendation:** Create `sm-translate-plugin` on the user-plugin mount pattern; squash PHP's rainlab→winter rename history into four final Postgres tables named `golem15_translate_*` (not PHP's `winter_translate_*`); export `Translatable() []string`, `WithLocale`, get/set-in-locale, and Translator current locale; land cabana `markdown` plus `mltext`/`mlmarkdown` in this phase so Phase 15 is not blocked; replace surf's Accept-Language-only house locale middleware with a backpack-published Translator when the plugin is mounted. -PHP table names in this pin are `winter_translate_locales`, `winter_translate_attributes`, `winter_translate_indexes`, and `winter_translate_messages`. CONTEXT D-10's `golem15_translate_*` placeholder is wrong against the frozen source. Use the verified `winter_translate_*` names so a Winter import and Journal cutover see the same tables. +PHP table names in this pin are `winter_translate_locales`, `winter_translate_attributes`, `winter_translate_indexes`, and `winter_translate_messages`. **Execution override (2026-10-06):** D-10 is locked to Go names `golem15_translate_*` with the PHP column/index shapes. Do not emit `winter_translate_*` in Go DDL. A Winter import will need a mapping later. ## Architectural Responsibility Map @@ -115,8 +115,8 @@ Do not use these. CONTEXT locked the storage, locale order, and YAML types. | Instead of | Could Use | Why rejected | |------------|-----------|--------------| -| `winter_translate_*` tables | JSON columns on host models | D-10 forbids it | -| `winter_translate_*` | Invented `golem15_translate_*` | Frozen models use `winter_translate_*` | +| `golem15_translate_*` tables | JSON columns on host models | D-10 forbids it | +| `golem15_translate_*` | PHP's `winter_translate_*` copied into Go | Execute lock 2026-10-06; Winter import is a later mapping | | URL/session/cookie/default | Accept-Language only | D-07 forbids reducing to it | | Cabana `mltext`/`mlmarkdown` | Plugin `type: widget` | Field types belong in cabana (12.1 pattern) | @@ -194,10 +194,10 @@ From `updates/version.yaml` [VERIFIED: `updates/version.yaml:1-155`]: Go migration IDs: follow the user-plugin pattern `"202609170001_create_users"` [VERIFIED: `../fonoteka.go/plugins/golem15/user/updates/00_base.go:13`]. Suggested squash IDs (planner may adjust date prefix, not the table names): -- `202610060001_create_winter_translate_locales` -- `202610060002_create_winter_translate_attributes` -- `202610060003_create_winter_translate_indexes` -- `202610060004_create_winter_translate_messages` +- `202610060001_create_golem15_translate_locales` +- `202610060002_create_golem15_translate_attributes` +- `202610060003_create_golem15_translate_indexes` +- `202610060004_create_golem15_translate_messages` - `202610060005_seed_en_pl_locales` Postgres types: `SERIAL` PK, `TEXT` for strings, `BOOLEAN`, `INTEGER` for `sort_order`, `TEXT` for `attribute_data`/`message_data`/`value` (PHP mediumText). Add btree indexes on the PHP-indexed columns (`code`, `name`, `locale`, `model_id`, `model_type`, `item`). @@ -505,7 +505,7 @@ Four plans. Present this count at the plan-count checkpoint. Unit tests last. | Plan | One-line scope | |------|----------------| -| **14.2.1-01** | Plugin repo + squashed `winter_translate_*` schema (all four tables) + Locale model + en/pl seed + Translator + surf Resolver seam. Manual: Gitea remote + local checkouts. | +| **14.2.1-01** | Plugin repo + squashed `golem15_translate_*` schema (all four tables) + Locale model + en/pl seed + Translator + surf Resolver seam. Manual: Gitea remote + local checkouts. | | **14.2.1-02** | Translatable API (`Translatable`, `WithLocale`, get/set, fallback, indexes) + Locales admin (`manage_locales`, YAML, phrasebook) + fixture save/read. | | **14.2.1-03** | Cabana `markdown` + `mltext` + `mlmarkdown` (SPA switcher, nested save, docs/OpenAPI/TS/`dist/`) + proof host `sm-grzybyfunkcjonalne-app` boots user+translate. | | **14.2.1-04** | Unit/integration tests last: Translator order, Translatable fallback, admin authz, ML save, migrations up/down. | @@ -526,13 +526,13 @@ Public/Admin HTTP Admin Locales CRUD → cabana.CRUDService (permission golem15.translate.manage_locales) - → winter_translate_locales + → golem15_translate_locales Admin Journal-like form (fixture / Phase 15) → mltext / mlmarkdown controls → default locale → host table columns - → other locales → winter_translate_attributes.attribute_data JSON - → indexed fields → winter_translate_indexes + → other locales → golem15_translate_attributes.attribute_data JSON + → indexed fields → golem15_translate_indexes Journal query (Phase 15) → Translator.Locale(ctx) or WithLocale(..., "pl") @@ -578,8 +578,8 @@ Framework touches: `modules/surf/router.go` locale seam; `modules/cabana/form_sc ### Anti-Patterns to Avoid -- **JSON-column "simpler" storage:** violates D-10 and Winter import. -- **Renaming tables to `golem15_translate_*`:** frozen PHP uses `winter_translate_*`. +- **JSON-column "simpler" storage:** violates D-10 and PHP attribute-row semantics. +- **Copying PHP `winter_translate_*` names into Go DDL:** D-10 is locked to `golem15_translate_*`; Winter import needs a later mapping. - **Translator singleton holding the request locale:** violates KERN-07. - **Accept-Language as the only resolver:** violates D-07; also stop stuffing the raw header into context when Resolver runs. - **Plugin-owned `type: widget` ML controls:** field types belong in cabana. @@ -603,10 +603,10 @@ Framework touches: `modules/surf/router.go` locale seam; `modules/cabana/form_sc ## Common Pitfalls ### Pitfall 1: Wrong table prefix -**What goes wrong:** Creating `golem15_translate_locales` because CONTEXT guessed that name. -**Why:** D-10 asked the researcher to confirm; models say `winter_translate_*`. -**How to avoid:** Use the verified names in every migration and query. -**Warning signs:** `Schema::hasTable('winter_translate_locales')` in Translator. +**What goes wrong:** Creating `winter_translate_locales` in Go because PHP models use that name. +**Why:** Execute-phase D-10 is locked to `golem15_translate_*`; PHP `winter_translate_*` stays a mapping concern. +**How to avoid:** Use `golem15_translate_*` in every Go migration and query. +**Warning signs:** Go source containing `winter_translate_` or `rainlab_translate_`. ### Pitfall 2: Nested ML save dropped **What goes wrong:** SPA posts `{title: {en, pl}}`; cabana drops maps; only default locale saves. @@ -680,7 +680,7 @@ DATA_r3t6y0ab_END | Old Approach (PHP) | Current Approach (Go) | When | Impact | |--------------------|----------------------|------|--------| -| RainLab then Winter table names | Squash to `winter_translate_*` | 2.0.0 rename | Do not emit rainlab tables | +| RainLab then Winter table names | Squash to `golem15_translate_*` | 2.0.0 rename in PHP; Go never emits rainlab or winter table names | Winter import needs a later mapping | | Eloquent `$implement` behavior | Go interface + GORM callbacks | this port | Explicit `Translatable()` | | Winter formwidget swap at runtime | Explicit YAML `mltext`/`mlmarkdown` | compiled admin | Journal YAML names ML types | | Translator singleton | `towel.WithLocale` + backpack service | KERN-07 | No request globals | @@ -753,7 +753,7 @@ No REQUIREMENTS.md IDs were mapped (TBD). Map locked decisions: | D-07 | URL prefix wins; invalid code ignored; session/cookie flag; not header-only | unit | `go test ./classes -run TestTranslatorResolve -count=1` | ❌ Wave 0 | | D-08 | Seed inserts `en` (default, enabled) and `pl` (enabled, not default); not `de` | integration | `go test ./updates -run TestSeedEnPl -count=1` | ❌ Wave 0 | | D-09/D-12 | `Translatable()` + get/set + `WithLocale` | unit | `go test ./classes -run TestTranslatableGetSet -count=1` | ❌ Wave 0 | -| D-10 | Tables `winter_translate_locales\|attributes\|indexes\|messages` exist after migrate | integration | `go test ./updates -run TestTranslateTables -count=1` | ❌ Wave 0 | +| D-10 | Tables `golem15_translate_locales\|attributes\|indexes\|messages` exist after migrate | integration | `go test ./updates -run TestTranslateTables -count=1` | ❌ Wave 0 | | D-11 | Missing `pl` falls back to default locale column | unit | `go test ./classes -run TestFallbackDefaultLocale -count=1` | ❌ Wave 0 | | D-17 | Host/plugin Activate with user+translate | smoke | `go test ./... -run TestBootUserTranslate -count=1` | ❌ Wave 0 | | T-SEC-01 | Unlisted locale never stored | unit | `go test ./classes -run TestInvalidLocaleRejected -count=1` | ❌ Wave 0 | diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md index 41ba419..43f3e21 100644 --- a/.planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md @@ -45,7 +45,7 @@ created: "2026-10-06" | 14.2.1-W0 | 04 | 0 | D-07 | T-14.2.1-02 | URL prefix wins; invalid code ignored; session/cookie flag; not header-only | unit | `go test ./classes -run TestTranslatorResolve -count=1` | ❌ W0 | ⬜ pending | | 14.2.1-W0 | 04 | 0 | D-08 | — | Seed inserts `en` (default, enabled) and `pl` (enabled, not default); not `de` | integration | `go test ./updates -run TestSeedEnPl -count=1` | ❌ W0 | ⬜ pending | | 14.2.1-W0 | 04 | 0 | D-09/D-12 | — | `Translatable()` + get/set + `WithLocale` | unit | `go test ./classes -run TestTranslatableGetSet -count=1` | ❌ W0 | ⬜ pending | -| 14.2.1-W0 | 04 | 0 | D-10 | — | Tables `winter_translate_locales\|attributes\|indexes\|messages` exist after migrate | integration | `go test ./updates -run TestTranslateTables -count=1` | ❌ W0 | ⬜ pending | +| 14.2.1-W0 | 04 | 0 | D-10 | — | Tables `golem15_translate_locales\|attributes\|indexes\|messages` exist after migrate | integration | `go test ./updates -run TestTranslateTables -count=1` | ❌ W0 | ⬜ pending | | 14.2.1-W0 | 04 | 0 | D-11 | — | Missing `pl` falls back to default locale column | unit | `go test ./classes -run TestFallbackDefaultLocale -count=1` | ❌ W0 | ⬜ pending | | 14.2.1-W0 | 04 | 0 | D-17 | — | Host/plugin Activate with user+translate | smoke | `go test ./... -run TestBootUserTranslate -count=1` | ❌ W0 | ⬜ pending | | 14.2.1-W0 | 04 | 0 | T-SEC-01 | T-14.2.1-03 | Unlisted locale never stored | unit | `go test ./classes -run TestInvalidLocaleRejected -count=1` | ❌ W0 | ⬜ pending |