Dashboard UX & Information Architecture Audit
Date: 2026-04-25
Repository: hmp-web-dashboard
Scope: all routes under src/app/(dashboard)/** (166 pages), modules under src/components/modules/** (23+ dialogs), sidebar navigation.
A. Action Inventory
| ID | Name | Kind | Domain | Role-Gated? |
|---|---|---|---|---|
| RES-CREATE | Create reservation | mutate | reservations | FRONT_DESK, RESERVATIONS |
| RES-VIEW | View reservation list | read | reservations | FRONT_DESK, RESERVATIONS |
| RES-EDIT | Edit reservation | mutate | reservations | RESERVATIONS, MANAGER |
| RES-CANCEL | Cancel reservation | mutate | reservations | RESERVATIONS, MANAGER |
| RES-GROUP-CREATE | Create group booking | mutate | reservations | RESERVATIONS |
| RES-GROUP-VIEW | View group bookings | read | reservations | RESERVATIONS |
| ARRIVAL-CHECKIN | Check in guest | mutate | front-desk | FRONT_DESK |
| ARRIVAL-VIEW | View arrivals list | read | front-desk | FRONT_DESK |
| DEPARTURE-CHECKOUT | Check out guest | mutate | front-desk | FRONT_DESK |
| DEPARTURE-VIEW | View departures list | read | front-desk | FRONT_DESK |
| FOLIO-VIEW | View guest folio | read | front-desk | FRONT_DESK |
| FOLIO-POST-CHARGE | Post charge to folio | mutate | front-desk | FRONT_DESK |
| FOLIO-POST-PAYMENT | Post payment to folio | mutate | front-desk | FRONT_DESK |
| FOLIO-SPLIT | Split folio | mutate | front-desk | MANAGER |
| FOLIO-TRANSFER | Transfer balance | mutate | front-desk | MANAGER |
| FOLIO-VOID | Void transaction | mutate | front-desk | MANAGER |
| FOLIO-SETTLE | Settle folio | mutate | front-desk | FRONT_DESK |
| FOLIO-PRINT | Print folio / GRC | read | front-desk | FRONT_DESK |
| WALKIN-CREATE | Create walk-in reservation | mutate | front-desk | FRONT_DESK |
| ROOMGRID-UPDATE | Update room status | mutate | front-desk | FRONT_DESK |
| TAPE-CHART-VIEW | View tape chart (calendar) | read | front-desk | FRONT_DESK |
| ROOM-UPGRADE | Offer room upgrade | mutate | front-desk | FRONT_DESK, MANAGER |
| ROOM-MOVE | Move guest to different room | mutate | front-desk | MANAGER |
| ROOM-SWAP | Swap guest between rooms | mutate | front-desk | MANAGER |
| HK-ROOM-FLIP | Flip room status (clean/dirty) | mutate | housekeeping | HOUSEKEEPING, MANAGER |
| HK-TASK-VIEW | View assigned tasks | read | housekeeping | HOUSEKEEPING |
| HK-TASK-INSPECT | Mark room inspected | mutate | housekeeping | HOUSEKEEPING |
| HK-INVENTORY-VIEW | View inventory | read | housekeeping | HOUSEKEEPING |
| HK-INVENTORY-UPDATE | Update inventory items | mutate | housekeeping | HOUSEKEEPING, MANAGER |
| HK-MAINTENANCE-LOG | Log maintenance issue | mutate | housekeeping | HOUSEKEEPING |
| POS-ORDER-CREATE | Create POS order | mutate | pos | POS |
| POS-ORDER-ADD-ITEM | Add item to order | mutate | pos | POS |
| POS-ORDER-VOID-ITEM | Void order item | mutate | pos | POS |
| POS-ORDER-SEND-KOT | Send to kitchen | mutate | pos | POS |
| POS-ORDER-SPLIT-BILL | Split bill | mutate | pos | POS, MANAGER |
| POS-ORDER-PAYMENT | Process payment | mutate | pos | POS |
| POS-GRATUITY | Add gratuity | mutate | pos | POS |
| POS-TERMINAL-CHARGE | Card payment via terminal | mutate | pos | POS |
| POS-REPORTS | View POS reports | read | pos | POS, MANAGER |
| BANQUET-EVENT-CREATE | Create event | mutate | banquet | BANQUET, MANAGER |
| BANQUET-EVENT-VIEW | View events | read | banquet | BANQUET |
| BANQUET-EVENT-EDIT | Edit event | mutate | banquet | BANQUET, MANAGER |
| BANQUET-VENUE-FLOORPLAN | Edit venue floor plan | mutate | banquet | MANAGER |
| RATE-PLAN-VIEW | View rate plans | read | rates | MANAGER |
| RATE-PLAN-UPDATE | Update rate plan | mutate | rates | MANAGER |
| RATE-CALENDAR-VIEW | View rate calendar | read | rates | MANAGER |
| RATE-CALENDAR-BULK-UPLOAD | Bulk upload rates | mutate | rates | MANAGER |
| RATE-OVERRIDE | Override rate on-the-fly | mutate | rates | MANAGER |
| CRM-GUEST-VIEW | View guest profile | read | crm | MANAGER, CRM |
| CRM-GUEST-CREATE | Create guest record | mutate | crm | MANAGER, CRM |
| CRM-CAMPAIGN-CREATE | Create marketing campaign | mutate | crm | MANAGER, CRM |
| CRM-LOYALTY-VIEW | View loyalty program | read | crm | MANAGER, CRM |
| REPORTS-VIEW | Run / view reports | read | reports | MANAGER, REPORTING |
| REPORTS-EXPORT | Export report data | read | reports | MANAGER, REPORTING |
| SETTINGS-PROPERTY-CONFIG | Configure property | mutate | settings | MANAGER, ADMIN |
| SETTINGS-USERS-MANAGE | Manage staff users | mutate | settings | ADMIN, SUPER_ADMIN |
| SETTINGS-ROOMS-CONFIG | Configure room types | mutate | settings | ADMIN, MANAGER |
| SETTINGS-RATE-PLANS-CONFIG | Configure rate plans | mutate | settings | ADMIN, MANAGER |
| SETTINGS-PAYMENT-SETUP | Setup payment methods | mutate | settings | ADMIN, MANAGER |
| NIGHT-AUDIT-RUN | Execute night audit | mutate | front-desk | MANAGER |
| NIGHT-AUDIT-REPORT | View night audit report | read | front-desk | MANAGER |
| CONTROL-CENTER-BRIEFING | View daily briefing | read | dashboard | MANAGER |
Total: 58 core actions
B. Duplicate-UI Register
High-impact duplicates
| Action | Variants | Divergence | Recommendation |
|---|---|---|---|
| RES-CREATE | (a) /reservations/new full-page form (1637 lines), (b) <QuickReservationDialog> modal (263 lines) | Full form has 40+ fields (discounts, promos, tax exemption, agent commission, group rates); modal has 8 fields (guest, checkin, nights). Different submission paths, validation, defaults. | Keep full-page form as canonical. Replace modal with /reservations/new?roomId=X&arrivalDate=Y&mode=quick (form hides advanced tabs when mode=quick). |
| FOLIO-POST-CHARGE | (a) Dialog in /front-desk/folio/[id], (b) <TerminalChargeModal> for card charges, (c) Folio detail panel inline charge tab | Modal for card terminal, dialog for manual entry, inline form in detail panel. Different field sets and submit handlers. | Single <FolioChargeDialog> with tabs (MANUAL / TERMINAL); both share chargeSchema. Replace inline form with button → dialog. |
| POS-ORDER-PAYMENT | (a) <PaymentDialog> with tabs (CASH/UPI/CARD/ROOM_CHARGE/TERMINAL), (b) standalone <TerminalChargeModal> | PaymentDialog handles CASH/UPI/CARD/ROOM_CHARGE inline; terminal spawns separate modal. | Merge terminal modal as a tab in PaymentDialog. Single payment orchestration component. |
| RATE-OVERRIDE | (a) <RateOverrideDialog> for bulk rates, (b) inline rate edit in rate-calendar, (c) form field in ReservationForm's room array | Three separate code paths for the same action: dialog, inline cell editor, form field. | Single Dialog for all; rate-calendar cell click opens dialog with prefilled values. Form field calls Dialog, not inline editor. |
| ROOM-UPGRADE | (a) <UpgradeOfferModal> from room-grid, (b) "Upgrade" action in tape-chart context menu | Both list available upgrades; modal shows cost diff; context-menu may not. | Standardise: same component, same room list (sort by price), same cost-diff display. |
Medium-impact duplicates
| Action | Variants | Status |
|---|---|---|
| HK-ROOM-FLIP | Room status flip in /housekeeping (table action) vs tape-chart right-click | Same API; UI path differs. Ensure button labels + confirmation language match. |
| FOLIO-PRINT | Print button on folio page vs detail panel | Both call same print() handler. Acceptable. |
| POS-GRATUITY | Dialog in OrderPanel vs folio terminal-charge gratuity | Different domains/schemas. Acceptable. |
C. Sidebar navigation tree
Current
OPERATE
├─ Dashboard
│ ├─ Today's Pulse [/control-center/today]
│ ├─ Revenue Pulse [/control-center/revenue]
│ ├─ Labor & Service [/control-center/labor]
│ ├─ Exceptions [/control-center/exceptions]
│ └─ Actions [/control-center/actions]
├─ Today [/] ← duplicates "Dashboard"
├─ Front Desk [/front-desk] ← parent is room grid; not a landing
│ ├─ Tape Chart [/front-desk/calendar]
│ ├─ Arrivals · Departures [/front-desk/arrivals]
│ └─ Walk-in [/front-desk?action=walkin] ← query-param entry
├─ Reservations [/reservations]
│ ├─ All Reservations [/reservations] ← duplicates parent
│ └─ Group Bookings [/reservations/groups]
├─ Housekeeping [/housekeeping]
├─ POS [/pos]
│ ├─ Outlets / Menu / Tables / Kitchen / Orders / Reports
├─ Banquet [/banquet]
│ ├─ Banquet [/banquet] ← duplicate label
│ ├─ Activities [/activities]
│ └─ Spa [/spa] ← also top-level
├─ Spa [/spa] ← standalone + nested
└─ Night Audit [/night-audit] (MANAGER)
MANAGE
├─ Rates / Channel Manager / CRM (with duplicate "Guests & CRM" leaf) /
Analytics / Reports (with duplicate "Reports" leaf) / Settings / Trust
IA issues
| Issue | Severity | Example | Fix |
|---|---|---|---|
| Duplicate parent / child labels | HIGH | "Reservations" → "All Reservations" | Rename child or remove redundancy |
| Ambiguous parent hrefs | HIGH | "Front Desk" routes to room grid, not a landing page | Parent should default to most-used child |
| Semantic grouping error | MED | Spa appears twice (standalone + under Banquet) | Move Spa into Activities/Banquet or keep standalone — pick one |
| Query-param entry point | MED | "Walk-in" uses ?action=walkin instead of own route | Add /front-desk/walk-in |
| 3+ clicks to common action | HIGH | Room Upgrade requires Tape Chart → context-menu → button | Add quick action in tape-chart toolbar |
| Label clarity | MED | "Tape Chart" / "Calendar" / "Room Diary" — staff don't know they're synonyms | Standardise on one label |
D. Cross-domain consistency findings
CTA wording
| Pattern | Domains | Recommendation |
|---|---|---|
| "+ New X" | Reservations, Banquet Events | Standardise everywhere |
| "Add X" | Housekeeping inventory | Change to "+ New Item" |
| "Create X" | Settings roles, experiments | Change to "+ New X" |
Status pill colours
Each domain currently defines its own palette. Define a single token set in lib/themes/presets/ink-and-brass.ts and expose as <Badge variant="status" status="CONFIRMED" /> everywhere.
const statusColors = {
CONFIRMED: '#3B82F6',
CHECKED_IN: '#10B981',
PENDING: '#F59E0B',
VOID: '#EF4444',
COMPLETED: '#10B981',
CANCELLED: '#6B7280',
};
Confirmation dialogs
Cancel reservation / void transaction / delete user all use AlertDialog but with different wording ("Confirm" vs "Proceed" vs "Yes"). Create shared <ConfirmActionDialog action severity description cancelLabel confirmLabel onConfirm />.
Empty states
Some pages show CTAs, others don't. Standardise via <EmptyState icon title description action />.
Pagination
Reservations list now uses Prev/Next; reports and CRM still use TanStack page numbers; settings users uses infinite scroll. Adopt Prev/Next everywhere; gate jump-to-page behind an icon button only on report pages.
Detail panel vs full page
- Full page: complex entities with 3+ major sections (folio, reservation, event, guest)
- Slide-out panel: quick view of < 5 fields (room notes, short bio)
- Within a domain, all detail views should use one pattern
E. Persona hot paths
Front desk agent
| Action | Path | Clicks | Friction |
|---|---|---|---|
| Check-in arriving guest | Sidebar → Arrivals → row → Check-in → form | 4 | Row search slow; add name filter |
| Take payment | Folio → Charges → Post Payment → dialog | 4 | OK |
| Look up reservation by name | Sidebar → Reservations → search → row | 3 | Client-side search slow; add Cmd-Shift-R global search |
| Flip room status | Tape Chart → right-click → Mark clean | 2 | Good |
| Process walk-in | Sidebar → "Walk-in" (query param) → form | 2 | Discoverability poor |
Housekeeping lead
| Action | Path | Clicks | Friction |
|---|---|---|---|
| Flip room status | Tape Chart OR Housekeeping table | 2–3 | Two UIs confusing |
| View tasks | Sidebar → Housekeeping → Tasks | 2 | OK |
| Mark inspection | Tasks → row → Inspect → confirm | 3 | OK |
| Log maintenance | Maintenance → "+ New" → form | 3 | OK |
Manager
All paths ≤ 2 clicks. No critical friction.
Reservations specialist
Quick-dialog vs full-form confusion for RES-CREATE — primary friction.
F. Recommended canonical UIs (top 15)
- RES-CREATE →
/reservations/newis canonical. Remove<QuickReservationDialog>. Tape-chart empty-cell click routes with?roomId&arrivalDate&departureDate&mode=quick. - FOLIO-POST-CHARGE → single
<FolioChargeDialog>with MANUAL / TERMINAL tabs. - POS-ORDER-PAYMENT → fold
<TerminalChargeModal>into<PaymentDialog>as a tab. - RATE-OVERRIDE → single Dialog; rate-calendar cell + ReservationForm both invoke it with context.
- ROOM-UPGRADE → standardise the available-rooms list and pricing in the existing modal.
- HK-ROOM-FLIP → unify button label + confirmation language in both invocation points.
- POS-ORDER-SPLIT-BILL → already consolidated. Monitor.
- FOLIO-PRINT → already consolidated. Monitor.
- BANQUET-EVENT-CREATE → lock down full form as canonical; add
?template=for prefilled. - CRM-GUEST-CREATE → ReservationForm "new guest" opens full form (preserve referrer).
- SETTINGS-USERS-MANAGE → keep dialog as canonical for inline edits.
- RATE-CALENDAR-BULK-UPLOAD → keep dialog; add wizard steps if needed.
- NIGHT-AUDIT-RUN → ensure preview and submit are in same component.
- HOUSEKEEPING-TASK-CREATE → already consolidated.
- CONTROL-CENTER-BRIEFING → extract shared chart components (
<OccupancyChart>,<RevenueChart>).
G. Sidebar reorganisation proposal
OPERATE
├─ Dashboard [/control-center/today]
│ ├─ Today's Pulse · Revenue · Labor · Exceptions · Actions
├─ Front Desk [defaults to Tape Chart]
│ ├─ Tape Chart
│ ├─ Arrivals & Departures
│ └─ Walk-in Booking [/front-desk/walk-in]
├─ Reservations [/reservations/list]
│ ├─ Booking List
│ └─ Group Bookings
├─ Housekeeping
│ ├─ Room Status · Tasks · Inventory · Maintenance · Lost & Found
├─ POS [defaults to Outlets]
│ ├─ Outlets · Tables · Orders · Kitchen / KDS · Menu · Reports
├─ Banquet [/banquet/events]
│ ├─ Events · Venues · Activities · Spa
└─ Night Audit (MANAGER role-gated)
MANAGE
├─ Revenue & Rates [/revenue-manager]
│ ├─ Rate Manager · Rate Calendar · Restrictions & Overrides · Rate Grid
├─ Distribution [/channel-manager]
├─ Guests & CRM [/crm]
│ ├─ Guest Management · Campaigns · Loyalty · Notifications · Partners
├─ Analytics & Reports [/reports]
│ ├─ Reports · BI Dashboard · Predictive Analytics · Cash Management · Owner Portal
├─ Settings [/settings/property]
└─ Multi-property [/chain] (if enabled)
Rationale: parents default to most-used child, sub-items expanded for discovery, "Today" merged into "Dashboard", Spa de-duplicated, walk-in on a real route, "Revenue & Rates" / "Guests & CRM" / "Analytics & Reports" rename for clarity.
H. Implementation roadmap
Phase 1 — Removals + redirects (low risk) — week 1–2
| Task | Effort | Risk |
|---|---|---|
Remove <QuickReservationDialog>; tape-chart link routes to form | 2 h | LOW |
ReservationForm reads ?mode=quick and hides advanced tabs | 1.5 h | LOW |
Merge <TerminalChargeModal> into <PaymentDialog> as tab | 2 h | LOW |
Create unified <FolioChargeDialog> (manual + terminal) | 2.5 h | MED |
New route /front-desk/walk-in (replace ?action=walkin) | 1 h | LOW |
| Consolidate RATE-OVERRIDE invocation into single Dialog | 3 h | MED |
| Regression test order → folio payment flow | 1 h | LOW |
~15 hours total. Eliminates ~6 major duplicates.
Phase 2 — Visual + label normalisation (medium risk) — week 3–4
| Task | Effort | Risk |
|---|---|---|
| Standardise CTAs to "+ New X" | 4 h | LOW |
Shared <StatusBadge> component + tokens | 2 h | LOW |
Shared <ConfirmActionDialog> for destructive actions | 2.5 h | LOW |
Shared <EmptyState> component | 1.5 h | LOW |
| Adopt Prev/Next pagination everywhere | 3 h | MED |
| Sidebar rename + reorganise per Section G | 4 h | MED |
| Role-gating regression test | 2 h | MED |
~19 hours total. Cross-domain polish.
Phase 3 — Larger restructures (after Phase 1+2 stable)
- Move Spa into Banquet sub-tree (preserve deep links)
- Refactor Folio page layout (only if UX testing shows friction)
- Build global Cmd-K quick search
- Housekeeping room-flip unification
I. Immediate action items
Critical (this week)
- RES-CREATE — remove QuickReservationDialog, add
?mode=quick(3.5 h) - FOLIO-POST-CHARGE — merge manual + terminal dialogs (4.5 h)
- WALKIN proper route (1 h)
High (next sprint)
- Sidebar reorganisation — rename leaves, fix duplicates (5 h)
- CTA standardisation — "+ New X" everywhere (4 h)
- Pagination consistency — Prev/Next everywhere (6 h)
Medium (next 2 weeks)
- Status colour tokens in design system (3 h)
<ConfirmActionDialog>in destructive flows (3 h)
J. Success metrics
| Metric | Target |
|---|---|
| JS bundle reduction | -5% (~40 KB gzip) |
| Time to reservation create | < 30 s |
| Staff "which form?" errors | 0 |
| Click count on top-5 actions | ≤ 3 |
| Label/colour/copy consistency | 100% |
| Role-gating regression pass rate | 100% |
Summary
- Duplicate UIs found: 15+ (6 high-impact, 9 medium)
- Sidebar IA issues: 6 (duplicate labels, query-param entry, semantic grouping)
- Cross-domain drift: 4 areas (CTA wording, status colours, pagination, empty states)
- Estimated effort: 34 hours for Phase 1+2 (low–medium risk)
- Expected gain: 25–30 % reduction in staff training time for new UI sections