Skip to main content

Cross-Service Data Access Issues

Root cause: The monorepo was split into 14 per-service repos, each with its own Prisma schema containing only the models it "owns". Code copied from the monorepo still tries to access models from other services directly via Prisma, causing runtime crashes.

Created: 2026-03-29 | Status: Open


Issue Categories​

Category A: Service accesses Prisma models it doesn't own​

These crash with Cannot read properties of undefined (reading 'findMany') or similar because the Prisma client for service X doesn't have model Y.

#ServiceAccessesUsed ByFilesPriority
A1property-serviceroomReservation (reservation model)Rate plan safeguard checkrate-plans.service.ts:342High — blocks rate updates
A2reservation-serviceroomType, room, property, ratePlanAvailability, booking engine, cartavailability.service.ts, booking-engine.service.ts, cart.service.tsCritical — blocks availability/booking
A3frontdesk-serviceauditLog (auth model), guest, reservationFolio void, night auditfolios.service.ts, night-audit.service.tsHigh — blocks folio operations
A4channel-servicereservation, room, roomType, propertyBooking download, parity syncbooking-download.cron.ts, sync.service.tsMedium — channel sync broken
A5notification-servicenotification model missingList notifications endpointnotification-queue.service.tsMedium — notification list broken
A6crm-serviceguest, guestCommunication, campaignStepDrip engine, dedup, feedbackdrip-engine.service.ts, guest-dedup.service.tsMedium — CRM features broken

Category B: Missing API endpoints (404s)​

The dashboard calls endpoints that either don't exist yet or aren't routed through the gateway.

#EndpointExpected ServiceWhat It Should ReturnPriority
B1GET /api/analytics/dashboard/metricsanalytics-serviceOccupancy, ADR, RevPAR, in-house countCritical — dashboard home KPIs
B2GET /api/analytics/dashboard/todayanalytics-serviceToday's arrivals, departures, in-house summaryCritical — dashboard home
B3GET /api/analytics/dashboard/activityanalytics-serviceRecent activity feedMedium — dashboard widget
B4GET /api/control-center/todayproperty-service or gatewayToday's operational pulseHigh — dashboard home
B5GET /api/control-center/revenueanalytics-serviceRevenue snapshotHigh — dashboard widget
B6GET /api/rooms/statusfrontdesk-serviceRoom grid with status/occupancyCritical — front desk page
B7POST /api/reservations/searchreservation-serviceSearch reservations with filtersCritical — reservations page

Category C: Controller reads propertyId/tenantId from wrong source​

These return 400 because the controller reads from x-property-id header or @CurrentTenant() decorator, but the JWT fallback payload for non-auth services doesn't populate these.

#ServiceEndpointIssueFix
C1property-serviceGET /api/properties/:id@CurrentTenant() returns undefinedUse user.tenantId fallback
C2frontdesk-serviceGET /api/rooms/statusReads from header, not queryAccept ?propertyId= query param
C3reservation-servicePOST /api/reservations/searchValidation fails — missing propertyIdAccept from JWT or query param

Proper Fix Strategy​

Approach: Inter-Service HTTP Client​

Each service that needs data from another service should call that service's API via HTTP, not access its database directly.

Implementation pattern:

// In reservation-service, create a PropertyClient
@Injectable()
export class PropertyClient {
constructor(private readonly httpService: HttpService) {}

async getRoomTypes(propertyId: string, token: string): Promise<RoomType[]> {
const { data } = await firstValueFrom(
this.httpService.get(
`http://hmp-property-service:3002/api/properties/${propertyId}/room-types`,
{ headers: { Authorization: `Bearer ${token}` } }
)
);
return data.data;
}

async getRooms(propertyId: string, token: string): Promise<Room[]> { ... }
async getProperty(propertyId: string, token: string): Promise<Property> { ... }
}

Where to create clients:

ServiceNeeds Data FromClient Module
reservation-serviceproperty-service (rooms, room types, rate plans)PropertyClient
frontdesk-serviceguest-service (guest details), reservation-service (reservations)GuestClient, ReservationClient
channel-servicereservation-service (bookings), property-service (rooms)ReservationClient, PropertyClient
crm-serviceguest-service (guest data)GuestClient
analytics-serviceAll services (KPI aggregation)PropertyClient, ReservationClient, FrontdeskClient

Approach: Dashboard Metrics Endpoints​

For Category B (missing endpoints), the analytics-service needs to aggregate data from multiple services. Two options:

Option 1: Analytics aggregates via inter-service calls

Dashboard → analytics-service → [property-service, reservation-service, frontdesk-service]
(HTTP calls to each)

Option 2: Gateway BFF (Backend-for-Frontend)

Dashboard → api-gateway → [property-service, reservation-service, frontdesk-service]
(parallel calls, compose response)

Recommendation: Option 2 (Gateway BFF) for dashboard-specific endpoints. The gateway already knows all service URLs and can parallelize requests. This avoids making analytics-service depend on every other service.

Approach: Shared Types​

Move shared types (RoomStatus, BookingStatus, MealPlan, etc.) to @hmp/api-contracts package so all services use the same enums and DTOs without depending on each other's Prisma schemas.


Sprint Plan​

Sprint 1: Foundation (unblocks dashboard home)​

  1. Create @hmp/api-contracts package with shared enums and DTOs
  2. Add gateway BFF endpoints for dashboard home (metrics, today, activity)
  3. Fix Category C issues (propertyId/tenantId extraction)

Sprint 2: Core Operations (unblocks front desk, reservations)​

  1. Create PropertyClient in reservation-service
  2. Create ReservationClient in frontdesk-service
  3. Create GuestClient in frontdesk-service
  4. Fix POST /api/reservations/search endpoint
  5. Fix GET /api/rooms/status endpoint

Sprint 3: Secondary Features (unblocks channels, CRM, notifications)​

  1. Create clients in channel-service
  2. Create clients in crm-service
  3. Fix notification-service list endpoint
  4. Remove all @ts-nocheck annotations and fix type errors

Sprint 4: Cleanup​

  1. Remove all cross-service Prisma model access
  2. Enable TypeScript strict mode per-service
  3. Add integration tests for inter-service communication

Files Reference: All @ts-nocheck Files​

These files have @ts-nocheck because they access Prisma models from other services:

ServiceFileAccesses
auth-serviceonboarding/seed-defaults.service.tsroom types, rate plans
reservation-serviceavailability/availability.service.tsroom types, rooms
reservation-serviceavailability/federated-availability.service.tsroom types, rooms
reservation-servicepayments/payments.service.tspayment types
reservation-servicebooking-engine/booking-engine.service.tsRoomStatus enum
reservation-servicereservations/reservations.service.tscross-service includes
reservation-servicecart/cart.service.tsroom types
frontdesk-servicefolios/folios.service.tsAuditAction, complex types
frontdesk-servicenight-audit/chain-audit-orchestrator.service.tscross-service
frontdesk-servicenight-audit/night-audit.service.tsunknown query results
pos-serviceorders/orders.service.tsunknown query results
notification-servicedispatcher/dispatcher.service.tsmissing event types
notification-servicechannels/whatsapp-catalog.service.tscross-service Prisma
notification-servicechannels/whatsapp-conversation.service.tscross-service Prisma
channel-servicesocial/reviews/review-aggregator.service.tsPrisma namespace
channel-servicesocial/listening/social-listening.service.tsPrisma namespace
crm-servicecampaigns/campaigns.service.tsGuestWhereInput
crm-servicechain-loyalty/chain-loyalty.service.tsunknown query results