pact.ListExtendRecords fills unstored fields of one list page before its
columns are read (WinterCMS listExtendRecords); such columns compile
unsortable and refuse sortable/searchable. pact.FormRecordTitle names a
record; the show, create and update responses send it as meta.title.
usePreferences.ts (quick 261016-0fm) caches the theme and locale codes in
localStorage, an accepted threat of that task; the hygiene allow-list was
not updated, so check-phase18.1.sh docs failed. Tokens stay forbidden.
- a detached Run sees no transaction and holds no row lock (FOR UPDATE
NOWAIT from another connection succeeds), with the empty, absent and
partial-selection rules, a ValidationError as 422 and earlier writes kept
- the same action without Detached still holds the transaction and locks
- test-only actions on the roster fixture through its wrap hook; README
Testing names the test
- pact.AdminBulkAction.Detached (json:"-"): opt-in; records loaded through the list scope without row locks, no write transaction in the context
- cabana BulkAction: detached branch with the same empty, partial-selection, failure and message rules; lockScoped is loadScoped with lock, the locked path unchanged
- docs: admin-controllers bulk route list, pact and cabana READMEs
- theme: light and dark ignore prefers-color-scheme, choices and guard
- i18n: ?locale= only with a preference, availableLocales from meta
- usePreferences: cache validation, cycle order and PUT bodies, revert
with a danger toast, profile apply, setLocale save, cache and reload
- rail theme button, user menu language group, --shell-offset and the
form save bar offset; fixture strings and resetState theme reset
AppShell exposes --shell-offset (the rail, plus the section panel when it
shows); the form, settings, My account and preview save bars start there,
so the rail's Settings item stays visible and clickable.
- loadStrings sends the chosen language as ?locale= and keeps
meta.locales as availableLocales
- the user menu lists the admin locales, each named in its own language;
choosing one saves it through PUT /account/preferences, caches it and
reloads the page
- boot loads the strings in the cached language; me() reloads them when
the stored preference differs
- principalFrom sets PreferredLocale from metadata admin_locale; personal
API token principals clear it, so token clients keep the request locale
- the guarded admin group runs locale.from-principal after the backend
guard, overriding the LocaleResolver or Accept-Language locale
- GET /lang honours a supported ?locale= and reports meta.locales
(cabana.LangEnvelope, cabana.LangMeta)
- Docker test for the override, refusals and /lang; docs and OpenAPI
The phrasebook SPA-key check scans admin/src for backend::lang literals;
the template-string key backend::lang.nav.theme_ did not resolve and
failed go test -short.
- the rail's top button cycles system, light and dark and names the
current choice; light and dark ignore prefers-color-scheme
- usePreferences applies the cached theme before the first await of boot,
saves the choice through PUT /account/preferences and reverts with a
toast when the save fails; me() applies the stored preference
- GET and PUT /account/preferences (own row only, interactive sessions,
CSRF header on cookie writes) store admin_theme and admin_locale in
backend_users.metadata, keeping every other key
- GET /auth/me and the My account answers carry preferences
- phrasebook.Translator.Locales lists the locales defining a prefix
- route tables, conformance cases, OpenAPI document, TS types and docs
- new setup/upgrading.md: version rule, the two 0.2 boot refusals with
their fixes, behaviour changes, and what 0.2 adds since 0.1
- architecture module table lists all 28 modules
- WinterCMS map: cache and reorder are provided; rows for field types,
sanitizing, singletons, API tokens, CORS, Turnstile, menu item types
- configuration keys for CORS profiles, api_docs, auth.cookie, turnstile
- index, setup intro and frontend page link the new topics
- caching.md: an https purge_url on another host goes through the site's
proxy; set NUXT_SITE_CACHE_ALLOW_PROXIED=true there, the token is then the
only gate
- cooler README: the purge_url row points at it