Skip to content

[PAY-01] Payment domain model, on-chain ID mapping & custody model decision - #1280

Merged
mftee merged 2 commits into
CodeGirlsInc:mainfrom
yusuftomilola:feature/pay-01-payment-domain-model
Aug 21, 2026
Merged

[PAY-01] Payment domain model, on-chain ID mapping & custody model decision#1280
mftee merged 2 commits into
CodeGirlsInc:mainfrom
yusuftomilola:feature/pay-01-payment-domain-model

Conversation

@yusuftomilola

Copy link
Copy Markdown
Contributor

Summary

This PR implements the foundational payment domain model for the FrieghtFlow payment track (issue #1274).

What's included

  • PaymentStatus enum (backend/src/common/enums/payment-status.enum.ts) — mirrors the on-chain EscrowStatus variants (Pending, Funded, Released, Refunded, Disputed) plus an internal Cancelled state.
  • Payment entity (backend/src/payments/entities/payment.entity.ts) — TypeORM entity with UUID FK to shipments, bigint onChainShipmentId for deterministic UUID-to-u64 mapping, wallet addresses, timestamps, and unique constraints on both shipmentId and onChainShipmentId.
  • PaymentsService (backend/src/payments/payments.service.ts) — getOrCreatePayment() lazily generates the on-chain ID on first funding attempt; DB unique constraint prevents double-creation on concurrent clicks. Lookup methods by shipment UUID or on-chain ID.
  • PaymentsModule (backend/src/payments/payments.module.ts) — registered in AppModule.
  • TypeORM migration (backend/src/migrations/1724140800000-CreatePaymentsTable.ts) — creates the payments table with enum type, unique constraints, and foreign key to shipments.
  • Custody-model ADR (backend/docs/payments-custody-model.md) — documents the hybrid custody model (non-custodial deposit + admin-arbitrated release), the admin keypair's blast radius, and required hardening before mainnet (multisig, timelock, on-chain audit trail, circuit breaker).

Design decisions

  • Postgres sequence, not UUID hashonChainShipmentId is dense and collision-free, avoiding the fragility of truncating/hashing UUIDs.
  • Lazy ID generation — IDs are only created on first funding attempt, not backfilled for historical shipments.
  • DB-level uniqueness — both shipmentId and onChainShipmentId have unique constraints; concurrent double-click failures are caught at the database layer, not just application logic.
  • No RPC/contract calls — this issue is purely the domain model foundation. Soroban integration comes in later issues.

How later issues consume this model

Subsequent issues in the payment track (PAY-02 through PAY-06) will:

  • Use PaymentsService.getOrCreatePayment() to create payment records when escrow funding is initiated
  • Use findByOnChainId() to resolve on-chain events back to backend payment records
  • Use updateStatus() to reflect on-chain state transitions (Funded, Released, Refunded, Disputed)
  • Reference Payment.shipperWalletAddress and Payment.carrierWalletAddress for Soroban RPC calls

closes #1274

…el ADR

- Create PaymentStatus enum mirroring on-chain EscrowStatus
- Create Payment entity with UUID FK to shipments, bigint on-chain ID mapping
- Add unique constraints on shipmentId and onChainShipmentId
- Implement PaymentsService with getOrCreatePayment (lazy ID generation)
- Register PaymentsModule in AppModule
- Add TypeORM migration for payments table
- Document hybrid custody model (non-custodial deposit + admin-arbitrated release)
- Flag admin keypair centralization risk; outline multisig/timelock requirements for mainnet
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

@yusuftomilola is attempting to deploy a commit to the Mftee's projects Team on Vercel.

A member of the Team first needs to authorize it.

@mftee mftee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the PAY-01 payment domain model changes. The design is solid:

  • PaymentStatus enum cleanly mirrors the on-chain EscrowStatus states with a sensible internal-only Cancelled addition.
  • Payment entity's dual unique constraints (shipmentId + onChainShipmentId) correctly push double-creation protection down to the DB layer instead of relying on app-level checks alone.
  • Lazy on-chain ID generation via getOrCreatePayment() avoids unnecessary backfill work for historical shipments — good call deferring that.
  • The custody-model ADR is a valuable addition, clearly documenting the admin keypair's blast radius and the hardening steps required before mainnet (multisig, timelock, audit trail, circuit breaker).
  • No RPC/contract calls in this PR keeps the scope tight to the domain model foundation, as intended for PAY-01.

CI is green across Backend, Frontend, and Contracts. The Vercel status check failure is an unauthorized/unlinked deployment integration issue, unrelated to the code itself.

Approving — nice groundwork for the PAY-02 through PAY-06 issues that build on this.

@mftee
mftee merged commit 662878f into CodeGirlsInc:main Aug 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PAY-01] Payment domain model, on-chain ID mapping & custody model decision

2 participants