RelationContract (hasMany) and FieldRelationContract (belongsTo) accept
ClearOnChange, a list of nullable columns set to NULL whenever the relation
changes the foreign key: a hasMany link and unlink (deferred ones included)
clear them on the child, and a form save that moves a belongsTo key to
another record or to none clears them on the record unless the same save
writes the column through its own field. Boot refuses the option on a
belongsToMany and for a missing, non-nullable, foreign-key or primary-key
column. The zero value changes nothing.
- bonfire.Sanitize (additive), moved from diary's console channel: tab
kept, CR and LF to a space, every other control character dropped
- applied before styling to every error-block line (message,
explanation, Try lines, -v chain), process-view item names and errors,
the current item of spinner and progress, failure lines, and table
headers and cells in both layouts
- diary's console handler calls bonfire.Sanitize; README and the
writing-commands page say so (WR-05)
- a failed open no longer disables the writer for good: it skips records
and tries again one minute later by its clock, or at the first record of
a new date, whichever comes first
- the warning (still 'daily log file disabled') appears once per date
- README and the logging page describe the retry (WR-04)
- the Try line replaces the value of every long flag whose name contains
password, passwd, secret, token or key with ***, in the --flag value and
--flag=value forms; other arguments are unchanged
- README and the writing-commands page say so (WR-08)
- dev.ShutdownGrace (internal, 15 seconds, longer than serve's 10-second
drain) is the grace child.stop waits after SIGTERM, instead of 2 seconds
- summer's delegates use the same constant (appShutdownGrace)
- scaffolding docs say summer dev waits for serve's shutdown report (WR-03)
- appStreams hands the app binary summer's own stdout and stderr on a
terminal, so it asks the production question, prints styled summaries
and animates its widgets
- off a terminal the binary's stdout goes through summer's Output and its
stderr to summer's stderr, so --json and -q output carry no log lines
- newAppCmd (unexported) takes the two writers; docs say the streams stay
apart (CR-03)
- bonfire.WithExitCode (additive) makes an error carry the exit code
bonfire.Execute returns; a code outside 1..255 gives 1
- runAppCmd, factored out of runAppBinary, returns
Reported(WithExitCode(err, code)) when the binary exited with a code, so
summer prints no second error block; a binary killed by a signal keeps
summer's block and exit 1
- README, console introduction and upgrading notes say so (CR-02)
- build runs go build under a spinner on a terminal and ends with
'Built bin/<name> in <time>'; make:* print 'Created <path>' per file
- make:*, plugin:add, new, parity:*, docs:build, docs:sync and every
delegate get long help and examples; delegates note that global options
pass through to the application binary
- make:* failures (no summer.yaml, invalid plugin ID or name, existing
artifact, unknown plugin) explain themselves and suggest a command
- docs:build and docs:sync return bonfire.Reported after the problem list
- TestCommandsDocumented covers the tool commands too
- docs: Upgrading to 0.4, delegates and global options, make: results and
hints, the checklist for a finished command
- migrate, migrate:rollback and deferred:purge gain --pretend and --force;
they and queue:clear confirm only in production on an interactive
terminal, so deploys over SSH proceed as before
- result lines: Applied N migrations, Rolled back <id> of <plugin>,
Cleared N jobs from <queue>
- --json for migrate:status, key:generate, route:list, admin:token:create,
admin:token:list, admin:token:scopes and websockets:health; -q keeps the
key and the token
- hints for an empty DSN, an unreachable database, an invalid app.key, a
missing uploads bucket and an application binary run below its root
- flare and websockets:health return bonfire.Reported after printing
- long help and examples for every application command, greeter:hello and
blog:publish; cmd/summer TestCommandsDocumented fails on any gap
- queue:work and schedule:run print a startup summary and a shutdown
report on a terminal, log them as records otherwise, and return nil
after a clean stop
- schedule:run --once ends with 'Ran N due entries (M failed)'
- summer dev runs bin/<app> serve with the forwarded global options,
reports through Output, stops the old server before starting the new
one and prints a dev report on Ctrl+C (exit 0)
- lagoon.DatabaseLabel describes a DSN without its secrets
- Long help and examples for queue:work, schedule:run, dev, docs:serve
- serve prints a startup summary on a terminal (version, environment, URL,
admin, database host and name, pending migrations, plugins, drivers) and
logs it as a 'startup summary' record plus 'listening on <addr>'
- on SIGINT/SIGTERM serve drains, prints and logs a shutdown report and
returns nil (exit 0), or the drain errors (exit 1)
- the request log is on by default under diary component http with
request_id; the route pattern, never the path, is logged
- lagoon.PendingMigrations, conga.Worker.Stats, diary.HideOnTTY,
bonfire.IsTerminal and bonfire.Details back the summary and report
- Spinner, gradient progress bar and the multi-row process view ported
from SSU to bubbletea v2 (input off, no signal handler, command
context); boxed tables through lipgloss/table
- Prompts use huh fields and a single-select port of SSU's selector with
its confirmation screen on an interactive terminal; line prompts off a
terminal and under --no-ansi are unchanged (piped passwords still work)
- -q hides decoration but keeps data and errors; -n returns defaults and
Secret fails with a hint on a terminal stdin; --no-ansi and non-TTY
runs print today's plain lines
- Helpers: GlobalsOf, VerbosityOf, IsQuiet, Interactive, ConfirmProceed,
Process, Current, Failed, PrintAbove, ItemProgress, ErrAborted
- diary's styled console lines print above a running live view
- help <command> and <command> --help print Description, Usage,
Arguments, Options with defaults, Global options, Help and Examples
- Command.Examples and Command.Hidden (appended, additive); list --all
shows hidden commands, list --format=json prints a bonfire.Listing
- CheckDocs reports commands lacking description, long help, examples or
argument and option descriptions
- Error block with the ERROR badge, WithHint explanation and Try lines
({bin} replaced), cobra suggestions as Try, -v error chain, messages
scrubbed by sunscreen; Reported errors print nothing and exit 1
- Global options -v/-vv/-vvv, -q, --ansi/--no-ansi, -n and --env on every
command; PeekGlobals reads them before config loads, OnGlobals hooks
re-apply them after parsing (diary.ApplyGlobals in the generated main)
- Bare binary, --help and list print the Artisan list with the version
header from BuildVersion and namespace blocks
- Execute runs the root through fang (no version, man page or completions)
and returns 0, 1 or 2; Fail renders errors before the root exists
- NewRoot rejects duplicate command names (ErrDuplicateCommand) and flags
that reuse a global option (ErrReservedFlag)
- Generated main and summer use PeekGlobals, compass.Open with --env,
diary.FromGlobals and bonfire.Execute; docs checker knows the globals
- stderr and null drivers; per-component levels from log.components
- SUMMER_LOG__ overrides parse as strings and overlay the defaults key by key
- Validation names the key: driver, format, level, days, stack children and cycles, daily path outside the root
- summer new writes config/log.yaml (stack of console and daily, river warn, http info)
- docs/services/logging.md: channels, config/log.yaml, component loggers, daily files, redaction
- Log keys in the configuration docs; ExampleFor backs the docs snippet
A browser navigation (Sec-Fetch-Mode navigate, or GET/HEAD without it; no
X-Requested-With; Accept naming text/html above every JSON type; not /api,
/_<name> or the admin prefix) that hits a framework-generated 404, 405 or
500 gets a self-contained SummerCMS page: unmatched routes and wrong
methods at the ServeMux, failed Where/WhereIn constraints, overlap-family
misses, the unpublished uploads route and recovered panics. Every other
request keeps the exact stdlib text, wire's opaque JSON 500 or the bare
raw-group 500.
Details (method, path, X-Request-Id) only with app.debug or outside
production. Applications replace the page with a published
surf.ErrorPageRenderer; http.error_pages.enabled false turns it off.
When a public image's thumb_url or url fails to load, the fileupload
field fetches its preview once through the authenticated thumb route
(session key in the header) and shows it from an object URL, revoked
when the item is forgotten and on unmount. The preview is reported as
unavailable only when that fetch or the object-URL image fails too.
Protected fields behave as before.
The record and relation-child thumb routes now also serve the thumbnail
of a public JPEG, PNG, GIF or WebP file, under the same record or
pending-session scope and D-10 headers as a protected one, so the admin
can preview a public image whose public URL does not load. The download
routes still answer 404 for every public file, and a public non-image
thumb stays 404.
TestPublicImageThumb covers owner, foreign and hidden records, image
types, a public row under a protected field, another admin's pending
upload and the relation-child route.
- capture rule from: response.form reads the value of the <input> with
the rule's name (a server-rendered form's one-shot token), so a parity
flow can post a consent form back
- README and parity docs list the capture sources
- DefaultOptions().Resource is empty; comments name the host application,
no consuming application (folded todo)
- Tests set an explicit neutral resource; TestDefaultOptionsResourceEmpty
- wristband README: new summary, two flavours, OIDC usage, API reference,
OIDC defaults, dependencies, testing; root README row matches
- docs/services/oauth-server.md: OpenID Connect provider section;
Resource described as required with an empty default
- ExampleNewOIDCServer and the newOIDCServer docs region
- One shared localizer for ValidationError and ForbiddenError, tested in
writeCRUDError's order; replaces the ForbiddenError-only one.
- Applied on the CRUD and relation service transactions, the detached bulk
branch, runAction, the record read (ShowRecord), and the reorder,
singleton and relation-options routes, which localized neither type.
- Only strings containing "::" are looked up, so translated text passes
through unchanged and logs no missing-key warning.
- Copy-on-write: the plugin's error value is never modified.
- README and backend docs describe the localized ValidationError.
An optional dependency is optional at activation, not at compile time:
importing the package that declares a looked-up type keeps the other
plugin in go.mod; only party.Plugin.Requires leaves it out.
- modules/breakwater exports Render(markdown) and Purify(html): goldmark GFM
in its default safe mode (raw HTML stripped, unsafe links dropped), then a
named bluemonday policy built from NewPolicy, not the UGC preset
- the policy is the PHP golem15/forum HTMLPurifier config 1:1: the fixed
element list, a[href|rel|target], http/https/mailto only, rel=nofollow on
every link, target=_blank plus noopener on fully-qualified links
- tests cover the PHP ForumMarkdownRenderTest corpus, links per scheme,
blank input, the Purify allow-list and concurrent use; testable examples
feed the docs page snippets
- module README, root module table row, introduction.md Utilities row and
docs/services/markdown.md (which gate serves user content vs admin fields)
- go.mod and go.sum unchanged: bluemonday v1.0.27 and goldmark v1.8.6 were
already pinned
- pact.NavigationItem gains Visible func(ctx) bool (json:"-"); nil keeps the
entry always listed
- cabana.Registry.Metadata runs it after the permission check, drops a main
item (with its side menu) or a side item that answers false, and relinks a
parent whose controller is a hidden child's to its first visible openable
child
- TestNavigationHidesInvisibleItemsAndRepointsTarget covers the rules
- pact and cabana READMEs, users-and-permissions and admin-controllers docs
describe the hook
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.
- 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
- 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 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
- PurgeSiteCacheAfterCommit queues the purge on a per-purger worker after
commit: one request in flight, saves committed meanwhile collapse into
one follow-up, so the admin request never waits for the site
- new cooler.SiteCachePurger.Wait drains the queue; Handle.Close waits for
it at shutdown (timeout plus one second)
- Purge stays the synchronous send; exported names and signatures unchanged
- the purge client's CheckRedirect returns http.ErrUseLastResponse: a 3xx
is logged as a failed purge with its status and the bearer token never
reaches the Location
- BuildRouter logs one warning with the route count and the production
flag when routes name turnstile:open or turnstile:closed and the
verifier has no secret; the secret is never logged
- attach.Store returns attach.ErrProtectedNeedsPrivateBucket for an
is_public false upload while storage.uploads.public_url is set, before
any blob is written
- OpenBucket's public_url line becomes a warning naming the refusal
- LoadCookieConfig refuses a Secure that resolves to false in production,
also when inferred from an http or unset app.url, naming
auth.cookie.secure and app.url
- with supports_credentials, a * origin must be the whole leftmost host
label, patterns must be anchored with ^ and $, and no origin rule may
match the probe origins outside any configured domain
- globally and per profile; non-credentialed configs load as before
- Router.wrap applies the route's profile outside recovery, body limit and
locale, whatever its position in the list or the group nesting
- bufferedResponse.commit merges Vary instead of replacing it
- TestCORSProfileHeadersOnRefusals, TestCORSProfileVaryKeptWithHandlerVary
required by name in the gate
- optional ReorderAfterSave(ctx, partition) runs after the new order is
written; an error rolls the reorder back through lifecycleFailure
- reorderPost runs in lagoon.Transaction so lagoon.AfterCommit work a hook
registers (a site-cache purge) runs only after the commit
- pact and cabana READMEs, admin hook table, tree reorder docs