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>
This commit is contained in:
2026-09-10 11:58:24 +02:00
co-authored by Claude Sonnet 5
parent 5059f40d4c
commit 79bd64ce8c
54 changed files with 3514 additions and 301 deletions
+61 -8
View File
@@ -11,6 +11,10 @@ export const seedGhostKitchen = async (db: NodePgDatabase<typeof schema>) => {
.values({ name: 'Ghost Kitchen' })
.returning()
const [prepTag] = await db
.insert(schema.machineTags)
.values({ name: 'prep' })
.returning()
const [ovenTag] = await db
.insert(schema.machineTags)
.values({ name: 'oven' })
@@ -24,6 +28,10 @@ export const seedGhostKitchen = async (db: NodePgDatabase<typeof schema>) => {
.values({ name: 'assembly' })
.returning()
const [prep1] = await db
.insert(schema.machines)
.values({ name: 'Prep Station 1', machineTagId: prepTag.id })
.returning()
const [oven1] = await db
.insert(schema.machines)
.values({ name: 'Oven 1', machineTagId: ovenTag.id })
@@ -47,12 +55,50 @@ export const seedGhostKitchen = async (db: NodePgDatabase<typeof schema>) => {
})
.returning()
await db.insert(schema.menuItemSteps).values({
menuItemId: pizza.id,
sequence: 1,
machineTagId: ovenTag.id,
estimatedDurationSeconds: 600,
})
await db.insert(schema.menuItemSteps).values([
{
menuItemId: pizza.id,
sequence: 1,
name: 'Flattening dough',
machineTagId: prepTag.id,
estimatedDurationSeconds: 30,
},
{
menuItemId: pizza.id,
sequence: 2,
name: 'Spreading sauce',
machineTagId: prepTag.id,
estimatedDurationSeconds: 20,
},
{
menuItemId: pizza.id,
sequence: 3,
name: 'Adding toppings',
machineTagId: prepTag.id,
estimatedDurationSeconds: 30,
},
{
menuItemId: pizza.id,
sequence: 4,
name: 'Baking in the oven',
machineTagId: ovenTag.id,
estimatedDurationSeconds: 600,
},
{
menuItemId: pizza.id,
sequence: 5,
name: 'Slicing',
machineTagId: assemblyTag.id,
estimatedDurationSeconds: 20,
},
{
menuItemId: pizza.id,
sequence: 6,
name: 'Packaging',
machineTagId: assemblyTag.id,
estimatedDurationSeconds: 20,
},
])
const [burger] = await db
.insert(schema.menuItems)
@@ -68,12 +114,14 @@ export const seedGhostKitchen = async (db: NodePgDatabase<typeof schema>) => {
{
menuItemId: burger.id,
sequence: 1,
name: 'Grilling patty',
machineTagId: grillTag.id,
estimatedDurationSeconds: 240,
},
{
menuItemId: burger.id,
sequence: 2,
name: 'Assembling burger',
machineTagId: assemblyTag.id,
estimatedDurationSeconds: 90,
},
@@ -81,8 +129,13 @@ export const seedGhostKitchen = async (db: NodePgDatabase<typeof schema>) => {
return {
brand,
machineTags: { oven: ovenTag, grill: grillTag, assembly: assemblyTag },
machines: { oven1, grill1, assembly1 },
machineTags: {
prep: prepTag,
oven: ovenTag,
grill: grillTag,
assembly: assemblyTag,
},
machines: { prep1, oven1, grill1, assembly1 },
menuItems: { pizza, burger },
}
}