docs: capture exploration — plugin-layout-winter-directories
This commit is contained in:
58
.planning/notes/plugin-layout-winter-directories.md
Normal file
58
.planning/notes/plugin-layout-winter-directories.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
title: Plugin file layout — WinterCMS directories as Go subpackages, models is a leaf
|
||||||
|
date: 2026-09-18
|
||||||
|
context: /gsd-explore during Phase 4 discussion (scaffold stub layout question); binds every plugin port (golem15, jz, pxpx)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Plugin file layout
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
A Go plugin mirrors the WinterCMS plugin directory layout. Each PHP directory becomes a Go package (or an embedded asset directory) under the plugin module root:
|
||||||
|
|
||||||
|
| WinterCMS | Go plugin | Kind |
|
||||||
|
|-----------|-----------|------|
|
||||||
|
| `Plugin.php` | `plugin.go` (root package) | registration; imports the leaves |
|
||||||
|
| `routes.php` | `routes.go` (root package) | `surf` group builder |
|
||||||
|
| `models/` | `models/` | package, **leaf** (see rule) |
|
||||||
|
| `classes/` | `classes/` | package, services, hooks, casts that need services |
|
||||||
|
| `controllers/` | `controllers/` | package, HTTP handlers and admin controllers |
|
||||||
|
| `console/` | `console/` | package, `bonfire.Command` implementations |
|
||||||
|
| `jobs/` | `jobs/` | package, framework Job interface (River from Phase 11) |
|
||||||
|
| `middleware/` | `middleware/` | package, named middleware |
|
||||||
|
| `updates/` | `updates/` | package, the plugin's gormigrate set |
|
||||||
|
| `lang/<locale>/*.yaml` | `lang/<locale>/*.yaml` | embedded assets (`HasLang`) |
|
||||||
|
| `views/mail/` | `views/mail/` | embedded assets (`HasMailTemplates`) |
|
||||||
|
| `config/` | `config/` | embedded assets (`HasConfig`) |
|
||||||
|
|
||||||
|
Chosen because conversion is mostly done by agents across many plugins: `models/Album.php` → `models/album.go` is a mechanical move and the agent's mental map of the plugin stays 1:1 with the PHP source. The alternative (flat single package, which the Phase 3 `fonoteka.go` plugins use) removes all intra-plugin imports but breaks the directory correspondence that conversion leans on.
|
||||||
|
|
||||||
|
## The rule: `models/` is a leaf package
|
||||||
|
|
||||||
|
`models/` never imports a sibling package of its own plugin. Consequences for the converter:
|
||||||
|
|
||||||
|
- **Casts move into `models/`.** PHP files `classes/casts/*` (e.g. Fonoteka `MarketPriceCast`) are model concerns filed elsewhere; in Go they live in `models/` (or in the framework `lagoon` when generic).
|
||||||
|
- **Service-calling lifecycle hooks move out.** A PHP model hook that reaches into `classes/` (e.g. `Album::beforeSave` using `ArtistResolver`) becomes a GORM callback registered on the model from `classes/` or `plugin.go` — the same callback-registry mechanism Phase 5 uses for cross-plugin model extension. One pattern for both intra- and cross-plugin hooks.
|
||||||
|
- Hooks that only touch the model itself (slug generation, timestamps) stay as methods on the model.
|
||||||
|
|
||||||
|
The rule is enforced by tooling, not documentation: `summer build` (or a framework `go test`) fails when a plugin's `models/` package imports another package of the same plugin module.
|
||||||
|
|
||||||
|
## Evidence (Fonoteka PHP plugin, 2026-09-18)
|
||||||
|
|
||||||
|
Cross-directory `use` edges in `plugins/golem15/fonoteka`:
|
||||||
|
|
||||||
|
- `classes/` → `models/`: 40 files
|
||||||
|
- `models/` → `classes/`: **1** (`models/Album.php`: `Classes\ArtistResolver`, `Classes\Casts\MarketPriceCast`)
|
||||||
|
- `models/` → `controllers/`: 0; `classes/` → `controllers/`: 0
|
||||||
|
- `jobs/`, `console/`, `middleware/` → `classes/`: 5; `traits/` → `models/`: 2
|
||||||
|
|
||||||
|
So the only cycle in the directory graph is `models ↔ classes`, caused by one file, in exactly the two categories the rule addresses (a cast and a service-calling hook). Everything else is already a DAG: `models ← classes ← jobs/console/middleware/controllers ← plugin.go`.
|
||||||
|
|
||||||
|
## Trade-off accepted
|
||||||
|
|
||||||
|
A converted model no longer shows its whole lifecycle in one file: `models/album.go` plus `classes/album_hooks.go` together replace `Album.php`. This is the price of the rule being mechanical and checkable before compile.
|
||||||
|
|
||||||
|
## Open
|
||||||
|
|
||||||
|
- The Phase 3 `fonoteka.go` plugins (`golem15.user`, `golem15.fonoteka`) are flat. They are restructured into this layout when Phase 5 widens them, not in Phase 4 (Phase 4 writes only to `summercms.go`).
|
||||||
|
- Validate the rule on a second and third plugin (keios.eu stack plugins, a jz/pxpx plugin) before the bulk port — see todo `verify-models-leaf-rule`.
|
||||||
19
.planning/todos/pending/verify-models-leaf-rule.md
Normal file
19
.planning/todos/pending/verify-models-leaf-rule.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
title: Verify the models-leaf layout rule against keios.eu and a jz/pxpx plugin before Phase 5
|
||||||
|
date: 2026-09-18
|
||||||
|
priority: medium
|
||||||
|
area: plugin layout / conversion
|
||||||
|
---
|
||||||
|
|
||||||
|
Before the bulk model port (Phase 5) and before any second-project port, repeat the dependency probe done for Fonoteka on 2026-09-18 (see `.planning/notes/plugin-layout-winter-directories.md`) on at least:
|
||||||
|
|
||||||
|
- one keios.eu stack plugin with models and services (`/media/nvme/dev/golem15/keios.eu/plugins/golem15/user` or `paymentgateway`)
|
||||||
|
- one jz project plugin
|
||||||
|
- one pxpx project plugin
|
||||||
|
|
||||||
|
For each, count `models/ → classes/` (and `models/ → any sibling dir`) `use` edges and classify them as cast / service-calling hook / other. The rule holds if every edge falls into "cast moves into models" or "hook becomes a callback registered from classes/plugin.go". Any "other" category means the rule (or the note) needs amending before agents apply it at scale.
|
||||||
|
|
||||||
|
```
|
||||||
|
grep -rl "Vendor\\\\Plugin\\\\Classes" plugins/vendor/plugin/models | wc -l
|
||||||
|
grep -rn "Vendor\\\\Plugin\\\\Classes" plugins/vendor/plugin/models
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user