AI-powered mock interview platform for software engineers.
Live voice conversations with an AI interviewer across coding, system design, and behavioral formats — with structured evaluations, dimension scoring, and progress tracking.
|
Email/password registration and login with JWT access/refresh token rotation. Email verification and password reset flows via Resend. Role-based access control with admin and user roles. |
Real-time WebSocket-powered interview sessions with an AI interviewer. State-machine-managed session lifecycle: prepare → active → paused → completed. Token-by-token AI response streaming. |
|
Monaco editor with syntax highlighting, multiple language support (Python, JavaScript, TypeScript, Java, C++, Go, Rust), and a Docker-based code execution sandbox with isolated test case evaluation. |
Post-interview evaluation via GPT-4o with structured output. Scores across multiple dimensions (problem-solving, code quality, communication), hire verdicts, strengths/improvements, and question-level breakdowns. |
|
Deepgram STT integration (nova-3 model) with configurable endpointing. Browser-based audio capture with live transcription and auto-submit on silence detection. |
WebSocket reconnection with jittered exponential backoff (10 max attempts), session state replay on reconnect, heartbeat monitoring, and database-backed session persistence across server restarts. |
|
Aggregated statistics, interview progress tracking, recent activity list, subscription status, and performance trend charts. Per-interview evaluation reports with radar charts and dimension scores. |
Upload and parse resumes (PDF/DOCX) and job descriptions. Keyword-based technology extraction and language suggestion. S3-compatible storage backed by MinIO for local dev and Supabase Storage for production. |
|
Sentry error tracking (backend + frontend), Redis-backed JWT blacklist, structured audit logging, APScheduler background jobs, feature flags, configurable CORS, and Docker Compose infrastructure. |
Coding — algorithmic problem-solving with live editor |
Screenshots are real captures from the running platform.
Landing page · Sign in
Dashboard with stats and activity · Setup wizard
Progress analytics · Evaluation reports
Coding interview with Monaco editor · Live interview session
Post-interview evaluation report · Registration
flowchart LR
Browser[Browser] --> Next.js[Next.js 15 SSR]
Browser --> WS[WebSocket]
Next.js --> API[FastAPI REST]
WS --> Sessions[Session Manager]
subgraph Backend [FastAPI Modular Monolith]
API
Sessions
Auth[Auth Module]
Interview[Interview Module]
Evaluation[Evaluation Pipeline]
Reports[Reports Module]
Workers[Background Workers]
Sessions --> AI[AI Orchestrator]
AI --> Provider[OpenAI / OpenRouter]
end
Backend --> DB[(PostgreSQL 17)]
Backend --> Redis[(Redis 7)]
Backend --> Storage[(S3 / MinIO)]
Sessions --> WS
stateDiagram-v2
[*] --> IDLE: Create session
IDLE --> PREPARING: Build AI context
PREPARING --> ACTIVE: Generate first question
ACTIVE --> PAUSED: User pauses
PAUSED --> ACTIVE: User resumes
ACTIVE --> COMPLETING: Last question answered
COMPLETING --> COMPLETED: Wrap-up message
COMPLETED --> ARCHIVED: Evaluation complete
ACTIVE --> FAILED: Irrecoverable error
ACTIVE --> TIMEOUT: Duration exceeded
TIMEOUT --> COMPLETED: Force complete
flowchart LR
Interview[Completed Interview] --> Transcript[Load Transcript]
Transcript --> Prompt[Build Evaluation Prompt]
Prompt --> GPT4[GPT-4o Structured Output]
GPT4 --> Parse[Parse Response]
Parse --> Scores[Dimension Scores]
Parse --> Verdict[Hire Verdict]
Parse --> Feedback[Strengths & Improvements]
Scores --> DB[(PostgreSQL)]
Verdict --> DB
Feedback --> DB
tayari.ai/
├── apps/
│ ├── api/ # FastAPI backend
│ │ ├── ai/ # AI provider + realtime engine
│ │ │ ├── realtime/ # Session state machine, orchestrator, memory
│ │ │ ├── openai_provider.py # OpenAI / OpenRouter integration
│ │ │ ├── mock_provider.py # Development mock
│ │ │ └── code_review.py # AI code review service
│ │ ├── core/ # Config, DB, auth, storage, errors
│ │ ├── features/ # Domain modules
│ │ │ ├── auth/ # JWT, guards, password hashing
│ │ │ ├── interview/ # CRUD, setup wizard, file uploads
│ │ │ ├── sessions/ # WebSocket session persistence
│ │ │ ├── reports/ # Evaluation pipeline
│ │ │ ├── billing/ # Stripe stubs
│ │ │ ├── dashboard/ # Aggregated stats
│ │ │ ├── users/ # Admin user management
│ │ │ ├── voice/ # Deepgram STT
│ │ │ ├── code/ # Code submissions
│ │ │ └── analytics/ # Usage analytics
│ │ ├── judge/ # Code execution sandbox
│ │ └── workers/ # APScheduler background tasks
│ └── web/ # Next.js 15 frontend
│ ├── app/ # App Router pages
│ ├── features/ # Feature-sliced UI modules
│ ├── lib/ # API client, utilities
│ └── components/ # Shared UI components
├── packages/
│ ├── prompts/ # AI prompt templates (Markdown)
│ ├── types/ # Zod schemas shared web↔api
│ ├── config/ # ESLint + TypeScript configs
│ └── ui/ # Shared React components
├── infrastructure/ # Docker Compose, Traefik
├── .github/workflows/ # CI/CD pipelines
└── assets/screenshots/ # Documentation images
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | Next.js 15 (App Router), React 19, TypeScript | SSR, client components, routing |
| Styling | Tailwind CSS v4, framer-motion | Utility-first CSS, animations |
| State | TanStack Query v5 | Server state, caching, mutations |
| Backend | Python 3.13, FastAPI 0.115, uvicorn | REST API + WebSocket |
| ORM | SQLAlchemy 2.0 (async), Alembic | Database access, migrations |
| Database | PostgreSQL 17 (via asyncpg) | Primary data store |
| Cache | Redis 7 | JWT blacklist, APScheduler job store |
| Auth | Custom JWT (RS256/HS256) | Token-based auth with refresh rotation |
| AI | OpenAI / OpenRouter (GPT-4o-mini, GPT-4o) | Interviewer + evaluator |
| STT | Deepgram (nova-3) | Speech-to-text |
| Resend | Transactional email | |
| Storage | S3-compatible (MinIO local / Supabase prod) | Resume/JD file storage |
| Monitoring | Sentry | Error tracking |
| Background Jobs | APScheduler (SQLAlchemyJobStore) | Async evaluation processing |
| Code Execution | Docker sandbox (subprocess fallback) | Isolated code runner (7 languages) |
| CI/CD | GitHub Actions | Lint, test, build, Docker |
| Containerization | Docker Compose, Traefik v3 | Local dev, reverse proxy |
| Package Manager | pnpm 9 (Node), uv (Python) | Monorepo dependency management |
| Monorepo | Turborepo 2 | Task orchestration |
| Tool | Version | Purpose |
|---|---|---|
| Python | 3.13+ | Backend runtime |
| Node.js | 22+ | Frontend runtime |
| pnpm | 9+ | Node package manager |
| uv | Latest | Python package manager |
| Docker | 24+ | PostgreSQL, Redis, MinIO |
| Git | 2.40+ | Version control |
# Clone the repository
git clone https://github.com/Mahnoor-Zaffar/Tayari.ai.git
cd Tayari.ai
# Start infrastructure (PostgreSQL, Redis, MinIO)
docker compose -f infrastructure/docker-compose.yml up -d
# Install Python dependencies
cd apps/api
uv sync --all-extras
uv run alembic upgrade head
uv run python scripts/seed.py
cd ../..
# Install Node dependencies
pnpm install
# Start development (API + Web concurrently)
pnpm dev| Service | URL |
|---|---|
| Web app | http://localhost:3000 |
| API docs | http://localhost:8000/docs |
| Health check | http://localhost:8000/health |
| MinIO Console | http://localhost:9001 (tayari / tayari_dev) |
The API requires a .env file at apps/api/.env. Copy the template:
cp apps/api/.env.example apps/api/.envRequired variables for full functionality:
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | postgresql+asyncpg://tayari:tayari_dev@localhost:5432/tayari |
PostgreSQL connection |
REDIS_URL |
Yes | redis://localhost:6379/0 |
Redis connection |
JWT_SECRET_KEY |
Yes | change-me-in-production |
Token signing key |
JWT_ALGORITHM |
Yes | RS256 |
Signing algorithm |
OPENAI_API_KEY |
For AI | "" |
OpenAI / OpenRouter key |
RESEND_API_KEY |
For email | "" |
Transactional email |
DEEPGRAM_API_KEY |
For voice | "" |
Speech-to-text |
SENTRY_DSN |
No | "" |
Error tracking |
STORAGE_ENDPOINT |
For uploads | "" |
S3-compatible endpoint |
STORAGE_ACCESS_KEY |
For uploads | "" |
S3 access key |
STORAGE_SECRET_KEY |
For uploads | "" |
S3 secret key |
Frontend variables go in apps/web/.env.local:
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_API_URL |
Yes | http://localhost:8000/api/v1 |
Backend URL |
NEXT_PUBLIC_SENTRY_DSN |
No | "" |
Frontend error tracking |
NEXT_PUBLIC_FF_* |
No | See .env.example |
Feature flags |
# Backend only
cd apps/api && uv run uvicorn main:app --reload --port 8000
# Frontend only
cd apps/web && pnpm dev
# Backend tests
cd apps/api && uv run pytest --ignore=tests/test_e2e_evaluation.py -v
# Frontend tests
pnpm --filter @tayari/web test
# Lint all
pnpm lint
# Typecheck all
pnpm typecheckThe API is organized into feature modules, each with its own router, schemas, service, and repository.
| Module | Prefix | Key Endpoints | Auth |
|---|---|---|---|
| Auth | /auth |
signup, login, logout, refresh, forgot-password, reset-password, verify-email |
No |
| Interviews | /interviews |
CRUD, upload resume/JD, device check, difficulty estimate, config validation | Yes |
| Sessions | /sessions |
WebSocket endpoint, pause/resume, reconnect, status | Yes |
| Evaluations | /evaluations |
Trigger evaluation, list, get by interview ID | Yes |
| Dashboard | /dashboard |
Aggregated stats, recent activity | Yes |
| Users | /users |
Profile, admin user management | Yes |
| Billing | /billing |
Stripe checkout stubs, subscription status | Yes |
| Code | /code |
Code submissions, review | Yes |
| Voice | /voice |
Deepgram transcription | Yes |
| Analytics | /analytics |
Usage analytics | Yes |
| Health | /health |
Service health check | No |
All responses follow a standard envelope:
{
"success": true,
"data": { ... },
"request_id": "uuid"
}Error responses:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "...",
"details": []
},
"request_id": "uuid"
}Each domain (auth, interview, reports, sessions, etc.) is a self-contained package with its own models, schemas, routes, services, repositories, and tests. Cross-feature dependencies are explicit and unidirectional.
# Example: features/auth/ owns EVERYTHING for auth
features/auth/
├── routes.py # FastAPI router
├── services.py # Business logic
├── repositories.py # Data access
├── schemas.py # Pydantic request/response models
├── guard.py # Auth guards (get_current_user, RoleChecker)
├── dependencies.py # DI wiring
├── domain/ # Domain models
├── jwt/ # JWT sub-module (config, service, blacklist)
└── password/ # Password hashing sub-moduleRepository Pattern — Data access abstraction
class UserRepository:
def __init__(self, session: AsyncSession) -> None:
self._session = session
async def find_by_email(self, email: str) -> User | None:
...
async def create_user(self, data: dict) -> User:
...Service Layer — Business logic separated from HTTP
class InterviewService:
def __init__(self, repository: InterviewRepository) -> None:
self._repo = repository
async def create_interview(self, user_id: UUID, request: CreateInterviewRequest) -> InterviewResponse:
# Validates free-tier limits, deduplicates, persists snapshot
...Dependency Injection — Testable components via FastAPI Depends
async def get_interview_service(
repository: InterviewRepository = Depends(get_interview_repository),
) -> InterviewService:
return InterviewService(repository)Async-First — Non-blocking I/O throughout
All database operations use SQLAlchemy async session. AI provider calls, WebSocket message handling, and background tasks all use asyncio. The code execution queue uses asyncio.Semaphore for concurrency control.
Modular Monolith — Microservice-ready boundaries without the operational cost
Feature modules are physically separated (own directory, own dependencies) but deployed as a single process. This gives clean boundaries for future extraction into microservices without paying the operational cost today.
| Layer | Framework | Tests | What's tested |
|---|---|---|---|
| Backend unit | pytest + pytest-asyncio | 49 | Auth validation, session guards, state machine transitions, code judge output comparison, background worker error handling, email service HTML generation |
| Backend integration | pytest + httpx AsyncClient | — | Full request→DB→response for auth endpoints |
| Frontend unit | Vitest + React Testing Library | 92 | Component rendering, error/loading/empty states, form validation |
| E2E | Playwright | 9 | Auth flows (login, register, forgot-password), auth guard redirects |
# All backend tests
cd apps/api && uv run pytest --ignore=tests/test_e2e_evaluation.py -v
# All frontend tests
pnpm --filter @tayari/web test
# E2E tests (requires running servers)
cd apps/web && pnpm test:e2e
# With coverage
cd apps/api && uv run pytest --cov --cov-report=termOn every git commit, the following run automatically via Husky + lint-staged:
- Prettier — formats TypeScript, JavaScript, JSON, Markdown files
- Ruff — lints and formats Python files (
ruff check --fix+ruff format) - pytest — runs Python tests if any Python files changed
The infrastructure/docker-compose.yml provides all services for local development:
| Service | Image | Ports | Purpose |
|---|---|---|---|
db |
postgres:17-alpine | 5432 | Primary database |
redis |
redis:7-alpine | 6379 | Cache + job store |
minio |
minio/minio | 9000 (API), 9001 (Console) | S3-compatible storage |
api |
Build from apps/api/Dockerfile.dev |
8000 | FastAPI with hot-reload |
web |
Build from apps/web/Dockerfile.dev |
3000 | Next.js with hot-reload |
Start all services:
docker compose -f infrastructure/docker-compose.yml up -dProduction Dockerfiles are available for both services:
| Service | Dockerfile | Base Image | Notes |
|---|---|---|---|
| API | apps/api/Dockerfile |
python:3.13-slim | Single-stage, uv sync --no-dev, HEALTHCHECK |
| Web | apps/web/Dockerfile |
node:22-alpine | Multi-stage, Next.js build then minimal runner |
The infrastructure/traefik/ directory contains a Traefik v3 reverse proxy configuration with automatic Let's Encrypt TLS for production deployments.
Triggers on push/PR to main and feature/** branches:
flowchart LR
Push --> Lint[Lint & TypeCheck]
Push --> JSTests[JS Tests]
Push --> PyTests[Python Tests]
Lint --> Build[Build]
Build --> Deploy[Deploy]
subgraph Lint [Lint & TypeCheck]
Ruff[Ruff] --> ESLint[ESLint]
ESLint --> MyPy[MyPy]
MyPy --> TSC[TypeScript]
end
subgraph JSTests [JS Tests]
Vitest[Vitest - 92 tests]
end
subgraph PyTests [Python Tests]
Pytest[Pytest - 49 tests]
Pg[PostgreSQL 17]
Redis[Redis 7]
end
| Job | Tools | Purpose |
|---|---|---|
lint-and-typecheck |
ruff, mypy, eslint, tsc | Static analysis + type checking |
js-tests |
vitest | Frontend unit tests |
python-tests |
pytest (with PostgreSQL + Redis containers) | Backend tests |
build |
next build | Frontend production build + performance budget |
docker |
Docker Buildx | Production image build (API + Web) |
The stack deploys to $0/month hosting within provider free-tier limits and for personal / non-commercial use:
- Frontend (Next.js) → Vercel Hobby (free; personal, non-commercial
only), root directory
apps/web - Backend (FastAPI + Redis + Postgres) → Google Cloud
e2-micro(Always Free: one instance, ≤30 GB disk, ≤1 GB egress/mo — costs accrue beyond these limits) viainfrastructure/docker-compose.prod.yml(Traefik = TLS; embedded Redis;postgres:17in a volume) - Feature branches / CI: runs all checks, no deployment
- Email/password authentication with JWT refresh rotation
- Three interview modalities (coding, system-design, behavioral)
- Real-time AI interviewer with token streaming
- Deepgram voice integration
- Post-interview evaluation with dimension scoring
- Dashboard with stats and activity tracking
- Resume and job description upload
- Session reconnection and resilience
- Background evaluation via APScheduler
- Docker Compose development environment
- Sentry error monitoring
- S3-compatible file storage
- Redis-backed JWT blacklist
- Admin user management
- E2E test suite
- Stripe billing integration
- Advanced analytics dashboard
- Interview replay (full session playback)
- Team / organization accounts
- Custom prompt management UI
- Multi-agent interview panels
- Video interview support
- Real-time collaborative whiteboard
- Interview question bank with community contributions
- API for third-party integrations
- AI-powered interview question generation
- Performance benchmarking against industry standards
Contributions are welcome. Please follow these guidelines:
- Branch: Create a feature branch from
main - CI: All checks must pass before merging
- Commits: Use conventional commit messages (
feat:,fix:,docs:,chore:, etc.) - Tests: Add tests for new functionality
- Lint: Run
pnpm lintand fix any issues before pushing - Review: Open a pull request with a clear description of changes
# Create a feature branch
git checkout -b feature/my-feature
# Make changes, add tests, commit
git add .
git commit -m "feat: my feature description"
# Push and open a PR
git push -u origin feature/my-feature- Python: Follow ruff rules (E, F, I, N, W, UP), line length 120, target Python 3.13
- TypeScript/React: ESLint with
@next/nextplugin, Prettier formatting - Imports: Use absolute imports (
@/for frontend, module paths for backend) - Typing: Strict mode in both mypy (Python) and TypeScript
This project is licensed under the MIT License.









