feat: add POST /api/scouts/:wallet/subscribe endpoint#230
Conversation
Implements the missing scout subscription purchase endpoint (P0).
Changes:
- src/services/stellar.ts: add purchaseSubscription(wallet, tier, duration)
with SubscriptionTier and SubscriptionResult types; stubs the Soroban
subscribe() contract call; maps INSUFFICIENT_FUNDS to PaymentError code 7
- src/controllers/scoutController.ts: add subscribeSchema (zod) validating
tier enum ('basic'|'premium') and duration (int 1–365); add subscribe()
handler returning 201 on success, 400 on bad input, 402 on insufficient funds
- src/routes/scout.ts: add POST /:wallet/subscribe protected by requireRole('scout')
- tests/routes/scout.test.ts: add 7 subscribe integration tests covering
201 success, 400 invalid tier, 400 missing duration, 400 out-of-range duration,
401 unauthenticated, 402 INSUFFICIENT_FUNDS, 403 wrong role
All 20 scout tests pass.
Fixes: missing POST /api/scouts/:wallet/subscribe route
|
This is a well-structured and sensible addition to the backend. It correctly fills a missing critical API path, and the overall design is clean: validation is handled with Zod, access control is enforced at the route level, and the response shape is consistent and easy for clients to consume. The test coverage is also strong, especially with the inclusion of both happy-path and multiple failure scenarios, which gives good confidence in expected behavior. |
|
Fix Ci |
Summary
Implements the missing
POST /api/scouts/:wallet/subscribeendpoint, resolving the P0 gap where scouts had no way to purchase a subscription through the backend.Changes
src/services/stellar.tsSubscriptionTiertype ('basic' | 'premium')SubscriptionResultinterface (transactionId,tier,expiresAt,status)purchaseSubscription(wallet, tier, duration)stub that wraps the Sorobansubscribe(scout, tier, duration)contract call; throwsPaymentErrorwith codeINSUFFICIENT_FUNDS(maps to contract error code 7) on insufficient XLM balancesrc/controllers/scoutController.tssubscribeSchema(zod): validatestieras'basic' | 'premium'enum anddurationas integer 1–365subscribe()handler: returns201with transaction data on success,400on validation failure,402onINSUFFICIENT_FUNDSPaymentErrorsrc/routes/scout.tsPOST /:wallet/subscriberoute guarded byrequireRole('scout')401if unauthenticated,403if role is notscouttests/routes/scout.test.tspurchaseSubscriptionandisSubscribed201— success with correct response shape400— invalid tier ('gold')400— missingduration400—durationout of range (400)401— unauthenticated request402—INSUFFICIENT_FUNDSfrom stellar stub403— wrong role (playerinstead ofscout)Response Shape
{ "success": true, "data": { "transactionId": "stub-sub-txid-...", "tier": "basic", "expiresAt": 1234567890, "status": "active" } }What Was Tested
npm test -- --testPathPattern=tests/routes/scout)api.test.ts(admin events/fees/validator) are unrelated to this changeNotes
purchaseSubscriptionis a stub pending Soroban RPC integration (marked withTODOcomments). The interface contract and error mapping are production-ready; only the inner transaction-building logic needs wiring once the contract is deployed.Fixes: missing
POST /api/scouts/:wallet/subscriberouteCloses #221