diff --git a/docs/api/waiter-floor-workflows.md b/docs/api/waiter-floor-workflows.md index 5a41857..d7ed7da 100644 --- a/docs/api/waiter-floor-workflows.md +++ b/docs/api/waiter-floor-workflows.md @@ -26,4 +26,5 @@ This BFF exposes execution-facing waiter workflows over REST while delegating or ## Notes - The update route currently reuses the operations order submission contract so waiter-floor can expose update semantics without introducing a new cross-repo dependency. +- Both order mutations project into the shared restaurant lifecycle owned by `operations-service`, which means kitchen and POS can observe the same order/check state after downstream stages are wired. - Correlation IDs are preserved through Thalos session checks and operations-service calls. diff --git a/docs/roadmap/feature-epics.md b/docs/roadmap/feature-epics.md index 0ab211f..e8dd8f9 100644 --- a/docs/roadmap/feature-epics.md +++ b/docs/roadmap/feature-epics.md @@ -9,12 +9,11 @@ waiter-floor-bff - Epic 3: Improve observability and operational readiness for demo compose environments. ## Domain-Specific Candidate Features -- Order lifecycle consistency and state transitions. -- Waiter assignment visibility with recent floor activity context. +- Waiter-facing projection over the shared restaurant order/check lifecycle. +- Waiter assignment visibility with recent floor activity derived from persisted restaurant state. - Waiter order update workflows that stay aligned with service-level restaurant order orchestration. -- Kitchen queue and dispatch optimization hooks. +- Cross-app order continuity from waiter submission to kitchen preparation and POS payment. - Operations control-plane policies (flags, service windows, overrides). -- POS closeout and settlement summary alignment. ## Documentation Contract Any code change in this repository must include docs updates in the same branch. diff --git a/docs/runbooks/containerization.md b/docs/runbooks/containerization.md index 714232b..2320e1a 100644 --- a/docs/runbooks/containerization.md +++ b/docs/runbooks/containerization.md @@ -39,5 +39,6 @@ docker run --rm -p 8080:8080 --name waiter-floor-bff agilewebs/waiter-floor-bff: - Integration artifact path: `greenfield/demo/restaurant/docker-compose.yml` ## Known Limitations -- Waiter-floor now delegates workflow snapshots to `operations-service`, but the upstream operations adapter still serves deterministic demo data rather than database-backed state. +- Waiter-floor now delegates workflow snapshots to `operations-service`, which in turn projects persisted shared lifecycle state from `operations-dal`. +- Kitchen-driven progression and POS payment visibility depend on the remaining Stage 46-48 restaurant flow tasks being wired end-to-end. - Demo PostgreSQL seeds validate integration contracts and smoke determinism, but do not yet imply full persistence implementation parity. diff --git a/src/Waiter.Floor.Bff.Application/Adapters/OperationsWaiterServiceClient.cs b/src/Waiter.Floor.Bff.Application/Adapters/OperationsWaiterServiceClient.cs index 76d47c0..a38fb15 100644 --- a/src/Waiter.Floor.Bff.Application/Adapters/OperationsWaiterServiceClient.cs +++ b/src/Waiter.Floor.Bff.Application/Adapters/OperationsWaiterServiceClient.cs @@ -57,7 +57,8 @@ public sealed class OperationsWaiterServiceClient(HttpClient httpClient) : IWait new SubmitRestaurantOrderPayload(request.ContextId, request.OrderId, request.TableId, request.ItemCount), cancellationToken); - // operations-service currently accepts a full order snapshot for both submit and update semantics. + // The waiter BFF deliberately reuses the shared order-write contract so both submit and update + // actions stay aligned with the canonical restaurant lifecycle owned by operations-service. var summary = payload.Accepted ? $"Updated order {payload.OrderId}. {payload.Summary}" : payload.Summary; diff --git a/tests/Waiter.Floor.Bff.Application.UnitTests/OperationsWaiterServiceClientTests.cs b/tests/Waiter.Floor.Bff.Application.UnitTests/OperationsWaiterServiceClientTests.cs index 8e7d977..cd82cd0 100644 --- a/tests/Waiter.Floor.Bff.Application.UnitTests/OperationsWaiterServiceClientTests.cs +++ b/tests/Waiter.Floor.Bff.Application.UnitTests/OperationsWaiterServiceClientTests.cs @@ -17,10 +17,10 @@ public sealed class OperationsWaiterServiceClientTests "locationId": "restaurant-demo", "summary": "2 active waiter assignments are currently visible.", "assignments": [ - { "waiterId": "waiter-01", "tableId": "T-12", "status": "serving", "activeOrders": 2 } + { "waiterId": "service-pool", "tableId": "T-12", "status": "Preparing", "activeOrders": 2 } ], "recentActivity": [ - "demo-context: table T-12 requested dessert menus" + "Order ORD-1002 is currently preparing for table T-12." ] } """); @@ -31,7 +31,8 @@ public sealed class OperationsWaiterServiceClientTests Assert.Equal("restaurant-demo", response.LocationId); Assert.Single(response.Assignments); Assert.Single(response.RecentActivity); - Assert.Equal("waiter-01", response.Assignments.Single().WaiterId); + Assert.Equal("service-pool", response.Assignments.Single().WaiterId); + Assert.Equal("Preparing", response.Assignments.Single().Status); } [Fact] @@ -44,7 +45,7 @@ public sealed class OperationsWaiterServiceClientTests "summary": "2 active waiter assignments are currently visible.", "assignments": [], "recentActivity": [ - "demo-context: table T-08 is waiting for payment capture" + "Order ORD-1003 was served at table T-21 and is ready for payment capture." ] } """); @@ -57,15 +58,15 @@ public sealed class OperationsWaiterServiceClientTests } [Fact] - public async Task SubmitOrderAsync_MapsOperationsPayloadToSubmitResponse() + public async Task SubmitOrderAsync_MapsSharedLifecycleAcceptanceResponse() { var client = CreateClient(""" { "contextId": "demo-context", "orderId": "ORD-42", "accepted": true, - "summary": "Order ORD-42 for table T-12 was accepted with 3 items.", - "status": "queued", + "summary": "Order ORD-42 was accepted and is ready for kitchen dispatch.", + "status": "accepted", "submittedAtUtc": "2026-03-31T10:15:00Z" } """); @@ -74,20 +75,21 @@ public sealed class OperationsWaiterServiceClientTests var response = await adapter.SubmitOrderAsync(new SubmitFloorOrderRequest("demo-context", "T-12", "ORD-42", 3), CancellationToken.None); Assert.True(response.Accepted); - Assert.Equal("queued", response.Status); + Assert.Equal("accepted", response.Status); Assert.Equal("demo-context", response.ContextId); + Assert.Contains("kitchen dispatch", response.Summary); } [Fact] - public async Task UpdateOrderAsync_PrefixesAcceptedUpdateSummary() + public async Task UpdateOrderAsync_PrefixesSharedLifecycleUpdateSummary() { var client = CreateClient(""" { "contextId": "demo-context", "orderId": "ORD-42", "accepted": true, - "summary": "Order ORD-42 for table T-12 was accepted with 4 items.", - "status": "queued", + "summary": "Order ORD-42 was accepted and is ready for kitchen dispatch.", + "status": "accepted", "submittedAtUtc": "2026-03-31T10:15:00Z" } """); @@ -96,7 +98,8 @@ public sealed class OperationsWaiterServiceClientTests var response = await adapter.UpdateOrderAsync(new UpdateFloorOrderRequest("demo-context", "T-12", "ORD-42", 4), CancellationToken.None); Assert.Contains("Updated order ORD-42.", response.Summary); - Assert.Equal("queued", response.Status); + Assert.Contains("kitchen dispatch", response.Summary); + Assert.Equal("accepted", response.Status); } private static HttpClient CreateClient(string json)