🔖 Title
Implement idempotency key support for financial mutation endpoints
📄 Description
The four financial mutation endpoints have no idempotency protection:
- `POST /loans/create`
- `POST /loans/:id/pay`
- `POST /liquidity/deposit`
- `POST /liquidity/withdraw`
On network timeouts or client retries, the same request can be submitted twice before the blockchain confirms the first transaction. This can create duplicate loan records or apply the same payment twice. No `Idempotency-Key` header is documented, validated, or stored anywhere in the codebase.
The existing blockchain-level deduplication (unique constraints on `event_id` in the indexer) only protects after on-chain confirmation — it does not prevent two `PENDING` loan rows from being inserted before either is confirmed.
✅ Tasks to complete
📚 Documentation/context for AI
(This link never should removed)
https://github.com/TrustUp-app/TrustUp-API/tree/main/docs
Relevant files:
- `src/modules/loans/loans.controller.ts`
- `src/modules/loans/loans.service.ts`
- `src/modules/liquidity/liquidity.controller.ts`
- `src/common/interceptors/`
- `src/common/decorators/`
🗒️ Additional notes
- Redis is already configured via `CacheModule` with `cache-manager-redis-store` — reuse the same `CACHE_MANAGER` token
- Cache key must include `userId` to prevent one user from replaying another user's idempotency key
- If the handler throws, do NOT cache the error response — only cache successful (2xx) responses
- Return a `X-Idempotent-Replayed: true` header on replayed responses so clients can detect them
- Idempotency key should be optional (no header = no idempotency protection, for backwards compatibility)
🔖 Title
Implement idempotency key support for financial mutation endpoints
📄 Description
The four financial mutation endpoints have no idempotency protection:
On network timeouts or client retries, the same request can be submitted twice before the blockchain confirms the first transaction. This can create duplicate loan records or apply the same payment twice. No `Idempotency-Key` header is documented, validated, or stored anywhere in the codebase.
The existing blockchain-level deduplication (unique constraints on `event_id` in the indexer) only protects after on-chain confirmation — it does not prevent two `PENDING` loan rows from being inserted before either is confirmed.
✅ Tasks to complete
📚 Documentation/context for AI
(This link never should removed)
https://github.com/TrustUp-app/TrustUp-API/tree/main/docs
Relevant files:
🗒️ Additional notes