You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
S08 — payment-request.v1 contract restore and validation core
Field
Value
ID
S08
ETA
2 — Auth and payment-request contract
Priority
P0
Complexity
Medium
Depends on
S03
Atomic tasks
SRV-031, SRV-032, SRV-033, SRV-034, SRV-035
Milestone
Public validate endpoint
Blocker
Yes — see Hard blockers section
Executive summary
This deliverable consolidates 5 atomic server tasks into one sprint-sized ticket for payment-request.v1 contract restore and validation core.
Success means: Public validate endpoint.
Product context
Ding Payments is a self-custodial Stellar P2P app: the server validates NFC payment requests, enforces hybrid Supabase + WebAuthn authorization, relays signed XDR to Horizon, and indexes history.
User stories
As a developer, I want S08 complete so I can run the next ETA without manual archaeology.
As a receiver, I want my NFC payment request validated consistently with the canonical contract.
As a sender, I want clear API errors when a payment request is malformed or expired.
As an operator, I want migrations, health checks, and logs sufficient to debug testnet payments.
Prerequisites
Deliverable S03 merged and deployed to dev
Node 20+, npm, Supabase project credentials, Postgres reachable via DATABASE_URL
Read Sections 3–6 of server-build-plan.md before coding
Atomic sub-task checklist
SRV-ID
Title
Key deliverable
SRV-031
Restore docs/payment-request.v1.md
Restore docs/payment-request.v1.md
SRV-032
Port payment-request.v1.ts from git
Port payment-request.v1.ts from git
SRV-033
Unit tests payment-request.v1 contract
Unit tests payment-request.v1 contract
SRV-034
PaymentRequestsModule scaffold
PaymentRequestsModule scaffold
SRV-035
POST /v1/payment-requests/validate
POST /v1/payment-requests/validate
Scope — In
All atomic tasks SRV-031, SRV-032, SRV-033, SRV-034, SRV-035 as specified in server-build-plan.md
NestJS 11 patterns: modules, providers, DTOs with class-validator, Swagger decorators where applicable
Unit and/or E2E tests for new behavior; keep CI green (ci-server.yml)
Restore docs/payment-request.v1.md and port payment-request.v1.ts from git 5d4e9de^
Public validate endpoint with PAYMENT_REQUEST_* error codes
Scope — Out
Client UI or Expo changes (ding-payments repo)
Mainnet launch configuration (testnet MVP only unless explicitly toggled)
Push notifications on payment confirmation (post-MVP P3)
Custodial wallets or server-side key storage
Features not listed in atomic SRV IDs for this deliverable
Architecture & conventions
Target architecture from server-build-plan.md Section 3: flat src/modules/* layout, ConfigModule validation, global exception filter, URI versioning /v1.
S08 — payment-request.v1 contract restore and validation core
Executive summary
This deliverable consolidates 5 atomic server tasks into one sprint-sized ticket for payment-request.v1 contract restore and validation core.
Success means: Public validate endpoint.
Product context
Ding Payments is a self-custodial Stellar P2P app: the server validates NFC payment requests, enforces hybrid Supabase + WebAuthn authorization, relays signed XDR to Horizon, and indexes history.
User stories
Prerequisites
DATABASE_URLAtomic sub-task checklist
Scope — In
ci-server.yml)docs/payment-request.v1.mdand portpayment-request.v1.tsfrom git5d4e9de^Scope — Out
Architecture & conventions
Target architecture from server-build-plan.md Section 3: flat
src/modules/*layout, ConfigModule validation, global exception filter, URI versioning/v1.Endpoint reference (MVP):
Endpoints
POST/v1/payment-requests/validatePOST/v1/payment-requestsGET/v1/payment-requests/:idPOST/v1/paymentsPOST/v1/payments/:id/authorizePOST/v1/payments/:id/submitGET/v1/payments/:idPOST/v1/transactions/simulateGET/v1/transactionsGET/v1/users/mePOST/v1/users/me/walletPOST/v1/webauthn/register/optionsPOST/v1/webauthn/register/verifyPOST/v1/webauthn/authenticate/optionsGET/healthGET/health/readyGET/health/stellarPayment state machine (Section 6 excerpt):
6. Payment state machine
States
stateDiagram-v2 [*] --> CREATED: POST payments CREATED --> AUTHORIZED: POST authorize WebAuthn OK AUTHORIZED --> SUBMITTED: POST submit XDR relay OK SUBMITTED --> CONFIRMED: Poll Stellar success SUBMITTED --> FAILED: Poll Stellar fail CREATED --> FAILED: Timeout without authorize AUTHORIZED --> FAILED: Timeout without submit CREATED --> FAILED: Request expired AUTHORIZED --> FAILED: Request expiredTransitions and rules
CREATEDPOST /v1/paymentsCREATEDAUTHORIZEDPOST /v1/payments/:id/authorizeAUTHORIZEDSUBMITTEDPOST /v1/payments/:id/submitSUBMITTEDCONFIRMEDSUBMITTEDFAILEDCREATEDFAILEDPAYMENT_SUBMIT_TIMEOUT_MSwithout authorizeAUTHORIZEDFAILED*FAILEDexpiresAtpassedEventEmitter2 events
payment.created{ paymentId, senderUserId, receiverUserId }payment.authorized{ paymentId, userId }payment.submitted{ paymentId, stellarTxHash }payment.confirmed{ paymentId, stellarTxHash, ledger }payment.failed{ paymentId, failureCode, failureReason }Configurable timeouts
PAYMENT_SUBMIT_TIMEOUT_MSPAYMENT_POLL_INTERVAL_MSPAYMENT_POLL_MAX_ATTEMPTSAppendix A — Error codes
Payment Request (PAYMENT_REQUEST_*):
Payment (PAYMENT_*):
Stellar (STELLAR_*):
WebAuthn (WEBAUTHN_*):
Files to create/modify
ding-server/docs/payment-request.v1.mdding-server/src/contracts/payment-request.v1.tsding-server/src/modules/payment-requests/See server-build-plan.md atomic files for SRV-031See server-build-plan.md atomic files for SRV-032See server-build-plan.md atomic files for SRV-033Implementation guide
npm run lintand fix any new violations.npm run test:e2ewhen HTTP surface changed.{ statusCode, message, code?, errors? }shape from Section 5..env.exampleand README.npm run start:devand curl/httpie against/v1routes.API examples —
POST /v1/payment-requests/validateRequest (public, no JWT):
{ "type": "payment-request", "version": 1, "recipient": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", "asset": "USDC", "amount": "25.00", "timestamp": "2026-06-17T12:00:00.000Z", "expiresAt": "2026-06-17T12:00:30.000Z", "requestId": "req_unique_123", "memo": "Coffee" }Response 200 (valid):
{ "valid": true, "normalized": { "type": "payment-request", "version": 1, "recipient": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", "asset": "USDC", "amount": "25.00", "timestamp": "2026-06-17T12:00:00.000Z", "expiresAt": "2026-06-17T12:00:30.000Z" }, "errors": [] }Response 200 (invalid):
{ "valid": false, "normalized": null, "errors": [ { "code": "PAYMENT_REQUEST_ASSET_UNSUPPORTED", "field": "asset", "message": "Asset BTC is not supported" } ] }Acceptance criteria
.envgitignorednpm run prisma:generate)Test plan
Client coordination
Lock schema with client C10/C11 before changing validate rules.
Security notes
SUPABASE_JWT_SECRET,SUPABASE_SERVICE_ROLE_KEY, or raw WebAuthn challengesRisks & pitfalls
Definition of done
Source: build plan