Files
summercms/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-DISCUSSION-LOG.md
2026-09-18 02:14:25 +02:00

7.7 KiB

Phase 4: CLI scaffolding, i18n and mail - Discussion Log

Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

Date: 2026-09-17 / 2026-09-18 Phase: 04-cli-scaffolding-i18n-and-mail Areas discussed: Lang file & plural syntax, Mail template format, Scaffold stub behavior, Mail drivers & test send


Lang file & plural syntax

Plural message form

Option Description Selected
CLDR category map {one, few, many, other} YAML map; 1:1 onto go-i18n; covers Polish's 4th category
Laravel pipe strings ":count wpis|:count wpisy|:count wpisów" plus {0}/[2,*] ranges, per summer-phrasebook
Both accepted Map = CLDR categories; string with | = Laravel-style ✓

Notes: Fonoteka PHP lang files contain no pipe plurals; the pipe form is for line-by-line ports of other WinterCMS plugins.

Parameter placeholders

Option Description Selected
:name WinterCMS/Laravel style with :Name/:NAME variants; phrasebook substitutes, go-i18n only selects plural category ✓
{{.Name}} go-i18n native Every ported string rewritten
You decide

Missing key

Option Description Selected
Fallback chain, then raw key requested → parent → fallback → key string; logged once in dev/test ✓
Fallback chain, then error (string, error) or panic in dev
You decide

Default locale

Option Description Selected
Config-driven, en default app.locale / app.fallback_locale, framework default en ✓
Config-driven, pl default
You decide

Mail template format

File shape

Option Description Selected
YAML front matter + body --- header parsed with goccy/go-yaml
Keep WinterCMS INI + == Exactly the PHP file shape; small hand-written header parser ✓
Go registration + body-only files Subject/layout declared in Go

Body format

Option Description Selected
Markdown, add a renderer html/template for vars, then Markdown → HTML; raw Markdown is the text part; one new dependency (goldmark expected) ✓
Plain HTML only Zero new deps; six templates hand-converted; no text part
HTML now, Markdown later Body-renderer seam, decide at Phase 12/13

Per-locale suffix

Option Description Selected
Suffix lookup with fallback postcard tries name-<locale> then name
Caller picks the full name Exactly like PHP; no locale logic in postcard ✓
You decide

Layouts

Option Description Selected
Registered by short name, HTML + text Mirrors registerMailLayouts and the three-section PHP layout; framework ships default ✓
HTML wrapper only Drops the text section
You decide

Scaffold stub behavior

Wiring

Option Description Selected
Auto-wire via generated registry file Per-plugin registry.gen.go; plugin.go never rewritten ✓
Edit plugin.go in place go/ast insertion
Write file, print the line to add

make:model output

Option Description Selected
Model + migration, flag to skip --no-migration ✓
Model only
Model + migration + fields.yaml/columns.yaml No consumer until Phase 9

make:admin-controller before Phase 9

Option Description Selected
Minimal interface + placeholder YAML Tiny pact interface, WinterCMS-shaped YAML placeholders ✓
Go stub only, no YAML
You decide

Stub templates

Option Description Selected
Embedded text/template .tmpl files internal/build/stubs, go/format, compile test in examples/hello ✓
Keep Go string builders
You decide

make:job before River

Option Description Selected
Framework job interface, River-shaped Kind() on args, Work(ctx, args) error; no River import ✓
Import River now River enters go.mod six phases early
You decide

File layout inside a plugin

Option Description Selected
Flat, one package, name suffixes fonoteka.go Phase 3 style; no intra-plugin imports
WinterCMS-style subpackages models/, controllers/, console/, jobs/, updates/ as packages ✓ (via /gsd-explore)
Flat Go, WinterCMS dirs for non-Go assets

User's choice: Deferred to /gsd-explore ("This is a difficult one"), then decided: WinterCMS-style subpackages because agents converting golem15/jz/pxpx plugins lean on the PHP directory, not the class graph. Added rule: models/ is a leaf package (user agreed "first option seems the best"), casts move in, service-calling hooks become callbacks from classes//plugin.go, enforced by summer build. Evidence: Fonoteka has 40 classes→models edges and exactly 1 models→classes edge (a cast and a hook in Album.php). Recorded in .planning/notes/plugin-layout-winter-directories.md.

Coexistence with hand-written plugins

Option Description Selected
Opt-in, merged by plugin.go Hand-written plugins call generated accessors; fonoteka.go untouched ✓
Migrate existing plugins in this phase Touches fonoteka.go, out of phase scope
You decide

Argument shape

Option Description Selected
make:model <vendor.plugin> <Name> Plugin ID inferred from plugin.go when inside a plugin dir ✓
Always explicit, no inference
You decide

Mail drivers & test send

Drivers

Option Description Selected
smtp + log + memory go-mail, logger, in-memory slice ✓
smtp + memory only
smtp only

Test send

Option Description Selected
Unit test + SMTP integration test memory driver unit test plus Mailpit container test gated like testcontainers Postgres ✓
Unit test with memory driver only
summer mail:test command Manual verification

Send API

Option Description Selected
Mailer service on the container postcard.Mailer.Send(ctx, Message{Template, To, Vars}) ✓
Typed message per template
You decide

Failures

Option Description Selected
Error returned, unknown template fails at boot Consistent with Phase 1 D-10 ✓
Error returned, lazy template check
You decide

Claude's Discretion

  • phrasebook API surface, aliases/overrides, request-context seam for Phase 7
  • Markdown renderer pick (research) and escaping of substituted values
  • registry.gen.go naming and accessor names; how the models-leaf check locates packages
  • What make:plugin scaffolds beyond Phase 1's minimum in the new layout
  • make:command naming under the plugin's colon prefix
  • Mailpit image and API access
  • Plan count and split

Deferred Ideas

  • Restructure Phase 3 fonoteka.go plugins into the directory layout — Phase 5
  • Validate the models-leaf rule on keios.eu / jz / pxpx plugins — todo verify-models-leaf-rule
  • summer mail:test production smoke command
  • Attachments on postcard.Message