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>
This commit is contained in:
Jakub Zych
2026-10-06 11:36:28 +02:00
parent 28bd45fa04
commit bd0a27f59f
9 changed files with 73 additions and 72 deletions

View File

@@ -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 |