Skip to content

About

CareerVoice is an AI-powered voice interview practice platform where users conduct live spoken interviews with an AI powered by Vapi, GPT-4, ElevenLabs, and Deepgram. Google Gemini generates tailored questions based on the user's role and stack, then evaluates the transcript to deliver structured performance report. Built with Next.js, typescript

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

CareerVoice

AI-powered voice interview practice platform with instant structured feedback.

Next.js TypeScript Firebase TailwindCSS Jest Docker


1. Project Overview

What is CareerVoice?

CareerVoice is a full-stack web application that lets users practice job interviews through real-time voice conversations with an AI interviewer. After each session, the platform automatically generates a structured performance report scored across five professional categories.

Problem It Solves

Most interview preparation happens through reading — flashcards, Q&A lists, or watching YouTube videos. But real interviews happen out loud, under pressure, in real time. That gap between reading and speaking is where candidates fail.

CareerVoice bridges that gap by giving you a realistic, spoken interview experience with an AI that listens, responds naturally, and tells you exactly what to improve — available any time, with no scheduling required.

Why It Is Useful

  • You get honest, structured feedback that a friend or peer rarely gives
  • Questions are tailored to your role, experience level, and tech stack — not generic
  • You can repeat sessions as many times as needed without any friction
  • The entire flow — setup, interview, feedback — takes under 15 minutes

2. Features

  • Real-time AI voice interviews — live spoken conversations using GPT-4, ElevenLabs voice, and Deepgram speech recognition, all orchestrated through Vapi AI
  • Custom question generation — Google Gemini 2.0 Flash generates tailored questions based on your role, experience level, tech stack, and interview type (Technical / Behavioral / Mixed)
  • Instant AI feedback — scored performance report across five categories: Communication Skills, Technical Knowledge, Problem Solving, Cultural Fit, and Confidence & Clarity
  • Personal dashboard — full interview history with score tracking, type badges, and links to past feedback
  • Community interview pool — browse and take interview sessions created by other users on the platform
  • Secure authentication — email/password sign-up and sign-in using Firebase Auth with httpOnly session cookies
  • Rate limiting — all API routes are protected with an in-memory sliding-window rate limiter
  • Structured logging — JSON-formatted logs on every API request with level, timestamp, and context
  • CI/CD pipeline — GitHub Actions workflow that runs lint, tests, coverage, and build on every push
  • Docker support — multi-stage production Docker build using a non-root user

3. Tech Stack

Category Technology
Framework Next.js 15 (App Router)
Language TypeScript 5
UI Library React 19
Styling TailwindCSS 4, Radix UI
Voice Orchestration Vapi AI (@vapi-ai/web)
AI Interviewer OpenAI GPT-4 (via Vapi)
Text-to-Speech ElevenLabs (via Vapi)
Speech-to-Text Deepgram Nova-2 (via Vapi)
Feedback & Questions Google Gemini 2.0 Flash (via Vercel AI SDK)
Database Firebase Firestore
Authentication Firebase Auth + Firebase Admin SDK
Schema Validation Zod
Form Handling React Hook Form + @hookform/resolvers
Notifications Sonner
Date Formatting dayjs
Icons Lucide React
Testing Jest 29, ts-jest, jest-environment-jsdom
Containerization Docker (node:20-alpine, multi-stage)
CI/CD GitHub Actions

4. Project Structure

