Skip to main content

Architecture Diagram

InterviewGuide is built as a modular monolithic application with clear separation of concerns between frontend, backend, and infrastructure layers. System Architecture

High-Level Architecture

The system follows a layered architecture pattern:

Frontend Layer

React 18.3 + TypeScript 5.6 SPA with Vite 5.4 build system

Backend Layer

Spring Boot 4.0 + Java 21 with modular service architecture

Data Layer

PostgreSQL + pgvector for relational and vector data storage

Project Structure

The backend follows a modular architecture organized by business domain:
app/src/main/java/interview/guide/
├── App.java                      # Main application entry point
├── common/                       # Shared utilities and abstractions
│   ├── ai/                       # AI integration utilities
│   ├── annotation/               # Custom annotations (e.g., @RateLimit)
│   ├── aspect/                   # AOP aspects for cross-cutting concerns
│   ├── async/                    # Abstract base classes for async processing
│   │   ├── AbstractStreamProducer.java
│   │   └── AbstractStreamConsumer.java
│   ├── config/                   # Application configuration
│   ├── constant/                 # Constants and enums
│   ├── exception/                # Global exception handling
│   ├── model/                    # Shared domain models
│   └── result/                   # Unified API response wrapper
├── infrastructure/               # Technical infrastructure services
│   ├── export/                   # PDF export functionality (iText 8)
│   ├── file/                     # File parsing (Apache Tika)
│   ├── mapper/                   # Entity-DTO mapping (MapStruct)
│   └── redis/                    # Redis service wrapper (Redisson)
└── modules/                      # Business domain modules
    ├── interview/                # Mock interview functionality
    │   ├── listener/             # Stream consumers/producers
    │   ├── model/                # Domain entities and DTOs
    │   ├── repository/           # JPA repositories
    │   └── service/              # Business logic services
    ├── knowledgebase/            # RAG knowledge base
    │   ├── listener/             # Vector processing streams
    │   ├── model/                # Knowledge base entities
    │   ├── repository/           # Data access layer
    │   └── service/              # KB management services
    └── resume/                   # Resume analysis
        ├── listener/             # Async analysis streams
        ├── model/                # Resume entities
        ├── repository/           # Resume data access
        └── service/              # Analysis services

Core Components

1. Module Architecture

Each business module (resume, interview, knowledgebase) follows a consistent structure:
Controller Layer: REST API endpoints
  • Request validation
  • Response formatting
  • HTTP-level concerns
Service Layer: Business logic
  • Domain operations
  • Transaction management
  • Orchestration between components
Repository Layer: Data persistence
  • JPA repositories for database access
  • Query methods and specifications
Listener Layer: Async processing
  • Stream producers for task queuing
  • Stream consumers for background processing
Model Layer: Domain objects
  • JPA entities for database mapping
  • DTOs for API communication
  • Request/Response objects

2. Common Infrastructure

Shared components provide cross-cutting functionality:
Template-based pattern using abstract base classes:
  • AbstractStreamProducer<T>: Base for message producers
  • AbstractStreamConsumer<T>: Base for message consumers
  • Handles retries, state transitions, error handling
Located in: app/src/main/java/interview/guide/common/async/

Data Flow Patterns

Synchronous Request Flow

For immediate operations like querying data or initiating tasks:

Asynchronous Processing Flow

For long-running AI operations (resume analysis, vectorization, interview evaluation):

Component Interaction

Resume Analysis Module

Complete lifecycle from upload to completed analysis:
1

File Upload

User uploads resume file (PDF/DOCX/DOC/TXT)
  • File stored in S3-compatible storage (RustFS/MinIO)
  • Resume entity created with PENDING status
  • Content hash calculated for duplicate detection
2

Task Queuing

AnalyzeStreamProducer sends message to Redis Stream
  • Message includes: resumeId, content, retryCount
  • Stream key: resume:analyze:stream
  • Immediate response to client with task ID
3

Background Processing

AnalyzeStreamConsumer processes the task
  • Updates status to PROCESSING
  • Calls Spring AI with structured output parsing
  • Extracts: skills, experience, education, score
  • Saves analysis results to database
4

Completion

Status updated to COMPLETED or FAILED
  • Frontend polls GET /api/resumes/{id}/detail
  • Analysis results displayed with scores and suggestions
  • PDF export available via /api/resumes/{id}/export

Interview Module

Real-time mock interview with intelligent follow-ups:
Session-Based Architecture: Each interview session maintains state in Redis cache for fast access, with persistent storage in PostgreSQL for history and reporting.
  1. Session Creation: POST /api/interview/sessions creates a new session based on resume content
  2. Question Generation: AI generates initial question from resume analysis
  3. Answer Submission: POST /api/interview/sessions/{id}/answers with streaming SSE response
  4. Follow-up Questions: Configurable multi-turn conversation (default: 1 follow-up per main question)
  5. Batch Evaluation: Answers evaluated in batches (default: 8 per batch) to avoid token limits
  6. Report Generation: Async aggregation of evaluation results into PDF report

Knowledge Base Module

RAG-powered question answering system:

Document Ingestion

  • Apache Tika parses PDF/DOCX/Markdown
  • Content chunked with overlap for context
  • Async vectorization via Redis Stream
  • Embeddings stored in pgvector

Query Processing

  • Question converted to embedding vector
  • Similarity search in pgvector
  • Top-k relevant chunks retrieved
  • LLM generates answer with context
  • Streaming response via SSE

State Management

Async Task State Machine

All async operations follow this state flow:
PENDING → PROCESSING → COMPLETED

                  FAILED (with retry)
State Transitions:
  • PENDING: Task queued, waiting for consumer
  • PROCESSING: Consumer actively processing
  • COMPLETED: Successfully finished
  • FAILED: Failed after max retries (3 attempts)
States are stored in database and can be polled via API endpoints.

Technology Choices

Architecture Simplification: Redis Stream provides sufficient messaging capabilities without the operational overhead of Kafka:
  • Consumer groups for load distribution
  • Message acknowledgment and replay
  • Built-in persistence and recovery
  • Lower resource requirements
  • Single dependency for both caching and messaging
Kafka would be overkill for this scale and adds unnecessary complexity.
Unified Data Store: Using PostgreSQL with pgvector extension eliminates need for separate vector database:
  • Single source of truth for relational and vector data
  • ACID transactions across all data types
  • Simplified deployment and backup
  • SQL joins between vectors and metadata
  • Sufficient performance for application scale (under 10k documents)
Dedicated vector DBs (Pinecone, Milvus) offer better performance at massive scale but add operational complexity.

Next Steps

Tech Stack

Detailed breakdown of all technologies and version dependencies

Async Processing

Deep dive into Redis Streams implementation with code examples

Build docs developers (and LLMs) love