Introduces a role-gated /admin section (sidebar layout, requireAdmin
checked both in route loaders and independently in every admin server
function) with three sections:
- Orders: every order across all customers, and an admin-only order
detail view nested under /admin so the sidebar persists and admin
access bypasses the guest-token check.
- Menu: create/edit/delete menu items, their options, and their
preparation steps; deleting an item with past orders is refused
(protected by the orderItems FK) instead of crashing.
- Kitchen: read-only live view of every machine's busy/idle status and
per-tag queue depth, with a manual refresh.
Also:
- Adds a `role` field to the user table (Better Auth additionalFields,
input:false so it can't be self-assigned) and a db:seed-admin script
to create/promote an admin account.
- Fixes a real bug found while building this: src/server/auth.ts's
shared session helpers were plain exported functions using a
server-only import, which the framework couldn't tree-shake out of
the client bundle once shared across multiple server/*.ts modules —
this silently broke hydration app-wide. Fixed with createServerOnlyFn.
- Removes the now-fully-unused @tanstack/devtools-vite plugin.
- Disables view transitions for in-admin navigation so the persistent
sidebar doesn't cross-fade/shift on every click.
- Gives the "your orders" empty state the same visual treatment as the
basket page's.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lets customers pick options on a menu item detail page before adding to the
basket, and makes displayed prices respect a configurable currency/locale
via VITE_CURRENCY/VITE_LOCALE. Also crossfades the basket's empty/filled
states with AnimatePresence in wait mode instead of animating both at once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Wire up Better Auth (email/password + Google/Apple SSO) with a
sign-in/sign-up UI, header account menu, and a basket that follows
the signed-in-or-guest state.
- Give the order status page a vertical timeline per preparation step
(with a distinct customer-facing name separate from the machine tag,
a done/in-progress/queued/pending look, and a sonar-ping highlight on
the active step), a formatted ETA (relative under 3h, absolute clock
time beyond that), and Buy again / Get help / Cancel actions.
- Expand Pizza's recipe into 6 steps across a shared prep station and
the existing oven/assembly stations, with matching schema, seed, and
domain changes plus updated/added test coverage.
- Add an Orders list (account orders via session, guest orders via a
locally remembered access-token list) with a shared getOrdersForCustomer
domain summary, and remember a guest's name/contact after their first
order so checkout doesn't ask again.
- Improve page transitions with the View Transitions API: a shared
element morph between an order card and its detail page, a stable
(non-jumping) header across navigations, and reduced-motion handling.
- Add a Ghost Kitchen wordmark (Space Grotesk, faded "Ghost", ghost
icon standing in for the "o") and shrink the basket icon to match
the rest of the header controls.
- Add a run-ghost-kitchen agent skill documenting local setup, the
dev-server driver, and the gotchas hit along the way.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds docker-compose.yml (Postgres on host port 5433, to avoid clashing
with another project's container already using 5432 on this machine)
and .env.example so `docker compose up -d` + `cp .env.example .env.local`
gets a working local DB. Adds a db:seed script alongside the existing
db:* scripts.
Rewrites README's "Adding a Database" section, which still described
Better Auth's DB as optional/hypothetical even though this project
already requires Postgres for both its own data and Better Auth's
tables. Fills in CLAUDE.md's Data layer connection-details placeholder
and fixes two more stale pnpm references and a wrong migrations path
(src/db/migrations/ instead of the actual drizzle/) found nearby.
Also fixes a real bug the new docs surfaced: `npm run db:seed` didn't
load .env.local the way drizzle-kit does, so DATABASE_URL was silently
unset when run as documented. seed.ts now loads env the same way
drizzle.config.ts already does.
Verified the full documented flow end-to-end against a fresh container:
migrate, better-auth migrate, seed, dev server, real page render.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>