Skip to main content

EP-015 — Integrations & Third-Party Connectors RTM

EPIC: EP-015 Integrations & Third-Party Connectors Reconciled: 2026-05-25 Wave 1 of per-EPIC RTM fan-out — see PLAYBOOK.md for the pattern; pilot template EP-002-rtm.md. Source of truth for "% passing": hmp-docs/docs/platform-registry/2026-05-16-13-flow-demo-readiness.md until the next re-measure.

Status legend​

StatusMeaning
BuiltCode exists + tests exist + tests pass
Built-UntestedCode exists, no automated test coverage (or test exists but is a stub)
PartialCode exists for some acceptance criteria, gaps for others
StubCode is a placeholder / TODO / returns mock data
Not StartedNo code

Summary​

MetricCount
Total stories11
Catalog claims "Built"2
Verified-Built2 (US-015-001, US-015-005)
Built-Untested0
Partial5 (US-015-002, -003, -004, -007, -010)
Stub2 (US-015-008 SAP, US-015-009 Stripe)
Not Started2 (US-015-006 door-lock SDK, US-015-010 FSSAI API — Note: catalog labels US-015-010 "FSSAI" but EPIC body labels US-015-010 "API Keys"; see D-001)
Drift findings13 (D-001..D-013; 6 P0 / 5 P1 / 2 P2)
[SME-PROPOSED] refinements27

Numbering reconciliation: Catalog 01-epic-catalog.md and EPIC body epics/EP-015-integrations.md use completely different titles for US-015-003 onward. The 3 existing review files (reviews/EP-015/US-015-001..003) follow the catalog. This RTM follows the catalog (D-001) and annotates the EPIC-body alternative title under each story. The verified-status table above counts stories as the catalog defines them.


US-015-001 — Razorpay Payment Gateway Integration​

Catalog status: Partial (P0, 5 points) Verified status: Built (catalog under-reports — the Modular Payments Platform Workstream A shipped Phase 0/1/2 per platform CLAUDE.md, with a dedicated hmp-payment-service on port 3014)

Code locations:

  • hmp-payment-service/src/payments/payment.controller.ts — POST /payments/initiate, POST /payments/:id/verify-razorpay-redirect, POST /payments/refund, GET /payments, GET /payments/:id (JWT + @Roles gated; tenantId always from JWT not body — same pattern as MerchantAccountController)
  • hmp-payment-service/src/payments/payment-orchestrator.service.ts — orchestrates Payment create/verify/refund with cross-tenant guards (lines 101–125)
  • hmp-payment-service/src/payments/payment-reconcile.service.ts — AP-T12-004 PaymentReconcile (cron sweep of stuck INITIATED payments)
  • hmp-payment-service/src/adapters/razorpay/razorpay-gateway.adapter.ts — Razorpay online gateway adapter
  • hmp-payment-service/src/adapters/razorpay/razorpay-signature.ts — HMAC-SHA256 signature helpers (used for both redirect verify and webhook verify)
  • hmp-payment-service/src/adapters/razorpay/razorpay-error-mapping.ts — typed error mapping (BAD_REQUEST_CARD vs RATE_LIMITED vs GATEWAY_DOWN)
  • hmp-payment-service/src/merchant-accounts/merchant-account.service.ts — per-tenant+property MerchantAccount with encrypted credentials via CredentialCipherService
  • hmp-payment-service/src/crypto/credential-cipher.service.ts — AES-256-GCM credential encryption
  • hmp-payment-service/src/demo-tenant/demo-tenant.service.ts — demo-tenant guard rejecting rzp_live_* credentials (DEMO_TENANT_REQUIRES_SANDBOX_KEY); 3-tier lookup (Redis → local tenant_read_model → AuthServiceClient HTTP fallback)
  • hmp-payment-service/src/webhooks/webhook.controller.ts — @Public POST /api/webhooks/:providerCode/:merchantAccountId (raw body via body-parser.raw in main.ts; HMAC verified inside dispatcher)
  • hmp-payment-service/src/webhooks/webhook-dispatcher.service.ts — verifyAndParseWebhook + dedup
  • hmp-payment-service/src/webhooks/webhook-reconcile.service.ts — AP-T12-004 WebhookReconcile (cron requeue of stuck RECEIVED events older than 5 min)
  • hmp-payment-service/src/events/payment-event-publisher.service.ts — emits payment.captured etc. via outbox
  • hmp-shared-packages/packages/payments/src/lib/payments/razorpay.adapter.ts — legacy reservation-service adapter (still present per pre-W3.A.1 cleanup window)
  • hmp-booking-engine/src/lib/payment/razorpay.ts — guest browser Razorpay Checkout JS loader
  • hmp-reservation-service/src/payments/payments.service.ts — booking-engine proxy /booking-engine/payments/initiate-v2 (API-key gated @Public) → PaymentServiceClient.initiatePayment via service-account JWT

