Skip to content
Docs

Command palette

Jump to a page or view, or find a todo by name.

Changelog

Changelog

New features, architectural changes and improvements to the template.

MarkdownRSS

Release notes are curated from repository history. Dates reflect integration into the main branch; grouped entries are not semantic-version tags. Each entry links to its implementation and current developer guide.

Bklit is the only chart library, Stageshow the only way to draw product UI

The unused shadcn chart wrapper and Recharts are gone, a test refuses any other chart library on the web, and faux product UI on landing, marketing and docs pages is built with Stageshow.

Two design defaults are now rules, stated in AGENTS.md, CODING_STANDARDS.md and on Design patterns. Every chart, sparkline and KPI or stat card on the web comes from Bklit UI, through the @bklit registry and the bklit-ui, bklit-ui-design and bklit-ui-migrate skills. Faux product UI on landing, marketing and docs pages (stills, feature cards, cursor demos, bento grids) is built with Stageshow and ships only after its loop passes film.mjs --gate.

The shadcn chart wrapper in packages/ui and the recharts dependency of apps/web and packages/ui are removed. Nothing imported them, so the built client and Worker are byte-identical, and an install fetches 35 fewer packages. scripts/web-chart-library.test.mjs runs in pnpm test and fails when apps/web/src or packages/ui/src imports Recharts, Chart.js, Nivo, Victory, visx, ECharts, ApexCharts, Highcharts, Tremor or a similar library, or when their package.json lists one. It is a test rather than a lint rule because an oxlint entry would replace the client boundary; see Enforcement. The Stageshow rule is held in review, with a new item in the Review checklist.

Bklit renders for React on the web only, so the Expo app is outside the rule. Its charts use victory-native, or Swift Charts through @expo/ui on an iOS-only screen. The dashboard KPI cards and the hand-built fragments of the landing feature board predate the rules and move to Bklit and Stageshow when they are reworked.

Signed-in navigation no longer waits on the session read

The /_auth guard revalidates the session in the background, GET /get-session runs outside the request transaction, and the browser's session read is served from Better Auth's 60-second signed cookie snapshot while every authorization still reads the database.

Three changes from issue #189. They were measured on the built Worker in local workerd with a production-like latency profile: the browser 120 ms from the Worker, the database 20 ms away. A second profile put the database 110 ms away. Medians of 3 rounds.

  • The /_auth guard is stale-while-revalidate. Once the cached session was older than 15 s, every signed-in navigation waited for GET /api/auth/get-session before the page's own loaders started. The guard now lets the navigation start on a cached signed-in session and re-reads it in the background; a signed-out answer sends the layout to /login. A navigation after 20 s idle went from about 220 ms to about 45 ms, and from about 820 ms to about 45 ms with the distant database. (c38e801)

  • GET /get-session runs outside the request transaction. Every auth request ran in db.transaction, so a session read cost BEGIN, the read and COMMIT. It is now one statement; every other auth request keeps its transaction. (f987550)

  • The browser's session read comes from Better Auth's cookie snapshot. session.cookieCache is on (compact, 60 s). The browser's presentation read no longer sends disableCookieCache, so a tab focus or a background revalidation costs no database statement. With the distant database, get-session dropped from about 290 ms to 8 ms. Authorization never uses the snapshot:

    • SSR, the oRPC context, the files gateway and admin still read the database;
    • the auth handler strips the snapshot from every other /api/auth/* request;
    • the web app re-reads from the database after its own session changes.

    Creating an Organization on the web now switches to it, as Better Auth and the native app already did. A session revoked on another device can keep the UI shell for up to 60 s, and its first data request is refused with 401. See Session reads.

Skullet is the only way to draw a loading skeleton

Every web loading skeleton goes through MeasuredSkeleton, and a test refuses hand-made pulse boxes, the shadcn Skeleton, other skeleton libraries and skeletons on public pages.

Since 2026-11-04 every loading state in the signed-in web app has been measured from a sample of the component it stands in for, with skullet. That is now a rule, stated in AGENTS.md, CODING_STANDARDS.md and on Design patterns: a loading skeleton is MeasuredSkeleton from @/platform/skeleton/measured-skeleton, fed data and a sample from the feature's <feature>.samples.ts. Only platform/skeleton/ imports skullet.

scripts/web-skeletons.test.mjs runs in pnpm test. It fails when apps/web/src or packages/ui/src imports skullet outside the wrapper, when app code imports a *Skeleton* component from a package (the shadcn Skeleton, SidebarMenuSkeleton, a UI kit's), when a feature or route draws an animate-pulse box with a muted fill, and when either package.json lists another skeleton library such as react-loading-skeleton or react-content-loader. It also walks the imports of every route outside routes/_auth/ and fails if one reaches the wrapper, so the skullet chunk stays off public pages, as the first-paint rule (W15) requires. A public page renders its data from the route loader, or a Spinner for a pending action. The Enforcement page and the Review checklist list the new check.

The shadcn skeleton.tsx stays in packages/ui, because the vendored sidebar and the ReUI emoji picker draw their own loading state with it. Skullet has no React Native build, so the Expo app keeps its SkeletonRows placeholder.

Earlier releases

Edit on GitHubDocumentation is in English.
Cookie settings
We use essential cookies to make our app work. With your consent, we also use optional cookies to improve your experience.

Read our Cookie Policy and Privacy Policy.