Skip to main content

πŸš€ Shared WABA MVP Guide: Mid-May Deadline

This document is the strict, hyper-focused Sprint Guide to deliver the Shared WABA MVP by Mid-May. It incorporates the Phase 0 & Phase 1 goals from the master roadmap, strictly dropping "Dedicated WABA" features (like Meta Embedded Signup) to guarantee we hit the deadline.

In the Shared WABA Model, Kloyst owns the WhatsApp Business API (WABA). Clients preload a wallet, we send messages on their behalf using our WABA, and we deduct their wallet based on Meta Webhook delivery status.


πŸ—οΈ 1. File Structure & Design Patterns​

To ensure rapid development without incurring technical debt, stick to NestJS standard conventions:

Clean Architecture Pipeline​

  1. Controllers (*.controller.ts): ONLY parse incoming HTTP payloads and return responses. No database calls.
  2. Services (*.service.ts): The core engine. Execute all business logic and Prisma queries here. ALWAYS inject vendorId into where clauses.
  3. DTOs (*.dto.ts): Data Transfer Objects defining the exact JSON shape.

Code & Security Practices (Non-Negotiable)​

  • Strict Validation: Use class-validator and class-transformer on every single incoming DTO. If a client sends garbage data, reject it before it hits the Service.
  • Tenant Isolation: Do NOT rely on the frontend to pass vendorId. Extract it from the JWT via the @CurrentUser() decorator.
  • Webhook Integrity: Meta signs webhooks with a SHA256 signature (X-Hub-Signature-256). Always verify this signature in a Guard/Interceptor to prevent malicious wallet deductions.
  • Transaction Locking: Wallet deductions MUST use BEGIN; SELECT ... FOR UPDATE; UPDATE; COMMIT; to prevent race conditions when 1,000 webhooks hit in 2 seconds.

πŸ—ΊοΈ 2. The Mid-May Sequential Sprint Workflow​

Build the APIs exactly in this sequence. This order ensures no developer gets blocked waiting on database structures from another feature.

Sprint 1: Identity, Auth & Vendor Setup (Foundation)​

Goal: Secure onboarding. Since we will be emailing invoices and handling wallet recharges, email verification is strictly mandatory.

  • Auth & Registration APIs (OTP Flow):

    • POST /auth/register (Accepts Email/Password. Creates user in PENDING_VERIFICATION state).
    • POST /auth/send-otp (Triggers an email via SendGrid/AWS SES with a 6-digit OTP stored temporarily in Redis with a 5-minute TTL).
    • POST /auth/verify-otp (Validates OTP, marks email as verified, creates the Vendor root profile, and returns the JWT).
    • POST /auth/login (Standard login returning JWT with vendorId and role).
  • Authorization & Role Checks:

    • JwtAuthGuard: Protects all routes ensuring the user is logged in.
    • RolesGuard: Ensures only users with ADMIN role can access billing and wallet recharge APIs (preventing standard staff from making purchases).
  • Vendor Profile APIs:

    • GET /vendor/me (Fetch vendor profile, company details, tax info for billing).
    • PATCH /vendor/me (Update business/billing info).

Sprint 2: Audience & Contact Management​

Goal: Vendors can build an audience list to message.

  • Kloyst APIs:
    • POST /contacts/bulk (Accept CSV or Array, validate E.164 phone numbers)
    • GET /contacts (Fetch paginated contact list)
    • DELETE /contacts/:id
  • Code Practice: Strip all formatting (+, , -) from phone numbers before saving to PostgreSQL. Meta requires strict integer strings.

Sprint 3: Meta Templates (The First Meta API Integration)​

Goal: Vendors submit templates for approval. Kloyst forwards them to Meta.

  • Meta APIs Used: POST /v18.0/{KLOYST_WABA_ID}/message_templates
  • Kloyst APIs:
    • POST /templates -> Parses input, saves PENDING to DB, fires POST to Meta Cloud API.
    • GET /templates -> Fetch list of local templates.
  • Meta Webhook Setup:
    • POST /webhook/meta -> Listen for message_template_status_update. Update local DB when Meta approves/rejects.

Sprint 4: Pre-Paid Wallet (Monetization MVP)​

Goal: Vendors must have credits before sending messages.

  • Kloyst APIs:
    • GET /wallet/balance
    • POST /wallet/recharge/init (Creates Razorpay/Stripe Order ID)
  • Payment Webhook:
    • POST /webhook/payment (Listens for payment.captured. Verifies signature, securely ADDS to Postgres wallet balance).

Sprint 5: The Campaign Engine & Bulk Dispatch (The Core Engine)​

Goal: Dispatch 10,000 messages safely without hitting Meta API rate limits.

  • Meta APIs Used: POST /v18.0/{KLOYST_PHONE_NUMBER_ID}/messages
  • Kloyst APIs:
    • POST /campaigns/launch (Accepts Template ID & Contact List ID)
  • Internal Workflow (Crucial for Scaling):
    1. API checks if Wallet Balance > (Contacts * Margin Cost). If false, reject 402 Payment Required.
    2. Insert Campaign record.
    3. Chunk contacts into individual "Jobs" and push to Redis Queue (BullMQ).
    4. Return 200 OK to frontend immediately.
    5. Background Workers pop jobs from Redis at a strict rate limit (e.g., 50/sec), fire the Meta messages API, and insert a MessageLog into Postgres with the returned wamid.XYZ.

Sprint 6: Webhooks & Financial Deductions​

Goal: Process message deliveries and deduct the wallet.

  • Meta Webhook Handling: POST /webhook/meta
  • Workflow:
    1. Meta sends a statuses array (e.g., status: delivered, pricing.category: marketing).
    2. Match the wamid in PostgreSQL MessageLog and mark as DELIVERED.
    3. IF Meta indicates a charge occurred:
      • Open Postgres Row Lock on Wallet.
      • Calculate Meta Cost + Kloyst Margin.
      • Deduct balance.
      • Insert Ledger transaction history.
      • Release Lock.
    4. Respond to Meta with 200 OK within 3 seconds. (If math is too slow, push Webhook to a Redis queue and resolve it asynchronously).

🚦 Future Scaling Considerations (Post-May)​

  • Redis Overload: For campaigns >100k, passing full contact data into Redis will exhaust memory. Later, we will pass just campaignId and offset, letting the worker fetch contacts from Postgres natively.
  • Dead-Letter Webhooks: Webhooks that fail processing will need a separate DLQ (Dead Letter Queue) so we can replay them and not lose revenue data.