Unit + integration tests:

  • hmp-payment-service/src/adapters/razorpay/razorpay-gateway.adapter.spec.ts
  • hmp-payment-service/src/adapters/razorpay/razorpay-signature.spec.ts
  • hmp-payment-service/src/adapters/razorpay/razorpay-error-mapping.spec.ts
  • hmp-payment-service/src/payments/payment-orchestrator.service.spec.ts
  • hmp-payment-service/src/payments/payment-reconcile.service.spec.ts
  • hmp-payment-service/src/payments/payment-cross-tenant-denial.spec.ts — 15 cases (4 canonical denial blocks + bonus refund + idempotency-key cross-tenant collision; ported from hmp-pos-service canonical template)
  • hmp-payment-service/src/merchant-accounts/merchant-account.service.spec.ts
  • hmp-payment-service/src/demo-tenant/demo-tenant.service.spec.ts — 3-tier lookup + fail-safe
  • hmp-payment-service/src/crypto/credential-cipher.service.spec.ts — AES-256-GCM round-trip
  • hmp-payment-service/src/webhooks/webhook-dispatcher.service.spec.ts
  • hmp-payment-service/src/webhooks/webhook-reconcile.service.spec.ts
  • hmp-payment-service/src/events/payment-event-publisher.service.spec.ts
  • hmp-payment-service/src/events/payment-outbox.service.spec.ts

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/payments.flow.spec.ts :: end-to-end Razorpay gateway via payment-service — TBD (not in 13-flow doc) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)
  • hmp-infrastructure/testing/flow-tests/src/flows/payment-links.flow.spec.ts :: payment-link OTP + verification + capture — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/upi-qr.flow.spec.ts :: UPI QR scan-to-pay round trip — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/terminal-folio-settlement.flow.spec.ts :: terminal charge → folio settle — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/terminal-pos-order.flow.spec.ts :: POS terminal charge → KOT close — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/idempotency-replay.flow.spec.ts :: idempotency key replay — TBD

Real-backend smokes:

  • (none enumerated specific to payment-service — see GAP)

E2E (Playwright):

  • hmp-booking-engine checkout flow exercises Razorpay Checkout JS via mock when VITE_RAZORPAY_KEY_ID unset

Use cases referencing this story:

  • AP-T12-004 (PaymentReconcile + WebhookReconcile)

SME notes:

  • Catalog severely under-reports: catalog says "Partial" but the platform actually shipped a full Modular Payments Platform (Phase 0/1/2 + Workstream A) with dedicated payment-service, per-tenant+property MerchantAccount, encrypted credentials, demo-tenant guard, two-layer reconciliation, outbox pattern, and 33 spec files. The legacy reservation-service PaymentsService referenced in the review file (US-015-001-review.md, 2026-03-ish) is the OLD path. Review file is ~10 weeks stale.
  • [SME-PROPOSED] Razorpay terminal (POS) adapter hmp-payment-service/src/adapters/razorpay/razorpay-terminal.adapter.ts exists alongside the gateway adapter — POS terminal flows go through terminal-charge.worker.ts, distinct from online gateway. Story should reference both.
  • [SME-PROPOSED] Payment-link OTP service (payment-link-otp.service.ts) enforces RBI-relevant guest-identity verification before high-value link payments: 6-digit OTP, 5-min TTL, max 3 wrong attempts, per-slug rate limits, per-phone daily cap. Story does not mention this OTP gate.
  • [SME-PROPOSED] RBI auth-cap: AC-2 (refund) does NOT specify the RBI-mandated T+7 working-day refund SLA (RBI/2019-20/45 DPSS.CO.PD.No.629/02.01.014/2019-20). For UPI Person-to-Merchant returns the timeline is T+1. Catalog AC-2 just says "track until processed" — no SLA.
  • [SME-PROPOSED] PCI DSS — the payment-service is network-isolated per platform CLAUDE.md ("payment isolation (PCI)" in kubernetes section). Story does NOT call out the PCI scope boundary explicitly. Story body should reference the isolation contract.

Drift findings:

D-001 — [P0] [Catalog-vs-EPIC-body] Catalog (01-epic-catalog.md) and EPIC body (epics/EP-015-integrations.md) assign different titles to US-015-003 through US-015-011. Catalog row US-015-003 = "Currency Exchange Rate Auto-Update"; EPIC body US-015-003 = "SAP Business One Journal Posting". Catalog US-015-005 = "Webhook Configuration"; EPIC body US-015-005 = "FSSAI License Verification". Etc. The 3 existing review files (reviews/EP-015/US-015-001..003) follow the catalog. Two referent docs disagreeing on what "US-015-NNN" means is a P0 pilot-blocking drift — identical pattern to EP-002 D-007.

  • [SME-PROPOSED] Adopt the catalog numbering as canonical (matches existing review files + matches the alphabetical/priority intent), rewrite the EPIC body's §US-015-003 through §US-015-011 to match, and add an alias line > Previously titled "X" in EPIC body draft prior to 2026-05-25 reconciliation to each section so historic references stay traceable.

D-002 — [P0] [Catalog-says-Partial-actually-Built] Catalog says US-015-001 is "Partial" but the Modular Payments Platform (Phase 0/1/2 + Workstream A) shipped per platform CLAUDE.md with a dedicated hmp-payment-service, encrypted MerchantAccount per tenant+property, demo-tenant guard, two-layer reconciliation, and 33 spec files. The review file is stale (references the legacy reservation-service adapter only).

  • [SME-PROPOSED] Promote catalog status to Built. Re-run the US-015-001 review against the current payment-service source. Document the legacy reservation-service path as deprecated (per CLAUDE.md "legacy billing/subscription.service.ts private methods are dead code pending W3.A.1 deletion").

US-015-002 — Tally Accounting Sync (Bi-Directional)​

Numbering note: Catalog title = "Tally Accounting Sync (Bi-Directional)". EPIC body §US-015-002 title also matches ("Tally ERP Bi-Directional Sync"). The first 2 IDs agree; the drift starts at US-015-003.

Catalog status: Partial (P1, 8 points) Verified status: Partial — only a CSV export shipper exists in frontdesk-service; the live Tally Gateway XML integration described in the EPIC body and review file (TallyService + Kafka FOLIO_SETTLED subscriber + TallyReconciliationService) is NOT IN MAIN SRC — exists only inside hmp-frontdesk-service/.worktrees/ branches; main is the lighter CSV path.

