docs(waiter-floor-bff): align waiter workflows to shared lifecycle

This commit is contained in:
José René White Enciso 2026-03-31 18:50:18 -06:00
parent bf78706997
commit 95dc218f28
5 changed files with 23 additions and 18 deletions

View File

@ -26,4 +26,5 @@ This BFF exposes execution-facing waiter workflows over REST while delegating or
## Notes ## 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. - 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. - Correlation IDs are preserved through Thalos session checks and operations-service calls.

View File

@ -9,12 +9,11 @@ waiter-floor-bff
- Epic 3: Improve observability and operational readiness for demo compose environments. - Epic 3: Improve observability and operational readiness for demo compose environments.
## Domain-Specific Candidate Features ## Domain-Specific Candidate Features
- Order lifecycle consistency and state transitions. - Waiter-facing projection over the shared restaurant order/check lifecycle.
- Waiter assignment visibility with recent floor activity context. - 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. - 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). - Operations control-plane policies (flags, service windows, overrides).
- POS closeout and settlement summary alignment.
## Documentation Contract ## Documentation Contract
Any code change in this repository must include docs updates in the same branch. Any code change in this repository must include docs updates in the same branch.

View File

@ -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` - Integration artifact path: `greenfield/demo/restaurant/docker-compose.yml`
## Known Limitations ## 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. - Demo PostgreSQL seeds validate integration contracts and smoke determinism, but do not yet imply full persistence implementation parity.

View File

@ -57,7 +57,8 @@ public sealed class OperationsWaiterServiceClient(HttpClient httpClient) : IWait
new SubmitRestaurantOrderPayload(request.ContextId, request.OrderId, request.TableId, request.ItemCount), new SubmitRestaurantOrderPayload(request.ContextId, request.OrderId, request.TableId, request.ItemCount),
cancellationToken); 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 var summary = payload.Accepted
? $"Updated order {payload.OrderId}. {payload.Summary}" ? $"Updated order {payload.OrderId}. {payload.Summary}"
: payload.Summary; : payload.Summary;

View File

@ -17,10 +17,10 @@ public sealed class OperationsWaiterServiceClientTests
"locationId": "restaurant-demo", "locationId": "restaurant-demo",
"summary": "2 active waiter assignments are currently visible.", "summary": "2 active waiter assignments are currently visible.",
"assignments": [ "assignments": [
{ "waiterId": "waiter-01", "tableId": "T-12", "status": "serving", "activeOrders": 2 } { "waiterId": "service-pool", "tableId": "T-12", "status": "Preparing", "activeOrders": 2 }
], ],
"recentActivity": [ "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.Equal("restaurant-demo", response.LocationId);
Assert.Single(response.Assignments); Assert.Single(response.Assignments);
Assert.Single(response.RecentActivity); 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] [Fact]
@ -44,7 +45,7 @@ public sealed class OperationsWaiterServiceClientTests
"summary": "2 active waiter assignments are currently visible.", "summary": "2 active waiter assignments are currently visible.",
"assignments": [], "assignments": [],
"recentActivity": [ "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] [Fact]
public async Task SubmitOrderAsync_MapsOperationsPayloadToSubmitResponse() public async Task SubmitOrderAsync_MapsSharedLifecycleAcceptanceResponse()
{ {
var client = CreateClient(""" var client = CreateClient("""
{ {
"contextId": "demo-context", "contextId": "demo-context",
"orderId": "ORD-42", "orderId": "ORD-42",
"accepted": true, "accepted": true,
"summary": "Order ORD-42 for table T-12 was accepted with 3 items.", "summary": "Order ORD-42 was accepted and is ready for kitchen dispatch.",
"status": "queued", "status": "accepted",
"submittedAtUtc": "2026-03-31T10:15:00Z" "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); var response = await adapter.SubmitOrderAsync(new SubmitFloorOrderRequest("demo-context", "T-12", "ORD-42", 3), CancellationToken.None);
Assert.True(response.Accepted); Assert.True(response.Accepted);
Assert.Equal("queued", response.Status); Assert.Equal("accepted", response.Status);
Assert.Equal("demo-context", response.ContextId); Assert.Equal("demo-context", response.ContextId);
Assert.Contains("kitchen dispatch", response.Summary);
} }
[Fact] [Fact]
public async Task UpdateOrderAsync_PrefixesAcceptedUpdateSummary() public async Task UpdateOrderAsync_PrefixesSharedLifecycleUpdateSummary()
{ {
var client = CreateClient(""" var client = CreateClient("""
{ {
"contextId": "demo-context", "contextId": "demo-context",
"orderId": "ORD-42", "orderId": "ORD-42",
"accepted": true, "accepted": true,
"summary": "Order ORD-42 for table T-12 was accepted with 4 items.", "summary": "Order ORD-42 was accepted and is ready for kitchen dispatch.",
"status": "queued", "status": "accepted",
"submittedAtUtc": "2026-03-31T10:15:00Z" "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); 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.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) private static HttpClient CreateClient(string json)