Commit Graph
60 Commits
Author SHA1 Message Date
lukasandClaude Opus 5.5 6fc315a5f2 Discard items left in their pickup box past a 15-minute window
An item's pickup window starts when it goes into its box. Once it runs
out, the item is discarded without a refund and the box is freed; a box
that's open at that moment is left alone. With no scheduler yet, reads,
box actions and the kitchen simulation check for expired items first.

The order card shows a live countdown under "Ready for pickup" and a
"Not picked up in time" banner once discarded. Also bounces the lock
icon and animates the pickup button's label changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:26:37 +02:00
lukasandClaude Opus 5.5 440f9e5696 Keep the closed box visible and tidy the order item card
- After closing, the box button stays disabled as "Box N closed" for
  5 minutes, timed from a new picked_up_at so it survives a reload
- Picked-up items keep showing their pickup box number
- Hide the steps toggle on ready and picked-up items
- Move "Buy again" and "Get help" into a dots menu in the item header

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:11:47 +02:00
lukasandClaude Opus 5.5 d68806aaf8 Draw the unlocked pickup box lock as an open padlock
The shackle now morphs instead of lifting: unlocked, the left leg stays
on the body and the right leg shrinks to a stub. The icon may draw past
its viewBox so the raised arc isn't clipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:38:31 +02:00
lukasandClaude Opus 5.5 3efde72524 Make the pickup box button hold-to-open and hold-to-close
Adds a reusable HoldButton that fires after an 800ms hold (pointer or
Space/Enter) with a fill showing progress, and cancels on early release.
The pickup box button now uses it, with extra space above it on mobile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:35:05 +02:00
lukasandClaude Opus 5.5 edd34a00a7 Collect ready items from pickup boxes instead of "I picked this up"
A ready Order Item now gets the lowest-numbered free Pickup Box (or waits
for one to free up), shown as "Pickup box N" on its status. The customer
opens the box from their order and closes it again; closing marks the
item picked up and hands the box to the next waiting item.

On the order card the box button comes first, full width on mobile, with
a padlock that lifts on open and snaps shut before the button collapses
away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:31:23 +02:00
lukasandClaude Opus 5.5 ac2aa770fb Make "Buy again" add the item to the basket
The order status view now carries each item's menu item id and the ids of
its current Options matching the ordered ones by name, since editing a
Menu Item recreates its Options under new ids. Options no longer on the
menu are left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:07:13 +02:00
lukasandClaude Opus 5.5 d987c71010 Drop the account name from the signed-in checkout button
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:04:20 +02:00
lukasandClaude Opus 5.5 1dae53f90a Animate the ETA, hide delays, and tidy the order card actions
- Slide the "Ready in about" value when it changes (new EtaMessage)
- Drop the "Running late" banner; delays only move the ETA now
- Remove the cancel-info tooltip and its icon button
- Shorten the steps toggle to "Steps" / "Hide"
- Add icons and more padding to the order card action buttons

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:02:35 +02:00
lukas 7cf286850c 🔧 update docs 2026-10-01 10:06:13 +02:00
lukasandClaude Opus 5.5 a6ac32d783 Show live order progress, delays, and kitchen cancellations
- Order cards derive their label from item progress (Not Started,
  Preparing, Partly Ready, Ready, Picked Up, Cancelled) instead of the
  order's own status; final states are coloured
- Order page: animated status banner per item (ready/picked up check,
  cancelled cross, running-late clock), steps collapse once an item is
  settled with a Show/Hide steps toggle, done steps are faded instead
  of struck through, and the per-item status badge is gone
- New Delay concept: machines can report extra time on a claimed step
  (preparation_step_instances.delay_seconds), which counts toward the ETA
- The kitchen can cancel an item at any point before it's ready, with a
  refund (order_items.cancelled_by records who cancelled)
- Dev kitchen simulation now runs server-side across every order, so a
  step nobody is watching no longer blocks the queue; each settled step
  may randomly be delayed or cancelled
- Humanize snake_case statuses in the UI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:11:08 +02:00
lukasandClaude Opus 5.5 c124b0415a Add a dev-only kitchen simulation to the order status page
- "Simulate kitchen (dev)" button advances each placed/paid item's
  Preparation Steps as a Machine would, polling fresh status per item