carrervoice/
│
├── app/                            # Next.js App Router — all pages and API routes
│   ├── (auth)/                     # Route group for unauthenticated pages
│   │   ├── layout.tsx              # Auth layout wrapper
│   │   ├── sign-in/page.tsx        # Sign-in page
│   │   └── sign-up/page.tsx        # Sign-up page
│   │
│   ├── (root)/                     # Route group for authenticated pages
│   │   ├── layout.tsx              # Main app layout with navigation
│   │   ├── page.tsx                # Dashboard — user history + community interviews
│   │   └── interview/
│   │       ├── page.tsx            # Interview setup and configuration
│   │       └── [id]/
│   │           ├── page.tsx        # Live voice interview session
│   │           └── feedback/
│   │               └── page.tsx    # Post-interview feedback and scores
│   │
│   ├── api/                        # REST API route handlers
│   │   ├── interviews/
│   │   │   ├── route.ts            # GET — paginated interview list with filters
│   │   │   ├── [id]/route.ts       # GET — single interview by ID
│   │   │   └── [id]/feedback/      # GET — feedback for a specific interview
│   │   │       └── route.ts
│   │   └── vapi/generate/
│   │       └── route.ts            # POST — AI question generation via Gemini
│   │
│   ├── layout.tsx                  # Root layout — fonts, dark theme, toast provider
│   └── globals.css                 # Global styles and design tokens
│
├── components/                     # Reusable UI components
│   ├── Agent.tsx                   # Core voice interview component and call state machine
│   ├── AuthForm.tsx                # Shared sign-in / sign-up form
│   ├── InterviewCard.tsx           # Dashboard card showing role, score, and feedback link
│   ├── DisplayTechIcons.tsx        # Stacked tech stack icons fetched from devicons CDN
│   ├── FormField.tsx               # Reusable form field wrapper
│   └── ui/                         # Low-level UI primitives
│       ├── button.tsx
│       ├── form.tsx
│       ├── input.tsx
│       ├── label.tsx
│       └── sonner.tsx
│
├── firebase/
│   ├── admin.ts                    # Firebase Admin SDK — server-side only (Firestore + Auth)
│   └── client.ts                   # Firebase Client SDK — browser-side only (Auth UI)
│
├── lib/
│   ├── actions/
│   │   ├── auth.action.ts          # Server Actions — signUp, signIn, signOut, getCurrentUser
│   │   └── general.action.ts       # Server Actions — createFeedback, getInterviews, getFeedback
│   ├── apiResponse.ts              # Typed success/error response factory for API routes
│   ├── logger.ts                   # Structured JSON logger (info, warn, error, request)
│   ├── rateLimit.ts                # In-memory sliding-window rate limiter
│   ├── validation.ts               # Zod schemas for API input validation
│   ├── vapi.sdk.ts                 # Vapi client singleton initialization
│   └── utils.ts                   # Utility functions — cn(), getTechLogos(), getRandomInterviewCover()
│
├── constants/
│   └── index.ts                    # Vapi assistant config, Zod feedback schema, tech name mappings
│
├── types/
│   ├── index.d.ts                  # Global TypeScript interfaces (User, Interview, Feedback, etc.)
│   └── vapi.d.ts                   # Vapi-specific type extensions
│
├── __tests__/                      # Unit tests
│   ├── apiResponse.test.ts
│   ├── logger.test.ts
│   ├── rateLimit.test.ts
│   └── validation.test.ts
│
├── public/                         # Static assets
│   ├── ai-avatar.png               # AI interviewer avatar
│   ├── user-avatar.png             # Default user avatar
│   ├── robot.png                   # Hero image
│   ├── covers/                     # Company brand covers (12 images)
│   └── *.svg                       # Icons and decorative assets
│
├── .github/
│   └── workflows/
│       └── ci.yml                  # GitHub Actions — test and build pipeline
│
├── Dockerfile                      # Multi-stage Docker build
├── .dockerignore
├── next.config.ts
├── jest.config.ts
├── tsconfig.json
├── postcss.config.mjs
├── eslint.config.mjs
└── components.json

5. Installation Guide

Prerequisites

Make sure you have the following before starting:

  • Node.js 20 or higher — Download here
  • npm — comes bundled with Node.js
  • Firebase project — Create one here with Firestore and Email/Password Authentication enabled
  • Vapi AI account — Sign up here and create a voice workflow
  • Google AI Studio API key — Get one here for Gemini access

Step 1 — Clone the Repository

git clone https://github.com/dharamdan01/carrervoice.git
cd carrervoice

Step 2 — Install Dependencies

npm install

Step 3 — Set Up Environment Variables

Create a .env.local file in the root of the project:

touch .env.local

Add the following variables and fill in your values:

# ── Firebase Admin SDK (server-side — never expose these publicly) ──
FIREBASE_PROJECT_ID=your_project_id
FIREBASE_CLIENT_EMAIL=your_service_account_email
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"

# ── Firebase Client SDK (browser-safe) ────────────────────────────
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id

# ── Vapi AI ────────────────────────────────────────────────────────
NEXT_PUBLIC_VAPI_WEB_TOKEN=your_vapi_public_token
NEXT_PUBLIC_VAPI_WORKFLOW_ID=your_vapi_workflow_id

# ── Google Gemini ──────────────────────────────────────────────────
GOOGLE_GENERATIVE_AI_API_KEY=your_gemini_api_key

Where to find each key:

  • Firebase Admin keys → Firebase Console → Project Settings → Service Accounts → Generate New Private Key
  • Firebase Client keys → Firebase Console → Project Settings → General → Your Apps
  • Vapi token → Vapi Dashboard → API Keys
  • Gemini key → Google AI Studio → API Keys

Step 4 — Run the Development Server

npm run dev

Open http://localhost:3000 in your browser.


6. Usage Guide

Running the App

# Development (with Turbopack)
npm run dev

# Production build
npm run build
npm run start

# Lint the codebase
npm run lint

User Flow

  1. Create an account at /sign-up using your email and password
  2. Sign in at /sign-in — a secure session cookie is issued automatically
  3. Dashboard shows your past interviews and available community sessions
  4. Start an interview by clicking "Start an Interview" — configure your:
    • Job role (e.g., Frontend Developer, Data Engineer)
    • Experience level (Junior / Mid / Senior)
    • Tech stack (e.g., React, Node.js, PostgreSQL)
    • Interview type (Technical / Behavioral / Mixed)
    • Number of questions (3 to 15)
  5. Click "Start Call" — the AI interviewer speaks to you and listens to your answers in real time
  6. Click "End Call" when done — feedback is generated automatically
  7. Review your feedback — scores, strengths, areas to improve, and a final assessment
  8. Revisit any past interview from the dashboard at any time

