Changelog · 2026-07-17
Sites v15 — every site your AI shipped, in one place
The biggest dashboard change since v14. Sites — every site your AI has shipped — moves from being a list inside `/deploys` to a first-class resource at `/sites`. Plus a top-to-bottom typography pass t
Released: 2026-07-17
The biggest dashboard change since v14. Sites — every site your AI has shipped — moves from being a list inside /deploys to a first-class resource at /sites. Plus a top-to-bottom typography pass that makes the dashboard look and read like a modern SaaS product instead of a dev tool.
Sites as a first-class resource
- New
/sitespage — a grid of cards, one per site. Click a card to drill into deploys, domain, files, and settings for that site. Empty state is a full dropzone — drop a folder, the AI ships it. - New
/sites/[id]site detail with four tabs:- Deploys — every deploy for this site, with status + live stream
- Domain — the custom domain or
*.krexel.comsubdomain attached to this site (M2) - Files — the tree of files in the latest deploy (M3)
- Settings — site-level controls: rename, change framework, danger zone (M4)
/deploysis gone — replaced by/sitesplus the new site-detail view. Old URLs redirect (308) so any bookmarks you have still work.- Sidebar swap — "My sites" → "Sites", "My URLs" removed. The new nav: Home, Sites, Integrations, API keys, Plan & billing, Settings, Team, Webhooks.
Dashboard typography pass
The audit called out the same thing on every page: too much font-mono + uppercase + tracking on labels, buttons, and pills. It read as "developer tool" not "your workspace."
- ~100+ mono-uppercase instances killed across every dashboard page and component. Buttons read as "Save changes" not "SAVE CHANGES". Form labels read as "Email" not "EMAIL". Section eyebrows read as "Workspace" not "WORKSPACE".
- Sidebar group label — "Workspace" / "Account" eyebrow now uses the modern sans + sentence-case style.
- TopBar breadcrumb — the redundant eyebrow above the breadcrumb is gone. The breadcrumb alone tells you where you are.
- StatusPill — was mono-uppercase, now sans + sentence case. "DRAFT" → "Draft", "MANAGED BY US" → "Managed by us".
- PageHeader — the "Workspace" / "Account" eyebrow is removed entirely. The page title alone is the heading now.
The marketing site is unchanged — its mono-uppercase micro-labels (e.g. "60s · ship", "PRO TIP") are part of the design language. Only the dashboard got swept.
Real <Table> component
The keys, deploys, and domains pages were using a CSS grid as a fake table. That's the textbook "vibe-coded" tell.
- New semantic
<Table>component with proper<thead>,<tbody>,<tr>,<th>,<td>. Supports column alignment, hover state, empty state, monospace cells for code identifiers. /keys,/deploys,/domainsnow use the real table. The CSS-Grid-as-table is gone.
Settings gets a sub-nav
Settings was a 240-line single page with 4 sections stacked. Now it has a horizontal pill sub-nav at the top: Account | Team | Webhooks. Each pill is a real route (/settings, /settings/team, /settings/webhooks).
The sub-nav also fixed a copy-paste bug from earlier: /settings/webhooks was rendering h1="Notifications" with eyebrow="Account · Notifications" — a leftover from when it was the notifications page. Now it's h1="Webhooks".
/integrations collapse
The page was 6 stacked blocks: a walkthrough, an MCP card, an amber notice, a row of 2 tiles (Custom domains + GitHub), and a Stripe "coming soon" tile. Five of those were just placeholders for features that don't exist yet.
- The GitHub and Stripe "coming soon" tiles are gone (−75 lines).
- Page is now: Walkthrough + MCP card + CustomDomainsTile. The 3 things you actually came here to do.
Icon stroke widths standardised
Icons had a mix of 1.5 / 1.6 / 1.75 / 2 stroke widths across the dashboard. Now standardised to 1.75 for every standard icon. Brand wordmarks (Google, ClaudeCode, ChatGPT) are left at their own weights — those are designed glyphs, not stroke icons.
Performance
/dashboardwarm load still 700-900ms. The 4-5s cold start on first nav is mostly Vercel Function boot, not the page code. Fix in this release: Vercel Cron warmup at/api/internal/warmuppings the bootstrap every 5 minutes so the function graph stays JITed. Subsequent user loads after a warmup should be near-instant.- Shared JS bundle stayed at 102 kB. All the work above shipped within the v14 bundle budget.
What stayed the same
- The marketing site (krexel.com, /pricing, /blog) is untouched.
- The worker endpoints, KV/Postgres schema, and Supabase auth flow are unchanged.
- The topbar (search, + New menu, breadcrumbs, avatar) is the v14 version, with one fix: the + New menu's "Drop a new site" entry points at the new
/sitesdropzone. - Cmd+K command palette (already in v14) still works.
Sites v15 worker surface (M1)
The dashboard's /sites page reads from the worker's new Sites API. The worker is the only writer to public.sites; the dashboard calls it via Bearer auth.
- 6 new CRUD endpoints at
/api/v1/sites/*— list, create, get, patch, soft-delete, list-deploys-for-site. POST /api/v1/admin/backfill-sites— idempotent one-shot backfill. Walks every customer, creates one site per(email, project_name)pair, skips anything that already has a site.?dry_run=1previews without writing. Action item: run this once so existing customers' deploys show up in their/sitesgrid:curl -X POST "https://api.krexel.com/api/v1/admin/backfill-sites" \ -H "Authorization: Bearer ***"- Site IDs are
site_<16-char>(~83 bits of randomness). Cloudflare Pages project names are auto-derived askrx-<slug>-<6-char-discriminator>so two customers with the same slug never collide in our shared CF account. - Slugs are 3-40 chars,
[a-z0-9-]. The DB hasUNIQUE (email, slug)as a backstop; the route pre-checks for a clean 409. - Non-owners get 404 (not 403) on
GET /sites/:idso site existence doesn't leak across customers. - Soft-delete sets
status='deleted'. The CF Pages project is preserved for 30 days so a restore is a support op, not a re-deploy. A future cron sweep purges orphaned projects. - Storage: production reads + writes go through Postgres (
public.sites); KV is a fallback for local dev + tests. Both stores implement the sameStoreinterface so the route handlers don't know which one is in use. - Tests: 20 cases in
worker/test/sites.test.ts— all passing. Covers happy paths, validation, authz (404 to non-owners), soft-delete, the?dry_run=1backfill path, and the 403-for-non-admin guard on the backfill.
The next milestones wire the deploy flow into the new model: POST /deploy will accept a siteId and atomically update the site row, the Domains tab and Files tab fill in M2 and M3.