Audit B — DTO Contract Diff Report
Generated: 2026-04-26 by automated audit. Part of Production Readiness Audit Plan.
Scope: 13 backend services × 47 dashboard API files. Focused on POST/PUT/PATCH/DELETE mutations.
Header injection audit
Sound — src/lib/api/client.ts correctly injects Authorization, X-Property-ID, X-Tenant-ID on every authenticated request. Issues are payload shape, not headers.
Concerns flagged:
getInvoicePdfUrlreturns a URL for<a href>— won't carry JWT, may 401 in prodpropertyIdread directly fromlocalStorage['hmp-app-store']in 4 modules — parallel source of truth, lags state on impersonate/property-switch
CRITICAL — payload will be rejected (14 findings)
1. POS Create Menu Item — isAvailable silently stripped
- Frontend form sends
isAvailable: booleanbut backendCreateMenuItemDtodoesn't have it. Item created but toggle ignored. (HIGH actually — silent data loss.)
2. Housekeeping Create Task — assignedTo free-text input vs @IsUUID() (issue #8 root cause)
…/housekeeping/tasks/page.tsx:485is<Input placeholder="Staff name (optional)">. BackendassignedTo?requires UUID. Any non-empty value 400s.
3. Settings Add User — missing required tenantId
CreateUserDtolackstenantId; backend requires@IsUUID() @IsNotEmpty(). Every Add User fails.
4. Reservation Cancel — DELETE with body (gateway may strip)
- Works locally; QA-stack-dependent.
5. Settings Add User — role: string vs backend UserRole enum
- Case mismatch fails IsEnum.
6. CRM Create Campaign — 5 simultaneous gaps (issue #3 root cause)
- Missing:
propertyId,channel,segmentRules,createdBy. Frontendtypevalues are channel codes, failIsInon backendtypeenum.
7. Guests Create — missing propertyId, lowercase gender
- Backend reads only
@Body() CreateGuestDto, no header fallback. Every Create Guest fails.
8. Settings Create Rate Plan — missing propertyId, bare-string enums
mealPlan/paymentPolicyare enums on backend.
9. Settings Create Cancellation Policy — missing propertyId, lowercase chargeType
- Backend
ChargeTypeisPERCENTAGE/FLAT/FIRST_NIGHT/FULL_STAY; frontend sends'percentage'/'fixed'/'nights'.
10. Frontdesk Check-In — multiple field mismatches
idDocumentType,idDocumentNumberREQUIRED on backend but OPTIONAL on frontendreservationIdREQUIRED in body, frontend only puts in URL- Field name mismatch:
signaturevssignatureImageUrl - Extra fields silently stripped:
guestPhoto,idExpiryDate,idIssuingCountry,arrivalTime,skipInspection,formC.passportNo
11. Frontdesk Post Charge — folioId missing from body, transactionCode regex (issue #17 path)
- Backend requires
folioIdin body (DTO@IsUUID @IsNotEmpty).transactionCodemust match/^[A-Z0-9_]+$/. Lowercase or hyphens fail.
12. Frontdesk Post Payment — folioId missing, paymentMode enum
- Same path-vs-body issue + lowercase enum strings fail.
13. Frontdesk Void Transaction — extra folioId, reason required min 3 chars
- Backend strips
folioId, requiresreason.
14. Rooms Update Status — wrong endpoint path (issue #6 root cause)
- Frontend hits
PATCH /rooms/:idbut backend only exposes@Put('rooms/:id')and@Patch('rooms/:id/status'). Returns 404/405. - Also: frontend
HousekeepingStatusenum has 6 values (includes OUT_OF_ORDER, OUT_OF_SERVICE) but backend has 4. Selecting OOO/OOS fails IsEnum.
19. CRM Drip Step — lowercase channel (issue #3 part)
- Frontend
'email'/'sms'/'whatsapp'/'push'/'wait'; backend uppercase. Every Drip Step send fails.
HIGH — likely to break edge cases (16 findings)
15-18, 20-30: see full audit. Banquet, spa, channel manager, maintenance, linen, loyalty, folio merge — all have similar weak typing or enum case issues.
Summary stats
- Total mutation paths sampled: ~95
- Confirmed-broken end-to-end: 14
- Critical missing-required-field gaps: 8 (
tenantId,propertyId,channel,segmentRules,createdBy,folioId,idDocumentType/Number,reservationId) - Enum-case mismatch gaps: 6 (gender, campaign type/channel, drip channel, charge type, payment mode, room status)
- Header-injection problems: 0 critical (interceptor is sound)
Top 10 prioritized fixes
- Frontdesk Check-In DTO — required fields, field rename, body vs URL.
- Settings Add User — add
tenantId, type role enum, validate password length. - CRM Create Campaign + Drip Step — split type/channel, add propertyId/segmentRules/createdBy, uppercase enums.
- Guest Create — inject
propertyId, uppercase Gender. - Settings Create Rate Plan / Cancellation Policy — add
propertyId, uppercase enums. - Folio Charge / Payment / Void — include
folioIdin body, uppercase enums, sanitizetransactionCode. - Housekeeping Create Task — Assignee — replace free-text Input with user picker.
- Room Update Status — fix path to
/rooms/:id/status, align HousekeepingStatus enum. - POS Create Menu Item —
isAvailable— either remove from form or add to backend DTO. - Banquet/Spa weak typing — replace
Record<string, unknown>with strong types.