Storefront ordering
The guest-facing menu, cart, checkout, and order-confirmation flow in current Restaurant source.
Openfront Restaurant includes a customer-facing menu and ordering application. Current routes cover the menu, cart checkout, order confirmation, sign-in, profile, addresses, and customer order history.
Current routes
/for the menu and cart entry;/menu/[id]for an item page;/checkoutfor contact, delivery, payment, and review steps;/order/confirmed/[id]for confirmation;/account,/account/profile,/account/addresses, and account order routes.
The storefront implementation lives under app/(storefront) and features/storefront. Keystone models and custom GraphQL operations remain the backend contract.
What drives the storefront
StoreSettingssupplies branding, locale, currency, hours, delivery rules, tax, and pickup settings.MenuCategory,MenuItem, andMenuItemModifiersupply menu content and customization.CartandCartItemhold checkout state.PaymentCollectionandPaymentSessionhold the selected provider session.RestaurantOrder,OrderItem, andPaymentare created when checkout completes.
Current checkout sequence
Create or resume a cart
The server stores a cart ID in the _restaurant_cart_id cookie. Cart reads and writes call custom operations that check the authenticated user or the matching cart cookie before using privileged Keystone access.
Add menu items and checkout details
The cart stores item quantities, modifiers, special instructions, contact data, pickup or delivery mode, and delivery fields. Guest contact submission currently creates a user record when no signed-in user exists and connects it to the cart.
Validate delivery and calculate totals
Checkout normalizes the address and checks the configured delivery mode, country, postal code, and minimum. completeActiveCart recalculates tax, tip, pickup discount, delivery fee, and total from current cart and StoreSettings data.
Select and confirm payment
The storefront initiates a PaymentSession. Stripe confirms card payment in the browser; PayPal uses its order approval flow; the manual provider records pending payment. Order completion checks or captures non-manual payment through the configured adapter before creating the order.
Create the order
completeActiveCart creates the RestaurantOrder, its OrderItem rows, a Payment, the cart-to-order link, and kitchen tickets for kitchen-active statuses. The confirmation page then reads the resulting order.
Checkout mutation
After a payment session has been selected and, where required, approved by the provider, the storefront completes the cart with this custom operation:
mutation CompleteRestaurantCart($cartId: ID!, $paymentSessionId: ID) {
completeActiveCart(cartId: $cartId, paymentSessionId: $paymentSessionId) {
id
orderNumber
status
secretKey
}
}Use the generated schema.graphql from the same source revision. Do not replace this workflow with unrestricted generated CRUD from an untrusted client.
Order access
getCustomerOrder(orderId, secretKey) returns an order to its authenticated customer. It also accepts the exact secretKey for an order that has one. Treat that value as a credential: keep it out of analytics, logs, referrers, screenshots, and shared caches, and test that wrong-user and wrong-secret requests return no order details.
Current payment paths
The storefront renders Stripe, PayPal, and manual payment controls when their provider sessions are selected. Availability still depends on installed provider records, environment configuration, credentials, adapter responses, and the exact checkout path being tested.
Current limitations
Current completion performs several privileged writes and provider calls without one encompassing database transaction or a caller-supplied idempotency key. Test retries, duplicate submission, partial order/item/payment writes, provider reconciliation, and kitchen-ticket recovery before accepting live orders.
- The application exposes no
/api/categories,/api/menu-items, or/api/orders/*REST routes in current source. External clients should use reviewed GraphQL operations or add a separately authenticated API contract. - The customer storefront does not include a reservations flow.
- A cart cookie contains the cart ID rather than a separate scoped cart token; cookie security and cross-owner negative tests remain important.
- Provider support in the UI does not establish end-to-end readiness for refunds, webhooks, retries, or reconciliation.
- Generated list CRUD remains distinct from the safer custom cart and order workflows and should not be exposed merely to simplify another client.