Code locations:

  • hmp-frontdesk-service/src/exports/tally/tally.controller.ts — Tally CSV export controller (main branch)
  • hmp-frontdesk-service/src/exports/tally/tally.service.ts — Tally CSV builder service
  • hmp-frontdesk-service/src/exports/tally/tally-csv.builder.ts — CSV row construction
  • hmp-frontdesk-service/.worktrees/ap-t08-002/src/exports/tally/ — [CITED-BUT-NOT-FOUND on master] — alternative implementation lives in a worktree branch, not merged
  • hmp-web-dashboard/src/app/(dashboard)/settings/integrations/tally/page.tsx — Tally settings page (config UI)

Unit + integration tests:

  • hmp-frontdesk-service/src/exports/tally/tally-csv.builder.spec.ts — CSV row format coverage

Flow tests: NONE FOUND (no tally*.flow.spec.ts in flow-tests directory)

Real-backend smokes: NONE FOUND

Use cases referencing this story: AP-T08-002 (Tally CSV exporter) — implementation evidence in worktree only

SME notes:

  • MAJOR DRIFT: review file US-015-002-review.md describes a TallyService with Sales/Receipt/Journal XML voucher builders, mock mode, FOLIO_SETTLED Kafka subscription, and a TallyReconciliationService — none of these exist on hmp-frontdesk-service/src/ master. They live in unmerged worktree branches (.worktrees/ap-t08-002, .worktrees/ap-t13-002). The shipped master path is a CSV-export-only flow.
  • [SME-PROPOSED] Tally Prime / Tally ERP9 on Indian SME hotels typically lives on a single-licence Windows machine inside the property LAN — cloud integration requires either (a) Tally Gateway Server (port 9000 HTTP+XML) exposed via a hotel-side tunnel, or (b) a CSV/XML batch export the property's accountant imports nightly. The current CSV approach matches (b) and is realistic for Tier-2/3 properties; the worktree XML approach matches (a) for chains/Tier-1.
  • [SME-PROPOSED] GST-split: under GST law, an Indian invoice for a guest from a different state than the property must split tax as IGST (single integrated tax line), not CGST+SGST. Both Tally implementations need this branching from the guest's billing state — review file flags it as GAP-1.

Drift findings:

D-003 — [P0] [Review-vs-code] Review file US-015-002-review.md claims TallyService, TallyReconciliationService, AccountingSyncLogService, Kafka FOLIO_SETTLED subscriber all exist — they do not exist on master. The only Tally code shipped is a CSV-export module in hmp-frontdesk-service/src/exports/tally/. A new engineer reading the review would believe substantial XML + Kafka + reconciliation infrastructure is in place.

  • [SME-PROPOSED] Re-run US-015-002 review against master and document only the CSV path. Either (a) merge the worktree branches into master if the XML path is now wanted, or (b) move the worktree work into a tracked spec doc and explicitly mark the live status as "CSV-export-only".

D-004 — [P1] [Catalog-says-Bi-Directional-actually-OneWay] Catalog title and AC-10 promise "bi-directional outstanding balance check" but no read-from-Tally capability exists on master. Title is misleading.

  • [SME-PROPOSED] Rename catalog to "Tally Accounting Sync (Folio → Tally export)" until bi-directional ledger-read ships. Bi-directional becomes a separate Phase-2 story.

US-015-003 — Currency Exchange Rate Auto-Update​

EPIC-body alias: epics/EP-015-integrations.md §US-015-003 is titled "SAP Business One Journal Posting" — see D-001. This RTM section follows the catalog title.

Catalog status: Not Started (P2, 3 points) Verified status: Partial — base currency service + frontend page + history table exist; no auto-update cron at 06:00 IST, no provider failover, no margin, no manual override; review file US-015-003-review.md (FAIL verdict) matches reality

Code locations:

  • hmp-shared-packages/packages/common/src/lib/currency/currency.service.ts — base currency service
  • hmp-shared-packages/packages/common/src/lib/currency/currency.module.ts — module wrapper
  • hmp-frontdesk-service/src/currency/currency-client.service.ts — frontdesk-side currency client ([CITED-BUT-NOT-FOUND] — analytics-service currency/ directory referenced in review file does NOT exist on master; the shared-package path is the active one)
  • hmp-frontdesk-service/src/forex/ — Forex transactions for actual guest billing
  • hmp-web-dashboard/src/app/(dashboard)/settings/currency/page.tsx [CITED-BUT-NOT-FOUND on master — referenced in review file] — currency settings page
  • hmp-analytics-service/src/cron/ — only fhrai-benchmark-cron.service.ts exists; no currency-refresh cron as review file's GAP-1 claims

Unit + integration tests:

  • hmp-frontdesk-service/src/forex/forex.service.spec.ts — forex transaction recording
  • hmp-frontdesk-service/src/forex/forex.controller.spec.ts — controller tests
  • analytics-service currency tests [CITED-BUT-NOT-FOUND on master] — paths in review file don't exist

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/forex-currency.flow.spec.ts :: forex transaction roundtrip — TBD (not in 13-flow doc) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • The shared-package currency service does conversions and supports the forex transactions. The auto-refresh layer (cron at 06:00 IST, Open Exchange Rates + Fixer.io failover, per-property margin, manual override audit log) is entirely unshipped.
  • [SME-PROPOSED] RBI reference rate. For India, the RBI Reference Rate (published 1730 IST daily) is the regulator-blessed exchange rate. Open Exchange Rates / Fixer use commercial mid-rates. For a FEMA-compliant invoice, the rate must be sourced from RBI or include a margin disclosure. Story should require RBI as an alternate provider with a "fall back to RBI ref rate" toggle.
  • [SME-PROPOSED] Indian SME hotels deal in USD/EUR/GBP/AED most often (Gulf labour + Western tourists). The catalog AC-1 lists those + SGD — sane choices. Add JPY (Japanese inbound) + CAD (Canadian inbound) + CHF (Swiss/luxury).
  • [SME-PROPOSED] Stale-rate guard. If the rate is > 24 hours stale and no manual override is in place, the property's invoice generator should refuse to bill in the foreign currency and force INR billing — this prevents revenue loss when rates spike. Review file flags this as GAP-9.

