TODOs and Gaps

Known limitations, incomplete features, and future work

Overview

This document tracks known gaps, incomplete features, and areas requiring future work in the payment system. These items are documented for transparency and to guide future development.

Client Side - MISSING

High Priority Gaps

1. HOST_PARTNER Share Tracking

Status: Not Implemented

Location: packages/srv-stripe-payment/src/completePayment.ts

Issue: Payments with hostPartnerSlug do NOT create HOST_PARTNER tracking records. Host partners won't receive their 10% of platform fee.

Code Reference:

// TODO: Calculate host partner share (10% of platform fee)
// For now, skip if not implemented

Impact: Medium. Host partners won't accumulate earnings. The schema, enums, and payout infrastructure all support it — only the share calculation logic is missing.

Severity: Medium

Future Work:

  • Implement host partner share calculation in createShareTrackingBatch()
  • Look up host partner account by hostPartnerSlug
  • Create HOST_PARTNER tracking record with 10% of platform fee
  • Ensure host partner has payout route configured

2. AMBASSADOR Share Tracking

Status: Not Implemented

Location: packages/srv-stripe-payment/src/completePayment.ts

Issue: Ambassador shares are not created. Ambassadors won't receive their referral share.

Code Reference:

// TODO: Look up ambassador relationships and create tracking records
// For now, skip if not implemented

Impact: Medium. Ambassadors won't accumulate earnings.

Severity: Medium

Additional Complexity: The user table is now decoupled to the auth project, so ambassador data needs to be stored in a separate table with one-to-one ambassador links.

Future Work:

  • Create account_ambassadors table for ambassador relationships
  • Implement ambassador share calculation in createShareTrackingBatch()
  • Look up ambassadors for the seller account
  • Create AMBASSADOR tracking records with appropriate share

3. External Refund Webhook Handler

Status: Not Implemented

Location: packages/srv-stripe-payment/src/webhook.ts

Issue: Refunds initiated from the Stripe Dashboard won't be reflected in the DB. Only refunds via the admin API endpoint work.

Code Reference:

case "charge.refunded": {
  // TODO: implement external refund handling (refunds initiated from Stripe Dashboard)
  await log.info("charge.refunded received (not yet implemented)", {
    chargeId: (event.data.object as Stripe.Charge).id,
  });
  break;
}

Impact: Medium. Admin-initiated refunds work, but if someone refunds via Stripe Dashboard, the payment records will become inconsistent with Stripe.

Severity: Medium

Future Work:

  • Implement charge.refunded webhook handler
  • Look up payment by stripeChargeId
  • Call processRefund() with the payment ID
  • Ensure idempotency (webhook may fire multiple times)

Medium Priority Gaps

4. Missing FOR UPDATE Lock in Refund Flow

Status: Known Limitation

Location: packages/srv-stripe-payment/src/refund.ts

Issue: A narrow race condition exists where two concurrent refund requests could both read the payment as SUCCEEDED before either commits.

Code Reference:

// NOTE: We should use FOR UPDATE lock here, but getStripePaymentById doesn't support it
// For now, we'll rely on status check — enhancement needed

Impact: Low. The idempotency key on the Stripe refund prevents double-refunding at the Stripe level, and the DB status update inside the transaction provides a secondary guard.

Severity: Low

Future Work:

  • Add FOR UPDATE lock support to getStripePaymentById() access function
  • Use FOR UPDATE lock in refund flow to prevent concurrent refunds

5. Missing FOR UPDATE Lock in Advance Offset

Status: Known Limitation

Location: packages/srv-stripe-payment/src/completePayment.ts

Issue: Two concurrent payment completions for the same payee could double-offset against the same advance balance.

Code Reference:

// NOTE: Should use FOR UPDATE lock, but access function doesn't support it yet
// This is a known limitation — race condition C4 may occur

Impact: Low. This is a rare edge case requiring two payments for the same talent completing simultaneously while an advance is active.

Severity: Low

