Setup
ShiftCall — Technical Handoff Document
Overview
ShiftCall is an AI-powered role-playing training simulator for high-turnover industries (call centers, retail, food service, healthcare). The buyer receives clean, deployable code (Next.js + Node.js backend) with voice AI integration, manager dashboard, and Stripe subscription billing.
---
1. Minimum Requirements to Run
Requirement Spec
Hosting Vercel (recommended) or AWS
Database PostgreSQL (Supabase free tier works)
Voice AI ElevenLabs API (text-to-speech for customer voice)
File storage AWS S3 or Cloudinary (for audio recordings)
Domain Custom domain (shiftcall.com or similar)
Budget (MVP) ~$100–200/month for APIs + hosting
---
2. API Keys & Secrets Needed
The buyer must obtain the following API keys:
Service Purpose Free tier limit Monthly cost at scale Sign-up link
OpenAI API GPT-4o for scoring responses + generating scenarios $5 free credit $50–200 platform.openai.com
ElevenLabs Text-to-speech (AI plays angry customer voice) 10,000 characters free/month $22–100 elevenlabs.io
Stripe Subscription billing ($199–499/location/month) Free 2.9% + $0.30 per transaction stripe.com
Supabase Database (users, companies, locations, scenarios) 500 MB free $25–50 supabase.com
AWS S3 Store voice recordings (trainee responses) 5 GB free $1–10 aws.amazon.com/s3
Resend (or SendGrid) Transactional emails (reports, invites) 3,000 emails/month free $0–20 resend.com
Deepgram (optional) Speech-to-text for voice responses (higher accuracy) $200 free credit $0.01–0.03 per minute deepgram.com
Vercel Hosting + environment variables Free tier available $20–50 vercel.com
Total monthly cost at 100 locations (each with 10 trainees = 1,000 users): ~$150–300
---
3. Environment Variables (.env.local)
The buyer creates a .env.local file with these variables:
```env
# ====================
# OPENAI
# ====================
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
# ====================
# ELEVENLABS (Voice AI)
# ====================
ELEVENLABS_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
ELEVENLABS_VOICE_ID=21m00Tcm4TlvDq8ikWAM # Default "Adam" voice
# ====================
# STRIPE (Payments)
# ====================
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxxxxx
STRIPE_PRICE_ID_LOCATION=price_xxxxxxxxxxxxxx # $199/location
STRIPE_PRICE_ID_ENTERPRISE=price_xxxxxxxxxxxxxx # Custom
# ====================
# DATABASE (Supabase)
# ====================
SUPABASE_URL=https://xxxxxxxx.supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... (keep secret)
# ====================
# AWS S3 (Audio storage)
# ====================
AWS_ACCESS_KEY_ID=AKIAxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
AWS_S3_BUCKET_NAME=shiftcall-recordings
AWS_REGION=us-east-1
# ====================
# DEEPGRAM (Speech-to-text - optional)
# ====================
DEEPGRAM_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
# ====================
# EMAIL (Resend)
# ====================
RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
RESEND_FROM_EMAIL=reports@shiftcall.com
# ====================
# APP CONFIG
# ====================
NEXT_PUBLIC_APP_URL=https://shiftcall.com
JWT_SECRET=randomly_generated_64_char_string
ADMIN_EMAIL=admin@shiftcall.com
# ====================
# RATE LIMITING
# ====================
RATE_LIMIT_PER_USER_PER_DAY=50 # Max simulations per day
```
---
4. Database Schema (SQL for Supabase/PostgreSQL)
The buyer runs this once:
```sql
-- Companies table
CREATE TABLE companies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
stripe_customer_id VARCHAR(255),
subscription_status VARCHAR(50) DEFAULT 'trialing', -- trialing, active, cancelled
created_at TIMESTAMP DEFAULT NOW()
);
-- Locations table (each company has multiple locations)
CREATE TABLE locations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID REFERENCES companies(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL, -- "Downtown Store" or "Call Center - East"
address TEXT,
subscription_tier VARCHAR(50) DEFAULT 'basic', -- basic($199), pro($399), enterprise($499)
stripe_subscription_id VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW()
);
-- Users (trainees and managers)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
full_name VARCHAR(255),
role VARCHAR(50) DEFAULT 'trainee', -- trainee, manager, admin
location_id UUID REFERENCES locations(id) ON DELETE SET NULL,
company_id UUID REFERENCES companies(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT NOW()
);
-- Scenario library (500+ pre-written scenarios)
CREATE TABLE scenarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
industry VARCHAR(50) NOT NULL, -- retail, call_center, food_service, healthcare
difficulty VARCHAR(20) DEFAULT 'intermediate', -- beginner, intermediate, advanced
title VARCHAR(255) NOT NULL,
description TEXT,
customer_voice_prompt TEXT, -- What the AI says (e.g., "I've been on hold for 30 minutes!")
expected_policy_points TEXT[] -- Array of policies trainee should mention
);
-- Simulation sessions
CREATE TABLE simulations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
scenario_id UUID REFERENCES scenarios(id),
mode VARCHAR(20) DEFAULT 'text', -- text or voice
customer_messages JSONB[], -- Full conversation history
trainee_responses JSONB[],
scores JSONB, -- { empathy: 85, speed: 90, policy: 70, overall: 82 }
ai_feedback TEXT,
audio_recording_url TEXT, -- S3 link (voice mode only)
started_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP
);
-- Manager coaching notes
CREATE TABLE coaching_notes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
simulation_id UUID REFERENCES simulations(id) ON DELETE CASCADE,
manager_id UUID REFERENCES users(id),
note TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Billing history
CREATE TABLE invoices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID REFERENCES companies(id),
location_id UUID REFERENCES locations(id),
stripe_invoice_id VARCHAR(255),
amount INT, -- in cents
status VARCHAR(50), -- paid, unpaid, refunded
period_start DATE,
period_end DATE,
created_at TIMESTAMP DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_simulations_user_id ON simulations(user_id);
CREATE INDEX idx_simulations_completed_at ON simulations(completed_at);
CREATE INDEX idx_users_location_id ON users(location_id);
CREATE INDEX idx_locations_company_id ON locations(company_id);
```
---
5. Deployment Steps (Buyer's Checklist)
Step Action Time
1 Sign up for Vercel (free) and connect GitHub 5 min
2 Create Supabase project, run the SQL schema above 15 min
3 Get OpenAI API key 5 min
4 Get ElevenLabs API key + select default voice 10 min
5 Get Stripe keys + create products ($199, $399, $499) 20 min
6 Configure Stripe webhook endpoint 10 min
7 Create AWS S3 bucket for audio recordings 10 min
8 (Optional) Get Deepgram API key for voice transcription 5 min
9 Copy all environment variables into Vercel dashboard 15 min
10 Deploy from GitHub → Vercel (one-click) 5 min
11 Connect custom domain (shiftcall.com) in Vercel 5 min
12 Set up Stripe webhook to https://shiftcall.com/api/stripe-webhook 5 min
13 Upload 500+ scenarios to database (CSV import) 30 min
14 Run test simulation (text mode) 10 min
15 Run test simulation (voice mode) 10 min
16 Go live —
Total setup time for technical buyer: ~2–3 hours
---
6. Code Repository Structure (What Buyer Receives)
```
shiftcall/
├── app/
│ ├── api/
│ │ ├── simulate/
│ │ │ ├── text/ # Text-based scenario handler
│ │ │ └── voice/ # Voice recording + scoring
│ │ ├── scenarios/ # Fetch scenario library
│ │ ├── dashboard/ # Manager analytics endpoint
│ │ ├── stripe-webhook/ # Subscription billing handler
│ │ └── auth/ # Supabase authentication
│ ├── dashboard/
│ │ ├── manager/ # Manager view (team scores)
│ │ ├── trainee/ # Trainee view (practice)
│ │ └── admin/ # Company admin (add locations)
│ ├── onboarding/ # New customer setup flow
│ └── page.tsx # Landing page
├── components/
│ ├── VoiceSimulator.tsx # ElevenLabs + recording UI
│ ├── TextSimulator.tsx # Chat-style scenario UI
│ ├── ScoreCard.tsx # Display AI scoring results
│ └── ManagerTable.tsx # Team performance table
├── lib/
│ ├── openai.ts # Scoring logic
│ ├── elevenlabs.ts # Text-to-speech
│ ├── deepgram.ts # Speech-to-text (optional)
│ ├── stripe.ts # Subscription billing
│ ├── supabase.ts # Database client
│ └── scoring-rubrics/ # Industry-specific scoring logic
│ ├── retail.ts
│ ├── call-center.ts
│ ├── food-service.ts
│ └── healthcare.ts
├── data/
│ └── scenarios.csv # 500+ scenarios (import to Supabase)
├── public/ # Static assets
├── .env.local # (excluded — buyer creates)
├── next.config.js
├── package.json
└── README.md # Full setup guide
```
---
7. 500+ Scenario Library Preview
Buyer receives a CSV with these columns:
Industry Title Customer Prompt Expected Policy Points
retail "Wrong Price at Register" "The sign said $9.99, but it rang up $14.99! This is false advertising!" price check, apology, manager override