diff --git a/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md
new file mode 100644
index 0000000..a82bb6c
--- /dev/null
+++ b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md
@@ -0,0 +1,136 @@
+# Phase 9: Backend admin authentication and schema pipeline - Context
+
+**Gathered:** 2026-09-23
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Phase 9 delivers two things. First, a backend admin identity separate from frontend users: `backend_users` with roles, a permissions registry declared by plugins, an admin login on a second bouncer guard, and gating of both navigation and admin controller access. Second, the schema pipeline: each admin controller's `config_form.yaml`, `config_list.yaml`, `config_filter.yaml` and `config_relation.yaml` (pointing at the model's `fields.yaml` and `columns.yaml`) are parsed with goccy/go-yaml into typed JSON form, list, filter and relation-manager schemas served over a new framework-wide admin API, together with admin CRUD endpoints that expose the Winter extension hooks, bulk delete through lifecycle hooks, and a settings screen bound to a singleton settings model.
+
+Framework code (guard, tables, permissions, navigation, schema parsers, admin API package, `admin:*` commands, scaffold layout change) lands in `summercms.go`. The five Płytarium controllers (Albums, Artists, Collections, Genres, Styles), their YAML, `HasPermissions`, `HasNavigation`, `HasSettings` and the Albums scoping hooks land in `fonoteka.go`. The Vue SPA that renders these schemas is Phase 10 and is out of scope here; this phase's acceptance is the JSON contract plus tests.
+
+Requirements: AUTH-08, ADMIN-01, ADMIN-02, ADMIN-03, ADMIN-04, ADMIN-05. Security-load-bearing: apply the security-review agent to the admin guard, permission enforcement and mass-assignment on admin saves.
+
+
+
+
+## Implementation Decisions
+
+### Admin identity and login
+- **D-01:** Backend admins live in Winter-shaped tables: `backend_users` (login, email, password bcrypt, first_name, last_name, is_activated, is_superuser, role_id, last_login, timestamps, soft delete) and `backend_user_roles` (name, code, description, permissions JSON, is_system). Table and column names match Winter so an existing WinterCMS `backend_users` table can be copied straight in at cutover. `backend_user_groups` is not ported. Role codes `developer` and `publisher` are seeded as system roles, matching `UserRole::CODE_DEVELOPER` / `CODE_PUBLISHER`.
+- **D-02:** Admin sessions are JWTs issued by a second named guard, `backend`, registered in the Phase 6 bouncer registry beside `jwt`. It has its own secret (`admin.jwt.secret`, fail-loud when empty, as Phase 3 did for the user secret) and an audience claim so a frontend token can never authenticate as an admin and vice versa. Mint, verify, TTL config, sliding refresh and the Postgres jti blacklist from Phase 7 are reused; Phase 7's bcrypt helpers hash and check admin passwords. No cookie session store and no new dependency (`alexedwards/scs` is not adopted).
+- **D-03:** Permissions keep Winter semantics. Plugins implement `HasPermissions` returning entries in the `registerPermissions()` shape (code, tab, label, roles). Checks: `is_superuser` passes everything; otherwise the admin's role `permissions` JSON is consulted; a code ending in `.*` matches by prefix, so `golem15.fonoteka.*` on the top navigation item works unchanged. An admin controller declares `RequiredPermissions() []string` and the framework enforces it (403 with the standard error envelope) before any list, form, relation or bulk-delete handler runs.
+- **D-04:** The first admin is created by a framework console command, `summer admin:create --email --password [--login] [--superuser] [--role=code]`, plus `summer admin:reset-password `. Scaffolded the Phase 4 way. No boot-time seed from config and no web setup wizard.
+
+### Schema pipeline shape
+- **D-05:** YAML layout is Winter's, not the Phase 4 scaffold's. `controllers//config_form.yaml` and `config_list.yaml` name the model and point at `models//fields.yaml` and `columns.yaml`; `config_filter.yaml` and `config_relation.yaml` sit beside them when present. The five Płytarium YAML sets are copied across unchanged apart from the one `partial` field (D-15). `summer make:admin-controller` is changed to emit this layout, and `pact.AdminController.ConfigDir()` points at the `controllers//` directory; all config is embedded through the plugin's `fs.FS`.
+- **D-06:** The JSON schema is typed: Go structs per field type and per column type, decoded with goccy/go-yaml `DisallowUnknownField` so an unsupported key or field type fails loudly at boot. JSON keys keep Winter's spelling (`nameFrom`, `emptyOption`, `span`, `tab`, `context`, `attributes`, `recordsPerPage`, `showSearch`, `toolbarButtons`) so the served schema reads like the YAML that produced it. Field types in scope: text, textarea, number, checkbox, switch, dropdown, relation, relation-manager. Column features in scope: searchable, sortable, `relation` + `select`, `type: datetime`, `type: switch`.
+- **D-07:** Labels, comments, tabs, `emptyOption` and navigation labels are resolved server-side through phrasebook in the admin's locale (Accept-Language, then `app.locale`). The SPA receives display strings only. A missing key falls back to the raw key, as phrasebook already does. Every schema endpoint carries the locale it resolved in `meta`.
+- **D-08:** `options: ` on a dropdown maps to an options-provider interface on the model: `DropdownOptions(field string) []Option` where `Option` is value plus label key (resolved per D-07). The pipeline calls it for any dropdown whose `options:` is a string and fails at boot if the model does not implement the interface. A YAML `options:` map is also accepted and served as-is. Album ports `getFormatOptions` this way.
+
+### Admin CRUD API contract
+- **D-09:** The admin API is a framework-wide, consistent layer for every non-parity API, owned by a new framework package and separate from the Phase 6 parity helpers in `fonoteka.go`. Paths: `/_admin/api/v1/{vendor}/{plugin}/{controller}` for records, `/_admin/api/v1/{vendor}/{plugin}/{controller}/schema/{form|list|filter}` and `.../schema/relation/{name}` for schemas, `/_admin/api/v1/auth/{login,refresh,logout,me}`, `/_admin/api/v1/navigation`, `/_admin/api/v1/settings/{code}` and `.../settings/{code}/schema`. Every handler carries swag v1 annotations so the OpenAPI document Phase 10 generates types from is complete by construction.
+- **D-10:** One envelope on every endpoint. Success: `{"data": ..., "meta": {...}}`. Error: `{"error": {"code": "...", "message": "...", "details": {...}}}` with a fixed vocabulary: `unauthenticated` 401, `forbidden` 403, `not_found` 404, `validation_failed` 422 (details is field to messages), `conflict` 409. The group is mounted raw-style under the `backend` guard, so no fonoteka house middleware applies.
+- **D-11:** One list contract for controller lists and relation-manager lists alike: query `search` (across `searchable` columns), `sort` and `dir` (only `sortable` columns, otherwise 422), `page`, `per_page` (default `recordsPerPage`, capped), and `filter[]=...`. Response meta is `{page, per_page, total, last_page}`. Relation columns join the related table and select the named column.
+- **D-12:** Filters come from `config_filter.yaml`, referenced by `filter:` in `config_list.yaml`. Three scope shapes are ported now, because those are the shapes the Golem15 user and journal plugins use: `switch` with two conditions on a named column, `daterange` on a named column, and a model-backed scope (`modelClass`, `nameFrom`, `scope`). Raw SQL `conditions:` strings are not supported: a scope either names a model scope method (`scope: filterByGroup` resolved through a `FilterScope(name string, db *gorm.DB, value any) *gorm.DB` interface on the model) or uses the built-in switch/daterange handling on a declared column. A YAML `conditions:` key is a boot error with a message pointing at this rule. Remaining Winter scope types are deferred.
+- **D-13:** Hooks are optional interfaces on the admin controller, type-asserted by the framework in the same style as pact's `Has*` capabilities: `ListExtendQuery(ctx, *gorm.DB) *gorm.DB`, `FormExtendQuery(ctx, *gorm.DB) *gorm.DB`, `FormBeforeCreate(ctx, model) error`, `FormBeforeUpdate(ctx, model) error`, `RelationExtendManageQuery(ctx, relation string, *gorm.DB) *gorm.DB`, `RelationBeforeLink(ctx, relation string, parent, related, pivot map) error`. The context carries the authenticated admin principal. Bulk delete (`POST .../bulk-delete` with `{ids}`) loads each record through `ListExtendQuery` and deletes it individually so Phase 5 lifecycle hooks and soft-delete cascades fire; it never issues a single `DELETE ... WHERE id IN`.
+- **D-14:** The Albums scoping hooks resolve the admin's active collection exactly as the PHP `BackendAlbumCollectionResolver` does: the backend admin's email, lower-cased and trimmed, must match exactly one frontend user, and that user's active collection (Phase 3 resolver) is used. Zero or two matches return 422 with the PHP messages. `FormBeforeUpdate` rejects a cross-collection update with the `backend::lang.form.not_found` message, as PHP does. No collection picker in the SPA.
+
+### Relation manager and settings
+- **D-15:** `config_relation.yaml` is parsed into a typed relation-manager schema (label, `view.list.columns`, `manage.list.columns`, `toolbarButtons`, `showSearch`) served at the relation schema endpoint. In `fields.yaml` the Collections `editors` entry becomes `type: relation-manager` with `relation: editors`, `tab`, `span: full`, `context: update`; `type: partial` does not exist in Go and is a boot error. Endpoints: `GET /{id}/relations/{name}` (linked, view columns), `GET /{id}/relations/{name}/candidates` (manage columns, search, `RelationExtendManageQuery` applied, so the owner is excluded), `POST .../link` and `POST .../unlink` with `{ids}`.
+- **D-16:** Link writes the pivot through the Phase 5 join-table contract and calls `RelationBeforeLink` so the app stamps pivot columns; for editors that is `role='editor'`, `granted_at=now`, `granted_by=`. Unlink deletes the pivot row. The framework never hardcodes pivot column names.
+- **D-17:** Settings pages are a framework capability: plugins implement `HasSettings` returning entries in the `registerSettings()` shape (code, label, description, category, icon, model, order, keywords, permissions). The model is a singleton-row GORM model with `Fillable()`, `Rules()` and a `models//fields.yaml`; the framework serves that form schema at `/settings/{code}/schema` and `GET`/`PUT /settings/{code}` reads and upserts the single row through `lagoon.Fill` and `lagoon.Validate`. Fonoteka binds its typed `golem15_fonoteka_settings` model (Phase 5) under code `fonoteka` gated by `golem15.fonoteka.manage_settings`.
+- **D-18:** Navigation is declared through `HasNavigation` in the `registerNavigation()` shape (label, icon, permissions, order, `sideMenu`), except that `url` is replaced by `controller` holding the admin controller ID (`golem15.fonoteka.albums`); the SPA derives its route from that ID. `GET /navigation` returns only items the admin's permissions allow (D-03 wildcard rules), with labels resolved (D-07), plus a separate `settings` list built from `HasSettings` entries the admin may manage.
+
+### Claude's Discretion
+- Package name and internal layout of the admin API and schema packages, following the existing beach-themed naming.
+- When YAML is parsed: recommended at boot with fail-loud errors naming plugin, controller and file, cached for the process lifetime.
+- Whether `rules:` keys in `fields.yaml` are honoured in addition to the model's `Rules()`; at minimum `required: true` must produce a 422.
+- Admin login throttling and password policy; reuse Phase 7's throttle shape if cheap, otherwise note as a Phase 10 or later hardening item.
+- Whether soft-deleted rows appear in admin lists (recommended: hidden, matching Winter's default).
+- Whether the settings row is created on first read or first write.
+- Pagination of relation candidates (recommended: same list contract, D-11).
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Roadmap and requirements
+- `.planning/ROADMAP.md` §Phase 9 — goal, success criteria, repos.
+- `.planning/REQUIREMENTS.md` — AUTH-08, ADMIN-01 through ADMIN-05.
+- `.planning/research/ARCHITECTURE.md` §Admin Form Save Flow and the capability-interface listing — the `HasAdminControls`/`HasNavigation`/`HasPermissions` sketch this phase makes real (its `scs` cookie-session suggestion is superseded by D-02).
+- `.planning/research/FEATURES.md` §Admin / forms — field and column feature inventory.
+- `.planning/research/STACK.md` — goccy/go-yaml, swag v1, validator.
+
+### Prior phase decisions this phase builds on
+- `.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-CONTEXT.md` — D-06 guard registry, D-16 raw groups, D-17 response conventions stay app-side.
+- `.planning/phases/07-user-plugin-and-authentication/07-CONTEXT.md` — D-06 to D-10 JWT lifecycle and blacklist, D-19 bcrypt.
+- `.planning/phases/05-data-layer-full-fidelity/05-CONTEXT.md` — Fillable/Hidden discipline, lagoon.Fill and lagoon.Validate, join-table contract, typed Settings table.
+
+### PHP reference (fonoteka, read-only)
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php` — `registerPermissions()`, `registerSettings()`, `registerNavigation()` bodies to port.
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/controllers/{albums,artists,collections,genres,styles}/` — `config_form.yaml`, `config_list.yaml`, Collections' `config_relation.yaml`, and the controller PHP with the hooks.
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/models/{album,artist,collection,genre,style,settings}/fields.yaml` and `columns.yaml` — the YAML the pipeline must parse.
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/models/Album.php` §getFormatOptions — the one model-method dropdown.
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/classes/BackendAlbumCollectionResolver.php` — email mapping for D-14.
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/user/controllers/users/config_filter.yaml` and `/media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/controllers/posts/config_filter.yaml` — the three filter scope shapes D-12 ports.
+- `/media/nvme/dev/golem15/fonoteka/modules/backend/database/migrations/` — Winter's `backend_users` and `backend_user_roles` migrations, the column source for D-01.
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `bouncer.Registry`, `Guard`, `CredentialGuard`, `UnauthorizedWriter` (`bouncer/registry.go`, `bouncer/guard.go`): the `backend` guard registers here under a new name with its own `UserProvider`.
+- `bouncer.NewJWTGuard`, `Mint`, `VerifyClaims`, `NewPostgresBlacklist`, `HashPassword`, `CheckPassword` (`bouncer/jwt.go`, `mint.go`, `password.go`): admin auth reuses them; the guard constructor may need an audience parameter.
+- `pact.AdminController` and `HasAdminControllers` (`pact/capabilities.go:100-112`): the only admin surface today; `HasNavigation` and `HasPermissions` exist as a comment at lines 140-142 and become real interfaces here.
+- `internal/build/artifact.go:230-304` and `internal/build/stubs/artifacts.tmpl`: the `make:admin-controller` generator whose layout D-05 changes.
+- `lagoon.Fill`, `lagoon.Validate`, `lagoon.Paginate`, `RegisterJoinTable` (Phase 5): admin saves, 422s, list meta and pivot writes go through these.
+- `phrasebook` per-locale bundles (Phase 4): label resolution for D-07.
+- `fonoteka.go/scripts/swagger2openapi.go` and `docs/openapi.json`: the swag v1 to OpenAPI 3 path the admin annotations feed.
+- `fonoteka.go/plugins/golem15/fonoteka/models/settings.go`: the typed singleton D-17 binds.
+- `fonoteka.go/plugins/golem15/fonoteka/models/collection.go:22`: the `Editors` many2many already declared.
+
+### Established Patterns
+- Optional capability interfaces type-asserted by the consumer package (pact); D-13, D-17, D-18 follow it.
+- Fail-loud boot on missing secrets and malformed plugin assets (Phase 3 secret, Phase 4 mail catalog validation); D-02, D-06, D-08, D-12 follow it.
+- Framework stays app-agnostic: no Fonoteka table names or pivot columns in `summercms.go` (D-16, D-14 resolver lives in `fonoteka.go`).
+- Parameterized middleware and raw groups in surf (Phase 6 D-05, D-16): the admin group is a raw group under the `backend` guard.
+
+### Integration Points
+- `party.Activate` / surf assembly: where `HasPermissions`, `HasNavigation`, `HasSettings` and `HasAdminControllers` are collected and the admin routes mounted.
+- `bouncer.Registry` shared through `backpack.App` Lookup/Publish as the user plugin does in `plugins/golem15/user/plugin.go:64-97`.
+- `lagoon` migrations: two new framework-owned tables (`backend_users`, `backend_user_roles`) plus their seed of system roles.
+- Phase 10 SPA consumes `/navigation`, the schema endpoints and the list/form/relation endpoints exactly as specified in D-09 to D-11.
+
+
+
+
+## Specific Ideas
+
+- The user explicitly wants this phase to be "our chance to introduce a nice and consistent API layer": the admin API contract in D-09 to D-11 is a framework convention meant to outlive Płytarium, not a one-off for five controllers.
+- Filters must work the Winter way (`config_filter.yaml`), even though Płytarium has none; the user and journal plugins are the reference consumers.
+- Model scope methods instead of SQL strings in YAML were accepted as a deliberate deviation from Winter.
+
+
+
+
+## Deferred Ideas
+
+- Remaining Winter filter scope types (`checkbox`, `dropdown`, `group`, `text`, `number`, `numberrange`, `date`) are added when a ported plugin needs them; the schema types should leave room for them. Note this in the roadmap when the user or journal plugin ports are planned.
+- `backend_user_groups` and Winter's user-preference and access-log tables: not needed by any Golem15 plugin yet.
+- Policy-based row or field-level admin permissions (Directus style) remain a post-v1 differentiator per FEATURES.md.
+- A boot-time admin seed from environment variables for containers, if deployment needs it later.
+- Admin login throttling and password policy hardening if not folded in under Claude's discretion.
+
+
+
+---
+
+*Phase: 09-backend-admin-authentication-and-schema-pipeline*
+*Context gathered: 2026-09-23*
diff --git a/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-DISCUSSION-LOG.md b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-DISCUSSION-LOG.md
new file mode 100644
index 0000000..e420c69
--- /dev/null
+++ b/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-DISCUSSION-LOG.md
@@ -0,0 +1,170 @@
+# Phase 9: Backend admin authentication and schema pipeline - 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-23
+**Phase:** 09-backend-admin-authentication-and-schema-pipeline
+**Areas discussed:** Admin identity and login, Schema pipeline shape, Admin CRUD API contract, Relation manager and settings
+
+---
+
+## Admin identity and login
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Winter-shaped tables | backend_users + backend_user_roles, groups skipped, is_superuser and role codes kept | ✓ |
+| Lean admin model | One summer_admins table with role string and permissions JSON | |
+| Reuse frontend users table with a flag | is_backend + role on users | |
+
+**User's choice:** Winter-shaped tables
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| JWT via a `backend` bouncer guard | Second guard beside `jwt`, own secret and audience, reuses Phase 7 mint/verify/blacklist | ✓ |
+| Cookie sessions with scs | HttpOnly cookie, Postgres session store, CSRF | |
+| You decide | | |
+
+**User's choice:** JWT via a `backend` bouncer guard
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Winter strings with wildcard | HasPermissions in registerPermissions shape, is_superuser, role JSON, `.*` prefix match, RequiredPermissions() enforced by framework | ✓ |
+| Flat permission list, no wildcards | Exact match only | |
+| You decide | | |
+
+**User's choice:** Winter strings with wildcard
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Console command | `summer admin:create` + `admin:reset-password` | ✓ |
+| Seeded from config | Boot-time superuser from YAML/env | |
+| Both | Command canonical, env seed opt-in | |
+
+**User's choice:** Console command
+
+---
+
+## Schema pipeline shape
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Winter layout | config_form/config_list point at models//fields.yaml and columns.yaml; scaffold updated | ✓ |
+| Scaffold layout | Keep controllers//fields.yaml as Phase 4 emits | |
+| You decide | | |
+
+**User's choice:** Winter layout
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Typed schema, Winter key names | Go structs per field type, unknown keys fail, Winter spelling in JSON | ✓ |
+| Pass-through map | Generic map served as-is | |
+| Typed schema, normalized names | snake_case house style | |
+
+**User's choice:** Typed schema, Winter key names
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Resolved server-side | phrasebook resolves labels in the admin's locale; SPA gets strings | ✓ |
+| Raw keys plus a lang bundle endpoint | SPA resolves locally | |
+| Both fields | label and labelKey side by side | |
+
+**User's choice:** Resolved server-side
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Options provider interface on the model | DropdownOptions(field) []Option; static YAML maps also work | ✓ |
+| Registry keyed by method name | Controller registers a map of func by name | |
+| You decide | | |
+
+**User's choice:** Options provider interface on the model
+
+---
+
+## Admin CRUD API contract
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| /_admin/api/v1, plain JSON, no envelope | Plain resource bodies, `{message, errors}` errors | |
+| Reuse the fonoteka house envelope | Same helpers as /_fonoteka/api/v1 | |
+| You decide | | |
+
+**User's choice:** Free text: "Do you really recommend 1? Our chance to introduce nice and consistent api layer." Claude proposed a framework-wide layer (plugin-namespaced paths, one envelope with a fixed error-code vocabulary, one list contract, one verb set, relation endpoints under the record, swag-annotated framework package). User: "Yes, let's proceed with that."
+**Notes:** Recorded as D-09 to D-11.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Winter list features only | search, sort, dir, page, recordsPerPage, relation columns | |
+| Add per-column filters | filter[column]=value exact matches | |
+| You decide | | |
+
+**User's choice:** Free text: "Filters in Winter are done with config_filters.yaml we need filters like that here." Claude found the user and journal plugins' config_filter.yaml files (switch, daterange, model-backed scope) and asked about scope coverage and raw SQL `conditions:`. User: "Port 3 shapes now, note for future phases that this will be extended and all shapes will be introduced in time. Model scope methods instead of SQL strings are fully acceptable."
+**Notes:** Recorded as D-12; remaining scope types deferred.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Optional interfaces on the controller | Type-asserted hooks with admin principal in context; bulk delete per record | ✓ |
+| Struct of func fields | Optional func fields on AdminController | |
+| You decide | | |
+
+**User's choice:** Optional interfaces on the controller
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Port the email mapping | Admin email must match exactly one frontend user; reuse its active collection; 422 otherwise | ✓ |
+| Explicit collection picker | SPA header on every request | |
+| Both | Mapping default, header override for superusers | |
+
+**User's choice:** Port the email mapping
+
+---
+
+## Relation manager and settings
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| config_relation.yaml as a first-class schema | Typed relation schema; `type: relation-manager` replaces `partial` | ✓ |
+| Keep `partial` as an alias | Map partial to relation manager | |
+| You decide | | |
+
+**User's choice:** config_relation.yaml as a first-class schema
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Pivot fields stamped by the framework hook | RelationBeforeLink stamps role, granted_at, granted_by; unlink deletes pivot | ✓ |
+| Bare pivot insert | Only the two foreign keys | |
+| You decide | | |
+
+**User's choice:** Pivot fields stamped by the framework hook
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| HasSettings capability + singleton model | registerSettings shape, /settings/{code} GET/PUT via Fillable | ✓ |
+| Settings as an ordinary admin controller | Form with no list, hand-written per page | |
+| You decide | | |
+
+**User's choice:** HasSettings capability + singleton model
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| HasNavigation in Winter's shape, URL becomes a route key | url replaced by controller ID; /navigation filtered by permissions | ✓ |
+| Winter shape with literal URLs | Keep url strings | |
+| You decide | | |
+
+**User's choice:** HasNavigation in Winter's shape, URL becomes a route key
+
+---
+
+## Claude's Discretion
+
+- Package naming and layout for the admin API and schema packages.
+- YAML parse timing (boot vs lazy), `rules:` in fields.yaml vs model Rules().
+- Admin login throttling and password policy.
+- Soft-deleted rows in admin lists; settings row creation timing; relation candidate pagination.
+
+## Deferred Ideas
+
+- Remaining Winter filter scope types.
+- backend_user_groups, preferences, access logs.
+- Policy-based row/field-level permissions.
+- Boot-time admin seed from environment.