Loading…
Loading…
Preplify: AI Interview Prep is a production-focused software project built by Sadam Hussain using Next.js, TypeScript, Node.js, and related technologies.
Production multi-provider LLM interview platform on Next.js and TypeScript: OpenAI and Gemini behind one orchestration layer, GraphQL for relational data, REST for AI workflows, WebSocket-driven sessions. AI interviewer: practice with an AI, get structured feedback. Outcome: failover-safe AI that degrades gracefully instead of failing loudly.
Tech Stack

Status
Production Ready
Type
Enterprise platform
Architected and delivered a scalable headless Next.js + TypeScript platform for AI-driven interview preparation, supporting concurrent users in a high-traffic, production-grade environment.
Designed a multi-provider LLM orchestration layer integrating OpenAI and Gemini APIs with provider-agnostic abstractions, enabling seamless failover and model switching without client-side changes.
Architected a hybrid API layer combining GraphQL (for complex relational queries like user history, session analytics, and role-based content) with REST endpoints (for high-throughput, stateless AI inference requests), each optimized for its specific access pattern.
Implemented strict API versioning and comprehensive error handling across all service boundaries, including retry logic with exponential backoff for LLM provider rate limits and transient failures.
Engineered 30+ reusable atomic UI components with Tailwind CSS following a systematic design token approach, establishing a consistent design system that accelerated frontend feature delivery across the platform.
Built real-time mock interview communication using WebSockets with automatic reconnection, heartbeat monitoring, and graceful degradation to polling when persistent connections are unavailable.
Implemented multi-step interview state management using Zustand with middleware for session persistence, enabling users to resume interrupted practice sessions with full context restoration.
Integrated Clerk Auth for secure authentication with role-based access control, session management, and OAuth provider support across the platform.
Optimized rendering performance through strategic use of SSR for SEO-critical pages, ISR for semi-dynamic content, and client-side rendering for interactive interview flows, with code-splitting at the route level.
Established a comprehensive testing pyramid with Jest and React Testing Library for unit/integration coverage, Playwright for end-to-end critical path validation, and GitHub Actions for automated CI/CD with Docker-based deployments to AWS.
Preplify is a production AI interview platform. Candidates practice with an AI interviewer that adapts to their role and history, then get structured feedback on clarity, depth, and reasoning. Under the hood: OpenAI and Gemini behind one orchestration layer with failover, retries, and streaming, so a provider outage never ends a session.
Traditional interview preparation often relies on static question banks that fail to mirror the dynamic, unpredictable nature of real conversations. Candidates practice with fixed questions and generic answers, which doesn't build the adaptive thinking that interviewers actually evaluate.
Preplify was built to solve this by providing a "living" preparation environment where every session is unique and contextually tailored.
The core problem: Static preparation creates a false sense of readiness. Candidates memorize answers instead of developing the ability to think on their feet under pressure.
Key product objectives:
Constraints that shaped the architecture:
The LLM integration isn't a bolt-on feature - it's a core architectural concern with its own abstraction layer, error handling strategy, and monitoring. The orchestration layer sits between the API routes and the LLM providers, handling prompt composition, response parsing, token usage tracking, and provider health monitoring. This separation means the rest of the application treats AI capabilities as a reliable internal service rather than dealing with the complexity of external API integration directly.
Not all pages are rendered the same way. The architecture uses a deliberate per-route rendering strategy:
Clerk Auth provides the identity layer with OAuth support (Google, GitHub), session management, and JWT-based API authentication. Role-based access control gates premium features and admin functionality. The integration is designed so that authentication state is available both server-side (for SSR pages) and client-side (for interactive flows) without duplication.
Zustand was chosen over Redux for its minimal boilerplate and natural fit with React's hook-based patterns. The state architecture separates concerns into discrete stores:
The most architecturally interesting challenge in Preplify is the LLM orchestration pipeline - making AI feel "native" rather than bolted-on.
The Problem: LLM APIs are inherently unreliable compared to traditional REST services. They have variable latency (sometimes 200ms, sometimes 8 seconds), strict rate limits, occasional downtime, and different response formats across providers. Building a production interview platform on top of this requires treating LLM integration as a distributed systems problem, not a simple API call.
The Architecture: The orchestration layer is structured as a pipeline with distinct stages:
Context Assembly: Before any LLM call, the system assembles the full context - user's target role, experience level, practice history, current session state, and any previous answers in the current interview. This context is structured as a typed object, not a raw string, ensuring consistency.
Prompt Composition: System prompts are templated and versioned. Each question type (behavioral, technical, system design) has its own prompt template with slots for dynamic context. This allows non-engineering team members to iterate on prompt quality by modifying templates without touching application code.
Provider Routing: A routing layer selects the appropriate LLM provider based on configurable rules - question complexity, current provider health, and cost considerations. Simple follow-up questions might route to a faster, cheaper model, while initial question generation uses a more capable one.
Response Handling: LLM responses are parsed, validated against expected schemas, and normalized into a provider-agnostic format before being passed to the application layer. Malformed responses trigger automatic retries with adjusted prompts.
Fallback Chain: If the primary provider fails, the system automatically retries with the secondary provider using equivalent prompts. The candidate never sees provider switching - they just experience a slightly longer response time.
Why this approach: Wrapping LLM calls in a simple try/catch and hoping for the best might work for a demo, but production traffic with real users requires the same rigor applied to any critical external dependency. The pipeline approach means each concern (context, prompting, routing, error handling) can be tested and evolved independently.
Challenge: LLM response latency varied wildly (200ms to 10+ seconds), making the interview experience feel inconsistent. Approach: Implemented streaming responses via server-sent events so users see feedback appearing in real-time. Added optimistic UI patterns where the interface transitions to "reviewing" state immediately while the AI generates its response. Why: Perceived performance matters more than actual latency. Streaming makes a 5-second response feel interactive rather than broken.
Challenge: Interview sessions are long-lived and stateful, but users frequently switch tabs, lose network connectivity, or close the browser accidentally. Approach: Built session state persistence using Zustand middleware that serializes to localStorage on every state change, with a reconciliation mechanism that merges persisted state with server state on reconnection. Why: Losing 20 minutes of interview practice due to an accidental tab close would be a major UX failure. The cost of persistence (minimal localStorage writes) is negligible compared to the value of session continuity.
Challenge: GraphQL and REST coexist in the same application, creating potential confusion about which to use for new endpoints. Approach: Established a clear convention: GraphQL for reads that involve relationships or flexible field selection, REST for writes and stateless AI operations. Documented the decision boundary so it's consistent across the team. Why: Hybrid API architectures can become messy without clear conventions. The key is making the choice obvious for each new endpoint rather than debating it every time.
Challenge: Different rendering strategies (SSR, ISR, CSR) across routes created complexity in data fetching and authentication patterns. Approach: Created wrapper components that abstract the rendering strategy from the page content. Each page declares its data requirements, and the wrapper handles whether that data comes from server props, incremental regeneration, or client-side fetching. Why: Without this abstraction, every page component would need to know whether it's server-rendered or client-rendered, leaking infrastructure concerns into UI code.
Preplify highlighted the technical maturity required to build AI-assisted production products. The key insight is that the AI model is the easy part - the hard part is everything around it: the orchestration layer that handles failure gracefully, the state management that keeps multi-step sessions coherent, and the delivery pipeline that ensures reliability at scale.
Patterns I'd reuse:
What I'd reconsider:
Trade-offs acknowledged: