Open Source Gong Alternative
See the codeAn open-source, AI-powered Sales Coaching & Call Evaluation platform. Analyze sales calls, grade rep performance against customized talk-tracks and qualification rubrics (e.g. Sandler), transcribe audio recordings with synchronized playback, and deliver targeted rep coaching feedback.
graph TD
A[Sales Call Audio or Transcript] -->|Upload / Ingest| B[Audio Transcription Engine]
B -->|Whisper / Gemini / Groq| C[Synchronized Timestamped Transcript]
C --> D{Evaluation Engine}
D -->|Configured Provider| E[LLM Evaluator: Gemini / OpenAI / Groq / Anthropic / DeepSeek]
D -->|Zero-Config Standalone| F[Deterministic Sales Coach Rubric Engine]
E --> G[Multi-Dimension Scorecard]
F --> G
G --> H[Sandler Qualification: Pain, Budget, Decision]
G --> I[Missed Opportunities & Early Folding Check]
G --> J[Talk-Track & Script Adherence]
G --> K[Manager 1:1 Talk-Track & Coaching Personas]
gemini-2.5-flash, gemini-2.5-pro)gpt-4o, gpt-4o-mini, o3-mini)llama-3.3-70b-versatile)claude-3-5-sonnet-latest, claude-3-5-haiku-latest)deepseek-chat, deepseek-reasoner)Dockerfile and docker-compose.yml.Strangers who only want Docker: SELF-HOST.md (docker compose up --build, Local Admin Mode, keys later, optional Clerk with BILLING_REQUIRED=false).
# 1. Clone repository
git clone https://github.com/Yz613/Sales-Coach.git
cd Sales-Coach
# 2. Install dependencies
npm install
# 3. One-step automated setup (creates .env.local & seeds database)
npm run setup
# 4. Start development server
npm run dev
Open http://localhost:3000 for the public marketing landing (pricing at /#pricing). Local next dev redirects / to /app/marketing; on Cloudflare the worker keeps the URL at /. The product lives at http://localhost:3000/app.
You will immediately be in Local Admin Mode with full access to all features: Call Bank, Reps, Coach, Analytics, Scripts, and Settings. The landing is also previewable at /app/marketing.
If you have Docker installed, you can start Sales Coach with a single command:
docker compose up --build
Then visit http://localhost:3000 (marketing; local Next redirects / to /app/marketing) or http://localhost:3000/app (product). Step-by-step for that path: SELF-HOST.md.
No GIF or screenshots are in the repo yet. Add them under docs/ (they are not created here) and link them from this section. Suggested alt text when you do:
Sales Coach marketing landingCall Bank with seeded sample callsCall evaluation with transcript and scorecardUntil those files exist, run the app and open the Call Bank. docker compose up --build and npm run setup both seed four sample calls — Marcus Vance (Apex Logistics), David Kim (Meridian BioTech), Chloe Bennett (Titan Heavy Supply), and Sarah Jenkins (Veritas Health Tech) — with transcripts and scorecards. No API key is required to read them. Pasted transcripts can be graded by the built-in rubric from Upload.
The revenue workspace adds searchable conversations, keyword and concept topic trackers, alert streams, saved searches, timestamped comments, coaching clip collections, manager score corrections, action items, a CRM deal pipeline, exports, retention and deletion controls.
Deal execution and forecasting: Open Deals to filter by CRM owner, forecast category, stage, or activity flags. Each deal has a manager review with a next step, due date, estimated win probability, and a MEDDICC qualification checklist. Attach exact transcript moments as supporting evidence and review buyer engagement, open call actions, and the conversation timeline. Forecast groups deals by calendar month or quarter, with separate currency totals for won, open, committed, upside, and weighted revenue. Submit a forecast with an optional single-currency target and notes; historical snapshots retain their original deal amounts and categories for comparison. These are manager-led forecasts, with no trained prediction. A HubSpot admin can map the saved forecast category to a deal property. See deal review and forecasting details.
The Admin → Integrations library includes 32 tools. Twenty-two support a direct account sign-in button when their deployment credentials are configured. Task tools let you select a destination after sign-in; Slack and Discord select the channel during consent. See One-click sign-in and deployment credentials. Each card and connection header uses a locally served brand logo, and each tool has a connection guide with permissions, supported capabilities, and setup steps.
| Category | Tools |
|---|---|
| Call recording | Fathom, Fireflies, tl;dv, Gong, Close, Aircall, Quo (formerly OpenPhone), Zoom, Google Meet, Microsoft Teams |
| CRM | HubSpot, Pipedrive, Attio |
| Calendar | Calendly, Google Calendar, Outlook Calendar |
| Team messaging | Slack, Discord |
| Automation | Zapier, Make |
| Tasks and coaching follow-ups | Asana, Notion, Trello, ClickUp, monday.com, Linear, Todoist, Airtable, GitHub, GitLab |
call.imported, call.reviewed, or manual call.shared events to a Zapier Catch Hook or Make Custom webhook. Catch URLs are encrypted. Payloads include summaries, action items, participants, CRM context, and available coaching results; transcript bodies and credentials are excluded. Receiving workflows must deduplicate by eventId before creating downstream records.To send a call, open Overview → Send to your tools as an admin and choose a connected destination. CRM and automation delivery status appears under the integration's Call exports. CRM exports create one note per connection, call, and linked target. Rate limits retry automatically; uncertain outcomes require checking the destination and confirming absence before resending. Task exports also keep delivery records to prevent automatic duplicate sends after ambiguous outcomes. Credentials are encrypted per workspace.
These connectors provide the workflows above. Automatic meeting recording, mailbox capture, arbitrary CRM field mapping, and Slack comment synchronization are not supported. See the Gong capability comparison for the full scope and remaining differences.
For local background sync, run npm run worker in a second terminal. Docker Compose starts both services. Hosted installations need an explicit encryption key; Cloudflare cron also needs its job-runner secret and public origin.
Integration checks cover provider contracts, all 32 logo assets, permissions and workspace isolation, retries, and duplicate delivery. The CRM stress test queues 3,000 duplicate requests for 300 exports across four workers and verifies exactly 300 notes. Native Workers/D1 tests check migrations, concurrent delivery claims, and outbound requests. Provider tests use simulated responses; live vendor acceptance requires account credentials and the controlled checks in the setup guides.
The public landing page's vs Gong calculator (/#compare-gong) compares a Gong quote with hosted Sales Coach plans or self-hosted model usage. Adjust reps, call volume, call duration, Gong seats, annual seat price, platform fee, and optional Forecast/Engage add-ons. Hosted mode includes plan allowances and overage, with automatic plan selection and Enterprise fair-use checks; self-hosted mode uses a selectable or custom cost per evaluation. Results show estimated monthly and annual costs and the difference between them.
Gong defaults are editable estimates. Replace them with your actual quote, and set self-hosted usage rates to your provider costs; the calculator estimates product/model costs, not your complete infrastructure and operating budget.
Admins can use the dashboard’s Team goals card to plan revenue by quarter, month, or week. Use Manage teams & reps to name teams and assign existing reps. Each rep belongs to one goal team; unassigned reps do not affect team rates. These goal teams are groups inside the current workspace and share its admin permissions.
Each team has its own revenue goal, average customer revenue, selling days, and planning rep count. The count follows its roster unless manually overridden; Use assigned count restores that behavior. Click Save team goals to persist goals and assignments for all admins in the current workspace.
Close rates remain read-only and come from logged calls with the Meeting booked outcome. The team estimate uses its combined historical rate. Individual targets split revenue equally across the planning rep count and use each rep’s own rate, so a 5% rep needs twice the calls of a 10% rep for the same customer target. The individual total can differ from the combined-rate estimate. Reps without logged calls or booked meetings show no call target until a usable rate exists. Planning assumes 13 weeks per quarter and 4⅓ weeks per month, and call targets round up.
You can add your API keys either directly in the web UI or via environment variables:
Create a .env.local file from the example template:
cp .env.example .env.local
Add your key(s):
GEMINI_API_KEY=your_gemini_api_key_here
# or
OPENAI_API_KEY=your_openai_api_key_here
# or
GROQ_API_KEY=your_groq_api_key_here
Audio Uploads Note: Transcribing uploaded audio files (MP3/WAV/M4A) uses Gemini, OpenAI (Whisper), or Groq (Whisper). Pasted text transcripts work with any configured provider or with the built-in rule engine.
By default, Sales Coach runs in Standalone Mode without any authentication needed. If you want to host it for a team with user logins, team workspaces, and role-based permissions:
.env.local:NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
npm run dev). The app will now enforce authentication:
org:admin): Full access to settings, scripts, analytics, rep personas, and team invites.org:member): Scoped access to the Call Bank, call uploads, and call evaluations.An existing active session on /app/sign-in opens the workspace automatically; pending team selection opens /app/select-organization. Workspace access and billing checks still run on the destination page. Hosted login scripts and their lazy chunks use the first-party /app/__auth/assets/ proxy. Login, sign-up, invites, and team selection show loading and recovery messages when authentication requests fail or a form cannot mount. ERR_BLOCKED_BY_CLIENT can also come from the optional Cloudflare analytics beacon; that request is not required for login. If sign-in fails, use Reload sign-in or try a private window to check whether a browser extension is blocking required requests.
Hosted deployments (BILLING_REQUIRED=true, the default whenever Clerk keys are present) send new teams through Stripe Checkout first. Coach and Team CTAs open Stripe; Clerk sign-up is blocked until that session is paid. Sign-in stays available for existing customers. Invited teammates skip checkout. Self-hosters using Clerk only for RBAC should set BILLING_REQUIRED=false.
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Optional: dashboard price ids. If unset, Checkout uses $399 / $1,499 monthly price_data.
# Enterprise is quoted at $4,997/month (not a self-serve Checkout price). Coach and Team overage is $1.25 per evaluation.
# STRIPE_PRICE_COACH=price_...
# STRIPE_PRICE_TEAM=price_...
Webhook URL: https://your-domain/app/api/webhooks/stripe (events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted). Put the secrets with wrangler secret put — do not commit them. Hosted teams cannot read another team's data, and they cannot pick a plan in Settings to skip checkout.
If you are migrating a production database that already has unscoped rows, set LEGACY_TENANT_ORG_ID to the original Clerk organization id. Ownership is never inferred from organization age. New organizations always start empty.
To send teammate invitations via transactional email, add a Resend API key:
RESEND_API_KEY=re_...
# Leave blank until the address is on a domain you verified. example.com is ignored.
# RESEND_FROM_EMAIL="Sales Coach <invites@example.com>"
INVITE_PRODUCT_NAME="Sales Coach"
The product name in invite mail defaults to Sales Coach. invites@refreshqueue.com is the hosted site’s sender only — do not copy it into a self-hosted .env. (You can also paste a Resend key in Admin → Settings.)
├── src/
│ ├── app/ # Next.js App Router (pages & API endpoints under /app)
│ │ ├── marketing/ # Public landing (also rewritten to apex /)
│ │ ├── calls/ # Call Bank & Call Evaluation detail views
│ │ ├── reps/ # Rep directory, performance trends & 1:1 talk tracks
│ │ ├── coach/ # Coach Builder & System prompt configuration
│ │ ├── admin/ # Analytics, Rubric/Script manager & Settings
│ │ └── api/ # REST API routes (transcription, scoring, team sync)
│ ├── components/ # React UI components (Glassmorphism + Tailwind)
│ └── lib/
│ ├── ai/ # Multi-provider LLM callers, JSON extractors, STT
│ ├── db/ # Drizzle ORM schemas, SQLite / D1 adapters & seeders
│ ├── integrations/ # Provider adapters, brand mapping & capability catalog
│ ├── revenue/ # Conversations, sync jobs, tasks, exports & privacy controls
│ └── auth.ts # Local Standalone & Clerk multi-tenant RBAC logic
├── public/ # Public static assets, including all 32 integration logos
├── fixtures/ # Private demo recordings
├── scripts/ # Setup & audio synthesis utilities
├── schema.sql # Cloudflare D1 SQL schema
├── wrangler.jsonc # Cloudflare Workers configuration
└── open-next.config.ts # OpenNext Cloudflare deployment adapter
| Command | Description |
|---|---|
npm run setup | One-command setup: environment file & database seeding |
npm run dev | Start the local development server |
npm run build | Compile Next.js production build |
npm test | Run the complete automated regression suite, including revenue integrations |
npm run test:revenue | Run conversation, integration, export, and duplicate-delivery checks |
npm run worker | Process integration jobs, scheduled sync and retention |
npm run worker:once | Run one background maintenance/job batch |
npx tsc --noEmit | Check TypeScript types |
npm run db:seed | Seed SQLite database with sample reps, stages, and calls |
npm run preview | Build and preview on local Cloudflare Worker runtime |
npm run deploy | Deploy to Cloudflare Workers |
Sales Coach is designed to run seamlessly on Cloudflare Workers using OpenNext and Cloudflare D1:
Log in to Cloudflare:
npx wrangler login
Create a D1 database:
npx wrangler d1 create sales-coach-db
Copy the output database_id into wrangler.jsonc under d1_databases[0].database_id.
Initialize the database schema:
npx wrangler d1 execute sales-coach-db --remote --file=./schema.sql
Set Production Secrets:
npx wrangler secret put CLERK_SECRET_KEY
npx wrangler secret put INTEGRATION_ENCRYPTION_KEY
npx wrangler secret put INTEGRATION_CRON_SECRET
npx wrangler secret put PUBLIC_APP_URL
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_WEBHOOK_SECRET
# Optional:
npx wrangler secret put GEMINI_API_KEY
npx wrangler secret put RESEND_API_KEY
Use a stable, securely generated 32-byte base64 encryption key, a random scheduler secret of at least 32 characters, and your canonical HTTPS origin. Enable authenticator MFA and backup codes in Clerk before inviting users. See production security setup. Hosted checkout also needs a Stripe webhook on /app/api/webhooks/stripe. GitHub Actions deploy resolves the D1 database_id from the sales-coach-db database in the Cloudflare account, so the placeholder in wrangler.jsonc does not have to be committed. The same deploy injects VISITOR_COMPANY_KV from the VISITOR_COMPANY_KV_ID repository variable when it is set, and otherwise uses the hosted namespace 05bb9e51843e4b26a424ed09dad780f6. That id is not a secret and is not committed. A self-hosted worker keeps its own config and still runs when the binding is absent.
Create private recording and cache buckets:
npx wrangler r2 bucket create sales-coach-recordings
npx wrangler r2 bucket create sales-coach-opennext-cache
Keep public access disabled on both buckets. Recordings are served through authenticated workspace routes.
Deploy:
npm run deploy
Apex domain: Point the zone apex (and /pricing and /integrations) at this worker, not only /app/*. The worker internally serves the marketing landing at GET /, the integrations catalog at GET /integrations, and redirects /pricing → /#pricing. The product remains at /app.
The signed-in main menu at /app/workspaces lists only the current user's verified team memberships and shows which teams have access. Checkout includes Back to main menu, so selecting an unpaid team does not trap someone who already belongs to a paid team. Each selected team still passes the normal server and API access checks.
For an internal test account, create a separate Clerk user, give it org:admin membership in a dedicated test team, and add that exact team ID to the operator's BILLING_EXEMPT_ORG_IDS repository variable and Worker secret. This enables all workspace features without checkout, evaluation limits, or overage charges. The test team keeps its own calls and integration credentials; third-party integrations still need their normal credentials. No user metadata, public query parameter, or client setting can grant an exemption.
We welcome contributions of all kinds! Please see:
Copyright (c) 2026 Yz613. This project is licensed under the MIT License. See the LICENSE file in the repository root for the full terms.
Production requires Clerk authentication, an active organization, a verified second factor, an HTTPS PUBLIC_APP_URL, and INTEGRATION_ENCRYPTION_KEY. Unauthenticated admin access is limited to local development. Read production security setup and the threat model before deployment.
Open Source Gong Alternative
See the codeAn open-source, AI-powered Sales Coaching & Call Evaluation platform. Analyze sales calls, grade rep performance against customized talk-tracks and qualification rubrics (e.g. Sandler), transcribe audio recordings with synchronized playback, and deliver targeted rep coaching feedback.
graph TD
A[Sales Call Audio or Transcript] -->|Upload / Ingest| B[Audio Transcription Engine]
B -->|Whisper / Gemini / Groq| C[Synchronized Timestamped Transcript]
C --> D{Evaluation Engine}
D -->|Configured Provider| E[LLM Evaluator: Gemini / OpenAI / Groq / Anthropic / DeepSeek]
D -->|Zero-Config Standalone| F[Deterministic Sales Coach Rubric Engine]
E --> G[Multi-Dimension Scorecard]
F --> G
G --> H[Sandler Qualification: Pain, Budget, Decision]
G --> I[Missed Opportunities & Early Folding Check]
G --> J[Talk-Track & Script Adherence]
G --> K[Manager 1:1 Talk-Track & Coaching Personas]
gemini-2.5-flash, gemini-2.5-pro)gpt-4o, gpt-4o-mini, o3-mini)llama-3.3-70b-versatile)claude-3-5-sonnet-latest, claude-3-5-haiku-latest)deepseek-chat, deepseek-reasoner)Dockerfile and docker-compose.yml.Strangers who only want Docker: SELF-HOST.md (docker compose up --build, Local Admin Mode, keys later, optional Clerk with BILLING_REQUIRED=false).
# 1. Clone repository
git clone https://github.com/Yz613/Sales-Coach.git
cd Sales-Coach
# 2. Install dependencies
npm install
# 3. One-step automated setup (creates .env.local & seeds database)
npm run setup
# 4. Start development server
npm run dev
Open http://localhost:3000 for the public marketing landing (pricing at /#pricing). Local next dev redirects / to /app/marketing; on Cloudflare the worker keeps the URL at /. The product lives at http://localhost:3000/app.
You will immediately be in Local Admin Mode with full access to all features: Call Bank, Reps, Coach, Analytics, Scripts, and Settings. The landing is also previewable at /app/marketing.
If you have Docker installed, you can start Sales Coach with a single command:
docker compose up --build
Then visit http://localhost:3000 (marketing; local Next redirects / to /app/marketing) or http://localhost:3000/app (product). Step-by-step for that path: SELF-HOST.md.
No GIF or screenshots are in the repo yet. Add them under docs/ (they are not created here) and link them from this section. Suggested alt text when you do:
Sales Coach marketing landingCall Bank with seeded sample callsCall evaluation with transcript and scorecardUntil those files exist, run the app and open the Call Bank. docker compose up --build and npm run setup both seed four sample calls — Marcus Vance (Apex Logistics), David Kim (Meridian BioTech), Chloe Bennett (Titan Heavy Supply), and Sarah Jenkins (Veritas Health Tech) — with transcripts and scorecards. No API key is required to read them. Pasted transcripts can be graded by the built-in rubric from Upload.
The revenue workspace adds searchable conversations, keyword and concept topic trackers, alert streams, saved searches, timestamped comments, coaching clip collections, manager score corrections, action items, a CRM deal pipeline, exports, retention and deletion controls.
Deal execution and forecasting: Open Deals to filter by CRM owner, forecast category, stage, or activity flags. Each deal has a manager review with a next step, due date, estimated win probability, and a MEDDICC qualification checklist. Attach exact transcript moments as supporting evidence and review buyer engagement, open call actions, and the conversation timeline. Forecast groups deals by calendar month or quarter, with separate currency totals for won, open, committed, upside, and weighted revenue. Submit a forecast with an optional single-currency target and notes; historical snapshots retain their original deal amounts and categories for comparison. These are manager-led forecasts, with no trained prediction. A HubSpot admin can map the saved forecast category to a deal property. See deal review and forecasting details.
The Admin → Integrations library includes 32 tools. Twenty-two support a direct account sign-in button when their deployment credentials are configured. Task tools let you select a destination after sign-in; Slack and Discord select the channel during consent. See One-click sign-in and deployment credentials. Each card and connection header uses a locally served brand logo, and each tool has a connection guide with permissions, supported capabilities, and setup steps.
| Category | Tools |
|---|---|
| Call recording | Fathom, Fireflies, tl;dv, Gong, Close, Aircall, Quo (formerly OpenPhone), Zoom, Google Meet, Microsoft Teams |
| CRM | HubSpot, Pipedrive, Attio |
| Calendar | Calendly, Google Calendar, Outlook Calendar |
| Team messaging | Slack, Discord |
| Automation | Zapier, Make |
| Tasks and coaching follow-ups | Asana, Notion, Trello, ClickUp, monday.com, Linear, Todoist, Airtable, GitHub, GitLab |
call.imported, call.reviewed, or manual call.shared events to a Zapier Catch Hook or Make Custom webhook. Catch URLs are encrypted. Payloads include summaries, action items, participants, CRM context, and available coaching results; transcript bodies and credentials are excluded. Receiving workflows must deduplicate by eventId before creating downstream records.To send a call, open Overview → Send to your tools as an admin and choose a connected destination. CRM and automation delivery status appears under the integration's Call exports. CRM exports create one note per connection, call, and linked target. Rate limits retry automatically; uncertain outcomes require checking the destination and confirming absence before resending. Task exports also keep delivery records to prevent automatic duplicate sends after ambiguous outcomes. Credentials are encrypted per workspace.
These connectors provide the workflows above. Automatic meeting recording, mailbox capture, arbitrary CRM field mapping, and Slack comment synchronization are not supported. See the Gong capability comparison for the full scope and remaining differences.
For local background sync, run npm run worker in a second terminal. Docker Compose starts both services. Hosted installations need an explicit encryption key; Cloudflare cron also needs its job-runner secret and public origin.
Integration checks cover provider contracts, all 32 logo assets, permissions and workspace isolation, retries, and duplicate delivery. The CRM stress test queues 3,000 duplicate requests for 300 exports across four workers and verifies exactly 300 notes. Native Workers/D1 tests check migrations, concurrent delivery claims, and outbound requests. Provider tests use simulated responses; live vendor acceptance requires account credentials and the controlled checks in the setup guides.
The public landing page's vs Gong calculator (/#compare-gong) compares a Gong quote with hosted Sales Coach plans or self-hosted model usage. Adjust reps, call volume, call duration, Gong seats, annual seat price, platform fee, and optional Forecast/Engage add-ons. Hosted mode includes plan allowances and overage, with automatic plan selection and Enterprise fair-use checks; self-hosted mode uses a selectable or custom cost per evaluation. Results show estimated monthly and annual costs and the difference between them.
Gong defaults are editable estimates. Replace them with your actual quote, and set self-hosted usage rates to your provider costs; the calculator estimates product/model costs, not your complete infrastructure and operating budget.
Admins can use the dashboard’s Team goals card to plan revenue by quarter, month, or week. Use Manage teams & reps to name teams and assign existing reps. Each rep belongs to one goal team; unassigned reps do not affect team rates. These goal teams are groups inside the current workspace and share its admin permissions.
Each team has its own revenue goal, average customer revenue, selling days, and planning rep count. The count follows its roster unless manually overridden; Use assigned count restores that behavior. Click Save team goals to persist goals and assignments for all admins in the current workspace.
Close rates remain read-only and come from logged calls with the Meeting booked outcome. The team estimate uses its combined historical rate. Individual targets split revenue equally across the planning rep count and use each rep’s own rate, so a 5% rep needs twice the calls of a 10% rep for the same customer target. The individual total can differ from the combined-rate estimate. Reps without logged calls or booked meetings show no call target until a usable rate exists. Planning assumes 13 weeks per quarter and 4⅓ weeks per month, and call targets round up.
You can add your API keys either directly in the web UI or via environment variables:
Create a .env.local file from the example template:
cp .env.example .env.local
Add your key(s):
GEMINI_API_KEY=your_gemini_api_key_here
# or
OPENAI_API_KEY=your_openai_api_key_here
# or
GROQ_API_KEY=your_groq_api_key_here
Audio Uploads Note: Transcribing uploaded audio files (MP3/WAV/M4A) uses Gemini, OpenAI (Whisper), or Groq (Whisper). Pasted text transcripts work with any configured provider or with the built-in rule engine.
By default, Sales Coach runs in Standalone Mode without any authentication needed. If you want to host it for a team with user logins, team workspaces, and role-based permissions:
.env.local:NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
npm run dev). The app will now enforce authentication:
org:admin): Full access to settings, scripts, analytics, rep personas, and team invites.org:member): Scoped access to the Call Bank, call uploads, and call evaluations.An existing active session on /app/sign-in opens the workspace automatically; pending team selection opens /app/select-organization. Workspace access and billing checks still run on the destination page. Hosted login scripts and their lazy chunks use the first-party /app/__auth/assets/ proxy. Login, sign-up, invites, and team selection show loading and recovery messages when authentication requests fail or a form cannot mount. ERR_BLOCKED_BY_CLIENT can also come from the optional Cloudflare analytics beacon; that request is not required for login. If sign-in fails, use Reload sign-in or try a private window to check whether a browser extension is blocking required requests.
Hosted deployments (BILLING_REQUIRED=true, the default whenever Clerk keys are present) send new teams through Stripe Checkout first. Coach and Team CTAs open Stripe; Clerk sign-up is blocked until that session is paid. Sign-in stays available for existing customers. Invited teammates skip checkout. Self-hosters using Clerk only for RBAC should set BILLING_REQUIRED=false.
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Optional: dashboard price ids. If unset, Checkout uses $399 / $1,499 monthly price_data.
# Enterprise is quoted at $4,997/month (not a self-serve Checkout price). Coach and Team overage is $1.25 per evaluation.
# STRIPE_PRICE_COACH=price_...
# STRIPE_PRICE_TEAM=price_...
Webhook URL: https://your-domain/app/api/webhooks/stripe (events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted). Put the secrets with wrangler secret put — do not commit them. Hosted teams cannot read another team's data, and they cannot pick a plan in Settings to skip checkout.
If you are migrating a production database that already has unscoped rows, set LEGACY_TENANT_ORG_ID to the original Clerk organization id. Ownership is never inferred from organization age. New organizations always start empty.
To send teammate invitations via transactional email, add a Resend API key:
RESEND_API_KEY=re_...
# Leave blank until the address is on a domain you verified. example.com is ignored.
# RESEND_FROM_EMAIL="Sales Coach <invites@example.com>"
INVITE_PRODUCT_NAME="Sales Coach"
The product name in invite mail defaults to Sales Coach. invites@refreshqueue.com is the hosted site’s sender only — do not copy it into a self-hosted .env. (You can also paste a Resend key in Admin → Settings.)
├── src/
│ ├── app/ # Next.js App Router (pages & API endpoints under /app)
│ │ ├── marketing/ # Public landing (also rewritten to apex /)
│ │ ├── calls/ # Call Bank & Call Evaluation detail views
│ │ ├── reps/ # Rep directory, performance trends & 1:1 talk tracks
│ │ ├── coach/ # Coach Builder & System prompt configuration
│ │ ├── admin/ # Analytics, Rubric/Script manager & Settings
│ │ └── api/ # REST API routes (transcription, scoring, team sync)
│ ├── components/ # React UI components (Glassmorphism + Tailwind)
│ └── lib/
│ ├── ai/ # Multi-provider LLM callers, JSON extractors, STT
│ ├── db/ # Drizzle ORM schemas, SQLite / D1 adapters & seeders
│ ├── integrations/ # Provider adapters, brand mapping & capability catalog
│ ├── revenue/ # Conversations, sync jobs, tasks, exports & privacy controls
│ └── auth.ts # Local Standalone & Clerk multi-tenant RBAC logic
├── public/ # Public static assets, including all 32 integration logos
├── fixtures/ # Private demo recordings
├── scripts/ # Setup & audio synthesis utilities
├── schema.sql # Cloudflare D1 SQL schema
├── wrangler.jsonc # Cloudflare Workers configuration
└── open-next.config.ts # OpenNext Cloudflare deployment adapter
| Command | Description |
|---|---|
npm run setup | One-command setup: environment file & database seeding |
npm run dev | Start the local development server |
npm run build | Compile Next.js production build |
npm test | Run the complete automated regression suite, including revenue integrations |
npm run test:revenue | Run conversation, integration, export, and duplicate-delivery checks |
npm run worker | Process integration jobs, scheduled sync and retention |
npm run worker:once | Run one background maintenance/job batch |
npx tsc --noEmit | Check TypeScript types |
npm run db:seed | Seed SQLite database with sample reps, stages, and calls |
npm run preview | Build and preview on local Cloudflare Worker runtime |
npm run deploy | Deploy to Cloudflare Workers |
Sales Coach is designed to run seamlessly on Cloudflare Workers using OpenNext and Cloudflare D1:
Log in to Cloudflare:
npx wrangler login
Create a D1 database:
npx wrangler d1 create sales-coach-db
Copy the output database_id into wrangler.jsonc under d1_databases[0].database_id.
Initialize the database schema:
npx wrangler d1 execute sales-coach-db --remote --file=./schema.sql
Set Production Secrets:
npx wrangler secret put CLERK_SECRET_KEY
npx wrangler secret put INTEGRATION_ENCRYPTION_KEY
npx wrangler secret put INTEGRATION_CRON_SECRET
npx wrangler secret put PUBLIC_APP_URL
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_WEBHOOK_SECRET
# Optional:
npx wrangler secret put GEMINI_API_KEY
npx wrangler secret put RESEND_API_KEY
Use a stable, securely generated 32-byte base64 encryption key, a random scheduler secret of at least 32 characters, and your canonical HTTPS origin. Enable authenticator MFA and backup codes in Clerk before inviting users. See production security setup. Hosted checkout also needs a Stripe webhook on /app/api/webhooks/stripe. GitHub Actions deploy resolves the D1 database_id from the sales-coach-db database in the Cloudflare account, so the placeholder in wrangler.jsonc does not have to be committed. The same deploy injects VISITOR_COMPANY_KV from the VISITOR_COMPANY_KV_ID repository variable when it is set, and otherwise uses the hosted namespace 05bb9e51843e4b26a424ed09dad780f6. That id is not a secret and is not committed. A self-hosted worker keeps its own config and still runs when the binding is absent.
Create private recording and cache buckets:
npx wrangler r2 bucket create sales-coach-recordings
npx wrangler r2 bucket create sales-coach-opennext-cache
Keep public access disabled on both buckets. Recordings are served through authenticated workspace routes.
Deploy:
npm run deploy
Apex domain: Point the zone apex (and /pricing and /integrations) at this worker, not only /app/*. The worker internally serves the marketing landing at GET /, the integrations catalog at GET /integrations, and redirects /pricing → /#pricing. The product remains at /app.
The signed-in main menu at /app/workspaces lists only the current user's verified team memberships and shows which teams have access. Checkout includes Back to main menu, so selecting an unpaid team does not trap someone who already belongs to a paid team. Each selected team still passes the normal server and API access checks.
For an internal test account, create a separate Clerk user, give it org:admin membership in a dedicated test team, and add that exact team ID to the operator's BILLING_EXEMPT_ORG_IDS repository variable and Worker secret. This enables all workspace features without checkout, evaluation limits, or overage charges. The test team keeps its own calls and integration credentials; third-party integrations still need their normal credentials. No user metadata, public query parameter, or client setting can grant an exemption.
We welcome contributions of all kinds! Please see:
Copyright (c) 2026 Yz613. This project is licensed under the MIT License. See the LICENSE file in the repository root for the full terms.
Production requires Clerk authentication, an active organization, a verified second factor, an HTTPS PUBLIC_APP_URL, and INTEGRATION_ENCRYPTION_KEY. Unauthenticated admin access is limited to local development. Read production security setup and the threat model before deployment.