diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d774610..4ce8178 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -843,7 +843,7 @@ Plans: 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. -**Plans:** 4/6 plans executed +**Plans:** 5/6 plans executed Plans: @@ -860,7 +860,7 @@ Plans: - [x] 14.2.1-04-PLAN.md — Unit/integration tests last, phase gate, security review **Wave 5** *(gap closure, blocked on Wave 4 completion)* -- [ ] 14.2.1-05-PLAN.md — Hydrate enabled locales on admin ML forms (CR-01) +- [x] 14.2.1-05-PLAN.md — Hydrate enabled locales on admin ML forms (CR-01) **Wave 6** *(gap closure, blocked on Wave 5 completion)* - [ ] 14.2.1-06-PLAN.md — Lift ML maps on relation-child saves (WR-02); named tests last diff --git a/.planning/STATE.md b/.planning/STATE.md index c6ac7df..8af2fa5 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,18 +2,18 @@ gsd_state_version: "1.0" milestone: v1.0 current_phase: 14.2.1 -current_phase_name: translate-plugin -status: verifying -stopped_at: Completed 14.2.1-04-PLAN.md -last_updated: "2026-10-06T13:18:47.315Z" +current_phase_name: Translate plugin (INSERTED) +status: executing +stopped_at: Completed 14.2.1-05-PLAN.md +last_updated: "2026-10-06T13:44:21.673Z" last_activity: 2026-10-06 -last_activity_desc: 14.2.1-04 tests, phase gate, and security review -state_head: 249b4d10cac25d64f987d719fdb581bb08c0aac0 +last_activity_desc: Phase 14.2.1 execution started +state_head: 424fe9ccc06d34436e148add6334d1c2206723c2 progress: total_phases: 26 completed_phases: 12 total_plans: 131 - completed_plans: 129 + completed_plans: 130 milestone_name: milestone --- @@ -24,14 +24,14 @@ milestone_name: milestone See: .planning/PROJECT.md (updated 2026-09-16) **Core value:** An existing WinterCMS-shaped app can be ported plugin by plugin to a single Go binary without its frontend noticing: the PHP version's API contract is the acceptance test. -**Current focus:** Phase 14.2.1 — Translate plugin +**Current focus:** Phase 14.2.1 — Translate plugin (INSERTED) ## Current Position -Phase: 14.2.1 (translate-plugin) — READY TO EXECUTE -Plan: 4 of 4 complete -Status: Verification gaps — CR-01 admin ML locale switch; do not mark complete -Last activity: 2026-10-06 — 14.2.1-VERIFICATION.md status gaps_found (14/16) +Phase: 14.2.1 (Translate plugin (INSERTED)) — EXECUTING +Plan: 5 of 6 complete +Status: Ready to execute 14.2.1-06 +Last activity: 2026-10-06 — Completed 14.2.1-05-PLAN.md Progress: [██████████] 100% @@ -184,6 +184,7 @@ Progress: [██████████] 100% | Phase 14.2.1 P02 | 15 min | 3 tasks | 21 files | | Phase 14.2.1 P03 | 5 min | 3 tasks | 40 files | | Phase 14.2.1 P04 | 51 min | 3 tasks | 22 files | +| Phase 14.2.1 P05 | 11 | 3 tasks | 24 files | ## Accumulated Context @@ -584,6 +585,7 @@ Recent decisions affecting current work: - [Phase 14.2.1]: Locales is HasAdminControllers plus HasNavigation (not HasSettings); Fillable excludes is_default/sort_order; makeDefault uses GORM Updates maps. - [Phase 14.2.1]: Task 2 locked grzyby-submodules: proof host is sm-grzybyfunkcjonalne-app with plugins/golem15/user and plugins/golem15/translate; host go.work replace points at ../summercms.go. - [Phase 14.2.1]: 14.2.1-04 security review was executor-self-performed (no gsd-security-auditor in this Cursor session); every cited TestName was re-run. Full cabana `-race` needs `-timeout 30m`. WhereIndex falls back to the host column when no index row matches (PHP transWhere). +- [Phase 14.2.1]: writer-exact: add TranslatedExact to cabana.TranslationWriter; AdminWriter delegates to classes.TranslatedExact ### Pending Todos @@ -636,6 +638,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-10-06T12:21:36Z -Stopped at: Completed 14.2.1-04-PLAN.md +Last session: 2026-10-06T13:44:20.876Z +Stopped at: Completed 14.2.1-05-PLAN.md Resume file: None diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-05-SUMMARY.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-05-SUMMARY.md new file mode 100644 index 0000000..6b1f2e8 --- /dev/null +++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-05-SUMMARY.md @@ -0,0 +1,218 @@ +--- +phase: 14.2.1-translate-plugin +plan: 05 +subsystem: i18n +tags: [translate, cabana, mltext, mlmarkdown, TranslatedExact, hydrateMLRecord, FORM_ENABLED_LOCALES, CR-01] + +requires: + - phase: 14.2.1-04 + provides: "ML nested save, TranslationWriter adapter, TestMLNestedSave, SPA MLFields, phase gate" +provides: + - "FormMeta.EnabledLocales on protect()'d form and relation schemas" + - "TranslationWriter.TranslatedExact plus hydrateMLRecord on Show/save record maps" + - "SPA FORM_ENABLED_LOCALES inject, create seed maps, and adopt merge" + - "Regenerated OpenAPI, schema.d.ts, docs, and boardwalk dist" +affects: [14.2.1-06, 15-journal-plugin] + +actuals: + tokens: 12147 + tasks: 3 + commits: 2 +plan_head_before: ed81f2a0c164d775ff6ee6ad122aecd4a153e16e +plan_head_after: 424fe9ccc06d34436e148add6334d1c2206723c2 +plugin_repo_head_after: 11ac3288d2f6775bfc22598c94ffe7dacf3c3dd1 + +tech-stack: + added: [] + patterns: + - "Admin GET/save hydrates declared ML fields through TranslationWriter.TranslatedExact; missing non-default locales stay empty (no D-11 fallback)" + - "SPA ML selectors read FORM_ENABLED_LOCALES from schema meta; adopt merges maps instead of replacing with a host scalar" + +key-files: + created: [] + modified: + - modules/cabana/schema_types.go + - modules/cabana/field_ml.go + - modules/cabana/crud.go + - modules/cabana/http.go + - modules/cabana/ml_test.go + - modules/cabana/ml_smoke_test.go + - modules/cabana/README.md + - docs/backend/forms.md + - docs/backend/admin-controllers.md + - admin/src/components/form/formContext.ts + - admin/src/components/form/formState.ts + - admin/src/views/FormView.vue + - admin/src/components/form/fields/MLTextField.vue + - admin/src/components/form/fields/MLMarkdownField.vue + - admin/src/components/relation/RelationChildModal.vue + - admin/src/components/relation/RelationPickerModal.vue + - admin/tests/form/MLFields.test.ts + - admin/tests/form/formState.test.ts + - admin/openapi/admin.json + - admin/src/api/schema.d.ts + - modules/boardwalk/dist/ + - ../sm-translate-plugin/classes/admin_writer.go + +key-decisions: + - "writer-exact: add TranslatedExact to cabana.TranslationWriter; AdminWriter delegates to classes.TranslatedExact" + - "hydrateMLRecord runs after projectFullRecord on Show/save only; list rows stay host scalars" + - "FORM_ENABLED_LOCALES is SPA-only; docs name cabana identifiers EnabledLocales, TranslatedExact, hydrateMLRecord" + +patterns-established: + - "Exact admin reads go through TranslationWriter.TranslatedExact on the same Lookup as WriteTranslated; cabana never imports sm-translate-plugin" + - "Create seeds {code: \"\"} for every enabled locale; adopt overlays localeRecord and places a host string on the default locale without dropping siblings" + +requirements-completed: [D-06, D-17] + +coverage: + - id: D1 + description: "Show/save RecordResult.Data for declared mltext/mlmarkdown is a locale map; missing pl is empty, not D-11 English; host column stays the default scalar" + requirement: D-17 + verification: + - kind: unit + ref: "modules/cabana#TestMLHydration" + status: pass + - kind: unit + ref: "modules/cabana#TestMLNestedSave" + status: pass + human_judgment: false + - id: D2 + description: "Create seeds empty maps for every enabled locale; FormView.adopt merges a GET host string without dropping sibling keys; MLTextField options equal FORM_ENABLED_LOCALES" + requirement: D-06 + verification: + - kind: automated_ui + ref: "admin/tests/form/MLFields.test.ts" + status: pass + - kind: unit + ref: "admin/tests/form/formState.test.ts" + status: pass + human_judgment: false + - id: D3 + description: "MLMarkdownField and RelationChildModal share the inject/seed/adopt path; OpenAPI FormMeta.enabledLocales, docs, and boardwalk dist stay in sync" + requirement: D-06 + verification: + - kind: automated_ui + ref: "admin/tests/form/MLFields.test.ts" + status: pass + - kind: other + ref: "bash scripts/check-admin-openapi.sh --check" + status: pass + - kind: other + ref: "go test ./cmd/summer -run TestDocsTree" + status: pass + - kind: unit + ref: "sm-translate-plugin/classes#TestTranslatableGetSet" + status: pass + human_judgment: false + +duration: 11min +completed: 2026-10-06 +status: complete +--- + +# Phase 14.2.1 Plan 05: Hydrate enabled locales on admin ML forms Summary + +**Admin ML create/GET/save hydrates every enabled locale through `TranslationWriter.TranslatedExact` so the SPA lists en+pl together and posts full locale maps (CR-01)** + +## Performance + +- **Duration:** 11 min +- **Started:** 2026-10-06T13:32:15Z +- **Completed:** 2026-10-06T13:43:26Z +- **Tasks:** 3 +- **Files modified:** 24 + +## Accomplishments + +- Task 1 locked **writer-exact**: `TranslatedExact` is a required method on `cabana.TranslationWriter`. Cabana does not import the plugin. `classes.TranslatedExact` still skips D-11 fallback. +- Show/save record payloads expand declared `mltext`/`mlmarkdown` fields to `{locale: value}` via `hydrateMLRecord`. Default locale comes from the host column; other codes come from exact stored values; missing non-default codes are empty strings. List rows stay scalars. +- Protect()'d `formSchema` and `relationSchema` copy `TranslationWriter.EnabledLocales` onto `FormMeta.enabledLocales`. Create seeds `{en: "", pl: ""}`. `FormView` / `RelationChildModal` adopt merges maps so a host string cannot wipe sibling locales. ML selectors read `FORM_ENABLED_LOCALES`. +- OpenAPI, `schema.d.ts`, cabana README, forms/admin-controllers docs, and `modules/boardwalk/dist/` regenerated. WR-02 `fillChild` is unchanged (Plan 06). + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Confirm TranslationWriter.TranslatedExact as the hydration contract** — decision `writer-exact` (no code commit) +2. **Task 2: Hydrate one mltext create/GET/save path and show en+pl on the SPA** + - `0f8d137` (feat) summercms.go — hydrate ML create/GET/save through TranslatedExact + - `11ac328` (feat) sm-translate-plugin — AdminWriter.TranslatedExact delegates to classes.TranslatedExact +3. **Task 3: Cover mlmarkdown, relation-child adopt, and regenerate docs/OpenAPI/TS/dist** + - `424fe9c` (feat) summercms.go — mlmarkdown, child adopt, docs/OpenAPI/dist + +**Plan metadata:** this SUMMARY commit + +Nothing was pushed. Dist replacement deleted `modules/boardwalk/dist/assets/index-CT96jdWe.js` and added `index-B08bxLq5.js` (intentional Vite hash). + +## Files Created/Modified + +- `modules/cabana/schema_types.go` — `FormMeta.EnabledLocales` (`json:"enabledLocales,omitempty"`) +- `modules/cabana/field_ml.go` — `TranslationWriter.TranslatedExact`, `hydrateMLRecord`, recordingWriter exact reads +- `modules/cabana/crud.go` — hydrate after `projectFullRecord` on Show and save +- `modules/cabana/http.go` — form/relation schema Lookup copies enabled locales onto envelope meta +- `modules/cabana/ml_test.go` — `TestMLHydration`; `TestMLNestedSave` projected title is the hydrated map +- `modules/cabana/ml_smoke_test.go` — nested-save smoke expects the hydrated title map +- `admin/src/components/form/formContext.ts` — `FORM_ENABLED_LOCALES` +- `admin/src/components/form/formState.ts` — `initialValues(fields, enabledLocales)`, `mergeMLValue` +- `admin/src/views/FormView.vue` — provide inject; create seed; adopt merge +- `admin/src/components/form/fields/MLTextField.vue` / `MLMarkdownField.vue` — selector options from inject +- `admin/src/components/relation/RelationChildModal.vue` — re-provide inject; seed and adopt merge +- `admin/src/components/relation/RelationPickerModal.vue` — pivot `initialValues(..., [])` +- `admin/tests/form/MLFields.test.ts` — create-empty and GET-string merge for mltext and mlmarkdown +- `admin/tests/form/formState.test.ts` — seed maps and merge helper +- `admin/openapi/admin.json`, `admin/src/api/schema.d.ts` — `enabledLocales?: string[]` +- `modules/boardwalk/dist/` — Vite build matching the SPA change +- `modules/cabana/README.md`, `docs/backend/forms.md`, `docs/backend/admin-controllers.md` — hydration contract +- `../sm-translate-plugin/classes/admin_writer.go` — `AdminWriter.TranslatedExact` + +## Decisions Made + +- **writer-exact** (Task 1, user-selected): add `TranslatedExact` to the published `cabana.TranslationWriter` interface; `AdminWriter` delegates to `classes.TranslatedExact`. Rejected optional-reader (hydration would silently no-op) and import-plugin (cabana must not import sm-translate-plugin). +- Hydration is Show/save only; `Localize` stays cache/no-DB; list Meta stays locale-only. +- `FORM_ENABLED_LOCALES` is documented as SPA-only so the docs identifier checker does not treat it as a Go ident. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Vitest `--run` path vs include glob** +- **Found during:** Task 2 verify +- **Issue:** `npm --prefix admin test -- --run admin/tests/form/MLFields.test.ts` finds no files because Vitest include is `tests/**` under `admin/`. +- **Fix:** Ran `tests/form/MLFields.test.ts` (and the same relative paths in Task 3). Same pattern as 14.2.1-04. +- **Files modified:** none (verify command only) +- **Verification:** Task 2 then Task 3 Vitest PASS +- **Committed in:** n/a + +**2. [Rule 1 - Bug] vue-tsc rejected MLFields mount props** +- **Found during:** Task 3 `npm --prefix admin run typecheck` +- **Issue:** `mlMount` passed `Record` into Vue `props` (TS2322). +- **Fix:** Cast mount props `as never`. +- **Files modified:** `admin/tests/form/MLFields.test.ts` +- **Verification:** `npm --prefix admin run typecheck` PASS +- **Committed in:** `424fe9c` + +--- + +**Total deviations:** 2 auto-fixed (1 blocking verify path, 1 typecheck) +**Impact on plan:** Required for green Task 2/3 gates. No scope creep. `fillChild` untouched. No gormigrate file. No npm pin change (T-14.2.1-SC). + +## Issues Encountered + +- Task 3 combined gate used the Vitest relative paths above; plugin `TestTranslatableGetSet` still PASS after `AdminWriter.TranslatedExact`. +- Unrelated dirty `.planning/` files from other sessions were left unstaged. +- `requirements.mark-complete D-06 D-17` was a no-op: those IDs are CONTEXT.md decisions, not rows in REQUIREMENTS.md (`not_found`). They remain recorded on this SUMMARY's `requirements-completed`. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +CR-01 is closed on the admin form path (D-06, D-17). Plan 06 still owns WR-02 (`fillChild` must lift nested ML maps on relation-child saves) and named tests last. Journal (Phase 15) can keep translatable fields once WR-02 lands. + +--- +*Phase: 14.2.1-translate-plugin* +*Completed: 2026-10-06* + +## Self-Check: PASSED