7. API / Components

API Endpoints

All endpoints require authentication via session cookie and include rate limiting, Zod input validation, and structured JSON logging.

Method Endpoint Description
GET /api/interviews Returns paginated list of user's interviews. Supports type, minScore, maxScore, page, and limit query params. Rate limit: 30 req/min.
GET /api/interviews/[id] Returns a single interview document by ID.
GET /api/interviews/[id]/feedback Returns the feedback document linked to a specific interview.
POST /api/vapi/generate Accepts role, level, type, techstack, amount, and userid. Calls Gemini to generate questions and saves the interview to Firestore. Rate limit: 10 req/min.

Key Components

Agent.tsx

The core component of the application. Manages the voice interview call lifecycle using a four-state enum (INACTIVE → CONNECTING → ACTIVE → FINISHED). Registers event listeners for Vapi call start/end, live transcripts, and speech detection. When the call ends, it triggers feedback generation and redirects the user.

AuthForm.tsx

A shared form used for both sign-in and sign-up, controlled by a type prop. Uses React Hook Form with Zod validation. On sign-up, calls Firebase Client SDK then the signUp server action. On sign-in, gets an ID token from Firebase and passes it to the signIn server action to create a session cookie.

InterviewCard.tsx

An async server component that fetches the feedback document for each interview card. Displays role, interview type (color-coded badge), date, tech stack icons, score (color-coded green/amber/red), and links to feedback or interview pages.

DisplayTechIcons.tsx

Normalizes raw tech stack strings (e.g., "react.js", "Node.js") using a mappings dictionary, fetches icons from the devicons CDN, and verifies each icon exists with a HEAD request before rendering. Falls back to a generic /tech.svg if an icon is not found.

Key Server Actions

lib/actions/auth.action.ts

Function Description
signUp(params) Creates a new user document in Firestore
signIn(params) Verifies the Firebase ID token and issues a session cookie
signOut() Deletes the session cookie
getCurrentUser() Reads and verifies the session cookie, returns the user object
isAuthenticated() Returns a boolean indicating whether a valid session exists

lib/actions/general.action.ts

Function Description
createFeedback(params) Sends transcript to Gemini, validates output against Zod schema, saves to Firestore
getInterviewById(id) Fetches a single interview document
getFeedbackByInterviewId(params) Queries feedback by interview ID and user ID
getLatestInterviews(params) Returns recent finalized interviews from other users
getInterviewsByUserId(userId) Returns all interviews belonging to the current user

Utility Modules

lib/apiResponse.ts — Typed response factory. Provides successResponse(), errorResponse(), and named helpers (errors.unauthorized(), errors.notFound(), errors.rateLimited(), etc.) for consistent API response shapes.

lib/rateLimit.ts — In-memory sliding-window rate limiter backed by a Map. Accepts a key (IP-based), max requests, and window duration. Returns { allowed, remaining, resetAt }.

lib/logger.ts — Structured JSON logger with info, warn, error, debug, and request methods. Each log entry includes level, message, timestamp, and optional context object.

lib/validation.ts — Zod schemas for paginationSchema, interviewFilterSchema, and createInterviewSchema used across API routes.


8. Future Improvements

  • Redis-backed rate limiting — replace the in-memory Map with Upstash Redis so rate limits persist across server restarts and work correctly with multiple instances
  • Route-level auth middleware — add middleware.ts to protect all authenticated routes at the edge and eliminate null assertion operators in page components
  • Google / GitHub OAuth — add social sign-in options alongside email/password
  • Stronger password policy — enforce a minimum of 8 characters with at least one uppercase letter and one number
  • Score trend charts — add analytics charts on the dashboard to visualize improvement over multiple sessions
  • Integration tests — add tests for server actions and API routes using the Firebase Emulator Suite
  • Batched Firestore reads — replace the per-card feedback query in the dashboard with a single batched read to reduce Firestore costs and latency
  • Multi-language support — allow interviews to be conducted in languages other than English
  • Video mode — optional webcam feed alongside the voice interview for more realistic practice

9. Author

Dharam Dan

Full-stack developer. Built CareerVoice to help developers practice the part of interviews that reading alone cannot prepare you for — speaking clearly, thinking out loud, and staying confident under pressure.


License

This project is licensed under the MIT License.


CareerVoice — Practice out loud. Get better. Land the job.

About

CareerVoice is an AI-powered voice interview practice platform where users conduct live spoken interviews with an AI powered by Vapi, GPT-4, ElevenLabs, and Deepgram. Google Gemini generates tailored questions based on the user's role and stack, then evaluates the transcript to deliver structured performance report. Built with Next.js, typescript

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages