Operations
1. Triển khai
| Thuộc tính | Giá trị |
|---|---|
| Dev port | 1190 ⚠️ (anh em dùng 310x0) |
| Local nginx upstream | invoice_upstream → 127.0.0.1:31140 (packages/gateway/local/nginx.conf) |
| Base path | /v1/api (không có segment riêng cho service) |
| Run modes | api, worker (BullMQ issuance + claim-expiry), migrate |
| Migration | bun run migrate:dev (seed dữ liệu hành chính VN, configs, webhooks, permissions) |
| Snowflake ID range | ⚠️ chưa đặt (APP_ENV_..._WORKER_ID chưa cấu hình) |
| Service code | SVC-00150-INVOICE (đã có trong ServiceCodes của core); Kafka id mặc định SVC-00150-INVOICE_CONSUMER |
⚠️ Đối chiếu trước production (từ AGENTS của package): gán một
SVCcode duy nhất, một snowflake worker id, và một port310x0; giải quyết va chạmSVC-00050với inventory trước khi deploy production.
Build & run
bash
bun run rebuild # clean + build (deps: core, iiapi, t-van, mq-pay)
bun run lint:fix # ESLint + Prettier
bun run server:dev # chạy với .env.development
bun run migrate:dev # migrations / seeds2. Observability
| Tín hiệu | Nguồn | Xem ở đâu |
|---|---|---|
| Logs | stdout (key-value có cấu trúc) | kubectl logs <pod> / Loki |
| Audit phát hành | invoice.InvoiceAuditTracing | vết sự kiện theo từng hoá đơn (eventType/outcome/before-after) |
| Health | route health mặc định của IGNIS | portal gateway |
Marker log chính
| Marker | Ý nghĩa |
|---|---|
[handlePaymentSuccess] | quyết định phát hành theo thanh toán |
[handleMerchantCDC] op=u tax unchanged, SKIP | short-circuit khi diff CDC |
[enqueueIssuance] ... partition: %s | định tuyến partition |
[_handleIssuanceFailure] Scheduling retry | retry tạm thời với backoff |
[DLQ] invoice-issuance | job cạn lượt → hoá đơn FAILED + audit |
3. Bảo mật
| Mối quan tâm | Giảm thiểu |
|---|---|
| AuthN | JWT (ES256, JWKS từ identity); VerifierApplication |
| AuthZ | Controller có cổng permission + AuthorizationService (cấp merchant) |
| Credential provider | AES-256-GCM, khoá = đúng 32 byte / 64 hex (APP_ENV_INVOICE_CREDENTIALS_KEY) |
| Tin cậy webhook | Hai HMAC secret: WEBHOOK_SECRET (merchant→platform), WEBHOOK_INTERNAL_SECRET (iiapi/commerce→platform, xác minh HMAC-SHA256) |
| Token claim người mua | UUID ngẫu nhiên, partial-unique, có thời hạn (claimDeadline) |
| Secrets | env / bảng Configuration (mã hoá); không bao giờ trong code |
| Soft-delete | deletedAt — mặc định không hard-delete |
4. Runbook
4.1 Lớp cảnh báo
| Cảnh báo | Kích hoạt | Kiểm tra | Khắc phục | Leo thang |
|---|---|---|---|---|
| Tăng vọt lỗi phát hành | tỷ lệ FAILED InvoiceAuditTracing ↑ | logs [_handleIssuanceFailure] / provider 4xx | xem response payload của provider; sửa config/credential | invoice-team |
| BullMQ DLQ phình | logs [DLQ] invoice-issuance | độ sâu queue Redis theo từng partition | re-enqueue sau khi sửa nguyên nhân gốc | on-call SRE |
| Lệch TaxInfo CDC | FE hiển thị thuế merchant cũ | so metadata.tax vs TaxInfo | kích hoạt cập nhật merchant (re-CDC); kiểm logic diff | invoice-team |
| Webhook bị từ chối | 401 trên /webhooks | sai chữ ký | xoay/đồng bộ lại secret WEBHOOK_* | invoice-team |
4.2 Thao tác thường gặp
| Thao tác | Cách làm |
|---|---|
| Tail logs | kubectl logs -n <ns> -f deploy/invoice |
| Xem trạng thái hoá đơn | query invoice.Invoice + InvoiceIssuance + InvoiceAuditTracing theo sourceId |
| Replay phát hành kẹt | re-enqueue qua luồng phát hành (jobId = orderId); idempotent trên hoá đơn active |
| Re-sync thuế merchant | re-emit/replay Merchant CDC; op=u diff-skip nếu không đổi |
| Xem partition của một order | partition = getPartitionByKey(orderId) (hashCode mod 3) |
4.3 Gotcha đã biết / nợ kỹ thuật
| Mục | Chi tiết |
|---|---|
| Không có một transaction | Tạo Invoice + InvoiceRequest không nguyên tử (payment-success có thể đến trước request) |
| Snapshot config bất biến | provider config được copy lúc tạo hoá đơn; sửa config giữa vòng đời không áp dụng |
| Lệch định danh service | code/worker-id/port chưa đặt (xem Triển khai ⚠️) |
Sự cố xuyên service: xem
/runbook/.