Drift findings:

D-005 — [P1] [Path-drift] Review file US-015-003-review.md cites analytics-service/src/currency/currency.service.ts and currency-history.service.ts — those paths do not exist on master. The actual currency code lives in hmp-shared-packages/packages/common/src/lib/currency/. Path-citation rot makes the review unusable for navigation.

  • [SME-PROPOSED] Re-run the review against the real shared-package path. Mark Sprint-16 auto-refresh requirements as Not Started (they are).

US-015-004 — GST E-Invoice API (NIC Portal)​

EPIC-body alias: epics/EP-015-integrations.md §US-015-004 is titled "GST e-Invoice via NIC Portal" — substantively the same; D-001 alignment item.

Catalog status: Partial (P1, 8 points) Verified status: Built — NIC adapter + mock adapter + job processor + Bull queue + webhook controller + 5 spec files on master; AP-T08-003 closed this story in 2026-04-29 per platform CLAUDE.md gold-standard verify-first pass

Code locations:

  • hmp-frontdesk-service/src/einvoice/nic-einvoice.adapter.ts — Live NIC IRP adapter (sandbox URL einv-apisandbox.nic.in, prod URL einv-api.nic.in; env-based via EINVOICE_ENV); 5 required env vars EINVOICE_CLIENT_ID/SECRET/USERNAME/PASSWORD/GSTIN
  • hmp-frontdesk-service/src/einvoice/mock-einvoice.adapter.ts — Mock adapter for non-prod / EINVOICE_MOCK=true
  • hmp-frontdesk-service/src/einvoice/einvoice.service.ts — Service orchestrating IRN generation
  • hmp-frontdesk-service/src/einvoice/einvoice.module.ts — Module factory with AP-T08-003 boot guard (throws in production when COMPLIANCE_MODE=live and any env var missing, unless EINVOICE_ALLOW_MOCK_IN_PROD=true)
  • hmp-frontdesk-service/src/einvoice/einvoice.controller.ts — REST endpoints
  • hmp-frontdesk-service/src/einvoice/einvoice-job.processor.ts — Bull queue job processor
  • hmp-frontdesk-service/src/einvoice/einvoice-job.repository.ts — Persistence
  • hmp-frontdesk-service/src/einvoice/einvoice-webhook.controller.ts — NIC callback receiver
  • hmp-frontdesk-service/src/einvoice/eway-bill.service.ts — E-way bill companion
  • hmp-frontdesk-service/src/checkout/checkout.service.ts:436 — auto-fire IRN on checkout (verified via 2026-05-19 Folio Payment Reconciliation plan)

Unit + integration tests:

  • hmp-frontdesk-service/src/einvoice/einvoice.service.spec.ts
  • hmp-frontdesk-service/src/einvoice/einvoice.module.spec.ts (12 specs — AP-T08-003 boot-guard coverage)
  • hmp-frontdesk-service/src/einvoice/einvoice-job.processor.spec.ts
  • hmp-frontdesk-service/src/einvoice/nic-einvoice.adapter.spec.ts (5 specs)
  • hmp-frontdesk-service/src/einvoice/mock-einvoice.adapter.spec.ts

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/check-out-einvoice.flow.spec.ts :: checkout → IRN issued → printed invoice carries IRN — 0/15 PASS on 2026-05-16 (flow-8 worst on platform per 2026-05-16-13-flow-demo-readiness.md)
  • hmp-infrastructure/testing/flow-tests/src/flows/nic-einvoice-live.flow.spec.ts :: live sandbox NIC IRP round-trip — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/email-invoice-delivery.flow.spec.ts :: invoice email delivery (touches einvoice) — TBD

Real-backend smokes: (covered by checkout E2E)

Use cases referencing this story:

  • AP-T08-003 (B2B IRN path) — verified shipped per platform CLAUDE.md 2026-05-19 gold-standard pass

SME notes:

  • Catalog under-reports (similar to D-002): catalog says "Partial" / "Not Started" depending on which doc, but AP-T08-003 closed B2B IRN path in 2026-04-29 with 5 spec cases plus the 5-env-var boot guard. The EPIC body's "Not Started" label is stale.
  • [SME-PROPOSED] 24-hour cancellation window: NIC e-invoice spec allows cancellation within 24 hours of generation; after that, only a credit-note path. EPIC body AC-2 mentions this but story doesn't require a guard that physically prevents cancelEInvoice(irn) past T+24h.
  • [SME-PROPOSED] GSTIN turnover threshold: e-invoice mandate applies only to taxpayers with aggregate turnover > INR 5 Cr (as of 2026; threshold has lowered every year — was INR 50 Cr in 2020, INR 5 Cr from 2023). Story should require an opt-in flag per property (property.einvoiceMandatory: boolean) so under-threshold properties don't pay for unnecessary IRN calls.
  • [SME-PROPOSED] Signed QR code embedding: NIC returns a signed QR code (256x256) that MUST be printed on the invoice for the legal binding. The print template + 48-char ESC/POS receipt template (per @hmp/common/printing) need to handle the QR rendering. Story body mentions QR but no AC requires the print-side verification.
  • [SME-PROPOSED] Failure handling: under FY 2024-25 changes, if IRN generation fails, the invoice is not legally valid — the property cannot deliver it. Story should require a hard block on invoice printing/emailing until IRN is issued OR einvoiceMandatory: false.

