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.
| # | Service | Accesses | Used By | Files | Priority |
|---|---|---|---|---|---|
| A1 | property-service | roomReservation (reservation model) | Rate plan safeguard check | rate-plans.service.ts:342 | High — blocks rate updates |
| A2 | reservation-service | roomType, room, property, ratePlan | Availability, booking engine, cart | availability.service.ts, booking-engine.service.ts, cart.service.ts | Critical — blocks availability/booking |
| A3 | frontdesk-service | auditLog (auth model), guest, reservation | Folio void, night audit | folios.service.ts, night-audit.service.ts | High — blocks folio operations |
| A4 | channel-service | reservation, room, roomType, property | Booking download, parity sync | booking-download.cron.ts, sync.service.ts | Medium — channel sync broken |
| A5 | notification-service | notification model missing | List notifications endpoint | notification-queue.service.ts | Medium — notification list broken |
| A6 | crm-service | guest, guestCommunication, campaignStep | Drip engine, dedup, feedback | drip-engine.service.ts, guest-dedup.service.ts | Medium — 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.
| # | Endpoint | Expected Service | What It Should Return | Priority |
|---|---|---|---|---|
| B1 | GET /api/analytics/dashboard/metrics | analytics-service | Occupancy, ADR, RevPAR, in-house count | Critical — dashboard home KPIs |
| B2 | GET /api/analytics/dashboard/today | analytics-service | Today's arrivals, departures, in-house summary | Critical — dashboard home |
| B3 | GET /api/analytics/dashboard/activity | analytics-service | Recent activity feed | Medium — dashboard widget |
| B4 | GET /api/control-center/today | property-service or gateway | Today's operational pulse | High — dashboard home |
| B5 | GET /api/control-center/revenue | analytics-service | Revenue snapshot | High — dashboard widget |
| B6 | GET /api/rooms/status | frontdesk-service | Room grid with status/occupancy | Critical — front desk page |
| B7 | POST /api/reservations/search | reservation-service | Search reservations with filters | Critical — 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.
| # | Service | Endpoint | Issue | Fix |
|---|---|---|---|---|
| C1 | property-service | GET /api/properties/:id | @CurrentTenant() returns undefined | Use user.tenantId fallback |
| C2 | frontdesk-service | GET /api/rooms/status | Reads from header, not query | Accept ?propertyId= query param |
| C3 | reservation-service | POST /api/reservations/search | Validation fails — missing propertyId | Accept 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:
| Service | Needs Data From | Client Module |
|---|---|---|
| reservation-service | property-service (rooms, room types, rate plans) | PropertyClient |
| frontdesk-service | guest-service (guest details), reservation-service (reservations) | GuestClient, ReservationClient |
| channel-service | reservation-service (bookings), property-service (rooms) | ReservationClient, PropertyClient |
| crm-service | guest-service (guest data) | GuestClient |
| analytics-service | All 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)
- Create
@hmp/api-contractspackage with shared enums and DTOs - Add gateway BFF endpoints for dashboard home (metrics, today, activity)
- Fix Category C issues (propertyId/tenantId extraction)
Sprint 2: Core Operations (unblocks front desk, reservations)
- Create
PropertyClientin reservation-service - Create
ReservationClientin frontdesk-service - Create
GuestClientin frontdesk-service - Fix
POST /api/reservations/searchendpoint - Fix
GET /api/rooms/statusendpoint
Sprint 3: Secondary Features (unblocks channels, CRM, notifications)
- Create clients in channel-service
- Create clients in crm-service
- Fix notification-service list endpoint
- Remove all
@ts-nocheckannotations and fix type errors
Sprint 4: Cleanup
- Remove all cross-service Prisma model access
- Enable TypeScript strict mode per-service
- 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:
| Service | File | Accesses |
|---|---|---|
| auth-service | onboarding/seed-defaults.service.ts | room types, rate plans |
| reservation-service | availability/availability.service.ts | room types, rooms |
| reservation-service | availability/federated-availability.service.ts | room types, rooms |
| reservation-service | payments/payments.service.ts | payment types |
| reservation-service | booking-engine/booking-engine.service.ts | RoomStatus enum |
| reservation-service | reservations/reservations.service.ts | cross-service includes |
| reservation-service | cart/cart.service.ts | room types |
| frontdesk-service | folios/folios.service.ts | AuditAction, complex types |
| frontdesk-service | night-audit/chain-audit-orchestrator.service.ts | cross-service |
| frontdesk-service | night-audit/night-audit.service.ts | unknown query results |
| pos-service | orders/orders.service.ts | unknown query results |
| notification-service | dispatcher/dispatcher.service.ts | missing event types |
| notification-service | channels/whatsapp-catalog.service.ts | cross-service Prisma |
| notification-service | channels/whatsapp-conversation.service.ts | cross-service Prisma |
| channel-service | social/reviews/review-aggregator.service.ts | Prisma namespace |
| channel-service | social/listening/social-listening.service.ts | Prisma namespace |
| crm-service | campaigns/campaigns.service.ts | GuestWhereInput |
| crm-service | chain-loyalty/chain-loyalty.service.ts | unknown query results |