From 4e05450f465c16a6a3c40b252bcdf612e091c390 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Wed, 30 Sep 2026 23:41:26 +0200 Subject: [PATCH] docs(11.1-05): log the scaffolder gaps found while porting the walkthrough - same-second migrations sort by name and can run out of order - make:admin-controller output does not boot and names the model after the controller - the DO NOT EDIT header on editable files, and commands that cannot reach the application --- .../scaffold-admin-controller-incomplete.md | 17 +++++++++++++++++ ...caffold-generated-header-and-command-deps.md | 15 +++++++++++++++ .../scaffold-same-second-migration-order.md | 12 ++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 .planning/todos/pending/scaffold-admin-controller-incomplete.md create mode 100644 .planning/todos/pending/scaffold-generated-header-and-command-deps.md create mode 100644 .planning/todos/pending/scaffold-same-second-migration-order.md diff --git a/.planning/todos/pending/scaffold-admin-controller-incomplete.md b/.planning/todos/pending/scaffold-admin-controller-incomplete.md new file mode 100644 index 0000000..0a24e48 --- /dev/null +++ b/.planning/todos/pending/scaffold-admin-controller-incomplete.md @@ -0,0 +1,17 @@ +--- +title: make:admin-controller output does not boot and names the model after the controller +date: 2026-09-30 +priority: medium +area: summercms.go internal/build +--- + +`summer make:admin-controller acme.blog Posts` writes a controller and YAML that compile but are not a working admin screen: + +- `ModelName()` returns `Posts` and both YAML files say `modelClass: Posts`, the controller name, where WinterCMS uses the model (`Post`). `fields.yaml` and `columns.yaml` go under `models/posts/`, the controller's snake name, not the model's. +- The controller implements only `pact.AdminController`. Without `pact.AdminRecordSource` (`NewRecord`) the admin API answers every record route with a capability error, and without `pact.AdminPermissioned` any signed-in administrator can open it (`cabana.Allows` treats an empty list as "any authenticated principal"). +- Neither `make:plugin` nor `make:admin-controller` gives the plugin an `AdminFS` (`pact.AdminAssets`), so once the admin is enabled `cabana.Activate` stops the start-up with "plugin acme.blog has admin controllers but no AdminFS". +- `config_list.yaml` offers only `create`; adding `delete` also needs `showCheckboxes: true`, which cabana enforces. + +Found while writing `docs/setup/porting-a-plugin.md` (Phase 11.1 plan 05). The walkthrough fixes each point by hand and the page lists them under "What the scaffolder leaves to you". + +Suggested fix: give `make:admin-controller` a model argument or flag (defaulting to the singular of the controller name), write `modelClass` and the model's YAML directory from it, generate `NewRecord` and a `RequiredPermissions` stub with `..access_`, and have `make:plugin` embed `controllers/*/*.yaml models/*/*.yaml` and implement `AdminFS` (with a harmless empty tree until the first controller exists). Update `docs/console/scaffolding.md` and the porting page in the same change. `internal/build` is outside the docs phase boundary, so it is not changed in Phase 11.1. diff --git a/.planning/todos/pending/scaffold-generated-header-and-command-deps.md b/.planning/todos/pending/scaffold-generated-header-and-command-deps.md new file mode 100644 index 0000000..ec94781 --- /dev/null +++ b/.planning/todos/pending/scaffold-generated-header-and-command-deps.md @@ -0,0 +1,15 @@ +--- +title: Scaffolded files carry a DO NOT EDIT header, and make:command cannot reach the application +date: 2026-09-30 +priority: medium +area: summercms.go internal/build +--- + +Two scaffolder conventions that the porting walkthrough had to work around: + +1. **The generated-code header on files the developer edits.** Every file a `make:` command writes starts with `// Code generated by summer make. DO NOT EDIT.`, although models, migrations, commands and admin controllers are meant to be edited. `refreshRegistry` (`internal/build/registry.go`, `isGeneratedFile`) only lists files that carry that marker, so a developer who removes the misleading header silently drops the artifact from `registry.gen.go` on the next `make:` run. Linters such as golangci-lint also skip files with that header, so the edited code is never linted. +2. **make:command's function takes no arguments.** The registry scanner accepts only exported, zero-parameter functions returning `bonfire.Command`, so a generated command cannot reach the database, the config or any published service. A command that needs them must take a parameter, which removes it from the generated accessor, and be returned from `Commands` by hand (the walkthrough's `blog:publish` does this with the plugin's `withDB`). + +Found while writing `docs/setup/porting-a-plugin.md` (Phase 11.1 plan 05). The page describes both as they are. + +Suggested fix: use a marker that does not claim the file is generated (for example a `//summer:make ` directive) for editable artifacts, keep the `Code generated ... DO NOT EDIT.` header for `registry.gen.go` only, and accept the old header during a transition. For commands, let the scanner also accept `func(*backpack.App) bonfire.Command` and have `generatedCommands` take the app that `Commands` receives from the plugin (which keeps it from `Boot`). Update `docs/console/scaffolding.md`, `docs/console/writing-commands.md` and the porting page in the same change. `internal/build` is outside the docs phase boundary, so it is not changed in Phase 11.1. diff --git a/.planning/todos/pending/scaffold-same-second-migration-order.md b/.planning/todos/pending/scaffold-same-second-migration-order.md new file mode 100644 index 0000000..e88aeb8 --- /dev/null +++ b/.planning/todos/pending/scaffold-same-second-migration-order.md @@ -0,0 +1,12 @@ +--- +title: make:model and make:migration in the same second produce migrations that run out of order +date: 2026-09-30 +priority: high +area: summercms.go internal/build +--- + +`nextMigrationFile` in `internal/build/artifact.go` names a migration `_` and only moves to the next second when a file with the same full name already exists. Two migrations with different slugs created in the same second share one timestamp, and `refreshRegistry` sorts them by file name. Running `summer make:model acme.news Item` and `summer make:migration acme.news AddFlag` back to back (a probe in a copy of examples/hello, 2026-09-30) wrote `20260930213644_add_flag.go` and `20260930213644_create_acme_news_items.go`, and `registry.gen.go` listed `AddFlag` before `CreateItems`. gormigrate runs the set in slice order, so the ALTER TABLE migration would run before the CREATE TABLE one and fail. + +Found while writing `docs/setup/porting-a-plugin.md` (Phase 11.1 plan 05). The page tells the developer to check `updates/` and rename a clashing file, and `docs/console/scaffolding.md` was corrected: it had said that migrations created in the same second get consecutive timestamps. + +Suggested fix: in `nextMigrationFile`, move to the next second while any file in `updates/` already starts with the candidate timestamp (or with a later one), not only when the same name exists, so every new migration sorts after every existing one. Add a unit test that creates two differently named migrations with a frozen `migrationNow`. Update `docs/console/scaffolding.md` and the porting page's note in the same change (the D-13 docs rule). `internal/build` is outside the docs phase boundary, so it is not changed in Phase 11.1.