AgentSkillsCN

Validatestrategy Payment Flow

Validatestrategy 支付流程

SKILL.md

ValidateStrategy Payment Flow Skill

Domain: Payment Processing, Webhooks, Analysis Triggering Project: ValidateStrategyLive


Overview

This skill contains project-specific knowledge about the ValidateStrategyLive payment → analysis pipeline.


Payment Flow Architecture

code
┌─────────────────────────────────────────────────────────────┐
│  PAYMENT FLOW                                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. User → Session creation (problemStatement + tier)       │
│           ↓                                                 │
│  2. User → Email megadás + Payment provider redirect        │
│           ↓                                                 │
│  3. Payment provider → Webhook to /api/webhooks/{provider}  │
│           ↓                                                 │
│  4. Webhook handler:                                        │
│      a. Verify signature (HMAC/Stripe signature)            │
│      b. Idempotency check (tryMarkWebhookProcessed)         │
│      c. Update purchase status → "completed"                │
│      d. Send payment confirmation email (IMMEDIATELY)       │
│      e. Call startAnalysisAfterPayment(sessionId)           │
│           ↓                                                 │
│  5. Analysis runs in background                             │
│           ↓                                                 │
│  6. Completion → Send analysis ready email with magic link  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Key Files

PurposeFile
Payment routerserver/routers/paymentRouter.ts
Webhook handlersserver/webhooks.ts
NOWPayments serviceserver/services/nowPaymentsService.ts
Stripe serviceserver/services/stripeService.ts
Analysis orchestratorserver/services/analysisOrchestrator.ts
Email serviceserver/services/emailService.ts

Critical Patterns

1. Webhook Idempotency (REQUIRED)

typescript
// ALWAYS use atomic idempotency check before processing
const shouldProcess = await tryMarkWebhookProcessed(
  webhookId,      // Unique webhook event ID
  "nowpayments",  // Provider name
  sessionId,      // Session being processed
  paymentId,      // Provider's payment ID
  "completed"     // New status
);

if (!shouldProcess) {
  return res.json({ received: true, duplicate: true });
}

2. Webhook Signature Verification (REQUIRED)

typescript
// NOWPayments - HMAC-SHA512
const expectedSignature = crypto
  .createHmac('sha512', process.env.NOWPAYMENTS_IPN_SECRET)
  .update(JSON.stringify(sortedPayload))
  .digest('hex');

// Stripe - Use SDK
const event = stripe.webhooks.constructEvent(
  req.body,
  req.headers['stripe-signature'],
  process.env.STRIPE_WEBHOOK_SECRET
);

3. Analysis Trigger (AFTER payment confirmed)

typescript
// server/webhooks.ts - startAnalysisAfterPayment helper
export async function startAnalysisAfterPayment(sessionId: string) {
  const session = await getAnalysisSessionById(sessionId);
  if (!session) return;

  // Update status to processing
  await updateAnalysisSessionStatus(sessionId, "processing");

  // Fire-and-forget background job
  const { startAnalysisInBackground } = await import("./services/analysisOrchestrator");
  startAnalysisInBackground(
    sessionId,
    session.problemStatement,
    session.tier,
    session.email
  );
}

Gotchas & Learnings

1. Raw Body for Stripe Webhooks

Stripe signature verification needs raw body, not parsed JSON:

typescript
// MUST be BEFORE express.json() middleware
app.use("/api/webhooks/stripe", express.raw({ type: 'application/json' }));

2. Email Before Analysis

Send payment confirmation email IMMEDIATELY after webhook, BEFORE starting analysis:

typescript
// Order matters!
await sendPaymentConfirmationEmail(session);  // 1. Email first
await startAnalysisAfterPayment(sessionId);   // 2. Then analysis

3. Fire-and-Forget Monitoring

Background jobs can fail silently. Always:

  • Log the start of analysis
  • Use circuit breaker for API calls
  • Add to retry queue on failure
  • Admin panel shows failed jobs

Database Schema

sql
-- purchases table
stripePaymentIntentId VARCHAR(255)
coinbaseChargeId VARCHAR(255)
paypalOrderId VARCHAR(255)
nowPaymentsInvoiceId VARCHAR(255)

-- paymentStatus enum
'pending' | 'completed' | 'failed' | 'refunded'

-- processedWebhooks table (idempotency)
webhookId VARCHAR(255) UNIQUE
provider VARCHAR(50)
sessionId VARCHAR(255)
processedAt TIMESTAMP

Testing Webhooks Locally

bash
# NOWPayments - use their sandbox
# Stripe - use CLI
stripe listen --forward-to localhost:3000/api/webhooks/stripe

# Trigger test event
stripe trigger payment_intent.succeeded

Security Checklist

  • Webhook signature verified before any processing
  • Idempotency key checked (tryMarkWebhookProcessed)
  • Payment amount validated against tier price
  • Session exists before updating
  • Email validated before sending
  • Rate limiting on payment endpoints