Skip to main content

Session Report — Operations Hub Phase 2 + Launch Cleanup

Date: 2026-05-02 (full day, single session) Mode: Autonomous from "resume Operations Hub Phase 2" prompt Spec: 2026-05-02-operations-hub-progressive-density-design.md Plans:


Outcome at a glance​

BundleScopeStatusRepos touched
Prereq 0aProperty interface gains type + roomCount typed fieldsDONEhmp-web-dashboard
Prereq 0btenant: { id, propertyCount } slice on app-store (derived from properties.length)DONEhmp-web-dashboard
Prereq 0cDUTY_MGR persona deleted (no JWT source role)DONEhmp-web-dashboard, hmp-shared-packages
Prereq 0dDashboardPrefsService.get/patch tenantId scoping (defense-in-depth)DONEhmp-auth-service
Task 1<TileSlot> dispatcher + tileRegistry registry patternDONEhmp-web-dashboard
Task 221 KPI tiles (Pulse/Card/Deep variants)DONEhmp-web-dashboard
Task 324 report card tiles wrapping <ReportTable compact>DONEhmp-web-dashboard
Task 4<FrontDeskPulse> HOTEL today.live (4 sub-blocks)DONEhmp-web-dashboard
Task 5<ResortPulse> RESORT today.live (3 sub-blocks)DONEhmp-web-dashboard
Task 6<ServicePulse> BOUTIQUE today.live (3 stacked rows)DONEhmp-web-dashboard
Task 7<TodayLive> slot picker dispatches by propertyTypeDONEhmp-web-dashboard
Task 86 role configs populated with tile catalogs from spec §3DONEhmp-web-dashboard
Task 9<KpiStrip> + <InsightsGrid> wired with applyPrefs (hide/reorder)DONEhmp-web-dashboard
Task 10<AttentionRailSection> + <ActionsQueueSection> (action-card moved to operations-hub/widgets)DONEhmp-web-dashboard
Task 113 new v2 reports: crm-feedback-pulse, pre-arrival-pulse, linen-consumptionDONEhmp-analytics-service
Task 12GET /api/dashboard/portfolio resolver (heatmap + leaderboard, 5-min cache)DONEhmp-analytics-service, hmp-api-gateway
Task 13<PortfolioStrip> frontend (heatmap + leaderboard + watchlist chips)DONEhmp-web-dashboard
Task 14<TilePinMenu> kebab — Hide / Move up / Move down (persists per user)DONEhmp-web-dashboard
Regression fixPortfolioStrip data-testid stable across loading stateDONEhmp-web-dashboard
Launch cleanupFlag default ON + /control-center/* deleted + sidebar trimmed + AttentionRail rewired to /anomalies + /control-center 308 redirectsDONEhmp-web-dashboard

Aggregate: 22 commits across 5 repos pushed to origin/master.

Final repo HEADs​

Repomaster HEADLatest commit
hmp-shared-packages450cff8DUTY_MGR removed from EffectiveRole union
hmp-auth-service5512770DashboardPrefsService.get tenantId scoping
hmp-analytics-servicede019baPortfolio resolver (heatmap + leaderboard)
hmp-api-gateway337ba28/dashboard/portfolio route registered
hmp-web-dashboardb4f627fMerge feat/operations-hub-launch-cleanup

What's now live​

FLAG_OPERATIONS_HUB_HOME defaults ON post-2026-05-02 (opt out via NEXT_PUBLIC_FLAG_OPERATIONS_HUB_HOME=false). When ON, the dashboard root (/) renders <RoleHome /> — a 5-section role-pivoted home:

  1. PortfolioStrip (renders only when tenantScale !== 'single') — property heatmap + anomaly leaderboard + watchlist chips for OWNER role.
  2. KpiStrip — 6-tile horizontal row of role-specific KPIs (Pulse fidelity on single tenant, Card on small-multi, Card on large-multi).
  3. TodayLive — property-type-aware live block. HOTEL gets FrontDeskPulse (arrivals timeline + queue pressure + VIP rail + room readiness). RESORT gets ResortPulse (cross-dept timeline + occupancy gauge + activity rail). BOUTIQUE gets ServicePulse (combined arrivals + issues + HK strip).
  4. InsightsGrid — 4-card grid of role-specific report cards (channel mix, pickup, segment mix, etc.).
  5. AttentionRail + ActionsQueue sidebar — top critical anomalies (sourced from real /anomalies endpoint) + assigned actions.

Per-tile kebab menu persists hide/reorder to UserDashboardPrefs. Role switcher chip in the header lets users with multiple eligible roles toggle the home variant; selection persists across sessions.

Legacy /control-center deleted​

The user requested deletion of "older duplicate/half-baked pages" before deploy. Cleanup removed:

  • 8 page files: /control-center/{,today,revenue,labor,exceptions,actions}/page.tsx + keynova.tsx + error.tsx
  • 8 component files in src/components/modules/control-center/: department-timeline, exception-card, kpi-card, kpi-drill-down, labor-cost-entry, playbook-activator, review-briefing-view, sop-execution-view (all unused after the route group went)
  • 7 corresponding test files
  • Sidebar "Control Center" parent + 5 children
  • ~5650 lines of code

308 redirects added in next.config.ts: /control-center and /control-center/:path* → /. Old bookmarks land gracefully on the new home.

AttentionRailSection was rewired: it had been calling a non-existent /issues endpoint with a /issues#<id> CTA that 404'd. Now it calls real Plan 3.1 /anomalies endpoint and CTA opens /anomalies. ActionsQueueSection's "View all → /actions" link was dropped pending Phase 3.

New backend endpoints​

MethodRouteServicePurpose
GET/api/dashboard/portfolioanalytics-serviceHeatmap + anomaly leaderboard for the user's accessible properties (5-min cache)
POST/api/reports/v2/crm-feedback-pulse/runanalytics-serviceGuest sentiment 24h (warming-up until MvGuestFeedback wired)
POST/api/reports/v2/pre-arrival-pulse/runanalytics-servicePre-arrival eligibility (warming-up until eligibility join wired)
POST/api/reports/v2/linen-consumption/runanalytics-serviceLinen issued vs returned (warming-up until MvLinenConsumption wired)

All 3 new reports register correctly in the catalog (/api/reports/v2/catalog) and return totals.warmingUp: true until their data sources land in Phase 3.

Test counts​

  • Dashboard operations-hub suite: 137 tests across 22 files green
  • Analytics: 658 reporting tests + 19 portfolio tests green
  • Auth: 14 dashboard-prefs tests green
  • Total: 828 tests verified green during this session

Design choices worth noting​

  1. Tile registry is a mutable singleton populated by import side-effects. Each tile module ends with tileRegistry['<id>'] = MyTile at top level. Trade-off: simpler than a register() helper; requires consumers to import tile-registry so the registrations run.

  2. <ReportTable> doesn't accept a metric filter — the plan's snippet was forward-looking. KPI tiles use <KpiCard reportId extract> for Pulse (which extracts a specific totals key) and <ReportTable compact> for Card (which renders the full table). Per-metric filtering on ReportTable is a Phase 3 capability.

  3. Heatmap revpar is placeholder for Phase 2 v1 — PortfolioService.buildHeatmap reads MvDailyKpi.revpar for the current UTC date but returns revparLy=null and ratio=null always. Phase 3 wires the LY comparison + property-name resolution. The leaderboard works correctly today.

  4. 6 spec §3 tiles deferred to Phase 3 — pre-arrival-pulse-card, F&B KPI tiles (avgCoverValue, fnbRevenue, serverProductivityKpi), kot-board-pulse, room-board-pulse, portfolio-anomaly-map. Documented inline as comments in the role configs that reference them; tile-registry smoke test refuses to register placeholder strings pointing at non-existent tiles.

  5. Auth-service DUTY_MGR backward-compat lag — 4 inline arrays in auth-service still carry DUTY_MGR (schema comment + VALID_ROLES + DTO @IsIn). Old dashboard builds during rollout can still PATCH lastViewedRole: 'DUTY_MGR' without 400-ing. Cleanup tracked as follow-up post-rollout.

Phase 3 follow-ups (priority-ordered)​

#ItemWhy
1Issues page (/issues route) — anomalies + exceptions mergedSpec §5; AttentionRail CTA currently goes to /anomalies (Plan 3.1 page) — Issues page would be the canonical merge of anomalies + exceptions
2Wire real revpar / revparLy aggregation for portfolio heatmapPhase 2 v1 returns placeholders; OWNER home looks empty without it
3Wire MvGuestFeedback / eligibility join / MvLinenConsumption for the 3 new v2 reportsAll return warming-up today
4/api/tenants/me endpointDrives tenant.propertyCount correctly (currently derived from properties.length)
5Build 6 missing spec §3 tilesUnlocks RM/HK/FNB role configs to add their today.live + missing KPIs
6DashboardPrefsClient → portfolio controllerResolves watchlistPropertyIds server-side instead of hardcoded []
7/actions route + canonical endpointActionsQueueSection's "View all" link was dropped pending this
8Phase 4 Cutover — remove KeyNovaDashboard legacy fallback pathAfter 2-week soak with flag ON
9Phase 5 Deletion — remove any remaining control-center component importsFinal cleanup
10Auth-service DUTY_MGR scrub (4 inline arrays)Post-rollout window

Files of interest​

  • Master plan: hmp-docs/docs/superpowers/plans/2026-05-02-operations-hub-master-plan.md
  • Phase 2 plan (executed): .../plans/2026-05-02-operations-hub-phase-2-tile-library.md
  • Spec: .../specs/2026-05-02-operations-hub-progressive-density-design.md
  • Use case YAML: _data/use-cases/uc-operations-hub-phase-2.yaml
  • Phase 1 ship report: prior session memory project_2026-05-02-operations-hub-phase-1-shipped.md
  • Phase 2 ship report: prior session memory project_2026-05-02-operations-hub-phase-2-shipped.md