An intelligent, interactive mock interview platform powered by Go, React, and PostgreSQL, designed to help users confidently prepare for Backend Engineering interviews.
- Overview
- System Architecture
- Key Features
- Tech Stack
- API Documentation
- Database Schema
- Billing System
- Deployment
- Local Development
- Security Implementation
- Testing Strategy
- Frontend
- License
Interviewer App is a robust backend service, coupled with a light demo frontend, that powers an interactive Backend Engineer interviewing experience. It leverages ChatGPT's conversational AI capabilities to create personalized, adaptive interview sessions tailored to each user's preferences.
The application was built with a focus on:
- Clean Architecture: Following repository-service pattern with clear separation of concerns
- Scalability: Designed for horizontal scaling with stateless API design
- Security: Implementing industry-standard JWT authentication with refresh token rotation
- Maintainability: Modular code structure with reusable components
┌─────────────────┐ ┌──────────────────────────────────────┐ ┌───────────────┐
│ │ │ │ │ │
│ React │◄────►│ Go Backend API │◄────►│ PostgreSQL │
│ Client App │ │ │ │ Database │
│ │ │ │ │ │
└─────────────────┘ └───────────────┬──────────────────────┘ └───────────────┘
│
│
▼
┌─────────────────────────┐
│ │
│ OpenAI API │
│ │
└─────────────────────────┘
The backend is structured using a layered architecture:
- Handler Layer: Request validation and response formation
- Service Layer: Business logic encapsulation
- Repository Layer: Data access and persistence
- Middleware: Cross-cutting concerns (authentication, logging, etc.)
- User Management: Secure user registration, authentication, and password recovery
- JWT-based Authentication: Access tokens with configurable expiration and refresh token rotation
- Structured Mock Interviews: Dynamic interview generation
- Conversational AI Integration: Seamless integration with OpenAI's GPT model
- Persistent Data Storage: Complete interview history stored for future review
- Billing & Subscription System: Credit-based access via Lemon Squeezy integration, supporting both one-time and recurring plans
- RESTful API Design: Consistent and predictable API endpoints
- Middleware Pipeline: Extensible middleware for request processing
- Environment-based Configuration: Flexible configuration for different deployment environments
- Integration and Unit Testing: Broad coverage utilizing Go's stdlib testing
- Email Service: Emails sent on key user actions using Resend.
- Wired to Deploy to AWS: ALB/ECS/Fargate configured and deployable for easy service switch from Fly.io in future
Component | Technology |
---|---|
Backend Language | Go (Golang) 1.20+ |
Database | PostgreSQL 15+ |
Authentication | JWT-based authentication (access & refresh tokens) |
AI Integration | OpenAI GPT API (4.0) |
Billing | Lemon Squeezy API |
Mailing | Resend API |
Testing | Go table-driven tests (unit + integration) |
Containerization | Docker |
Deployment | Fly.io |
Database Hosting | Supabase (PostgreSQL) |
Version Control | Git |
┌─────────┐ ┌─────────┐ ┌─────────┐
│ │ │ │ │ │
│ Client │ │ Server │ │ Database│
│ │ │ │ │ │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ POST /api/users (Register) │ │
│───────────────────────────────────────────►│ │
│ │ │
│ │ Store User │
│ │────────────────────────────────►│
│ │ │
│ 201 Created │ │
│◄───────────────────────────────────────────│ │
│ │ │
│ POST /api/auth/login │ │
│───────────────────────────────────────────►│ │
│ │ Verify Credentials │
│ │────────────────────────────────►│
│ │ │
│ 200 OK (Access Token + Refresh Token) │ │
│◄───────────────────────────────────────────│ │
│ │ │
│ Request with Access Token │ │
│───────────────────────────────────────────►│ │
│ │ Validate Token │
│ │ │
│ Response │ │
│◄───────────────────────────────────────────│ │
│ │ │
│ POST /api/auth/token (Refresh) │ │
│───────────────────────────────────────────►│ │
│ │ Verify Refresh Token │
│ │────────────────────────────────►│
│ │ │
│ 200 OK (New Access Token + Refresh Token) │ │
│◄───────────────────────────────────────────│ │
│ │ │
POST /api/users
– Register a new userGET /api/users/{id}
– Get user profileDELETE /api/users/delete/{id}
– Delete user accountPOST /api/auth/check-email
– Check if an email existsPOST /api/auth/request-verification
– Send verification emailPOST /api/auth/request-reset
– Request password reset emailPOST /api/auth/reset-password
– Reset password
POST /api/auth/login
– User login (email/password)POST /api/auth/github
– GitHub OAuth loginPOST /api/auth/token
– Refresh access token
POST /api/interviews
– Create a new interviewGET /api/interviews/{id}
– Fetch a specific interviewPATCH /api/interviews/{id}
– Update interview status (e.g., pause/resume)
POST /api/conversations/create/{interview_id}
– Create a new conversation for interviewPOST /api/conversations/append/{interview_id}
– Append a response to an ongoing conversationGET /api/conversations/{interview_id}
– Get full conversation history for an interview
POST /api/jd
– Process job description input for interview tailoring
POST /api/payment/checkout
– Start a new subscription checkout sessionPOST /api/payment/cancel
– Cancel subscriptionPOST /api/payment/resume
– Resume canceled subscriptionPOST /api/payment/change-plan
– Change subscription tierPOST /api/webhooks/billing
– Lemon Squeezy billing webhook handler
GET /api/user/dashboard
– Retrieve user dashboard data
GET /health
– Service health check
All schema definitions are managed via SQL migration files located in /database/migrations/
.
To apply them:
make migrate-up # or specify your migration tool/command
The schema includes tables for users
, interviews
, conversations
, questions
, messages
, refresh_tokens
, processed_webhooks
, and credit_transactions
. See individual migration files for full definitions.
The Interviewer platform supports both one-time purchases and recurring subscriptions using Lemon Squeezy. Credits are granted based on the user's payment plan and control access to AI-powered mock interviews.
- Individual Plan: Buy one credit at a time. These credits never expire and persist across account changes.
- Subscription Plans:
- Pro: 10 monthly credits
- Premium: 20 monthly credits
- Subscription credits pause when a user cancels, and reactivate upon resumption.
- Unused credits roll over, but require an active subscription to be used.
- Real-time Lemon Squeezy events power the billing system:
subscription_created
→ Assign plan tier + grant creditssubscription_payment_success
→ Monthly credit refreshsubscription_cancelled
/expired
→ Pause credit usagesubscription_resumed
→ Reinstate usage of rolled-over creditsorder_created
→ Grant one-time creditsubscription_plan_changed
→ Upgrading or downgrading a plan
- All webhook events are idempotent via tracked
webhook_id
- Credits are separated by type:
individual
vssubscription
- System enforces credit availability before allowing interview creation
My current deployment approach prioritizes simplicity, cost-efficiency, and flexibility:
- Primary/Early deployment via Fly.io — Ideal for rapid iteration, minimal infrastructure overhead, and a smooth path to initial user feedback. This is my default platform for going to market quickly.
- AWS ECS Fargate + ALB fully configured — I’ve pre-wired an AWS deployment path using ECS, ALB, and ACM certificates. This allows me to scale seamlessly by simply pointing DNS to the ALB once traffic or organizational needs warrant it.
- Manual deploy for now — To avoid accidental production pushes, I’ve chosen manual deployment. I’ll revisit full CD/staging setup as traffic/updates warrant it.
The project uses a GitHub Actions CI workflow to enforce code quality and test reliability. Every push and pull request to the main
branch triggers:
- Linting (
go vet
) to catch potential bugs - Integration Tests (
make test
) against a Dockerized PostgreSQL test database - Environment Setup: Test environment variables are injected securely during the workflow
- Isolation: No production deployment is automatically triggered to maintain staging integrity
- Application Hosting: Fly.io (containerized deployment)
- Frontend Hosting: Vercel
- Database: Supabase PostgreSQL
- Environment Variables: Managed through Fly.io secrets
- Future Prod: AWS - ALB/ECS/Fargate - Deployment infra is available under
infra/aws/
andinfra/ecs/
- Build Docker container using the included Dockerfile
- Push to Fly.io platform
- Configure environment variables for production
# Deploy to Fly.io
fly launch
fly secrets set JWT_SECRET=your-secret DATABASE_URL=your-supabase-url OPENAI_API_KEY=your-api-key
fly deploy
- Go 1.20+
- PostgreSQL 15+
- Docker (optional, for containerized development)
-
Clone the repository
git clone https://github.com/yourusername/interviewer.git cd interviewer
-
Install dependencies
go mod download
-
Set up environment variables
cp .env.example .env # Edit .env with your configuration
-
Create the database
# Create PostgreSQL database named 'interviewerio' createdb interviewerio # Apply migrations # Either manually execute SQL files in database/migrations or use a migration tool
-
Run the application
go run main.go
docker build -t interviewer .
docker run -p 8080:8080 --env-file .env interviewer
- Password Hashing: Passwords are securely hashed and never stored in plaintext
- JWT Authentication: Short-lived access tokens with refresh token rotation
- Prepared Statements: All database queries use prepared statements to prevent SQL injection
- CORS Configuration: Configured to restrict origins in production environments
- Environment Variables: Sensitive configuration stored in environment variables
The app is tested with both unit tests (mocked repositories) and integration tests (real PostgreSQL + full HTTP stack).
- Unit Tests: Every core domain (
user
,token
,interview
,conversation
) is covered using table-driven tests and a mock repository layer. This verifies business logic independently from the database. - Integration Tests:
handlers/handlers_test.go
validates full end-to-end request flows using a Dockerized PostgreSQL test database. TheMakefile
automates setup, teardown, and migration steps to simulate a production-like environment.
Tests are run consistently during development and are integrated into the CI pipeline to ensure correctness, stability, and maintainability.
https://github.com/MichaelBoegner/interviewer-ui
Copyright (c) 2024 Michael Boegner
This source code is proprietary. All rights reserved. No part of this code may be reproduced, distributed, or used without explicit permission from the author.
Created by Michael Boegner - GitHub Profile