Integration
1. Sister Services
| Sister | Direction | Surface | Auth | Failure Mode |
|---|---|---|---|---|
@nx/sale | → (payment dispatches) | HTTP webhook to POST /v1/api/sale/webhooks/payment | none (Cilium network policy) | Retry per WebhookConfig.metadata.maxRetries; failed dispatches logged |
@nx/sale (initiator) | ← (sale calls) | HTTP — initiate transaction via @nx/mq-pay controllers | JWT | sale handles errors |
@nx/identity | → (verify) | HTTP — JWKS at /jw-certs | none | Cached locally |
@nx/identity (Casbin) | → | HTTP — PolicyDefinitionService | JWT | Redis cache |
@nx/signal | → | WebSocket emitter | — | best-effort |
2. External Systems
| System | Direction | Surface | Auth | Notes |
|---|---|---|---|---|
| VN Pay (QR MMS) | ↔ | HTTPS REST + IPN | Encrypted credentials per merchant | @nx/mq-pay provider |
| VN Pay (PhonePOS) | ↔ | HTTPS REST + IPN | Same | |
| VN Pay (SmartPOS) | ↔ (placeholder) | HTTPS REST | Same | Provider declared, integration WIP |
| PostgreSQL | ↔ | DB | password from env | Schemas: mq_pay, shared Configuration + WebhookConfig |
| Redis | ↔ | TCP | password from env | BullMQ queues + cache |
3. Critical Cross-Service Flows
3.1 Sale → Payment → Provider → Sale (full lifecycle)
3.2 Webhook subscriber registration
3.3 Mode-based deployment topology
Each WORKER pod must have a unique
APP_ENV_NODE_ID(Snowflake worker ID) to avoid id collisions.
4. MQ-Pay Bridge Detail
@nx/mq-pay is not a separate service — it's a third-party package consumed by @nx/payment via MQPayComponent. Lifecycle:
| Step | What happens |
|---|---|
| Boot | ApplicationPaymentComponent.binding() reads APP_ENV_MQ_PAY_MODE |
| Configure | Builds IMQPayOptions with: mode, credentialGetter, vnpay configs (decrypted), eventHandler |
| Register | Calls application.component(MQPayComponent) |
| MQPayComponent boot | Validates mode; sets up Redis/BullMQ; registers TransactionRepository, etc.; conditionally registers controllers (FULL/API) and workers (FULL/WORKER) |
| Event handler set | AppRegistry.setEventHandler(WebhookEventHandlerHelper) |
| Runtime | Workers emit events → AppRegistry.emit → WebhookEventHandlerHelper.handle |
AppRegistry is a separate singleton (NOT IGNIS DI) that manages cross-cutting state for MQ-Pay (Redis, BullMQ, providers, event handler).
5. Contract Stability
| Surface | Stability | Versioning |
|---|---|---|
Webhook payload (mq-pay:* events) | stable | additive only |
WebhookConfig REST (/webhook-configs) | stable | URL prefix /v1/ |
Configuration table (payment rows) | stable | code namespace owned by payment |
| MQ-Pay endpoints | stable | URL prefix /v1/ (controller paths owned by @nx/mq-pay) |
WebSocket topics observation/payment/* | stable | additive |
6. Crosscutting concerns
| Concern | Handling |
|---|---|
| Trust | IPN signed by provider (verified in MQ-Pay); webhook to subscribers signed via HMAC if WebhookConfig.signingMethod set |
| At-rest encryption | Provider creds encrypted with AES-256-GCM in Configuration.credential; key from APP_ENV_APPLICATION_SECRET |
| At-flight encryption | TLS at gateway; intra-cluster traffic plaintext |
| Mode coordination | API + WORKER pods share Redis (BullMQ) and PostgreSQL — must use same encryption key |
| Webhook retry | WebhookDispatcherService per WebhookConfig.metadata.maxRetries (default 3) with exponential backoff |