- Each simulated step takes 10–30s, scaled from its estimated duration
- Timeline connector fills in with a Framer Motion animation when a
  step completes; finished steps and the line now use the success green

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:25:52 +02:00
lukasandClaude Sonnet 5 815939cbc6 Add account settings page and polish avatar/SSO button edge cases
- New /account route: edit name/email, change password, delete account
  (detaches the user's orders instead of leaving a dangling reference,
  since orders.customerId has no DB-level FK to better-auth's user table)
- Better Auth: allow email changes without a verification email (no
  email sending is wired up anywhere in this app) and enable account
  deletion
- Header avatar: fall back to the initials placeholder if the profile
  image fails to load, not just when there's no image URL
- Fix low-contrast "Continue with Google" button in dark mode (it used
  the page background color and a hardcoded dark-gray label, so it
  nearly disappeared against a dark background)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 22:23:50 +02:00
lukasandClaude Sonnet 5 7f72baf97d Center both stepper glyphs on the item customization page
The +/- glyphs were wrapped in a flex-centered div, but only the +
button had been converted — the - button still used a plain span and
rendered off-center. Apply the same wrapping to both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:52:48 +02:00
lukasandClaude Sonnet 5 8481032e30 Add menu item allergens, drop nav Help link, animate customizer price
- Menu items can now list allergens (shared catalog + join table),
  shown on the menu grid and item detail pages when applicable, and
  editable from the admin menu item form.
- Removed the top-nav "Help" link now that the footer links to it.
- The item customization page's price now uses the sliding
  AnimatedNumber, matching the basket line price.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:50:17 +02:00
lukasandClaude Sonnet 5 917fc275f9 Add a sticky site footer
Adds a Footer with the brand, quick links (Menu, Basket, Your orders,
Help), and a copyright line, rendered on every page. Body is now a
full-height flex column so the footer sits at the bottom of the
viewport on short pages instead of floating right under the content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:34:04 +02:00
lukasandClaude Sonnet 5 a8e655a810 Add a Help page with FAQ and contact form
Adds a /help route with an animated FAQ accordion and a contact form
(persisted via a new contact_messages table). The per-order-item "Get
help" link now points here and passes the order/item/status as search
params, which the page uses to show a short, state-specific note and
prefill the message field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:24:51 +02:00
lukasandClaude Sonnet 5 7f3728b5bf Animate basket price and item changes
Reflow remaining basket lines with framer-motion when an item is
removed, slide the per-line price when it changes, and tween the
basket total up/down to its new amount instead of snapping to it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:05:24 +02:00
lukasandClaude Sonnet 5 3d736769e0 Wrap stepper button glyphs in a span for iOS Safari centering
Flexbox centering of a bare text node inside a <button> is a known
WebKit quirk — Safari (including iOS) doesn't always vertically center
it the same way it centers an element child. Wrapping the +/- glyph in
its own <span aria-hidden="true"> (the button's own aria-label already
conveys the meaning) is the standard workaround.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 21:26:46 +02:00
lukasandClaude Sonnet 5 b0ef917cfc Center the +/- glyphs in the quantity stepper buttons
.stepperButton relied on the browser's default button content
centering, which the appearance: none reset in the previous commit
took away. Explicitly flex-center it (and zero out padding/line-height)
across all three copies (MenuItemCustomizer, MenuList, basket).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 21:24:23 +02:00
lukasandClaude Sonnet 5 05a91bb5c3 Fix buttons rendering with iOS Safari's default blue chrome
globals.scss's button reset only set font: inherit — no appearance
reset, no color fallback. Several buttons only set a background and
relied on inherited text color, which iOS Safari doesn't honor for
unstyled <button> elements, so their labels/icons rendered in Safari's
native blue instead of the theme color:

- .stepperButton in MenuItemCustomizer, MenuList, and basket
- .refreshButton in admin/kitchen
- .addButton in admin/MenuItemForm (color was only set on :hover)

Added explicit `color` to each, and hardened globals.scss's button
reset with `color: inherit` plus `-webkit-appearance: none` /
`appearance: none` as a fallback for any future button that forgets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 21:22:11 +02:00
lukasandClaude Sonnet 5 0da1f47573 Match the basket's empty-state CTA styling to the orders page
Basket's "Browse the menu" button still had its original plain style
(flat opacity hover, no arrow) from before that button was reworked on
the orders page. Bring it in line: shadow, hover lift, and the shifting
arrow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 20:57:25 +02:00
lukasandClaude Sonnet 5 de158d7c36 Remove the food-icon backdrop, back to a plain empty state
Drop MenuBackdrop entirely and put the icon, title, text, and CTA
directly back on the empty state's own solid background — no separate
overlay card needed once there's no pattern behind it to cover up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 20:54:39 +02:00
lukasandClaude Sonnet 5 04a0e4a708 Zoom the icon pattern in and reduce blur
Scale the background pattern up (background-size 240px -> 340px) and
back off the blur (8px -> 3px) so icons read more clearly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 20:49:45 +02:00
lukasandClaude Sonnet 5 5bc57f0200 Remove the diagonal scroll animation and bump blur to 8px
Static now — drop the background-position keyframe animation and its
now-stale comment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 20:48:36 +02:00
lukasandClaude Sonnet 5 c539ef84cd Rework the icon backdrop into a seamlessly scrolling tiled pattern
Replace the per-icon DOM elements (with client-side randomized
placement) with a single small SVG tile rendered once and set as a
repeating CSS background-image. Icons sit in a 4x4 grid within the
tile, evenly spaced and the same size, cycling through the food-icon
shapes and color palette.

Animates via background-position instead of per-element transforms:
moving by exactly one tile size per loop (linear, infinite) scrolls
the whole pattern diagonally forever with a perfectly seamless wrap,
which per-icon placements couldn't do without quadruplicating the DOM.
Also tried a grayscale pass (filter: grayscale(1)) alongside the blur,
now bumped from 2px to 4px.

This also sidesteps the hydration-mismatch concern entirely — there's
no more client-only randomization step, so no server/client mismatch
risk to guard against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvYdJ3os7tumimsLdLu2j9
2026-09-13 20:47:21 +02:00
lukasandClaude Sonnet 5 aa8d40bc4e Fix icon colors being overridden, and expand the palette
The .empty svg rule (styling the OrdersIcon/BasketIcon) was a plain
descendant selector, so it also matched — and, with higher specificity
than inherited color, overrode — the backdrop's own food-icon svgs
nested inside the same .empty box. Scope it to a direct child (> svg)
so it only targets the actual empty-state icon.

Also expands the backdrop palette from 3 to 6 colors (adds basil,
berry, and cocoa) for more variety across the icons.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:35:00 +02:00
lukasandClaude Sonnet 5 6a81b305bc Give each backdrop icon a distinct light color
Cycle a small warm palette (terracotta, golden-brown, golden-yellow)
across the icons via a CSS custom property instead of one flat tint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:31:43 +02:00
lukasandClaude Sonnet 5 6bd63b53c6 Soften the empty-state icon backdrop with a slight blur
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:29:12 +02:00
lukasandClaude Sonnet 5 8653418778 Match the empty orders icon style to the empty basket state
Drop the tinted circle badge around the icon and use the same plain,
muted-gray sizing as basket.module.scss's empty state instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:26:27 +02:00
lukasandClaude Sonnet 5 2f37b6bba1 Move the food-icon backdrop onto the empty basket/orders cards and animate it
Confine MenuBackdrop to whatever card renders it instead of the whole
viewport: it's now position: absolute inset:0 within its container
(previously position: fixed, spanning the page) with a gentle floating
animation per icon (staggered delay, respects prefers-reduced-motion).
Wired it into the empty basket and empty orders states instead of the
menu list page.

Also gives .empty on both pages position: relative + z-index: 0 so it
forms its own stacking context — without an explicit z-index, the
backdrop's z-index: -1 child was escaping to the document root and
painting either fully behind everything or (on the basket page, where
motion.div meant `.empty` never picked up a context on its own) above
the card's own text, depending on the surrounding markup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:21:10 +02:00
lukasandClaude Sonnet 5 315491dd5b Add a scattered food-icon backdrop to the menu page and tastier copy
MenuBackdrop renders pizza, burger, and fries stroke icons at fixed,
hand-placed positions (no Math.random(), to avoid an SSR/client
hydration mismatch) as a fixed, pointer-events-none layer behind the
page content. Also tweaks the intro line to call out "your tasty menu".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:11:18 +02:00
lukasandClaude Sonnet 5 c5ed038bca Animate the empty orders state in and make its CTA more inviting
Fades/slides the empty state in on mount, gives the icon a tinted
circle badge instead of a bare stroke icon, and gives the "Browse the
menu" button a shadow, hover lift, and a shifting arrow instead of a
flat opacity hover.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:07:39 +02:00
lukasandClaude Sonnet 5 f4f3c26e1e Expose the dev server on the local network
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:04:11 +02:00
lukasandClaude Sonnet 5 5f375a0966 Animate orders out with a CSS transition instead of the View Transitions API
The prior attempt wrapped the sign-out router.invalidate() in
document.startViewTransition(), but that had two problems: invalidate()
does its own network refetch inside the transition's update callback,
which freezes the page for the round-trip instead of animating
anything, and TanStack Router's invalidate() explicitly opts itself out
of view transitions (sets shouldViewTransition = false) for exactly
that reason. On top of that, OrdersRoute briefly returns null between
the account loader clearing and the guest-orders lookup resolving,
unmounting OrdersListView and wiping any exit-animation state anyway.

Replace it with a plain, self-contained approach:
- OrdersRoute now keeps rendering the last known non-null orders list
  through that brief gap (a lastKnownOrders ref) instead of unmounting
  OrdersListView, so its local animation state survives.
- OrdersListView holds onto the previous non-empty list for
  EXIT_DURATION_MS after it goes empty, applying an `orderExiting`
  class that fades/slides each card out via a plain CSS transition,
  then swaps to the actual empty state once the transition finishes.

This has no dependency on browser view-transition support, network
timing, or router internals.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:03:33 +02:00
lukasandClaude Sonnet 5 8d7f99848c Animate the Orders list out on sign out via the View Transitions API
Wraps the sign-out-triggered router.invalidate() in
document.startViewTransition() so the cleared order cards cross-fade
out (and the empty state fades in) instead of popping away instantly.
Each order card already carries its own view-transition-name (see
OrdersListView), so this reuses that per-card exit; the existing
::view-transition-group(*) timing in globals.scss applies automatically.

Falls back to a plain invalidate() where the API is unsupported, and
swallows rejection on the transition's ready/finished promises since
the browser can abort it in some states (e.g. a backgrounded tab) —
router.invalidate() still runs regardless.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:55:14 +02:00
lukasandClaude Sonnet 5 f819b0cd46 Invalidate the router on sign out so account orders clear immediately
Signing out only clears the auth session cookie; a route already
loaded (e.g. /orders) keeps its stale loader data until something
triggers a reload. Call router.invalidate() once signOut succeeds so
the current route's loader reruns against the now-signed-out session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:43:58 +02:00
lukasandClaude Sonnet 5 a2e97c293d Clear guest order refs and basket on sign out
Guest order refs and the basket both live in localStorage independent
of the auth session, so they'd otherwise linger for the next person to
use the browser. Add clearGuestOrderRefs (mirroring clearGuestIdentity)
and call it alongside the existing basket clear() from the sign-out
handler.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:39:10 +02:00
lukasandClaude Sonnet 5 86d1a32dd8 Use neutral dark gray instead of brown-tinted dark mode palette
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:39:05 +02:00
lukasandClaude Sonnet 5 370e77f1a6 Add dark mode based on device color-scheme preference
Move the color palette into CSS custom properties (:root in
globals.scss) with a prefers-color-scheme: dark override, and point the
existing $color-* Sass variables at them so every component picks up
dark mode automatically. Replaced the handful of rgba($color, alpha)
call sites with color-mix(), since Sass can't alpha-blend a color that's
now a CSS variable at compile time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:33:31 +02:00
lukasandClaude Sonnet 5 a716080f7d Give the top nav bar a translucent glass effect
Adds a backdrop blur and semi-transparent background/border so page
content shows through the sticky header while scrolling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 19:27:58 +02:00
lukasandClaude Sonnet 5 439932c168 Fix admin panel mobile layout and inconsistent page padding
The admin layout's .layout used align-items: flex-start, correct for
the desktop row (sidebar + content) but wrong once it stacks to a
column at mobile width — align-items controls the cross axis, which
flips from height to width, so children were shrinking to fit their
own content instead of stretching to the viewport. This is what caused
the sidebar's nav links to render squashed/tall and the menu list to
overflow horizontally. Same root cause on .sidebar's own flex-basis,
which fixed its height instead of width once stacked.

Also stacks the menu item form's option/step rows to a column below
the tablet breakpoint (they didn't fit and forced horizontal scroll),
and removes AdminOrdersView's leftover standalone-page padding/max-width
— it was still wrapping its content in the styling meant for a
top-level page, giving "All orders" visibly more padding than Menu/
Kitchen, which just use the admin layout's own padding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 23:34:42 +02:00
lukasandClaude Sonnet 5 c8d1721358 Add an admin panel: orders dashboard, menu management, kitchen status
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>
2026-09-10 23:14:28 +02:00
lukasandClaude Sonnet 5 18a7d2030e Fix crashes on unknown menu item / order routes
Both loaders threw a plain Error that the router doesn't treat as a
route-level not-found, so visiting /items/<bad-id> or /orders/<bad-id>
(or a valid order with a missing/wrong ?token) crashed instead of
showing the NotFound page. Menu item lookups now throw notFound()
directly; the order loader catches the server function's error and
maps both "order not found" and "wrong access token" to notFound(),
so a guessed id can't be used to probe which orders exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 21:21:29 +02:00
lukasandClaude Sonnet 5 927f6ff56e Add a NotFound page and remove the TanStack devtools panel
Configures a notFoundComponent on the root route so unmatched paths get a
branded empty state instead of TanStack Router's generic "Not Found" text,
and drops the always-on devtools panel from the root layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 21:09:43 +02:00
lukasandClaude Sonnet 5 d66e09f515 Add menu item customization/detail pages and configurable currency formatting
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>
2026-09-10 21:00:45 +02:00
lukasandClaude Sonnet 5 e98b0d86d2 Animate quantity steppers and make the nav bar sticky
- Add an AnimatedNumber component that slides a quantity stepper's
  count horizontally — left on increment, right on decrement — and
  wire it into both the menu and basket steppers.
- Make the top nav bar position: sticky, with an explicit background
  so scrolled content doesn't show through it.
- Reserve the scrollbar's gutter on every page (scrollable or not) so
  the sticky header doesn't shift width when navigating between short
  and tall pages.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 12:30:56 +02:00
lukasandClaude Sonnet 5 79bd64ce8c Add guest/account auth flows, order tracking, and order history UI
- 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>
2026-09-10 11:58:24 +02:00
lukasandClaude Sonnet 5 5059f40d4c Add an auth:migrate npm script for Better Auth's own migrations
Installs @better-auth/cli as a devDependency instead of fetching it via
npx each time, and updates the README to use the new script.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 08:22:17 +02:00
lukasandClaude Sonnet 5 cacfce8eae Update README styling section to match the SCSS Modules convention
Was still describing Tailwind, which was removed from the project.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 08:14:27 +02:00
lukasandClaude Sonnet 5 0d8f8f8148 Bring the codebase in line with CLAUDE.md conventions
- Convert getRouter, OrderingPage, and OrderStatusRoute from function
  declarations to arrow functions
- Migrate header-user.tsx off raw Tailwind classes onto a co-located
  SCSS module, and remove Tailwind entirely (deps, Vite plugin,
  styles.css) since it was the only consumer and duplicated the
  documented SCSS Modules system
- Fix CLAUDE.md's stale ~/ alias example and structure diagram to
  match the project's actual #/ and @/ aliases and directories

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 08:06:22 +02:00