UI Functionality + E2E Coverage Audit
Date: 2026-04-26 Method: 8 parallel deep-dive agents inspected 38 dashboard pages, 90+ Playwright specs, and traced each user-visible feature to its API binding. Scope: Front Desk + Reservations + Tape Chart, Housekeeping + Maintenance + Inventory, POS + Kitchen, CRM + Guests + Loyalty, Banquet + Spa + Activities, Settings + Property + Rates, Cash + Payments + Billing + Channel Manager, Reports + Analytics + Misc.
Severity legend
- CRITICAL — blocks a daily-revenue or daily-ops business function. Cannot ship to a paying customer.
- HIGH — feature is broken or stub but a workaround exists. Visible to users; embarrassing.
- MEDIUM — stub/dummy data or missing E2E test, but the function is not on the daily critical path.
- LOW — nice-to-have, not currently working, no business impact.
Aggregate scoreboard
| Domain | CRITICAL | HIGH | MEDIUM | LOW | Notes |
|---|---|---|---|---|---|
| Front Desk + Reservations + Tape Chart | 3 | 2 | 4 | 1 | Folio settle untested; arrival/departure/in-house tabs are placeholder strings |
| Housekeeping + Maintenance + Inventory | 0 | 3 | 4 | 0 | Core CRUD wired; reorder + lost-found have stub buttons + no E2E |
| POS + Kitchen + KOT | 1 | 3 | 3 | 1 | P1-B1 email-bill endpoint shipped but no UI button |
| CRM + Guests + Loyalty | 2 | 1 | 3 | 0 | P0-12 guardian fields + P1-C4 DSAR have NO UI yet (despite backend) |
| Banquet + Spa + Activities | 4 | 3 | 2 | 0 | Function sheets + contract PDF + costing + EventItem.menuItemId all UI-missing |
| Settings + Property + Rates | 2 | 4 | 2 | 0 | Logo upload + SAP/Tally/WhatsApp integrations are pure UI stubs |
| Cash + Payments + Billing + Channel | 2 | 0 | 2 | 1 | SendGrid bounce events not surfaced; Razorpay LIVE gate missing |
| Reports + Analytics + Dashboard Home + Misc | 1 | 1 | 4 | 0 | /partners is hardcoded mock; Notifications templates+settings pages missing |
| Total | 15 | 17 | 24 | 3 | 59 findings |
CRITICAL (15) — must fix before paying customer
CRITICAL-1: Front Desk arrivals / departures / in-house tabs render literal strings
File: src/app/(dashboard)/front-desk/arrivals/keynova.tsx
Symptom: {tab === 'arrivals' && 'Arrivals — content pending'} — no data table.
Impact: Front desk cannot see today's arriving / in-house / departing guests from the canonical entry point. Workaround via /reservations?filter=… exists but trains staff on a different navigation pattern.
E2E gap: front-desk-arrivals.spec.ts only checks page load; never asserts row content.
Fix: Render ArrivalsTable / InHouseTable / DeparturesTable driven by useReservations with the date filter.
CRITICAL-2: Folio settle flow has no E2E coverage
File: src/app/(dashboard)/front-desk/folio/[id]/page.tsx lines 560-563
Symptom: Settle button calls a mutation but no test verifies folio.status='SETTLED' transitions, no test verifies post-settle UI redirect.
Impact: Audit trail can silently break; we'd only catch via finance reconciliation after the fact.
Fix: New E2E folio-settle.spec.ts covering balance-zero settle, non-zero settle rejection, SETTLED status visible in list.
CRITICAL-3: Reservations list "Today's Arrivals/Departures/In-House" chip filters not tested
Status: UI works (verified by direct curl); no Playwright test exercises the filter chips.
Fix: Extend 15-crud-reservations.spec.ts to click each chip and assert filtered count > 0 against seeded data.
CRITICAL-4: POS POST /orders/:id/email endpoint shipped (P1-B1) but no UI button
File: src/app/(dashboard)/pos/orders/... (no email-bill button anywhere)
Impact: New endpoint is unreachable to staff. Hot fix: add "Email Bill" button next to "Print Receipt" in the order detail panel.
E2E gap: No test for the endpoint via dashboard; the flow test exists at the API layer (smoke-pos-order.real.spec.ts).
CRITICAL-5: P0-12 guardian fields have backend + flow tests but NO dashboard UI
Files: src/app/(dashboard)/crm/guests/... — no guardianName / guardianRelation / guardianPhone capture in the create/edit guest form.
Impact: DPDPA §9 compliance enforced at API layer but staff cannot fill the fields from the dashboard. Front-desk would 400 on minor check-in until the fields are added.
Fix: Add a "Guardian (required for minors)" section to the guest form, conditional on dateOfBirth < 18.
CRITICAL-6: P1-C4 DSAR (DPDP request) tracking has NO UI
File: none — the /crm/dsar page does not exist.
Impact: Backend stores DsarRequest rows with 30-day SLA + audit entries (P1-C4 shipped this week) but staff cannot view, advance, or close them. Compliance officer can't run DPDP §13(3).
Fix: New page /crm/dsar with list (filtered by status), detail, status-flip controls, audit-entry timeline.
CRITICAL-7: Banquet function sheet CRUD has no UI at all
Files: none — no /banquet/events/[id]/function-sheet page.
Impact: Banquet ops cannot capture setup, seating, menu, AV, timeline, staff. Catalogued as P0 by audit before; verified again now.
Fix: Add full function-sheet editor with the JSON columns existing on the schema.
CRITICAL-8: Banquet contract PDF generation has no UI
Status: Puppeteer Chromium runtime fix shipped this week (banquet 84d5055) but no dashboard button calls /api/events/:id/contract/generate.
Fix: Add "Generate Contract" + "Download PDF" + "Send for Signature" actions in event detail page.
CRITICAL-9: Banquet costing breakdown not wired into UI
Status: banquetApi.getEventPnl() exists; CostingService backend is now PosServiceClient-backed (this week); event detail page never calls it.
Fix: Add a "Costing" tab on event detail invoking getEventPnl() + render the ingredient-cost breakdown.
CRITICAL-10: Banquet EventItem.menuItemId link UI missing
Status: Schema column shipped this week + DTO accepts it; the event-items table on the dashboard has no column for it and no "link to menu" picker.
Fix: Add a MenuItem picker for FOOD/BEVERAGE event items; show linked status; wire to eventItemsApi.update({menuItemId}).
CRITICAL-11: Settings → Branding → Logo / Favicon upload is fake
File: src/app/(dashboard)/settings/branding/page.tsx line 177
Symptom: onChange={() => { updateField('logoUrl', 'uploaded'); }} — never sends file to S3, just sets a string.
Impact: Hotel uploads logo, sees "uploaded" text, refresh shows nothing. Trust-killing on Day 1.
Fix: Either implement signed S3 upload (presigned URL via /api/uploads/sign + S3 PUT) or remove the upload UI until vendor C-4 SendGrid + AWS S3 wiring lands.
CRITICAL-12: Settings → Integrations → SAP / Tally / WhatsApp are massive UI stubs
Files: src/app/(dashboard)/settings/integrations/{sap,tally,whatsapp}/ (515-620 LoC each)
Symptom: Pages render comprehensive sync-log + reconciliation UIs but call /api/integrations/{sap,tally,whatsapp}/* endpoints that don't exist on any backend service.
Impact: Sales demo discovery — "you said this works." Buyer concern when the buttons silently 404.
Fix: Either gate behind a "Coming Q3" feature flag or remove from sidebar until backend lands.
CRITICAL-13: SendGrid bounce/complaint events have no UI surface (P1-C2 follow-up)
Status: Webhook receiver shipped + writes opt-out to NotificationPreference; no page lists bounced emails or shows the complaint count.
Impact: Marketing manager can't see why a campaign's open-rate dropped.
Fix: Add a "Deliverability" tab on /crm/campaigns/:id/metrics showing bounce/spam/unsubscribe counts with drill-through.
CRITICAL-14: Razorpay LIVE-key gating not enforced in payment-link create
File: src/app/(dashboard)/payments/links/...
Symptom: No check that the active merchant account is in LIVE mode before letting staff send a real payment link to a guest.
Impact: First Day 1 payment goes to test environment; guest gets confused; charge never settles.
Fix: Disable "Create Link" button when merchant account mode='TEST'; add prominent banner.
CRITICAL-15: /partners page is hardcoded mock data
File: src/app/(dashboard)/partners/page.tsx lines 18-31, 34-99
Symptom: Static array of 8 fake partners with hardcoded commission tiers. Zero API calls.
Impact: Buyer asks "show me the channel partner module" → demo lies.
Fix: Either implement real backend (KeyNova has a partner-org concept tracked separately) OR remove from the sidebar.
HIGH (17) — broken/stub but workaround exists
HIGH-1: Front Desk Room Move / Room Upgrade / Print GRC buttons → toast('coming soon')
File: src/app/(dashboard)/front-desk/page.tsx lines 40-50
Fix: Wire frontDeskApi.moveRoom() + roomUpgradesApi.offer() + GRC PDF endpoint, OR remove buttons.
HIGH-2: Tape chart drag-and-drop reservation move is not implemented
File: src/app/(dashboard)/front-desk/calendar/keynova.tsx
Status: Heatmap renders; drag-drop not wired.
Fix: Add HTML5 DnD calling POST /reservations/assign-room.
HIGH-3: Housekeeping room board "Mark Clean" button not wired to PATCH mutation
Symptom: Selection panel renders checklist + "Mark Clean" but the click is a no-op.
Fix: Wire to useUpdateTaskStatus({status:'COMPLETED'}) for the latest task on that room.
HIGH-4: HK auto-reorder "Add Rule" + "Check Stock Levels" buttons are toast stubs
File: src/app/(dashboard)/housekeeping/inventory/reorder/page.tsx
Status: P3-1 shipped backend (this week); list/approve/receive flows wired; "Add Rule" form missing.
Fix: Add CreateReorderRule dialog (POST /api/housekeeping/inventory/reorder/rules).
HIGH-5: HK lost-found "Register Found Item" button is toast stub
Fix: Add CreateLostFoundItem dialog (POST /api/housekeeping/lost-found).
HIGH-6: POS void-approval workflow has no E2E
Files: VoidRequestDialog + VoidApprovalDialog exist; mutations wired; no test.
Fix: New pos-void-approval.spec.ts covering request → approve → reject paths.
HIGH-7: POS split-bill / merge / room-charge validation lack E2E
Status: UI dialogs ship; no test exercises the API contracts.
Fix: Extend 18-pos-workflow.spec.ts.
HIGH-8: POS WebSocket KOT real-time updates untested
Status: useRealtimeKitchen listens to 4 events; never validated in CI.
Fix: New E2E creates an order in tab A, watches KDS in tab B, asserts socket-driven update.
HIGH-9: Banquet event payments are read-only
File: event detail page lines 319-351 Fix: Add CreatePayment / EditPayment dialogs.
HIGH-10: Spa packages have no UI page
Status: usePackages hook exists; no /spa/packages route.
Fix: Build the page (treatments + therapists pages exist as templates).
HIGH-11: Spa therapist availability schema validator (P1-B4) has no UI
Status: Backend rejects malformed JSON; dashboard saves without client-side validation, surface errors only as 400 toasts. Fix: Add a structured editor (per-day toggle + start/end pickers) so staff never sends invalid JSON.
HIGH-12: Settings API Keys management is hardcoded mock
File: src/app/(dashboard)/settings/api/page.tsx
Fix: Either implement key CRUD (backend already has /auth/api-keys per the api-key flow test) or remove the page.
HIGH-13: Settings Compliance (DSAR) page renders mock requests
File: src/app/(dashboard)/settings/compliance/page.tsx
Fix: Replace mockDsarRequests with the real DSAR list (P1-C4 backend ready) — fold into the new /crm/dsar page from CRITICAL-6.
HIGH-14: Notifications Templates + Settings sub-pages are placeholders
Status: Queue Status page real; the other 2 nav links go to "coming soon"-type pages. Fix: Implement template CRUD + per-tenant comm-preferences UI.
HIGH-15: AI / NLQ backend query logic untested
Status: NLQueryBar component scaffolded; backend /api/analytics/nlq likely returns mock or 501.
Fix: Verify backend, gate UI behind a feature flag if not ready.
HIGH-16: Channel manager rate-parity reconciliation view absent
Status: Sync logs + throughput exist; no parity check tab. Fix: Add parity tab on channel detail page.
HIGH-17: Dashboard home falls back to mock data on API failure
File: src/app/(dashboard)/page.tsx
Symptom: When /api/analytics/kpi fails, KPIs show static mock data without an error banner.
Fix: Replace mock fallback with an error banner + retry; on a paying customer's stack, "always shows data" hides real outages.
MEDIUM (24) — stub data or missing E2E, not daily critical
| # | Finding | File / Test |
|---|---|---|
| M-1 | Folio void-transaction flow has no E2E | folio/[id]/page.tsx |
| M-2 | Folio post-adjustment with balance recalc has no E2E | same |
| M-3 | Front Desk key-cards page — encode/revoke/replace mutations untested + payload shape uncertain | front-desk/key-cards/page.tsx |
| M-4 | Front Desk PBX phone — wake-up + call-history UI exists but Schedule button is toast stub | front-desk/phone/page.tsx line 183 |
| M-5 | Reservations detail → upsells / services tabs say "integration pending" | reservations/[id]/keynova.tsx |
| M-6 | Group bookings rooming-list editor missing | reservations/groups/[id]/keynova.tsx |
| M-7 | Check-in form Form C / foreign-guest path has no E2E | front-desk/check-in/[id]/keynova.tsx |
| M-8 | Check-out feedback rating capture has no E2E | front-desk/check-out/[id]/keynova.tsx |
| M-9 | HK maintenance-request real-backend E2E missing (only mocked) | tests/housekeeping-maintenance.spec.ts |
| M-10 | HK inventory linen-movement no E2E | housekeeping/inventory/page.tsx |
| M-11 | HK auto-reorder PO approve/receive no E2E | housekeeping/inventory/reorder/page.tsx |
| M-12 | Lost & Found claim/dispose no E2E | housekeeping/lost-found/page.tsx |
| M-13 | POS pricing rules / surge pricing — Revenue Manager only, not POS | pos/... |
| M-14 | POS terminal-payment Stripe path partially shown | PaymentDialog |
| M-15 | CRM guest dedup / merge has API but no UI | crm/guests/... |
| M-16 | CRM guest preferences edit page may be stub | guests/[id]/preferences |
| M-17 | CRM loyalty earn / redeem manual UI missing | crm/loyalty/... |
| M-18 | Banquet event-status transitions have shallow E2E (badge check only) | banquet-status.spec.ts |
| M-19 | Banquet activities real-backend E2E missing | activities/... |
| M-20 | Settings currency + in-room-tech backend likely stub | settings/currency, settings/in-room-tech |
| M-21 | Bed-map (Vishramgruh) zone switching untested | bed-map/page.tsx |
| M-22 | Pilot snapshot rollback path untested | pilot/page.tsx |
| M-23 | Owner Portal data assertions absent in E2E | owner-portal/page.tsx |
| M-24 | Reports export file content not validated in E2E | reports/page.tsx + ReportExportBar |
LOW (3) — cosmetic / nice-to-have
| # | Finding |
|---|---|
| L-1 | E2E tests use brittle text-based selectors instead of data-testid attributes |
| L-2 | KDS timer skeleton missing during 15-second re-render tick |
| L-3 | Tape chart drag-handle visual hint not styled |
E2E test plan
Tests to ADD (new specs)
| Priority | Spec | Coverage |
|---|---|---|
| P0 | folio-settle.spec.ts | Balance-zero settle, non-zero rejection, SETTLED status visible (CRITICAL-2) |
| P0 | dashboard-arrivals-tabs.spec.ts | Click each chip on /front-desk/arrivals, assert table populates (CRITICAL-1) |
| P0 | crm-dsar-lifecycle.spec.ts | Create DPDP request, advance status, close (CRITICAL-6) |
| P0 | crm-guardian-fields.spec.ts | Minor guest creation requires guardian (CRITICAL-5) |
| P0 | pos-email-bill.spec.ts | Bill sent → notification log row (CRITICAL-4) |
| P0 | banquet-function-sheet.spec.ts | Once UI ships (CRITICAL-7) |
| P0 | banquet-contract-pdf.spec.ts | Once UI ships (CRITICAL-8) |
| P1 | pos-void-approval.spec.ts | Request → approve → reject (HIGH-6) |
| P1 | pos-websocket-kot.spec.ts | Two-tab realtime KDS update (HIGH-8) |
| P1 | housekeeping-purchase-orders.spec.ts | Approve + receive PO + stock incremented (HIGH-4) |
| P1 | housekeeping-lost-found.spec.ts | Register + claim + dispose (HIGH-5) |
| P1 | front-desk-key-cards.spec.ts | Encode + revoke + replace (M-3) |
| P1 | front-desk-phone.spec.ts | Wake-up calls + call history (M-4) |
| P2 | crm-feedback-respond.spec.ts | Survey → response → status flip |
| P2 | crm-drip-execution.spec.ts | Drip launch → step progression |
| P2 | pilot-baseline-active-completed.spec.ts | Full state machine |
Tests to ENHANCE (existing specs are page-load smoke only)
| Spec | Add scenario |
|---|---|
16-checkin-checkout.spec.ts | Form submission + API mock + success path |
17-housekeeping-tasks.spec.ts | Status-transition click sequence PENDING→INSPECTED |
front-desk-folio.spec.ts | Charge / payment / transfer / split mutations |
housekeeping-maintenance.spec.ts | Real-backend E2E (currently mocked-only) |
front-desk-tape-chart.spec.ts | Drag-drop reservation move (when UI ships) |
banquet-status.spec.ts | Transition button click + mutation + new status visible |
loyalty-program.spec.ts | Enroll member + earn points + tier upgrade |
crm-campaigns.spec.ts | Recipient preview + launch + metrics refresh |
06-control-center.spec.ts | Click an action → mutation → state change |
Recommended sequencing
Sprint 1 (4 d): CRITICAL 1, 4, 5, 6, 11, 14, 15. Net effect: every demo-blocking lie is gone. Sprint 2 (5 d): CRITICAL 7, 8, 9, 10. Banquet feature parity. Shipping these together because they all touch the same UI surface. Sprint 3 (3 d): CRITICAL 2, 3, 12, 13. E2E gaps + integrations triage (gate-or-remove). Sprint 4 (continuous): HIGH list — split across pods, ~2 items / week. Backlog: MEDIUM + LOW — pull when associated CRITICAL/HIGH ships.
Ownership matrix
| Domain | Lead | CRITICAL items |
|---|---|---|
| Front Desk + Reservations | Eng-1 | 1, 2, 3 |
| POS | Eng-2 | 4 |
| CRM + Guests | Eng-3 | 5, 6 |
| Banquet | Eng-4 | 7, 8, 9, 10 |
| Settings | Eng-5 | 11, 12 |
| Cash + Payments | Eng-6 | 13, 14 |
| Misc / Partners | Eng-7 | 15 |
What's NOT in this report
- Booking-engine (separate React app)
- Mobile apps
- Admin portal
- Backend service correctness (covered by flow tests already)
- Performance / load testing
- Accessibility audit (separate
accessibility.spec.tsexists; gaps not assessed here)