From 685837a3c8e23c2f05e2b367f42bd8d53e9b432b Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Tue, 6 Oct 2026 18:49:08 +0200 Subject: [PATCH] docs(15-02): complete journal admin YAML and import/export plan Co-authored-by: Cursor --- .../phases/15-journal-plugin/15-02-SUMMARY.md | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 .planning/phases/15-journal-plugin/15-02-SUMMARY.md diff --git a/.planning/phases/15-journal-plugin/15-02-SUMMARY.md b/.planning/phases/15-journal-plugin/15-02-SUMMARY.md new file mode 100644 index 0000000..8354a00 --- /dev/null +++ b/.planning/phases/15-journal-plugin/15-02-SUMMARY.md @@ -0,0 +1,223 @@ +--- +phase: 15-journal-plugin +plan: 02 +subsystem: plugins +tags: [journal, cabana, mlmarkdown, goldmark, bonfire, admin, import-export] + +requires: + - phase: 15-01 + provides: "sm-journal-plugin ID golem15.journal Requires golem15.translate, squashed golem15_journal_* schema, host gitlink + TestBootUserTranslateJournal" +provides: + - "Posts/Categories/Tags YAML admin with mltext/mlmarkdown and FormatHTML on save" + - "HasPermissions/HasNavigation/HasSettings; journal-icon.svg embedded in AdminFS" + - "journal:export-posts and journal:import-posts plus Posts toolbar access_import_export" +affects: [15-03, 15-04, 16] + +actuals: + tokens: 22500 + tasks: 3 + commits: 6 +plan_head_before: 8d7979f87e33fec150ff1c2eb9e518e8bd6f837b +plugin_repo_head_after: 4ff98f7de85a6404987373ad5630b17fc5542ade +host_repo_head_after: d09583ef2825e5fa73b7d5e4cca953834a018c6e + +tech-stack: + added: ["github.com/yuin/goldmark v1.8.6 (plugin FormatHTML)"] + patterns: + - "Admin YAML embed file-by-file; NavigationItem has no IconSvg so journal-icon.svg is go:embed in AdminFS" + - "preset is valid only on type: text; post/category mltext slugs omit preset" + - "PHP journal:export-posts/import-posts are JSON-per-slug files, not Winter CSV; toolbar HasAdminActions names are not create/delete" + - "Host gitlink is a nested clone; bump via file:// fetch with protocol.file.allow=always" + +key-files: + created: + - ../sm-journal-plugin/admin.go + - ../sm-journal-plugin/admin_permissions.go + - ../sm-journal-plugin/admin_navigation.go + - ../sm-journal-plugin/assets/images/journal-icon.svg + - ../sm-journal-plugin/classes/format_html.go + - ../sm-journal-plugin/controllers/posts.go + - ../sm-journal-plugin/controllers/categories.go + - ../sm-journal-plugin/controllers/tags.go + - ../sm-journal-plugin/console/export_posts.go + - ../sm-journal-plugin/console/import_posts.go + - ../sm-journal-plugin/console/columns.go + - ../sm-journal-plugin/posts_admin_smoke_test.go + modified: + - ../sm-journal-plugin/plugin.go + - ../sm-journal-plugin/models/post.go + - ../sm-journal-plugin/models/post/fields.yaml + - ../sm-journal-plugin/README.md + - ../sm-grzybyfunkcjonalne-app/boot_test.go + - ../sm-grzybyfunkcjonalne-app/plugins/golem15/journal + +key-decisions: + - "D-11 is a no-op: post content is mlmarkdown; cabana.RenderMarkdown is not edited; FormatHTML lives in the plugin with goldmark Footnote+Table+WithAttribute plus rejectUnsafe" + - "user_id is WritableForeignKey; FormBeforeCreate stamps it when empty; without access_other_posts List/FormExtendQuery restrict to principal user_id (fail-closed)" + - "publish without access_publish returns ForbiddenError; toolbar import uses the same guard" + - "CLI is JSON files per slug (--path, --dry-run, --force) matching PHP ExportPosts/ImportPosts; PostExport/PostImport column names are the shared field list, not a CSV framework" + - "Toolbar extra buttons exportPosts/importPosts require golem15.journal.access_import_export; names are not create or delete" + +patterns-established: + - "Compiled journal admin: HasAdminControllers + file-by-file YAML embed + SVG in AdminFS" + - "FilterCategories expands NestedTree children via nest_left/nest_right; switch published uses column: published" + - "HasCommands registers PHP command names; HasAdminActions toolbar reuses console.ExportToDir/ImportFromDir" + +requirements-completed: [D-04, D-06, D-08, D-10, D-11, D-13] + +coverage: + - id: D1 + description: "Posts admin YAML with mltext/mlmarkdown, FormatHTML on save, nav SVG embed, access_posts and author/publish guards" + requirement: D-04 + verification: + - kind: integration + ref: "../sm-journal-plugin#TestPostsFormCompiles" + status: pass + - kind: integration + ref: "../sm-journal-plugin#TestPostsAdminCreateSmoke" + status: pass + human_judgment: false + - id: D2 + description: "Categories, Tags, and settings singleton registered; host cabana.Activate sees golem15.journal.posts|categories|tags and settings code journal" + requirement: D-04 + verification: + - kind: integration + ref: "../sm-grzybyfunkcjonalne-app#TestBootUserTranslateJournal" + status: pass + human_judgment: false + - id: D3 + description: "journal:export-posts and journal:import-posts registered; Posts toolbar exportPosts/importPosts require golem15.journal.access_import_export" + requirement: D-13 + verification: + - kind: unit + ref: "../sm-journal-plugin#TestJournalCommands" + status: pass + human_judgment: false + - id: D4 + description: "Post content YAML type is mlmarkdown; title/slug/excerpt are mltext; cabana markdown types were not re-added" + requirement: D-10 + verification: + - kind: other + ref: "../sm-journal-plugin/models/post/fields.yaml" + status: pass + human_judgment: false + - id: D5 + description: "No Winter.Pages menu types and no dashboard widget in plugin.go or admin_navigation.go; README stays application-neutral" + requirement: D-13 + verification: + - kind: other + ref: "../sm-journal-plugin/plugin.go" + status: pass + human_judgment: false + +duration: 75min +completed: 2026-10-06 +status: complete +--- + +# Phase 15: Journal plugin plan 02 Summary + +**YAML-driven Posts/Categories/Tags admin with plugin FormatHTML, plus JSON journal:export-posts/import-posts and a permissioned Posts toolbar** + +## Performance + +- **Duration:** 75 min +- **Started:** 2026-10-06T15:30:00Z +- **Completed:** 2026-10-06T16:48:34Z +- **Tasks:** 3 +- **Files modified:** 39 + +## Accomplishments +- Posts, Categories, and Tags admin controllers boot from adapted YAML (`mltext`/`mlmarkdown`); nav embeds `assets/images/journal-icon.svg` +- `classes.FormatHTML` regenerates `content_html` on admin save (goldmark footnote/table/attribute + rejectUnsafe) without editing `cabana.RenderMarkdown` +- Without `access_other_posts`, list/form queries restrict to the backend principal; publish without `access_publish` returns `ForbiddenError` +- `journal:export-posts` / `journal:import-posts` match PHP JSON-per-slug CLI flags; Posts toolbar `exportPosts`/`importPosts` require `golem15.journal.access_import_export` +- Proof host `TestBootUserTranslateJournal` still activates user+translate+journal after the gitlink bump to `4ff98f7` + +## Task Commits + +Each task was committed atomically in the owning repo: + +1. **Task 1: Posts admin + mlmarkdown + FormatHTML** - `dea0934950a290b98feb3dbe66c5b066a5c8b0a9` (feat) sm-journal-plugin +2. **Task 2: Categories, Tags, Settings + query guards** + - `afd0a2cafcc62fcfb13359530147ae798349cfa1` (feat) sm-journal-plugin + - `ab0656964103aef4bc91553818447981e9c91b1d` (fix) gofmt settings.go + - `469182d4103343fd1cd6f71b88668e0c658c0dfc` (feat) host gitlink + boot_test controller/settings assertions +3. **Task 3: export/import commands + Posts toolbar** + - `4ff98f7de85a6404987373ad5630b17fc5542ade` (feat) sm-journal-plugin + - `d09583ef2825e5fa73b7d5e4cca953834a018c6e` (chore) host gitlink `4ff98f7` + +**Plan metadata:** (this commit) + +## Files Created/Modified +- `../sm-journal-plugin/controllers/posts.go` - Posts controller, query guards, FormatHTML hook, HasAdminActions +- `../sm-journal-plugin/classes/format_html.go` - plugin markdown HTML (not cabana.RenderMarkdown) +- `../sm-journal-plugin/models/post/fields.yaml` - mltext title/slug/excerpt, mlmarkdown content +- `../sm-journal-plugin/console/export_posts.go` - `journal:export-posts` +- `../sm-journal-plugin/console/import_posts.go` - `journal:import-posts` +- `../sm-journal-plugin/README.md` - CLI command names with acme/blog examples +- `../sm-grzybyfunkcjonalne-app/plugins/golem15/journal` - gitlink `4ff98f7` + +## Decisions Made +- D-11 no-op: keep existing cabana `mlmarkdown`; FormatHTML is plugin-local goldmark with footnote/table/attribute plus the same rejectUnsafe gate +- `preset` omitted on mltext slugs (cabana allows preset only on `type: text`); tag slug stays `type: text` with preset +- PHP CLI is JSON files, not Winter CSV; shared column sets are `ExportColumns`/`ImportColumns`; `--force` is included because PHP ImportPosts has it +- Toolbar import refuses published writes without `access_publish` (CLI has no principal) +- Navigation SVG is go:embed; `NavigationItem` has no IconSvg field + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] preset on mltext fails schema compile** +- **Found during:** Task 1 (YAML compile) +- **Issue:** cabana accepts `preset` only on `type: text`; PHP post/category slugs are mltext +- **Fix:** Drop preset on post and category slugs; keep it on tag slug (`type: text`) +- **Files modified:** `../sm-journal-plugin/models/post/fields.yaml`, `models/category/fields.yaml` +- **Verification:** `TestPostsFormCompiles` PASS +- **Committed in:** `dea0934` (Task 1) + +**2. [Rule 3 - Blocking] nav cannot name unknown controllers** +- **Found during:** Task 1 (`cabana.Activate`) +- **Issue:** Task 1 nav listing categories/tags fails boot until those controllers exist +- **Fix:** Defer categories/tags side-menu entries to Task 2 +- **Files modified:** `../sm-journal-plugin/admin_navigation.go` +- **Verification:** Task 1 smoke PASS; Task 2 `TestBootUserTranslateJournal` PASS +- **Committed in:** `dea0934` / `afd0a2c` + +**3. [Rule 3 - Blocking] goldmark must be a direct plugin require** +- **Found during:** Task 1 (`go get` / FormatHTML import) +- **Issue:** FormatHTML imports goldmark; tidy via HTTPS could not resolve sm-translate-plugin without go.work +- **Fix:** Direct-require goldmark v1.8.6 (and gocloud.dev already used by admin smokes); run vet/test with `GOWORK=plugin/go.work` +- **Files modified:** `../sm-journal-plugin/go.mod` +- **Verification:** `go vet ./...` PASS +- **Committed in:** `dea0934` (Task 1) + +**4. [gofmt] settings.go left unstaged after Task 2 commit** +- **Found during:** Task 2 (post-commit `git status`) +- **Issue:** gofmt rewrote `models/settings.go` after the feat commit; amend is disallowed +- **Fix:** Separate fix commit +- **Files modified:** `../sm-journal-plugin/models/settings.go` +- **Verification:** `gofmt` clean +- **Committed in:** `ab06569` (Task 2 fix) + +--- + +**Total deviations:** 4 auto-fixed (3 blocking compile/boot, 1 gofmt follow-up) +**Impact on plan:** Required for cabana schema boot and FormatHTML. No scope creep. CLI is JSON (PHP) rather than inventing CSV. + +## Issues Encountered +- Plan verify `go test ./... -run '^(TestJournalCommands)$'` (and Task 1 `TestPosts*`) prints `[no tests to run]` / `[no test files]` for `models`, `updates`, `classes`, `console`, `controllers`. Named tests still `--- PASS`. Same leaf-package shape as 15-01; stubs were not added. +- Host `go test` must run with `GOWORK` unset so it does not inherit the plugin workspace +- Nested host gitlink is a separate clone from sibling `sm-journal-plugin`; bump with `git -c protocol.file.allow=always fetch file://…` +- Journal remote still has no refs; gitlink records local SHA `4ff98f7`. Do not push unless asked + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +Ready for 15-03 (`/_journal/api/v1`, buckets, backend Bearer writes, media, Typesense gate off). Admin screens and import/export CLI are in. Pages menu types and dashboard widgets remain absent by design. + +--- +*Phase: 15-journal-plugin* +*Completed: 2026-10-06*