Release v1.9.0 · July 26, 2026

Feedback tickets, Stream video, and a rebuilt dashboard

A large release — an in-app feedback and ticketing tool, a Cloudflare Stream video pipeline with an in-house player, per-user notifications, a new account settings dialog, and a wide polish pass across dashboard fields, filters, media, and activity.

Highlights

This is the biggest release since 1.0 — 175 commits across the engine, the dashboard, and the public rendering primitives. Three genuinely new subsystems land (feedback tickets, Stream video, notifications), the account surface moves into a settings dialog, and almost every dashboard screen gets a design pass.

Feedback and tickets

A complete in-app feedback tool. Editors report an issue from the live site by picking an element on the page; the ticket keeps the anchor, so Open on page takes anyone straight back to the reported element.

  • Kanban board and list view, both with the same priority and assignee treatment
  • A ticket sheet over the board with a threaded discussion, screenshot, and attachments
  • Multiple assignees per ticket, with live profile-photo avatars
  • Priority picker in the composer and ghost priority buttons in the sheet
  • Custom statuses, editable as a sortable list
  • Clause-based filters, including a date-reported range filter
  • Comment counts on cards and list rows, hover cards for timestamps and assignees

Cloudflare Stream video

Video uploads now route through Cloudflare Stream, provisioned entirely from the CLI with no credential copying — inline stream connect sets up the binding, bucket CORS, and the webhook.

  • Binding-first pipeline: direct upload, ingest webhook, and a reconcile cron for stragglers
  • Reingest for failed assets; a failed upload downgrades gracefully to plain R2 playback
  • Poster-frame scrubber, so the thumbnail is a choice rather than a coin flip
  • Signed playback URLs for private video

The CmsVideo player

One in-house player chrome across mp4, Stream, and YouTube sources — the Island capsule. HLS now runs through hls.js on Chrome and Edge and uses native playback only on Apple browsers, which fixes Chrome starting a stream at a blurry low rung before ABR caught up. Seeking no longer restarts from zero, and the scrubber thumb tracks smoothly.

Notifications

A per-user notification inbox with a redesigned drawer, fed by a shared notify() facade with several producers. Comments support @mentions, which notify the mentioned user directly.

Account settings dialog

/inline/profile is gone. The account surface is now a ?settings= dialog with side tabs — profile, security, notifications, account — reachable from anywhere in the dashboard, with search that spans every tab. Forced 2FA enrolment uses the same dialog.

Dashboard

  • Fields. A UX pass across all 22 field types: reworked relationship picker, a searchable icon picker, and improvements to gallery, colour, date-range, link, file, form, and table fields. The repeater is now numbered cards in a dashed frame; nested repeaters drill via breadcrumbs.
  • Filters. The smart-search typeahead is replaced by a composable clause filter builder, with date-range presets, an is not operator, and contextual indicators in the dropdowns.
  • Media library. Redesigned grid and list views, a folder path bar, and clause-based filters.
  • Activity. The table becomes a day-grouped timeline of accordion events, with free-text search that matches entry ids.
  • Content. A publish-date column and filter on listings, per-content-type sidebar icons, and a view switcher that lives in the breadcrumbs.
  • Content calendar. The old /schedule route is renamed, with search and clause filters.
  • Email templates. Rebuilt on the dashboard TipTap editor with an inbox-accurate preview, merge tags, an audience picker, and a create-from-dialog flow.
  • Command palette. Media, forms, users, releases, and create actions are now in Cmd+K.
  • Safety rails. Unsaved-changes protection across every editor, default error states for both routers, and a themed confirm dialog in place of the last window.confirm.

Permissions

  • A publish-vs-edit split for content, so an editor can draft without shipping
  • Locale-scoped role permissions, so a translator can be granted only their locales

Edge cache

Several purge gaps closed, including one that made every production purge a silent no-op. Pages now carry render-time dependency tags, so a listing or referencing page is purged when its content changes; the edge fresh window rises to an hour, backed by purges from cron and releases. 404s are negatively cached, and delivery purges are type-scoped.

Look and feel

A new primary colour, retuned contrast across the palette, pastel gradient avatars with dark ink initials, a gradient home hero highlighting what changed since your last visit, toasts on Base UI, and dialog scroll areas that fade content into the surface at clipped edges. Every icon-only button now has an accessible name.

Fixes

  • Change-email flow works again against Better Auth 1.6.23, and the two_factor schema is caught up
  • 2FA and Google sign-in can no longer be enabled together
  • The publish gate no longer loses the session in the standalone editor
  • A phantom rich-text onChange no longer falsely dirties the form editor
  • The dev S3 media adapter ignored ranged reads, which killed video playback a couple of seconds in
  • Date-filter calendar navigation, range-end rounding, and day-cell selection states

Upgrading

Run inline update. This release adds nine D1 migrations — feedback tables, media Stream columns, two-factor lockout fields, and a role-permission backfill for the publish split — all applied by the update's migrate step. No codemods are required; no public API changed.