Skip to content

feat: add POST /api/scouts/:wallet/subscribe endpoint#230

Merged
Petah1 merged 4 commits into
scout-off:mainfrom
johnsaviour56-ship-it:feat/scout-subscribe-endpoint
Jun 23, 2026
Merged

feat: add POST /api/scouts/:wallet/subscribe endpoint#230
Petah1 merged 4 commits into
scout-off:mainfrom
johnsaviour56-ship-it:feat/scout-subscribe-endpoint

Conversation

@johnsaviour56-ship-it

@johnsaviour56-ship-it johnsaviour56-ship-it commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the missing POST /api/scouts/:wallet/subscribe endpoint, resolving the P0 gap where scouts had no way to purchase a subscription through the backend.

Changes

src/services/stellar.ts

  • Added SubscriptionTier type ('basic' | 'premium')
  • Added SubscriptionResult interface (transactionId, tier, expiresAt, status)
  • Added purchaseSubscription(wallet, tier, duration) stub that wraps the Soroban subscribe(scout, tier, duration) contract call; throws PaymentError with code INSUFFICIENT_FUNDS (maps to contract error code 7) on insufficient XLM balance

src/controllers/scoutController.ts

  • Added subscribeSchema (zod): validates tier as 'basic' | 'premium' enum and duration as integer 1–365
  • Added subscribe() handler: returns 201 with transaction data on success, 400 on validation failure, 402 on INSUFFICIENT_FUNDS PaymentError

src/routes/scout.ts

  • Added POST /:wallet/subscribe route guarded by requireRole('scout')
  • Returns 401 if unauthenticated, 403 if role is not scout

tests/routes/scout.test.ts

  • Extended stellar mock to include purchaseSubscription and isSubscribed
  • Added 7 integration tests covering all documented error cases:
    • 201 — success with correct response shape
    • 400 — invalid tier ('gold')
    • 400 — missing duration
    • 400duration out of range (400)
    • 401 — unauthenticated request
    • 402INSUFFICIENT_FUNDS from stellar stub
    • 403 — wrong role (player instead of scout)

Response Shape

{
  "success": true,
  "data": {
    "transactionId": "stub-sub-txid-...",
    "tier": "basic",
    "expiresAt": 1234567890,
    "status": "active"
  }
}

What Was Tested

  • All 20 scout route tests pass (npm test -- --testPathPattern=tests/routes/scout)
  • Pre-existing failures in api.test.ts (admin events/fees/validator) are unrelated to this change

Notes

purchaseSubscription is a stub pending Soroban RPC integration (marked with TODO comments). 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/subscribe route

Closes #221

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
@Petah1

Petah1 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

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.
The main concern is that the core purchaseSubscription logic is still a stub. Even though the interface and error mapping are well designed, exposing a real endpoint that depends on unimplemented Soroban integration introduces a risk of false production readiness. This should ideally be feature-flagged or clearly isolated so it cannot be accidentally relied on before the contract integration is complete.
Another point to watch is consistency in error semantics. Using 402 for insufficient funds is reasonable, but it should align with how other payment-related errors are represented across the system to avoid fragmentation in client-side handling.
Overall, this is a solid implementation with good API discipline and strong testing

@Petah1

Petah1 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Fix Ci

@Petah1 Petah1 merged commit de7ef74 into scout-off:main Jun 23, 2026
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.

Add POST /api/scouts/:wallet/subscribe route

2 participants