Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Revenue Rocket

AI Commerce & Procurement Platform for every service vertical, built to the OKX "Revenue Rocket" brief. A customer (human or AI agent) describes what they need in one sentence, the platform searches vetted providers, verifies availability, quotes a price with a 10 % platform fee, and issues a real hosted checkout. Payment webhooks flip the booking to AWAITING_PROVIDER_CONFIRMATION; the provider accepts and the money settles. The whole loop is drivable by an AI agent through three REST tools exposed under /api/agent/*, or by a human via the in-app Vercel-AI-SDK copilot.

The winning story: an AI agent executes real commerce end-to-end and the platform captures a 10 % take.

The same engine books photographers, caterers, consultants, agencies, venues, tradespeople, event vendors, and creative or performing talent — every category is a first-class provider vertical. See spec/10_generic_refactor.md for the generic-terminology reference.


Platform (multi-tenant)

Revenue Rocket is a generic AI-native commerce & procurement platform. Providers (photographers, chefs, consultants, agencies, venues, vendors, creative talent, …) onboard into workspaces owned by an organization; each workspace gets its own catalog, branding, coupons, integrations, API keys, and AI agent. The full product vision lives in spec/07_platform_prd.md; this section is the implementation quick-start. The generic booking flow above is unchanged — the platform layer is purely additive.

Concepts

  • Organization — the tenant root (a brand, agency, marketplace, or enterprise). Owns one or more workspaces and carries branding.
  • Workspace — the tenant boundary. Owns its providers, services, categories, requests/bookings, coupons, API keys, integrations, and a branded AI agent.
  • Membership — user↔workspace RBAC: OWNER · ADMIN · FINANCE · MANAGER · MEMBER · PROVIDER · GUEST.
  • API keys — per-workspace credentials (LIVE | TEST | SANDBOX) minted from the org dashboard; verified by prefix lookup + constant-time hash.
  • Coupons — workspace-scoped PERCENT/FLAT discounts, applied to gross before the platform fee.
  • Integrations — Stripe · Razorpay · Dodo · OKX · Slack · Discord · Google Calendar · Zapier · HubSpot · Salesforce · Webhooks — enabled per-workspace.
  • Per-org AI agent — same booking engine, per-workspace prompt and branding, so every tenant gets its own "book any service" copilot.

Endpoints — /api/org/*

Every route accepts either an authenticated session or a workspace API key via the x-workspace-key: rr_live_… (or rr_test_…) header. Machine callers (external agents, integrations, OKX.AI) use the header.

Path Purpose
/api/org/workspaces List / create workspaces for the org
/api/org/members Invite, list, and role-update memberships
/api/org/providers Workspace-scoped provider CRUD
/api/org/services Bookable service offerings per provider
/api/org/categories Category taxonomy (Photography, Catering, …)
/api/org/requests Requests → bookings for procurement flows
/api/org/coupons Mint / list / redeem coupons
/api/org/api-keys Mint (returns plaintext once), list, revoke
/api/org/integrations Enable Stripe / OKX / Slack / … per workspace
/api/org/agent Per-workspace branded copilot endpoint

Domain code lives under lib/platform/* (workspace context, API-key verification, RBAC, coupons, categories, integrations); it wraps the same lib/booking + lib/payments engines every provider vertical uses.

Seed the demo org

The main seed populates a mixed roster of providers and demo bookers; layer the platform seed on top to create categories, link providers to their categories, and mint a demo organization (boAt, workspace boat) with an OWNER member, one TEST + one LIVE API key, a WELCOME20 coupon, and Stripe + OKX integrations. Idempotent — safe to re-run.

npm run db:seed
npx dotenv -e .env.local -- npx tsx prisma/seed-platform.ts

Log in as boat-owner@demo.com, jump into /org, and drive the multi-tenant story: create a coupon, mint an API key, hit /api/org/providers from curl, watch the same 10 % take-rate settle inside that workspace.

For the full PRD (positioning, entity naming, dashboards, migration recommendation), read spec/07_platform_prd.md.


Architecture

Layer Technology
App framework Next.js 16 (App Router, Server Components, async request APIs)
Language / typing TypeScript 5 (strict) + Zod v4 validators
Data Prisma 6 + Postgres 16
Search Meilisearch v1.10 (fuzzy match on providers, filtered by city / budget)
Auth Auth.js v5 (next-auth@5.0.0-beta) with Google OAuth
Payments (pluggable) Stripe · Razorpay · Dodo Payments — swap via PAYMENT_PROVIDER
AI agent surface Vercel AI SDK v6 (streamText + tools) — same tools exposed as REST
Styling Tailwind CSS v4 (@theme inline tokens) + shadcn/ui + tw-animate-css
Testing Vitest 3 (unit + API), @playwright/test (E2E smoke)

Single Next.js app — no monorepo. Domain code lives under lib/ and is shared between the OKX agent endpoints and the in-app copilot so validation, availability, fee math, and DB writes are guaranteed to behave identically.

Directory tour

app/
  (marketing)/       Landing pages
  (auth)/            Split-screen /login, /signup, /forgot-password, /reset-password,
                     /verify-email, /join, /dev-login (legacy /sign-in,/sign-up redirect)
  (provider)/dashboard Provider dashboard (profile, availability, bookings, earnings)
  (booker)/          Discover + provider detail
    discover/        Copilot + search results
    providers/[id]/  Canonical provider detail page
  (org)/org/         Organization dashboard (workspace-scoped)
  (portal)/p/        Branded per-workspace public booking page
  bookings/[id]/     Booking detail (post-checkout)
  checkout/[id]/     Fallback in-app checkout (dev without provider keys)
  api/
    agent/           OKX agent tool endpoints (secured by x-okx-agent-key)
    org/             Workspace-scoped platform APIs (session OR x-workspace-key)
    webhooks/[p]/    Multi-provider payment webhook (stripe|razorpay|dodo)
    chat/            In-app copilot streaming endpoint
    providers/       ProviderProfile CRUD (session-auth)
    availability/ bookings/ analytics/  CRUD + revenue dashboards
lib/
  booking/           Shared engine — discover, checkAvailability, initiate
  payments/          Provider adapter interface + fees.ts + registry
  meilisearch/       Index + search helpers
  validators/        Zod schemas (single source of truth for wire contracts)
  analytics/         Revenue event ledger
  auth/              Auth.js v5 config + prisma adapter
  platform/          Workspace context, API keys, RBAC, coupons, integrations
prisma/
  schema.prisma      Booking lifecycle, fees, webhook ledger, analytics.
                     First-class names throughout: `ProviderProfile`,
                     `Role.PROVIDER`, `BookingStatus.AWAITING_PROVIDER_CONFIRMATION`.
                     DB tables, columns, and enum values were physically
                     renamed in migration `20260705173629_provider_full_rename`
                     (RENAME + UPDATE only — data preserved).
  seed.ts            14+ providers across several verticals, availability, 2 demo bookers
spec/                Product + engineering specs (source of truth)
tests/
  unit/              Fee math, state machine, validators
  api/               Agent contract tests + webhook idempotency + race
  e2e/               Playwright smoke pack

Setup

Prerequisites: Node 20+, Docker (for Postgres + Meilisearch), and a POSIX shell.

# 1) Install deps (Next 16 / React 19 peers require the flag).
npm install --legacy-peer-deps

# 2) Start Postgres + Meilisearch.
docker compose up -d
#    ...or point DATABASE_URL / MEILISEARCH_HOST at your own instances.

# 3) Copy env and fill secrets.
cp .env.example .env.local
#    Minimum for a local demo:
#      DATABASE_URL, AUTH_SECRET, PAYMENT_PROVIDER=stripe,
#      MEILISEARCH_HOST, MEILISEARCH_API_KEY, OKX_AGENT_API_KEY

# 4) Migrate the DB and seed demo data.
npx dotenv -e .env.local -- npx prisma migrate dev
npm run db:seed

# 5) Sync the provider search index.
npm run search:sync

# 6) Boot the app.
npm run dev
#    → http://localhost:3000

Environment variables

Variable Purpose
DATABASE_URL Postgres connection string
AUTH_SECRET Auth.js JWT secret (openssl rand -base64 32)
NEXTAUTH_URL App base URL (http://localhost:3000 in dev)
AUTH_GOOGLE_ID / _SECRET Google OAuth client (optional in dev)
NEXT_PUBLIC_APP_URL Public origin used in checkout success/cancel URLs
PAYMENT_PROVIDER stripe | razorpay | dodo
PLATFORM_FEE_BPS Fee in basis points (default 1000 = 10 %)
DEFAULT_CURRENCY usd | inr
STRIPE_SECRET_KEY etc. Stripe / Razorpay / Dodo credentials
MEILISEARCH_HOST / _API_KEY Meilisearch instance
MEILISEARCH_INDEX_PROVIDERS Provider search index name (defaults to providers)
AI_PROVIDER openai or anthropic (in-app copilot only)
OPENAI_API_KEY / ANTHROPIC_ LLM keys for the copilot
OKX_AGENT_API_KEY Shared secret required on every /api/agent/* call
OKX_AI_API_KEY, _BASE_URL (optional) OKX-hosted model endpoint

.env.example in the repo lists every variable with its canonical name.


Roles & sign-in

The platform Role enum has three values (BOOKER, PROVIDER, ADMIN) stored under those exact names in the DB:

  • BOOKER — customer discovering + booking services (/discover).
  • PROVIDER — manages profile, availability, bookings, earnings (/dashboard).
  • ADMIN — platform-level admin (fees / moderation, schema-only MVP).

Organizations are represented via workspace membership (WorkspaceRole: OWNER · ADMIN · FINANCE · MANAGER · MEMBER · PROVIDER · GUEST) on the platform-tenant layer, not a top-level Role value.

Sign-in / sign-up — the split-screen /login page is a single linear form for existing users; /signup carries the intent picker for new accounts and routes each intent to the matching dashboard:

Intent (on /signup) Role provisioned Lands on
Buy / book Role.BOOKER /discover
Offer services Role.PROVIDER /dashboard
Set up an organization Org + Workspace + OWNER /org
Join a team (via /join) Role.BOOKER + Membership /org

Legacy /sign-in and /sign-up URLs redirect to /login and /signup respectively. See spec/10_generic_refactor.md for the full role / route mapping.


Accounts & authentication

Revenue Rocket runs Auth.js v5 with three sign-in surfaces layered on top of each other — a full email/password Credentials provider (id: "password"), Google OAuth, and a dev-only passwordless shortcut for local demos. The complete plan lives in spec/13_authentication.md; this section is the operator quick-start.

Auth routes

Every user-facing auth surface is a clean split-screen page under app/(auth)/ — brand on the left, form on the right. Legacy /sign-in and /sign-up URLs redirect to /login and /signup.

Page Purpose
/login Linear log-in form (email + password, Google, "forgot?" link).
/signup Intent-picker sign-up (buy / offer / setup / join).
/forgot-password Request a password-reset email.
/reset-password Consume a reset token and set a new password.
/verify-email Consume an email-verification token; offers resend on expiry.
/join Accept a workspace invite by code (signup or login inline).
/dev-login Passwordless shortcut for seeded users; disabled in production.

Email + password APIs

Password rows sit in User.passwordHash (bcryptjs cost 12) alongside the existing OAuth Account rows, so a single user can hold both a Google identity and a password. All flows below run in the Node runtime, validate with Zod (lib/validators/auth.ts), and are non-enumerating: register / forgot return generic success regardless of whether the email is on file.

Route Body Behaviour
POST /api/auth/register { email, password, name, intent, organizationName? } Creates the user (+ Organization/Workspace/OWNER Membership when intent="organization"), issues an EmailVerificationToken. Returns 201 { ok, needsVerification, devVerifyUrl? }.
POST /api/auth/verify-email { token } Consumes an unexpired verification token, stamps User.emailVerified = now(), deletes sibling tokens.
POST /api/auth/resend-verification { email } Idempotent — mints a fresh verification link for an unverified user. Generic 200.
POST /api/auth/forgot-password { email } Issues a PasswordResetToken (1h TTL). Generic 200; returns devResetUrl in non-production.
POST /api/auth/reset-password { token, password } Rotates User.passwordHash, marks the token usedAt, wipes sibling reset tokens, verifies email if it was still unverified.

The four intent flows

POST /api/auth/register accepts an intent selector that fans out into the sign-up path spec/13 §Flows describes:

  • buyer (default) — plain Role.BOOKER user; lands on /discover after verification.
  • business — Role.PROVIDER user; lands on /dashboard to complete the provider profile.
  • organization — user + Organization + Workspace + OWNER Membership created in a single transaction; lands on /org. organizationName is required in this branch.
  • member — plain user record; Membership is attached separately when the user opens /join?code=… and accepts the invite.

Login uses Auth.js directly (signIn("password", { email, password })) — there is no custom login endpoint. The provider enforces the verified-email gate by throwing "email_not_verified" so the UI can offer a resend link.

Google OAuth + dev login (still work)

Google OAuth stays wired up whenever AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET are set — pick "Continue with Google" on /login. Registering with the same email as an existing OAuth-only user links credentials onto that row rather than creating a duplicate.

For quick local demos without any OAuth keys, open /dev-login and sign in as any seeded user. Enabled unless ENABLE_DEV_LOGIN=false or NODE_ENV === "production" — see Dev login.

Email delivery (dev fallback)

No SMTP / Resend provider is wired up yet. Until one is:

  • Verification and password-reset URLs are console.loged from the route handler (search for [auth] / [api/auth/…] in the dev server output).
  • In non-production the same URLs come back inside the JSON response as devVerifyUrl / devResetUrl, so /signup and /reset-password (and the Vitest suite in tests/api/auth-flow.test.ts) can complete the flow without a mailbox.

Wire a real provider before shipping — the TODO markers in app/api/auth/{register,forgot-password,resend-verification}/route.ts mark the hand-off point.


OKX Agent API contract

Three tools, all under /api/agent/*. Every request MUST carry x-okx-agent-key: $OKX_AGENT_API_KEY or the server returns 401.

The exact wire contract is documented in spec/04_okx_agent_tools.md; this section is the quick-start.

Naming note. The OKX-facing tool names (search_providers, check_availability, initiate_booking) and their snake_case request fields (provider_id, booker_email, …) are the wire contract; they read from ProviderProfile / User.role = PROVIDER under the hood (see spec/10_generic_refactor.md).

1. search_providers — POST /api/agent/search

Fuzzy match against the provider index, filtered by city, budget, and availability on a target date.

curl -s http://localhost:3000/api/agent/search \
  -H "Content-Type: application/json" \
  -H "x-okx-agent-key: $OKX_AGENT_API_KEY" \
  -d '{
    "query": "jazz saxophonist",
    "location": "Bengaluru",
    "max_budget": 1500000,
    "target_date": "2026-07-20"
  }'

Returns at most three top-ranked results in an LLM-friendly shape:

{
  "results": [
    {
      "provider_id": "clx...",
      "name": "Aarav Rao",
      "specialty": "Jazz Saxophonist",
      "city": "Bengaluru",
      "base_rate": 1200000,
      "currency": "inr",
      "rating": 4.8,
      "available": true,
      "quick_action": "initiate_booking with provider_id"
    }
  ],
  "count": 1
}

2. check_availability — POST /api/agent/availability

curl -s http://localhost:3000/api/agent/availability \
  -H "Content-Type: application/json" \
  -H "x-okx-agent-key: $OKX_AGENT_API_KEY" \
  -d '{ "provider_id": "clx...", "target_date": "2026-07-20" }'

3. initiate_booking — POST /api/agent/book

Creates a PENDING_PAYMENT booking and a hosted checkout link. The transactional re-check inside lib/booking/engine.ts is the double-booking lock; concurrent calls on the same (provider, date) produce exactly one success.

curl -s http://localhost:3000/api/agent/book \
  -H "Content-Type: application/json" \
  -H "x-okx-agent-key: $OKX_AGENT_API_KEY" \
  -d '{
    "provider_id": "clx...",
    "event_date": "2026-07-20",
    "event_location": "Bengaluru",
    "offer_amount": 1400000,
    "booker_email": "demo@example.com",
    "event_type": "Wedding",
    "duration_mins": 120
  }'

Response:

{
  "booking_id": "clx...",
  "checkout_url": "https://checkout.stripe.com/...",
  "amount": 1400000,
  "platform_fee": 140000,
  "currency": "inr",
  "status": "PENDING_PAYMENT"
}

Error responses are stable and machine-readable:

Status Body When
400 { "error": "invalid_input", "issues" } Zod validation failure
401 { "error": "unauthorized" } Missing / wrong x-okx-agent-key
404 { "error": "provider_not_found" } Unknown provider_id
409 { "error": "date_unavailable" } Date blocked, booked, or race lost
422 { "error": "below_minimum", "minimum" } offer_amount < provider.baseRate

Demo script (~2 min)

  1. npm run dev (or docker compose up -d && npm run dev).
  2. Open http://localhost:3000 — pitch the landing (Revenue Story section spells out the 10 % take).
  3. Hit /discover, drop the canonical prompt into the copilot:

    "Jazz saxophonist in Bengaluru under ₹15,000 for 20 July 2026" The copilot calls search_providers, presents three matches, then initiate_booking with the top provider.

  4. Follow the checkout link. In dev without Stripe keys the app falls back to the in-app /checkout/[id] page which lets you simulate payment — this posts a fake checkout.session.completed back into the webhook.
  5. Booking flips to AWAITING_PROVIDER_CONFIRMATION. Sign in as the provider, accept from /dashboard/bookings, watch the earnings tile move.
  6. Open /dashboard/earnings (or /api/analytics/revenue) — the 10 % platform fee is captured against the platform_fee_captured analytics event.

The same three tools are hittable from an external OKX agent by pointing it at the curl examples above — the copilot flow and the agent flow share one lib/booking/engine.ts.


Switching payment providers

PAYMENT_PROVIDER selects the default provider used by getPaymentProvider(); adapters live in lib/payments/providers/*.ts and all implement a common interface (createCheckout, verifyAndParse, refund — see lib/payments/types.ts).

Provider Enable by setting
Stripe PAYMENT_PROVIDER=stripe + STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
Razorpay PAYMENT_PROVIDER=razorpay + RAZORPAY_KEY_ID, _SECRET, _WEBHOOK_SECRET
Dodo PAYMENT_PROVIDER=dodo + DODO_API_KEY, DODO_WEBHOOK_SECRET

The webhook handler at app/api/webhooks/[provider]/route.ts dispatches by URL segment, so all three can be enabled simultaneously — point each provider's webhook at /api/webhooks/stripe, /api/webhooks/razorpay, /api/webhooks/dodo respectively.

Idempotency: the WebhookEvent ledger (unique on eventId) short- circuits replays before they touch the state machine or the PaymentTransaction table.


Testing

# Unit + API contract + DB-guarded (Vitest 3).
npx dotenv -e .env.local -- npm test

# E2E smoke (Playwright — boots `next dev` if nothing is on :3000).
npx dotenv -e .env.local -- npm run test:e2e

What's covered:

  • tests/unit/fees.test.ts — 10 % split, rounding, edge cases.
  • tests/unit/state-machine.test.ts — every legal + illegal transition.
  • tests/unit/validators.test.ts — Zod schemas for the agent tools.
  • tests/api/agent-search.test.ts — auth, validation, happy path (mocked engine).
  • tests/api/agent-book.test.ts — 401 / 400 / 404 / 409 / 422 / 200.
  • tests/api/webhook-idempotency.test.ts — replays don't double-write PaymentTransaction (DB-backed; skipped when Postgres is unreachable).
  • tests/api/double-booking.test.ts — concurrent initiate_booking on the same (provider, date) produces exactly one winner (DB-backed).
  • tests/e2e/smoke.spec.ts — landing renders, /discover renders, /dashboard redirects to /login when signed out.

Further reading

The spec/ directory holds the deterministic source of truth used to coordinate parallel agent work — read the files in numeric order:

  • 00_STACK.md — every pinned dependency and its version-specific rules.
  • 01_product_requirements.md — roles, flows, lifecycle, pricing.
  • 02_system_architecture.md — layers, data flow, tenancy model.
  • 03_database_schema.md — Prisma schema (ProviderProfile, Role.PROVIDER, …).
  • 04_okx_agent_tools.md — the authoritative agent wire contract.
  • 05_test_suite.md — the coverage matrix this test suite fulfils.
  • 06_design_and_ux.md — design tokens, layout, and screen-by-screen UX.
  • 07_platform_prd.md — multi-tenant platform vision + terminology mapping.
  • 08_enterprise_platform.md — full enterprise PRD (modules, MVP scope, roadmap).
  • 09_procure_to_pay_prd.md — procure-to-pay module PRD.
  • 10_generic_refactor.md — generic-terminology rename map (authoritative).
  • 11_positioning_and_copy.md — AI Commerce & Procurement positioning + copy.
  • 13_authentication.md — email/password + Google + dev-login auth surface.

Enterprise platform (multi-tenant)

Beyond the generic provider marketplace, Revenue Rocket ships an AI-Native Commerce & Service Orchestration Platform layer. It is fully additive — the marketplace workflow above is unchanged.

  • Workspaces / Organizations — every business gets a tenant workspace with RBAC (OWNER, ADMIN, FINANCE, MANAGER, MEMBER, PROVIDER, GUEST).
  • Organization dashboard /org/[workspaceId] — Overview, Providers, Services, Requests, Members, Teams, Procurement (approvals), Campaigns, Affiliates & Referrals, Coupons, Invoices, API Keys, Integrations, AI Agent config, Branding, Audit Log, Check-in, Settings.
  • Branded portals — public per-workspace booking page at /p/[slug] (demo: /p/boat), themed by PortalConfig.
  • QR operations — bookings issue a QRPass (/pass/[token]), staff check-in at /org/[workspaceId]/checkin, tracked as Attendance.
  • Growth — coupons/campaigns + affiliate/referral links (/r/[code] → attributed /discover).
  • Developer platform — per-workspace API keys (LIVE/TEST/SANDBOX), webhooks, x-workspace-key auth on /api/org/*.
  • Security — workspace isolation, RBAC guards, AuditLog, hashed + rotatable API keys.

Seed the demo org (boAt): npx dotenv -e .env.local -- npx tsx prisma/seed-platform.ts then ... prisma/seed-enterprise.ts.

Dev login (no OAuth keys needed)

For local demos, open /dev-login to sign in as any seeded user (provider → /dashboard, org owner → /org, booker → /discover) via a dev-only passwordless Credentials provider. Disabled in production; set ENABLE_DEV_LOGIN=false to force off. Configure Google OAuth for real auth.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages