docs(15-02): complete journal admin YAML and import/export plan

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-06 18:49:08 +02:00
parent 8d7979f87e
commit 685837a3c8

View File

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