diff --git a/docs/architecture/frontend-boundary.md b/docs/architecture/frontend-boundary.md
index 28cc840..2c116de 100644
--- a/docs/architecture/frontend-boundary.md
+++ b/docs/architecture/frontend-boundary.md
@@ -23,9 +23,9 @@
## UI Workflow Coverage
-- Customer order status dashboard with current orders
+- Customer order status dashboard with current orders from the shared restaurant lifecycle
- Selected order detail lookup
- Recent order history and event feed
-- Customer order submission and recent submission results
+- Customer order submission and recent submission results with shared-lifecycle progression hints
- Session-expired handling with reauthentication guidance
- Protected route shell for status, submission, and session inspection
diff --git a/docs/runbooks/local-development.md b/docs/runbooks/local-development.md
index 777b87e..67d2098 100644
--- a/docs/runbooks/local-development.md
+++ b/docs/runbooks/local-development.md
@@ -25,8 +25,8 @@ npm run dev
## Available Screens
-- `/status`: current order status, selected order detail, history, and recent events
-- `/submit`: customer order submission and recent submission results
+- `/status`: current order status, selected order detail, history, recent events, and shared-lifecycle guidance
+- `/submit`: customer order submission and recent submission results with kitchen/payment readiness hints
- `/session`: current Thalos session profile payload
## Build
diff --git a/docs/runbooks/testing.md b/docs/runbooks/testing.md
index 07ca6d3..a1194a1 100644
--- a/docs/runbooks/testing.md
+++ b/docs/runbooks/testing.md
@@ -17,7 +17,7 @@ npm run test:ci
- `src/api/client.test.ts`: runtime-config precedence and fallback behavior.
- `src/api/dashboardApi.test.ts`: endpoint path/query composition for status, detail, history, and submit flows.
- `src/auth/oidcLogin.test.ts`: OIDC start-url generation and safe return-url fallback.
-- `src/App.test.tsx`: central login screen, status/detail/history loading, order submission, and session-expired reauthentication guidance.
+- `src/App.test.tsx`: central login screen, shared-lifecycle order messaging, order submission progression hints, and session-expired reauthentication guidance.
## Notes
diff --git a/src/App.test.tsx b/src/App.test.tsx
index 5fd772e..7f10eca 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -57,20 +57,20 @@ describe('Customer Orders App', () => {
vi.mocked(loadDashboard).mockResolvedValue({
contextId: 'demo-context',
summary: '2 open orders',
- orders: [{ orderId: 'CO-1001', tableId: 'T-08', status: 'Submitted', guestCount: 2, itemIds: ['ITEM-101'] }],
+ orders: [{ orderId: 'ORD-1001', tableId: 'T-08', status: 'Preparing', guestCount: 2, itemIds: ['ITEM-101'] }],
recentEvents: ['status payload event']
});
vi.mocked(loadOrderHistory).mockResolvedValue({
contextId: 'demo-context',
summary: 'recent history',
- orders: [{ orderId: 'CO-0999', tableId: 'T-04', status: 'Completed', guestCount: 3, itemIds: ['ITEM-202'] }],
- recentEvents: ['Order CO-0999 completed']
+ orders: [{ orderId: 'ORD-0999', tableId: 'T-04', status: 'Served', guestCount: 3, itemIds: ['ITEM-202'] }],
+ recentEvents: ['Order ORD-0999 completed service and is ready for payment capture']
});
vi.mocked(loadOrderDetail).mockResolvedValue({
contextId: 'demo-context',
summary: 'selected order',
- order: { orderId: 'CO-1001', tableId: 'T-08', status: 'Submitted', guestCount: 2, itemIds: ['ITEM-101'] },
- recentEvents: ['Order CO-1001 confirmed']
+ order: { orderId: 'ORD-1001', tableId: 'T-08', status: 'Preparing', guestCount: 2, itemIds: ['ITEM-101'] },
+ recentEvents: ['Order ORD-1001 confirmed']
});
render();
@@ -80,9 +80,10 @@ describe('Customer Orders App', () => {
await waitFor(() => expect(loadDashboard).toHaveBeenCalledWith('demo-context'));
expect(loadOrderHistory).toHaveBeenCalledWith('demo-context');
- expect(loadOrderDetail).toHaveBeenCalledWith('demo-context', 'CO-1001');
+ expect(loadOrderDetail).toHaveBeenCalledWith('demo-context', 'ORD-1001');
expect(await screen.findByText('2 open orders')).toBeInTheDocument();
- expect(await screen.findByText('Order CO-0999 completed')).toBeInTheDocument();
+ expect(await screen.findByText('Order ORD-0999 completed service and is ready for payment capture')).toBeInTheDocument();
+ expect(await screen.findByText('Submitted customer orders progress through kitchen preparation and become payable only after service is complete.')).toBeInTheDocument();
});
it('submits customer order from action route', async () => {
@@ -94,21 +95,22 @@ describe('Customer Orders App', () => {
});
vi.mocked(submitCustomerOrder).mockResolvedValue({
contextId: 'demo-context',
- orderId: 'CO-2200',
+ orderId: 'ORD-2200',
accepted: true,
- summary: 'accepted',
- status: 'Submitted'
+ summary: 'Order ORD-2200 was accepted and is ready for kitchen dispatch.',
+ status: 'accepted'
});
render();
await waitFor(() => expect(screen.getByText('Submit Order')).toBeInTheDocument());
fireEvent.click(screen.getByText('Submit Order'));
- fireEvent.change(screen.getByPlaceholderText('Order Id'), { target: { value: 'CO-2200' } });
+ fireEvent.change(screen.getByPlaceholderText('Order Id'), { target: { value: 'ORD-2200' } });
fireEvent.click(screen.getByRole('button', { name: 'Submit Customer Order' }));
await waitFor(() => expect(submitCustomerOrder).toHaveBeenCalledTimes(1));
- expect((await screen.findAllByText('Submitted')).length).toBeGreaterThan(0);
+ expect((await screen.findAllByText('accepted')).length).toBeGreaterThan(0);
+ expect(await screen.findByText('The kitchen should receive this order next.')).toBeInTheDocument();
});
it('shows reauthentication guidance when status loading returns session expired', async () => {
diff --git a/src/App.tsx b/src/App.tsx
index fa33d9f..e6ecf8f 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -71,7 +71,7 @@ const orderColumns = [
{
title: 'Status',
dataIndex: 'status',
- render: (value: string) => {value}
+ render: (value: string) => {value}
},
{ title: 'Guests', dataIndex: 'guestCount' },
{
@@ -96,7 +96,7 @@ function CustomerOrdersShell() {
const navigate = useNavigate();
const [contextId, setContextId] = useState('demo-context');
- const [statusOrderId, setStatusOrderId] = useState('CO-1001');
+ const [statusOrderId, setStatusOrderId] = useState('ORD-1001');
const [statusPayload, setStatusPayload] = useState(null);
const [detailPayload, setDetailPayload] = useState(null);
const [historyPayload, setHistoryPayload] = useState(null);
@@ -241,7 +241,7 @@ function CustomerOrdersShell() {
Customer Orders
- Protected order workflows for status, detail, history, and submission through the customer-orders BFF.
+ Protected order workflows for status, detail, history, and submission through the shared restaurant lifecycle.
{session.error && }
{workflowState.error && (
@@ -292,6 +292,9 @@ function CustomerOrdersShell() {
{statusPayload.contextId}
{statusPayload.summary}
+
+ Submitted customer orders progress through kitchen preparation and become payable only after service is complete.
+
pagination={false}
@@ -313,9 +316,12 @@ function CustomerOrdersShell() {
{detailPayload.summary}
{detailPayload.order.orderId}
{detailPayload.order.tableId}
- {detailPayload.order.status}
+
+ {detailPayload.order.status}
+
{detailPayload.order.guestCount}
{detailPayload.order.itemIds.join(', ')}
+ {orderProgressHint(detailPayload.order.status)}
) : (
@@ -354,7 +360,7 @@ function CustomerOrdersShell() {
layout="vertical"
initialValues={{
contextId,
- orderId: 'CO-1001',
+ orderId: 'ORD-1001',
tableId: 'T-08',
guestCount: 2,
itemIdsText: 'ITEM-101,ITEM-202'
@@ -385,8 +391,11 @@ function CustomerOrdersShell() {
{orderResponse.contextId}
{orderResponse.orderId}
{String(orderResponse.accepted)}
- {orderResponse.status}
+
+ {orderResponse.status}
+
{orderResponse.summary}
+ {orderProgressHint(orderResponse.status)}
) : (
@@ -406,7 +415,10 @@ function CustomerOrdersShell() {
title: 'Accepted',
render: (_, record) => {String(record.accepted)}
},
- { title: 'Status', dataIndex: 'status' },
+ {
+ title: 'Status',
+ render: (_, record) => {record.status}
+ },
{ title: 'Summary', dataIndex: 'summary' }
]}
/>
@@ -447,4 +459,48 @@ function providerLabel(provider: IdentityProvider): string {
return String(provider);
}
+function workflowTagColor(status: string): string {
+ switch (status.toLowerCase()) {
+ case 'accepted':
+ case 'submitted':
+ return 'blue';
+ case 'preparing':
+ case 'cooking':
+ return 'gold';
+ case 'ready':
+ case 'readyforpickup':
+ return 'cyan';
+ case 'served':
+ return 'green';
+ case 'paid':
+ return 'purple';
+ case 'blocked':
+ case 'failed':
+ case 'canceled':
+ return 'red';
+ default:
+ return 'default';
+ }
+}
+
+function orderProgressHint(status: string): string {
+ switch (status.toLowerCase()) {
+ case 'accepted':
+ case 'submitted':
+ return 'The kitchen should receive this order next.';
+ case 'preparing':
+ case 'cooking':
+ return 'Kitchen is actively preparing this order.';
+ case 'ready':
+ case 'readyforpickup':
+ return 'This order is ready for handoff or table delivery.';
+ case 'served':
+ return 'The restaurant can now open payment capture for this check.';
+ case 'paid':
+ return 'This order and its check are fully completed.';
+ default:
+ return 'Track this order across the shared restaurant lifecycle.';
+ }
+}
+
export default App;