A growth/ folder in the monorepo where the growth org (16+ people across sales + AM) uses Cursor to build internal tools and automate workflows. One monolith Next.js app serves all tools, deployed to Vercel, distributed via whop.com/growth. AI skills guide non-engineers through everything.
Rollout: Pilot with 2-4 power users, then expand to the full team. Phase 1 target: next week.
graph TD
subgraph monorepo [Monorepo]
subgraph growthDir ["growth/"]
app["app/<br/>(single Next.js project)"]
tools["app/tools/<br/>(one route group per tool)"]
docs["docs/<br/>(reference material)"]
CLAUDE["CLAUDE.md"]
end
subgraph skills [".claude/skills/growth-*"]
pipedrive["growth-pipedrive"]
newTool["growth-new-tool"]
deploy["growth-deploy"]
dailySync["growth-daily-sync"]
createSkill["growth-create-skill"]
check["growth-check"]
end
end
app -->|"one Vercel project"| vercel["Vercel"]
vercel -->|"one deployment"| whopGrowth["whop.com/growth"]
whopGrowth -->|"many experiences"| sidebar["Sidebar:<br/>Sales Onboarding<br/>Churn Dashboard<br/>CRM Analytics<br/>..."]
check -->|"sentry + third eye"| monitoring["Monitoring"]
Each tool the growth team builds is a route group inside a single Next.js project. Multiple Whop app listings share the same base_url but use different view paths.
graph LR
subgraph vercelDeploy ["One Vercel Deployment"]
salesOnboarding["/tools/sales-onboarding/"]
churnDash["/tools/churn-dashboard/"]
crmAnalytics["/tools/crm-analytics/"]
end
subgraph whopListings ["Whop App Listings (separate)"]
listing1["Sales Onboarding App<br/>experience path: /tools/sales-onboarding/exp_id"]
listing2["Churn Dashboard App<br/>experience path: /tools/churn-dashboard/exp_id"]
listing3["CRM Analytics App<br/>experience path: /tools/crm-analytics/exp_id"]
end
listing1 --> salesOnboarding
listing2 --> churnDash
listing3 --> crmAnalytics
subgraph whopSidebar ["whop.com/growth sidebar"]
exp1["Sales Onboarding"]
exp2["Churn Dashboard"]
exp3["CRM Analytics"]
end
whopSidebar --> whopListings
Why monolith over separate apps:
growth/
├── CLAUDE.md # Entry point for AI — written for non-engineers
├── CONVENTIONS.md # Hard rules (stay in growth/, no jargon, etc.)
├── .cursor/rules/
│ ├── guardrails.mdc # Never touch files outside growth/
│ ├── app-development.mdc # Whop app patterns for growth/app/
│ ├── secret-scanning.mdc # Block secrets from entering code
│ └── git-workflow.mdc # AI handles all git ops for non-engineers
├── app/ # THE Next.js 16 project (single deployment)
│ ├── package.json # dev: doppler run -- whop-proxy -- next dev
│ ├── next.config.ts # Sentry, Tailwind
│ ├── instrumentation.ts # Sentry init
│ ├── vercel.json
│ ├── .env.example # Documents keys (no values)
│ ├── app/
│ │ ├── layout.tsx # WhopApp, Tailwind, Sentry error boundary
│ │ ├── page.tsx # Root redirect
│ │ ├── tools/
│ │ │ ├── sales-onboarding/
│ │ │ │ └── [experienceId]/page.tsx
│ │ │ ├── churn-dashboard/
│ │ │ │ └── [experienceId]/page.tsx
│ │ │ └── _template/ # Copy this folder to add a new tool
│ │ │ └── [experienceId]/page.tsx
│ │ └── dashboard/
│ │ └── [companyId]/page.tsx # Shared admin/manager view
│ ├── lib/
│ │ ├── whop-sdk.ts # SDK setup (reads from runtime env)
│ │ ├── schema.ts # Drizzle schema (all tools' tables, prefixed)
│ │ └── db.ts # PlanetScale connection via Drizzle
│ └── components/ # Shared UI components
├── docs/ # Reference material for AI context
│ ├── whop-product/ # Product knowledge (from quiz data)
│ ├── building-whop-apps/ # Auth, views, iframe, deployment
│ ├── integrations/ # ElevenLabs, Granola, Pipedrive, Slack, Claude
│ ├── reference-apps/ # Sales dashboard patterns
│ └── sales-playbook/ # Scoring rubric, roleplay personas
├── scripts/
│ └── setup.sh # Called by whop growth onboard
└── README.md
whop growth CLIwhop growth onboard # First-time: doppler login, verify access, welcome
whop growth dev # Start local dev (doppler run + whop-proxy + next dev)
whop growth deploy # Build + deploy to Vercel production
whop growth new-tool <name> # Scaffold a new tool route group under app/tools/
whop growth check # Sentry health check — any errors?
One app = no app name argument needed. whop growth dev just works.
growth dev: cd growth/app && doppler run --project growth --config app -- pnpm devgrowth deploy: cd growth/app && vercel deploy --prodgrowth new-tool <name>: copies app/tools/_template/ to app/tools/<name>/, creates Whop app listing via POST /apps API automaticallygrowth onboard: doppler login, verifies access to growth + growth-personal projects, creates ~/.growth-config.jsongrowth check: queries Sentry for recent errors, reports statusThe Growth Whop is the hub. Every tool shows up as an experience in the sidebar.
Each Cursor rule has a matching CI check. The rule prevents mistakes; CI enforces it. Belt AND suspenders.
| Rule | Prevents | CI check that enforces it |
|---|---|---|
| guardrails.mdc | Editing outside growth/ | Scope guard |
| secret-scanning.mdc | Secrets in code | gitleaks |
| app-development.mdc | Bad patterns, non-responsive UI | TypeScript + build + import boundary |
| git-workflow.mdc | Git mistakes | CODEOWNERS + auto-merge |
guardrails.mdc (alwaysApply, globs: growth/**) - NEVER modify files outside growth/. If the user asks for something that requires changes elsewhere, explain what's needed and say they should ask an engineer. - NEVER use technical jargon. Say "saved your changes" not "committed to the feature branch." - Ask before any destructive action (delete, overwrite, drop table). - NEVER import from outside growth/app/. Only use npm packages and code within growth/. - NEVER modify protected files (layout.tsx, whop-sdk.ts, db.ts, next.config.ts, instrumentation.ts, package.json, any .cursor/rules/ file) without explicitly telling the user this requires an engineer's approval.
secret-scanning.mdc (alwaysApply, globs: growth/**)
- NEVER write API keys, tokens, passwords, or secrets into any file.
- All secrets are managed by Doppler. Use doppler run for local dev, doppler secrets set for storing new tokens.
- If the user shares a token in chat, store it in Doppler immediately. Do NOT echo it back, write it to a file, or include it in code.
- Before ANY git add or commit, scan ALL staged files for: api_token=, xoxp-, xoxb-, sk-, grn_, whop_, Bearer, any string >30 chars that looks like a hex/base64 key. If found, REFUSE to commit and explain.
app-development.mdc (globs: growth/app/**)
- Auth is pre-configured in lib/whop-sdk.ts. Do NOT modify it.
- Every page under tools/ MUST call checkAccess before rendering content. No exceptions.
- ALL UI MUST be mobile responsive. Whop apps load on iOS and Android in iframes. Rules:
- Use Tailwind responsive prefixes (sm:, md:, lg:) for layout changes
- No fixed widths over 360px
- Use flex/grid layouts, never hardcoded pixel positions
- Test at 375px minimum (iPhone SE)
- Touch targets minimum 44x44px
- Use Tailwind for ALL styling. No inline styles. No CSS modules.
- Use @whop/react for iframe interactions (opening external URLs, in-app purchases).
- Prefer server components. Only use "use client" when you need interactivity (forms, buttons, real-time data).
- When adding database tables, prefix with 2-3 letter tool abbreviation (e.g., so_ for sales-onboarding).
- When adding dependencies to package.json, prefer well-known packages. Never add dependencies that duplicate what's already available (e.g., don't add axios when fetch exists).
git-workflow.mdc (alwaysApply, globs: growth/**)
- The user has never used git. Handle ALL git operations yourself.
- Before starting work: git checkout -b growth/<username>/<short-description> from latest main.
- Commit frequently with clear messages using conventional commits (feat:, fix:, docs:).
- When work is done, push and create a PR. Fill in the PR template.
- If there are merge conflicts, resolve them yourself.
- NEVER commit directly to main. ALWAYS use a branch.
- Use simple language: "Your changes are live" not "merged to main and deployed via Vercel."
- After creating a PR, tell the user: "Your changes are being tested. If everything passes, they'll go live automatically."
The growth team uses Macs. whop growth onboard installs everything and gets them running in one command.
What whop growth onboard does:
doppler login (opens browser for OAuth — no tokens to copy)growth and growth-personal Doppler projects~/.growth-config.json with non-secret metadata (user name, etc.)cd growth/app && pnpm installThe actual day-1 experience:
growth/ folder in Cursorwhop growth onboard in the terminalInternal docs page at internal-docs/engineering/getting-started/growth-team.mdx — a step-by-step guide written for non-engineers. Linked from the Growth Whop and from CLAUDE.md.
The growth team has never used git. They should never have to. The AI agent handles all git operations transparently.
git-workflow.mdc (always-on Cursor rule for growth/**):
git checkout -b growth/<username>/<short-description>"gh pr create. Fill in the PR template."The growth team's experience: They describe what they want. The AI builds it, saves it, and says "Your changes are ready for review." They never see a git command.
PR review — auto-merge: PRs that only touch growth/ auto-merge when the Vercel build passes. No engineering review required — these are internal tools with low blast radius. The shared-merge-gate.yml already waits for all checks to pass. Branch protection is configured to allow merges when CI is green for paths under growth/.
Growth tools that need persistent data (quiz scores, call transcripts, dashboard metrics) share a single PlanetScale database.
Setup:
growth-db on PlanetScale (separate from the main app's DB)growth/app/lib/schema.ts — all tables for all tools in one fileDATABASE_URL in the growth/app Doppler config (runtime injected)Schema structure:
// growth/app/lib/schema.ts
// Each tool's tables are prefixed with the tool name
// sales-onboarding tables
export const soUsers = mysqlTable("so_users", { ... });
export const soQuizAttempts = mysqlTable("so_quiz_attempts", { ... });
// churn-dashboard tables
export const cdAccounts = mysqlTable("cd_accounts", { ... });
// shared tables
export const growthUsers = mysqlTable("growth_users", { ... });
Migrations:
npx drizzle-kit push against a PlanetScale dev branch (safe, isolated)growth-new-tool skill guides users through adding tables to schema.tsso_ for sales-onboarding, cd_ for churn-dashboard)"Migration CI:
drizzle-kit check to validate schema consistencyWhat the growth team sees: They say "I need to store user scores." The AI adds a table to schema.ts, runs the migration, and it works.
Six skills in .claude/skills/, all prefixed growth-:
growth-pipedrive — Bear's Pipedrive skill, moved from Downloads. Updated to store tokens in Doppler instead of plaintext JSON. Handles deals, activities, Granola sync, Slack sync.
growth-new-tool — Scaffolds a new tool. Asks what they want to build, runs whop growth new-tool <name>, then guides them to describe the UI and builds it. Automatically creates the Whop app listing via POST /apps API (no manual dashboard step) and installs it on whop.com/growth. All UI must be mobile responsive — the template enforces this.
growth-deploy — Runs whop growth deploy. On first deploy, walks through setting the base URL in the Whop developer dashboard.
growth-daily-sync — EOD routine: Granola notes to Pipedrive deals, Slack channel updates to deal notes. Runs inside doppler run --project growth-personal --config $(whoami) for personal tokens.
growth-create-skill — Self-serve skill builder. Interviews the user about a manual workflow, builds a SKILL.md, places it in .claude/skills/growth-<name>/, tests it. Bear's Pipedrive skill is the reference example.
growth-check — "Is my app working?" Wraps Sentry/Third Eye. Returns plain-language results.
graph LR
subgraph doppler ["Doppler"]
appConfig["growth/app<br/>WHOP_API_KEY, SENTRY_DSN"]
personalConfig["growth-personal/{user}<br/>PIPEDRIVE, SLACK, GRANOLA"]
end
doppler -->|"doppler run<br/>in-memory only"| localDev["Local Dev"]
doppler -->|"Doppler-Vercel sync"| vercel["Vercel Env Vars"]
gitignore[".gitignore + secret-scanning.mdc"] -->|"defense in depth"| repo["Git Repo"]
One Doppler config for the app (growth/app): WHOP_API_KEY, WHOP_WEBHOOK_SECRET, NEXT_PUBLIC_WHOP_APP_ID, SENTRY_DSN, DATABASE_URL (PlanetScale), plus any integration keys (ELEVENLABS_API_KEY, ANTHROPIC_API_KEY, etc.)
One Doppler config per person (growth-personal/<username>): PIPEDRIVE_API_TOKEN, SLACK_USER_TOKEN, GRANOLA_API_KEY
Runtime injection: doppler run injects env vars in-memory. No .env.local files. Nothing on disk. Tokens vanish when the process ends.
Vercel sync: Doppler's native Vercel integration auto-syncs secrets to the Vercel project. Growth team never runs vercel env.
Secret-scanning Cursor rule (always-on): blocks the AI from writing tokens to code, scans for xoxp-, sk-, api_token= patterns before commits.
One-time setup by engineering:
growth and growth-personal Doppler projectsdoppler login once (browser OAuth)Two layers: Vercel for builds/deploys + a custom growth-ci.yml for guardrails. Every check must pass before merge. Non-engineers cannot bypass any of these.
growth-ci.ymlTriggers on PRs that touch growth/**. Runs these checks in order:
1. Scope guard (most critical)
- Diffs the PR against main
- If ANY file outside growth/ is modified, FAIL immediately with: "This PR modifies files outside the growth/ folder. Only files in growth/ can be changed. Please ask an engineer for help."
- This is the single most important check. It makes it impossible to break the main app.
2. Secret scan
- Runs gitleaks detect --source . --log-opts="origin/main..HEAD" on the diff
- Catches any committed tokens, API keys, passwords (xoxp-, sk-, api_token=, Bearer, etc.)
- FAIL with clear explanation: "A secret was detected in your changes. Secrets must go in Doppler, never in code."
3. Protected files check
- These files form the foundation and must not be modified without eng review:
- growth/app/app/layout.tsx
- growth/app/lib/whop-sdk.ts
- growth/app/lib/db.ts
- growth/app/next.config.ts
- growth/app/instrumentation.ts
- growth/app/package.json (flag new dependencies for review)
- growth/.cursor/rules/*
- If modified, don't fail — but require eng review via CODEOWNERS (block auto-merge for this PR)
4. TypeScript check
- cd growth/app && pnpm tsc --noEmit
- Catches type errors before they reach the build
5. Schema validation
- cd growth/app && npx drizzle-kit check
- Validates schema.ts is consistent — catches broken table definitions, missing columns, etc.
6. Build check
- cd growth/app && pnpm build
- Catches anything TypeScript missed — runtime import errors, missing env vars in build, bad config
7. Import boundary check
- Custom script: scan all .ts/.tsx files in growth/app/ for imports that reference paths outside growth/
- Catches: import { something } from '../../../../frontend/...' or import { whatever } from '@whop/internal-package'
- FAIL with: "Your code imports from outside the growth/ folder. Growth tools should only use their own code and npm packages."
# Growth tools and docs — no review required (auto-merge)
growth/app/app/tools/
growth/docs/
# Growth core infrastructure — requires eng review
growth/app/app/layout.tsx @sharkey11
growth/app/lib/whop-sdk.ts @sharkey11
growth/app/lib/db.ts @sharkey11
growth/app/lib/schema.ts @sharkey11
growth/app/next.config.ts @sharkey11
growth/app/instrumentation.ts @sharkey11
growth/app/package.json @sharkey11
growth/.cursor/rules/ @sharkey11
This means:
- Changes to growth/app/app/tools/** and growth/docs/** → auto-merge when CI passes
- Changes to core files → eng review required (can't break auth, monitoring, or DB for everyone)
On top of the GitHub Actions checks: - Preview deploy on every PR (Vercel Git integration) - Production deploy on merge to main - Preview URL commented on the PR so the growth team can test before merge
PR opened → growth-ci.yml runs →
✓ Scope guard (nothing outside growth/)
✓ Secret scan (no tokens in code)
✓ Protected files (no core changes, or eng review if so)
✓ TypeScript (no type errors)
✓ Schema (DB is valid)
✓ Build (app compiles)
✓ Import boundary (no external imports)
✓ Vercel preview (app works)
→ All green + no CODEOWNERS required → auto-merge → Vercel deploys to production
If ANY check fails, the PR cannot merge. The growth team sees a clear error message explaining what went wrong and how to fix it (or that they need to ask an engineer).
Baked into the app:
growth-check skill: "Is my app working?" calls Sentry and returns plain-language results.
Alerting: Sentry posts to #growth-app-errors Slack channel.
Loaded with institutional knowledge from the sales-internal-dashboard and Whop docs:
Actual requests from the team, mapped to how they get built:
| Request | Who | Type |
|---|---|---|
| Granola notes to Pipedrive + next steps | Bear | Skill (done) |
| Auto-score calls + daily report | Cam | Skill |
| Lead scraper from Trustpilot | Cam | Skill |
| Mutual connection finder | Cam | Skill |
| Lead finder + one-click outreach | Rob | Skill |
| CRM analytics / AM performance | Ike | Tool (route group) |
| Gift sending agent via Ramp | Ari, Ike | Skill |
| AI agent for creator Slack questions | Ari | Tool (route group) |
| Churning accounts dashboard | AB | Tool (route group) |
| Change fees/checkout/flags via text | Derek | Tool (needs eng support) |
| Third Eye for product questions | Skyler | Skill (works) |
Target: Phase 1 done next week.
Before piloting with the growth team:
- [ ] Doppler: create growth and growth-personal projects
- [ ] Doppler: assign growth team access via Okta
- [ ] Cursor: assign licenses to pilot users via Okta
- [ ] GitHub: verify pilot users have monorepo access (or add them)
- [ ] whop.com/growth: create the Whop, set up access pass
- [ ] PlanetScale: create growth-db database
- [ ] Vercel: create project linked to growth/app/, enable Doppler sync
- [ ] Sentry: create growth project, get DSN into Doppler
whop growth onboard installs everything (Node, pnpm, Doppler) via Homebrew on their Mac.