Future Work:

  • Add FOR UPDATE lock support to getPayoutsWithAdvanceBalance() access function
  • Use FOR UPDATE lock when reading advance payouts in payment completion flow

6. Missing Email Notifications in Payout Daemon

Status: Not Implemented

Location: packages/srv-stripe-payment/src/payoutDaemon.ts

Issue: Talent with failed payouts won't receive notification emails about outstanding payouts. The emailOutstandingPayout flag exists but is never updated.

Impact: Low. This is a nice-to-have notification feature, not a core flow.

Severity: Low

Future Work:

  • Implement email sending when payout fails
  • Call updateEmailOutstandingPayout(accountId, true) after sending email
  • Reset flag to false when payout later succeeds
  • Use existing email service infrastructure

Low Priority Gaps

7. Constants Not in Config

Status: Technical Debt

Location: packages/srv-stripe-payment/src/getProductByPayForId.ts and packages/util/src/calculateStripeFees.ts

Issue: Stripe fee percentages and platform fees are hardcoded. Changing them requires code changes and redeployment.

Code Reference:

// In getProductByPayForId.ts
const PLATFORM_FEE_STANDARD_CENT = 500; // $5.00 fixed
// In @zooly/util calculateStripeFees
const STRIPE_FEE_FIXED_CENT = 30;
const STRIPE_FEE_PERCENTAGE_BPS = 290;

Impact: Low. This is a maintenance concern, not a correctness issue.

Severity: Low

Future Work:

  • Move constants to environment variables or configuration file
  • Support per-product fee configuration
  • Add admin UI for fee configuration (future)

8. Subscription/Product Sync Webhook Handlers

Status: Deferred

Location: packages/srv-stripe-payment/src/webhook.ts

Issue: Several webhook event types are logged but not implemented:

  • invoice.payment_succeeded (subscription tracking)
  • product.created / product.updated (product sync)
  • price.created / price.updated (price sync)

Impact: None for current scope — these are P2 features marked as deferred in the plan.

Severity: None for current scope

Future Work:

  • Implement product/price sync when subscription feature is prioritized
  • Create stripe_products and stripe_prices tables (schema exists but unused)
  • Sync product catalog from Stripe webhooks

Design Decisions Requiring Review

9. Advance Payout Support

Status: Under Review

Issue: It's not clear if advance payouts should still be supported. The feature is implemented but may not be needed.

Impact: If removed, simplifies the codebase. If kept, requires concurrency protection improvements.

Future Work:

  • Decision needed: Keep or remove advance payout feature
  • If kept: Implement FOR UPDATE locks for advance offset
  • If removed: Remove advance payout code and related fields

10. Concurrency Protection

Status: Known Limitations

Issue: Concurrency protections are explicitly missing in critical money flows. Code comments acknowledge missing FOR UPDATE protection for advance-offset and refund lock paths.

Rationale: Concurrency can only happen if a user makes 2 purchases at the exact same time, which is extremely unlikely.

Future Work:

  • Evaluate if concurrency protection is needed based on usage patterns
  • If needed: Implement FOR UPDATE locks in all critical paths
  • Add integration tests for concurrent payment scenarios

Summary

GapPrioritySeverityStatus
HOST_PARTNER Share TrackingHighMediumNot Implemented
AMBASSADOR Share TrackingHighMediumNot Implemented
External Refund WebhookHighMediumNot Implemented
FOR UPDATE Lock (Refund)MediumLowKnown Limitation
FOR UPDATE Lock (Advance)MediumLowKnown Limitation
Email NotificationsMediumLowNot Implemented
Constants in ConfigLowLowTechnical Debt
Subscription SyncLowNoneDeferred

Next Steps

  1. Immediate: Implement HOST_PARTNER and AMBASSADOR share tracking
  2. Short-term: Implement external refund webhook handler
  3. Medium-term: Add FOR UPDATE locks where needed
  4. Long-term: Move constants to configuration, implement subscription sync