Drift findings:

D-006 — [P1] [Catalog-vs-reality status drift] Catalog labels US-015-004 "Partial" but B2B IRN code path + 12 module spec cases + 5 NIC adapter spec cases + 5-env-var boot guard all shipped under AP-T08-003 (2026-04-29). Promote to Built.

  • [SME-PROPOSED] Promote catalog status. Add a new sub-story US-015-NEW-EINVOICE-B2C covering B2C self-pickup path (no IRN needed; QR-on-receipt only, per NIC's "B2C QR Code" mandate for businesses > INR 500 Cr turnover).

D-007 — [P0] [Flow-test failing] check-out-einvoice.flow.spec.ts was 0/15 PASS on 2026-05-16 — the worst-performing flow on the entire platform. The downstream issue is documented in BF-005 (Check-out + e-invoice) recommended flow #3 in the playbook. Property #1 launch-blocker.

  • [SME-PROPOSED] Schedule BF-005 (Check-out + e-invoice) reconciliation immediately after this RTM lands. The flow-test failures are likely a cross-EPIC issue (folio close + IRN generation + e-invoice webhook), not a unit-level bug.

US-015-005 — Webhook Configuration for External Systems​

EPIC-body alias: epics/EP-015-integrations.md §US-015-009 is titled "Webhook Management with Retry & Dead-Letter" — same domain; D-001 alignment.

Catalog status: Built (P1, 5 points) Verified status: Built — webhook receiver (payment-service inbound), webhook outbound dispatcher (channel-service), HMAC signature verify, dedup, replay tooling, two-layer reconciliation; coverage across 6 service repos

Code locations:

  • hmp-payment-service/src/webhooks/webhook.controller.ts — @Public POST /api/webhooks/:providerCode/:merchantAccountId (inbound — Razorpay → us)
  • hmp-payment-service/src/webhooks/webhook-dispatcher.service.ts — HMAC verify + parse + dedup
  • hmp-payment-service/src/webhooks/webhook-reconcile.service.ts — AP-T12-004 cron requeue
  • hmp-channel-service/src/webhooks/webhook-management.controller.ts — outbound webhook registration + replay
  • hmp-channel-service/src/webhooks/webhook-management.service.ts — outbound webhook persistence + dispatch
  • hmp-channel-service/src/connections/webhook-registration.service.ts — per-connection webhook config
  • hmp-channel-service/src/adapters/urbanpiper/urbanpiper-webhook.controller.ts — UrbanPiper-specific inbound webhook
  • hmp-channel-service/src/intermediary/providers/resavenue/resavenue-webhook.controller.ts — ResAvenue (OTA) inbound webhook
  • hmp-channel-service/src/intermediary/abstract-intermediary-webhook.controller.ts — Shared OTA webhook base
  • hmp-frontdesk-service/src/einvoice/einvoice-webhook.controller.ts — NIC e-invoice callback
  • hmp-notification-service/src/channels/email-webhook.controller.ts — SES bounce/complaint webhook
  • hmp-notification-service/src/channels/whatsapp-webhook.controller.ts — WhatsApp Meta webhook
  • hmp-auth-service/src/billing/billing-webhook.controller.ts — Razorpay subscription billing webhook (legacy)

Unit + integration tests:

  • hmp-payment-service/src/webhooks/webhook-dispatcher.service.spec.ts
  • hmp-payment-service/src/webhooks/webhook-reconcile.service.spec.ts
  • hmp-channel-service/src/webhooks/__tests__/webhook-management-replay.spec.ts — replay tooling
  • hmp-channel-service/src/intermediary/__tests__/abstract-intermediary-webhook.spec.ts
  • hmp-channel-service/src/intermediary/providers/resavenue/__tests__/resavenue-webhook-hmac.spec.ts — HMAC verification
  • hmp-channel-service/src/intermediary/providers/resavenue/__tests__/resavenue-webhook-booking.spec.ts — Booking event dispatch
  • hmp-channel-service/src/adapters/urbanpiper/urbanpiper-webhook.service.spec.ts
  • hmp-notification-service/src/channels/whatsapp-webhook.controller.spec.ts

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/idempotency-replay.flow.spec.ts :: webhook idempotency dedup — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/channel-sync.flow.spec.ts :: OTA webhook → reservation create — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/whatsapp-feedback.flow.spec.ts :: WhatsApp webhook → feedback intent — TBD

Real-backend smokes: (none enumerated)

Use cases referencing this story: AP-T12-004 (two-layer payment reconciliation)

SME notes:

  • The webhook surface is HEAVILY built but scattered across 6 services. There is no central webhook registry / replay UI for operators; each service exposes its own controller.
  • [SME-PROPOSED] HMAC raw-body requirement — payment-service main.ts registers body-parser.raw({ type: 'application/json' }) on /api/webhooks BEFORE the global JSON parser. Any JSON re-serialisation invalidates the HMAC. Story should make this an explicit AC: "Webhook receivers MUST verify HMAC against the raw request body, NOT a re-serialised JSON".
  • [SME-PROPOSED] Dedup window — webhook-dispatcher de-dups by event ID; the reconciler retries stuck events > 5 min old. Story body should cite both windows (real-time dedup + post-5min reconciliation).

Drift findings:

D-008 — [P2] [Orphaned-code-and-scattered-ownership] 8 distinct webhook controllers exist across 6 services with no central registry. A new integrator asking "where do I register a webhook?" has no single answer.

  • [SME-PROPOSED] Author a new story US-015-NEW-WEBHOOK-REGISTRY "Unified webhook administration console" — single dashboard surface listing all webhooks across all services, with replay, dead-letter inspection, and per-source delivery metrics. This is referenced as a gap in US-015-001-review.md GAP-3 too.

US-015-006 — Door Lock Integration (ASSA ABLOY)​

EPIC-body alias: epics/EP-015-integrations.md §US-015-006 also titled "Door Lock System Integration (ASSA ABLOY)" — IDs align here.

Catalog status: Not Started (P3, 8 points) Verified status: Partial — SmartLockService shell + multiple vendor adapter stubs in @hmp/hardware (Saflok / Salto / Dormakaba / VingCard) exist; no live SDK integration; live key-encoder flow untested

Code locations:

  • hmp-frontdesk-service/src/smart-lock/smart-lock.controller.ts — Smart lock REST endpoints
  • hmp-frontdesk-service/src/smart-lock/smart-lock.service.ts — Service shell wrapping SmartLockProvider
  • hmp-frontdesk-service/src/smart-lock/smart-lock.module.ts — Provider injection module
  • hmp-shared-packages/packages/hardware/src/lib/vendors/saflok.adapter.ts — Saflok adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/salto-smart-lock.adapter.ts — Salto KS adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/dormakaba.adapter.ts — Dormakaba adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/vingcard.adapter.ts — ASSA ABLOY VingCard adapter (closest to "ASSA ABLOY" in the catalog title)
  • hmp-shared-packages/packages/hardware/src/lib/mock/ — Mock provider
  • hmp-shared-packages/packages/hardware/src/lib/simulators/ — Simulator implementations

Unit + integration tests:

  • hmp-frontdesk-service/src/smart-lock/smart-lock.controller.spec.ts
  • hmp-shared-packages/packages/hardware/src/lib/vendors/dormakaba.adapter.spec.ts
  • hmp-shared-packages/packages/hardware/src/lib/vendors/salto-smart-lock.adapter.spec.ts

Flow tests: NONE FOUND

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • The catalog title says "ASSA ABLOY" specifically but the codebase actually has adapter shells for 4 vendors — VingCard (an ASSA ABLOY brand), Saflok (also ASSA ABLOY), Salto KS, and Dormakaba. Catalog should be vendor-agnostic.
  • [SME-PROPOSED] Story should require TLS + certificate-pinning to the lock server (Visionline IP is typically on a hotel-side VLAN); without cert-pinning, a man-in-the-middle on the property LAN can issue rogue keys.
  • [SME-PROPOSED] Audit log retention — under Indian Penal Code 461/378, the lock audit log is a critical evidentiary artifact in theft investigations. Story should require 5-year audit retention with tamper-evident hashing.

Drift findings:

D-009 — [P2] [Orphaned-code-and-incomplete-status] Vendor adapters for VingCard/Saflok/Salto/Dormakaba exist but none have live SDK integration; smart-lock controller is a thin pass-through. Catalog "Not Started" is technically correct for the live integration, but masks the substantial scaffolding that did ship.

  • [SME-PROPOSED] Promote catalog to Partial (scaffolding shipped; live SDK + key-encoder hardware integration pending). Rename catalog title to "Door Lock Integration (Multi-Vendor: ASSA ABLOY VingCard / Saflok, Salto KS, Dormakaba)".

US-015-007 — POS Terminal / Printer Integration​

EPIC-body alias: epics/EP-015-integrations.md §US-015-007 titled "Thermal Printer & KOT Printing (ESC/POS)" — substantively same; D-001 alignment.

Catalog status: Not Started (P2, 5 points) Verified status: Partial — receipt-template ESC/POS code is shipped (@hmp/common/printing), PoS terminal payment adapter shipped (Pinelabs + Razorpay terminal); no live thermal printer driver path tested with hardware per review's GAP

Code locations:

  • hmp-shared-packages/packages/common/src/lib/printing/receipt-templates.ts — generateFolioReceipt() + generatePosReceipt() (48-char ESC/POS, KeyNova brand header, GST CGST/SGST/IGST, HSN/SAC codes, IST date format, Indian number grouping, IRN support) — per platform CLAUDE.md
  • hmp-shared-packages/packages/common/src/lib/printing/receipt-templates.spec.ts — 47 byte-level tests verifying ESC/POS control codes
  • hmp-shared-packages/packages/hardware/src/lib/vendors/escpos.adapter.ts — ESC/POS adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/star-micronics.adapter.ts — Star Micronics printer adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/cash-drawer-serial.adapter.ts — Cash drawer (kick) serial adapter
  • hmp-shared-packages/packages/hardware/src/lib/vendors/pinelabs.adapter.ts — Pinelabs POS terminal adapter
  • hmp-payment-service/src/adapters/pinelabs/pinelabs-terminal.adapter.ts — Pinelabs payment-service adapter
  • hmp-payment-service/src/adapters/pinelabs/plutus-ecr.codec.ts — Plutus ECR codec (Pinelabs proprietary)
  • hmp-payment-service/src/adapters/razorpay/razorpay-terminal.adapter.ts — Razorpay POS terminal adapter
  • hmp-payment-service/src/terminals/terminal-charge.worker.ts — Background worker for terminal charges

Unit + integration tests:

  • hmp-shared-packages/packages/common/src/lib/printing/receipt-templates.spec.ts (47 tests)
  • hmp-shared-packages/packages/hardware/src/lib/vendors/star-micronics.adapter.spec.ts
  • hmp-payment-service/src/adapters/pinelabs/pinelabs-terminal.adapter.spec.ts
  • hmp-payment-service/src/adapters/pinelabs/plutus-ecr.codec.spec.ts
  • hmp-payment-service/src/adapters/razorpay/razorpay-terminal.adapter.spec.ts
  • hmp-payment-service/src/terminals/terminal-charge.worker.spec.ts
  • hmp-payment-service/src/terminals/terminal-charge.service.spec.ts
  • hmp-payment-service/src/terminals/terminal-charge.controller.spec.ts
  • hmp-payment-service/src/terminals/terminal-devices.service.spec.ts
  • hmp-payment-service/src/terminals/terminal-event.handler.spec.ts

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/terminal-folio-settlement.flow.spec.ts :: terminal charge → folio settle — TBD
  • hmp-infrastructure/testing/flow-tests/src/flows/terminal-pos-order.flow.spec.ts :: POS terminal charge — TBD

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • POS-hardware in hmp-pos-service — there is NO hardware/ module in hmp-pos-service/src/. The shipped pos-service is order/KOT/menu only; printer integration is via the shared @hmp/hardware package. EPIC-body description "POS hardware controller in pos-service" is inaccurate.
  • The shipped path: order ships → KitchenGateway emits WebSocket event to KDS kiosk → KDS displays. No automatic printer-side KOT path is fully wired (printer adapter exists in @hmp/hardware, but no consumer service emits KOT-print events to it).
  • [SME-PROPOSED] Print station routing — catalog AC-1 (EPIC body US-015-007 AC) mentions per-station printer mapping but no service code does the station→printer fan-out. The KDS websocket path is the substitute solution (kitchen sees the order on a screen instead of paper). Property #1 may need printer-based fallback for non-KDS sites.
  • [SME-PROPOSED] Dual-currency receipts — for foreign guests, the 48-char ESC/POS template must show INR + foreign currency lines (Forex compliance). Receipt template handles this per its tests but the story body doesn't AC it.

Drift findings:

D-010 — [P1] [Story-incomplete + scattered-ownership] EPIC-body says "POS hardware controller in pos-service" — incorrect. Hardware code lives in @hmp/hardware and @hmp/common/printing. Pinelabs+Razorpay POS terminal flows live in hmp-payment-service/src/terminals/ and adapters/pinelabs/. A new engineer can't find the POS-printer code from the story.

  • [SME-PROPOSED] Story body should enumerate the 3 owning locations explicitly. Promote to Partial in catalog.

US-015-008 — SAP Accounting Connector​

EPIC-body alias: epics/EP-015-integrations.md §US-015-003 titled "SAP Business One Journal Posting" — same domain; D-001 alignment item.

Catalog status: Partial (P3, 8 points) Verified status: Stub / Not Started — EPIC-body description references SapService and SapReconciliationService in integration-service; no integration-service exists in the platform; only .tpl-worktree/.../sap UI scaffolding found

Code locations: NONE on master (drift candidate)

  • EPIC-body cites SapService + SapReconciliationService — neither exists on master
  • .tpl-worktree/src/app/(dashboard)/settings/integrations/sap/ — dashboard UI scaffolding only (worktree, unmerged)

Unit + integration tests: NONE FOUND

Flow tests: NONE FOUND

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • The EPIC-body's "Current Implementation Status" section cites a SapService + SapReconciliationService in integration-service. The platform has no integration-service (see CLAUDE.md service list). The EPIC body is referencing an architecture that was never built.
  • [SME-PROPOSED] SAP Business One is mostly used by 5+ property chains in India (Indian Hotels Co Ltd / Lemon Tree groups). For Property #1 (Tier-2 SME) the Tally integration (US-015-002) is the relevant accounting connector. SAP can stay deferred.

Drift findings:

D-011 — [P0] [Stub-shipped-as-Partial + EPIC-body-references-nonexistent-service] Catalog says US-015-008 "Partial" — actually nothing exists on master. EPIC body references a non-existent integration-service.

  • [SME-PROPOSED] Demote catalog to Not Started. Remove the EPIC-body references to non-existent services. Defer the story until Tier-1 chain customers prioritise it.

US-015-009 — Stripe Payment Gateway (Roadmap)​

EPIC-body alias: epics/EP-015-integrations.md §US-015-011 titled "Stripe Payment Gateway (International)" — same; D-001 alignment.

Catalog status: Not Started (P3, 5 points) Verified status: Stub — StripeAdapter exists in legacy @hmp/payments package (referenced in US-015-001-review.md line 102), but the dedicated hmp-payment-service only carries Razorpay adapters; no Stripe in hmp-payment-service/src/adapters/

Code locations:

  • hmp-shared-packages/packages/integrations/src/lib/payments/stripe.adapter.ts [CITED via US-015-001-review.md] — legacy Stripe adapter in shared integrations
  • hmp-shared-packages/packages/integrations/src/lib/payments/stripe.adapter.spec.ts
  • hmp-payment-service/src/adapters/ — NO stripe/ directory (only mock, pinelabs, razorpay)

Unit + integration tests:

  • hmp-shared-packages/packages/integrations/src/lib/payments/stripe.adapter.spec.ts

Flow tests: NONE FOUND

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • The shared-package Stripe adapter is leftover from the pre-payment-service architecture. It is NOT plugged into the modern hmp-payment-service. Calling this "Stub" is accurate.
  • [SME-PROPOSED] Stripe-in-India context — Stripe India launched 2025 but with limitations: domestic INR routing requires RBI-compliant card networks (RuPay/Visa/MC), no UPI capture, no NetBanking. For international guests, Stripe makes sense; for INR-only properties, Razorpay covers everything Stripe does plus UPI/NetBanking. Story should narrow scope to "International cards only".
  • [SME-PROPOSED] PCI scope expansion — adding Stripe means a second PCI-scoped data path. The payment-service network isolation contract (per platform CLAUDE.md "payment isolation (PCI)") would need to be re-attested.

Drift findings: (no new — captured in summary as Stub)

  • [SME-PROPOSED] Defer Stripe until Property #1 launch + ≥5 international-card properties onboard. Track as BACKLOG not Not Started.

US-015-010 — FSSAI License Verification API​

EPIC-body alias: epics/EP-015-integrations.md §US-015-005 titled "FSSAI License Verification & Alerting", §US-015-010 titled "API Key Management with Scoped Permissions" — completely different titles attached to ID 010 between catalog and EPIC body. See D-001.

Catalog status: Not Started (P2, 3 points) Verified status: Not Started — no FSSAI API integration; the EPIC body's §US-015-005 acknowledges "documentation-only compliance"

Code locations: NONE FOUND (only hmp-web-dashboard/src/lib/api/amc-contracts.ts mentions fssai in a contract schema)

Unit + integration tests: NONE FOUND

Flow tests: NONE FOUND

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • The FSSAI Food Safety and Standards Authority of India does NOT currently expose a public verification API — license verification is a manual lookup via foscos.fssai.gov.in. The story's AC-2 ("calls the FSSAI verification API") is technically not achievable as written.
  • [SME-PROPOSED] Rewrite story to support manual license entry + scheduled expiry alerting (60/30/15/7 day reminders) without any live API. This is what Indian SME hotels actually need.
  • [SME-PROPOSED] Tie FSSAI compliance to POS-outlet activation: if an outlet's FSSAI expires, the outlet's POS module is disabled until renewed. Property loses revenue → strong incentive to renew.

Drift findings:

D-012 — [P1] [Story-asks-for-nonexistent-API] AC-2 requires an FSSAI verification API call that the regulator does not provide. Story is unbuildable as written.

  • [SME-PROPOSED] Rewrite AC-2 to "manual license entry with periodic expiry-reminder cron + dashboard expiry warning banner". Drop the verification-API requirement entirely.

US-015-011 — Multi-Currency Billing Configuration​

EPIC-body alias: epics/EP-015-integrations.md §US-015-011 titled "Stripe Payment Gateway" — completely different concern attached to ID 011 between catalog and EPIC body. See D-001.

Catalog status: Built (P1, 5 points) Verified status: Built — property.currency field exists, currency module + forex module shipped; multi-currency billing on receipts confirmed via 47 receipt-template tests

Code locations:

  • hmp-property-service/prisma/schema.prisma [CITED-BUT-NOT-FOUND — exact line] — Property.currency field (default "INR")
  • hmp-shared-packages/packages/common/src/lib/currency/currency.service.ts — conversion + formatting
  • hmp-frontdesk-service/src/forex/forex.service.ts — forex transactions for actual foreign-currency billing
  • hmp-frontdesk-service/src/forex/forex.controller.ts — REST endpoints
  • hmp-shared-packages/packages/common/src/lib/printing/receipt-templates.ts — receipt currency formatting + dual-currency line support
  • hmp-web-dashboard/src/components/forms/currency-input.tsx [CITED via .tpl-worktree] — currency input widget
  • hmp-web-dashboard/src/lib/utils/currency.ts [CITED via .tpl-worktree] — UI-side conversion helpers

Unit + integration tests:

  • hmp-frontdesk-service/src/forex/forex.service.spec.ts
  • hmp-frontdesk-service/src/forex/forex.controller.spec.ts
  • hmp-shared-packages/packages/common/src/lib/printing/receipt-templates.spec.ts (47 byte-level tests — dual-currency lines verified)
  • hmp-web-dashboard/src/components/forms/__tests__/currency-input.test.tsx [CITED via .tpl-worktree]

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/forex-currency.flow.spec.ts :: forex transaction roundtrip — TBD

Real-backend smokes: NONE FOUND

Use cases referencing this story: none

SME notes:

  • Multi-currency billing config = "property carries a default currency + can issue foreign-currency invoices when guest's billing country differs". This is shipped.
  • The auto-refresh rate is US-015-003 (Not Started) — these two stories are tightly coupled and the catalog separates them sensibly.
  • [SME-PROPOSED] FEMA RBI 8(2) — for INR-denominated invoices delivered to non-resident guests, the property must declare the equivalent foreign currency at the rate applicable on the date of payment, not the date of folio open. The receipt template needs to know which rate to print; today there's no enforcement.
  • [SME-PROPOSED] Forex transaction reporting — properties licensed as Authorised Money Changers (AMC, RBI cat II) must file monthly Form A2 reports of forex sales. Story should require an exportable monthly Form A2 report from the forex module.

Drift findings:

D-013 — [P0] [Catalog-numbering-collision] US-015-011 in catalog = "Multi-Currency Billing Configuration"; US-015-011 in EPIC body = "Stripe Payment Gateway (International)". Same numeric ID, completely different scope. This is the worst symptom of D-001 — two stories share an ID.

  • [SME-PROPOSED] After D-001 is resolved, this collision goes away. Until then, no PR should claim to "close US-015-011" without specifying which doc's interpretation it serves.