Overview
InterviewGuide leverages modern Java and TypeScript ecosystems with carefully selected libraries optimized for AI-powered applications.
Backend Stack
Core Framework
Spring Boot 4.0.1
Java 21
Gradle 8.14
Latest major version with enhanced modularity Spring Boot 4.0 introduces significant improvements:
Java 21 LTS baseline : Virtual threads, pattern matching, records
Modular starters : Fine-grained dependency control
Native compilation : GraalVM native image support
Observability : Built-in metrics and tracing
// From build.gradle
plugins {
id 'org.springframework.boot' version '4.0.1'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
Key Configuration (app/src/main/resources/application.yml):spring :
application :
name : interview-guide
datasource :
url : jdbc:postgresql://localhost:5432/interview_guide
username : postgres
password : ${POSTGRES_PASSWORD}
driver-class-name : org.postgresql.Driver
jpa :
hibernate :
ddl-auto : update # create for first run, then update
properties :
hibernate :
dialect : org.hibernate.dialect.PostgreSQLDialect
Long-Term Support release with modern language features Java 21 enables cleaner, more maintainable code:
Virtual Threads (Project Loom) : Lightweight concurrency for high-throughput async operations
Record Classes : Immutable data carriers (used in producers/consumers)
Pattern Matching : Enhanced switch expressions and instanceof
Sequenced Collections : Predictable iteration order
// Using records for immutable payloads
record AnalyzeTaskPayload ( Long resumeId, String content) {}
// Virtual threads for consumer pools (Spring Boot 4.0 auto-configures)
@ Bean
ExecutorService executor () {
return Executors . newVirtualThreadPerTaskExecutor ();
}
// From build.gradle
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
Modern build tool with Kotlin DSL support Gradle chosen over Maven for:
Incremental builds : Faster compilation times
Version catalogs : Centralized dependency management
Better IDE integration : IntelliJ IDEA optimization
Flexible plugin system : Custom build logic
# gradle/libs.versions.toml
[ versions ]
spring-boot = "4.0.1"
spring-ai = "2.0.0-M1"
tika = "2.9.2"
lombok = "1.18.36"
redisson = "4.0.0"
mapstruct = "1.6.3"
aws-sdk = "2.29.51"
itext = "8.0.5"
[ libraries ]
tika-core = { module = "org.apache.tika:tika-core" , version.ref = "tika" }
tika-parsers = { module = "org.apache.tika:tika-parsers-standard-package" , version.ref = "tika" }
AI Integration
Spring AI 2.0.0-M1 provides a unified abstraction over multiple LLM providers, allowing easy switching between OpenAI, Azure OpenAI, AWS Bedrock, and Alibaba DashScope.
// Spring AI dependencies
implementation "org.springframework.ai:spring-ai-starter-model-openai:2.0.0-M1"
implementation "org.springframework.ai:spring-ai-starter-vector-store-pgvector:2.0.0-M1"
Why Spring AI?
Unified API Single interface for multiple LLM providers:
OpenAI GPT-4
Azure OpenAI
Alibaba Qwen (DashScope)
AWS Bedrock
Switch providers with configuration, no code changes.
Vector Store Integration Native support for vector databases:
pgvector (PostgreSQL)
Pinecone
Chroma
Weaviate
Automatic embedding and similarity search.
Structured Output Type-safe response parsing: @ JsonClassDescription ( "Resume analysis" )
record ResumeAnalysis (
@ JsonProperty ( required = true )
int overallScore,
@ JsonProperty ( required = true )
List < String > skills
) {}
// Spring AI handles JSON schema generation
ResumeAnalysis result = chatClient . call (
prompt, ResumeAnalysis . class
);
Streaming Support Server-Sent Events (SSE) for real-time responses: Flux < String > stream = chatClient
. stream (prompt)
. map (ChatResponse :: getContent);
return SseEmitter . event ()
. data (stream);
Configuration (application.yml):
spring :
ai :
openai :
# OpenAI-compatible API (Alibaba DashScope)
base-url : https://dashscope.aliyuncs.com/compatible-mode/v1
api-key : ${AI_BAILIAN_API_KEY}
chat :
options :
model : ${AI_MODEL:qwen-plus}
temperature : 0.7
vectorstore :
pgvector :
initialize-schema : true # Auto-create vector_store table
index-type : HNSW # Hierarchical Navigable Small World
distance-type : COSINE_DISTANCE
dimensions : 1536 # OpenAI embedding dimension
Database Layer
PostgreSQL 14+
pgvector Extension
Spring Data JPA
Production-grade relational database with vector extension PostgreSQL selected for:
ACID compliance : Reliable transactions
Rich data types : JSONB, arrays, full-text search
pgvector extension : Native vector storage and similarity search
Mature ecosystem : Excellent tooling and community support
Schema Initialization :-- Enable pgvector extension
CREATE EXTENSION IF NOT EXISTS vector ;
-- Spring AI auto-creates this table
CREATE TABLE vector_store (
id UUID PRIMARY KEY ,
content TEXT ,
metadata JSONB,
embedding vector ( 1536 ) -- OpenAI embedding size
);
-- HNSW index for fast similarity search
CREATE INDEX ON vector_store
USING hnsw (embedding vector_cosine_ops);
Native vector operations in PostgreSQL pgvector provides:
Vector data type : Store embeddings directly in table columns
Distance functions : Cosine, L2 (Euclidean), inner product
Index types : IVFFlat (faster inserts), HNSW (faster queries)
SQL integration : Query vectors with standard SQL
Why pgvector over dedicated vector DB? Requirement pgvector Pinecone/Milvus Setup complexity Low (single extension) High (separate service) Data consistency ACID transactions Eventually consistent Join queries Native SQL joins Application-level joins Scale (< 10M vectors) Sufficient Overkill Operational cost Single DB to maintain Multiple services
Performance Characteristics :-- Similarity search query (Spring AI generates this)
SELECT id, content, metadata,
1 - (embedding <=> '[0.1, 0.2, ...]' ) AS similarity
FROM vector_store
WHERE 1 - (embedding <=> '[0.1, 0.2, ...]' ) > 0 . 7
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 5 ;
HNSW index : O(log n) approximate nearest neighbor search
Recall rate : 95%+ for typical RAG applications
Throughput : 1000+ QPS for knowledge base scale
ORM layer for entity management @ Entity
@ Table ( name = "resumes" )
public class ResumeEntity {
@ Id
@ GeneratedValue ( strategy = GenerationType . IDENTITY )
private Long id ;
private String fileName ;
@ Enumerated ( EnumType . STRING )
private AsyncTaskStatus analyzeStatus ; // PENDING/PROCESSING/COMPLETED/FAILED
@ Column ( columnDefinition = "TEXT" )
private String content ;
@ Column ( columnDefinition = "TEXT" )
private String analyzeError ;
// Analysis results stored as JSON
@ Type ( JsonType . class )
@ Column ( columnDefinition = "jsonb" )
private ResumeAnalysisResponse analysis ;
}
Repository Pattern :public interface ResumeRepository extends JpaRepository < ResumeEntity , Long > {
// Custom query methods
List < ResumeEntity > findByAnalyzeStatus ( AsyncTaskStatus status );
@ Query ( "SELECT r FROM ResumeEntity r WHERE r.contentHash = :hash" )
Optional < ResumeEntity > findByContentHash (@ Param ( "hash" ) String hash );
}
Redis Layer
Redisson 4.0.0 - Advanced Redis Java client with Spring Boot 4.0 compatibility
implementation "org.redisson:redisson-spring-boot-starter:4.0.0"
Dual Purpose Architecture :
Caching Layer
Message Queue (Stream)
Session cache for interview state spring :
redis :
redisson :
config : |
singleServerConfig:
address: "redis://localhost:6379"
database: 0
connectionPoolSize: 64
connectionMinimumIdleSize: 10
@ Service
public class InterviewSessionCache {
private final RedisService redisService ;
private static final Duration SESSION_TTL = Duration . ofHours ( 2 );
public void cacheSession ( String sessionId , InterviewSession session ) {
String key = "interview:session:" + sessionId;
redisService . set (key, session, SESSION_TTL);
}
public InterviewSession getSession ( String sessionId ) {
String key = "interview:session:" + sessionId;
return redisService . get (key);
}
}
Why Redis cache over ConcurrentHashMap?
Shared state : Multiple backend instances can access same cache
TTL management : Automatic expiration of old sessions
Persistence : Survives application restarts
Memory limits : Eviction policies prevent OOM
Async task processing with Redis Streams // Create consumer group (app/infrastructure/redis/RedisService.java:255)
public void createStreamGroup ( String streamKey, String groupName) {
RStream < String , String > stream = redissonClient . getStream (streamKey, StringCodec . INSTANCE );
stream . createGroup ( StreamCreateGroupArgs . name (groupName). makeStream ());
}
// Producer sends task (app/common/async/AbstractStreamProducer.java:22)
protected void sendTask ( T payload) {
String messageId = redisService . streamAdd (
streamKey (),
buildMessage (payload),
AsyncTaskStreamConstants . STREAM_MAX_LEN // 1000 messages
);
}
// Consumer processes task with blocking read (app/infrastructure/redis/RedisService.java:222)
public boolean streamConsumeMessages (
String streamKey, String groupName, String consumerName,
int count, long blockTimeoutMs,
StreamMessageProcessor processor) {
RStream < String , String > stream = redissonClient . getStream (streamKey, StringCodec . INSTANCE );
// BLOCK parameter offloads waiting to Redis server
Map < StreamMessageId , Map < String , String >> messages = stream . readGroup (
groupName, consumerName,
StreamReadGroupArgs . neverDelivered ()
. count (count)
. timeout ( Duration . ofMillis (blockTimeoutMs)) // 1000ms
);
messages . forEach ((id, data) -> processor . process (id, data));
return ! messages . isEmpty ();
}
Why Redis Stream over Kafka? Feature Redis Stream Kafka Setup Single Redis instance Zookeeper + Kafka cluster Memory ~100MB ~1GB+ per broker Consumer groups ✅ Yes ✅ Yes Message ACK ✅ Yes ✅ Yes (commit offsets) Persistence ✅ AOF/RDB ✅ Log segments Latency under 1ms ~5ms Throughput (this app) 1000+ msg/s 100k+ msg/s Use case fit Perfect for under 10k msg/s Overkill for this scale
Document Processing
Apache Tika 2.9.2
iText 8.0.5
Universal document parser implementation 'org.apache.tika:tika-core:2.9.2'
implementation 'org.apache.tika:tika-parsers-standard-package:2.9.2'
Tika handles multiple formats:
PDF : Using Apache PDFBox
Microsoft Office : DOCX, DOC, XLSX, PPTX
OpenOffice : ODT, ODS, ODP
Plain text : TXT, CSV, Markdown
HTML/XML : Web documents
@ Service
public class FileParsingService {
private final AutoDetectParser parser = new AutoDetectParser ();
public String extractText ( InputStream input ) throws Exception {
BodyContentHandler handler = new BodyContentHandler ( - 1 ); // No limit
Metadata metadata = new Metadata ();
ParseContext context = new ParseContext ();
parser . parse (input, handler, metadata, context);
return handler . toString ();
}
}
Supported Resume Formats :
PDF (most common)
DOCX (Microsoft Word 2007+)
DOC (legacy Word)
TXT (plain text)
PDF generation for reports implementation "com.itextpdf:itext-core:8.0.5"
implementation "com.itextpdf:font-asian:8.0.5" // Chinese font support
Features :
Custom fonts : Bundled Chinese font (珠圆玉润仿宋)
Complex layouts : Tables, charts, nested sections
PDF/A compliance : Long-term archival format
Digital signatures : Optional document signing
@ Service
public class PdfExportService {
private final PdfFont chineseFont ;
@ PostConstruct
public void init () throws IOException {
// Load custom font from resources
InputStream fontStream = getClass ()
. getResourceAsStream ( "/fonts/ZhuqueFangsong-Regular.ttf" );
this . chineseFont = PdfFontFactory . createFont (
fontStream . readAllBytes (),
PdfEncodings . IDENTITY_H // Unicode encoding
);
}
public byte [] generateResumeAnalysisPdf ( ResumeAnalysis analysis ) {
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
PdfWriter writer = new PdfWriter (baos);
PdfDocument pdf = new PdfDocument (writer);
Document document = new Document (pdf);
// Add styled content
document . add ( new Paragraph ( "简历分析报告" )
. setFont (chineseFont)
. setFontSize ( 20 )
. setBold ());
// Add analysis sections...
document . close ();
return baos . toByteArray ();
}
}
Utilities
MapStruct 1.6.3 Compile-time object mapping implementation "org.mapstruct:mapstruct:1.6.3"
annotationProcessor "org.mapstruct:mapstruct-processor:1.6.3"
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
@ Mapper ( componentModel = "spring" )
public interface ResumeMapper {
ResumeDTO toDTO ( ResumeEntity entity );
@ Mapping ( target = "id" , ignore = true )
ResumeEntity toEntity ( ResumeCreateRequest request );
}
Why MapStruct over manual mapping?
Type-safe at compile time
Zero reflection overhead
Auto-generated code visible in IDE
Lombok integration
Lombok 1.18.36 Boilerplate reduction compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
@ Slf4j // Auto-generates logger
@ Service
@ RequiredArgsConstructor // Constructor for final fields
public class ResumeService {
private final ResumeRepository repository ;
private final FileParsingService fileParser ;
public void processResume ( MultipartFile file ) {
log . info ( "Processing resume: {}" , file . getOriginalFilename ());
// ...
}
}
Storage
S3-compatible object storage implementation "software.amazon.awssdk:s3:2.29.51"
app :
storage :
endpoint : http://localhost:9000 # RustFS or MinIO
access-key : ${APP_STORAGE_ACCESS_KEY}
secret-key : ${APP_STORAGE_SECRET_KEY}
bucket : interview-guide
region : us-east-1
@ Service
public class S3StorageService {
private final S3Client s3Client ;
public String uploadFile ( String key , InputStream input , long size ) {
PutObjectRequest request = PutObjectRequest . builder ()
. bucket (bucketName)
. key (key)
. contentLength (size)
. build ();
s3Client . putObject (request, RequestBody . fromInputStream (input, size));
return generatePublicUrl (key);
}
}
Supported storage backends :
RustFS : Lightweight S3-compatible server (Docker deployment)
MinIO : Self-hosted S3-compatible storage
AWS S3 : Production cloud storage
Alibaba OSS : China region deployment
Frontend Stack
Core Framework
// frontend/package.json
{
"dependencies" : {
"react" : "^18.3.1" ,
"react-dom" : "^18.3.1" ,
"react-router-dom" : "^7.11.0" ,
"typescript" : "~5.6.2" ,
"vite" : "^5.4.10"
}
}
React 18.3
TypeScript 5.6
Vite 5.4
Modern UI library with concurrent features
Concurrent rendering : Automatic batching, transitions
Suspense : Declarative loading states
Server Components : Future-ready architecture
Hooks : Functional component patterns
Type-safe JavaScript // src/types/resume.ts
export interface ResumeAnalysis {
id : number ;
fileName : string ;
analyzeStatus : 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED' ;
overallScore : number ;
skills : string [];
experience : ExperienceItem [];
}
export interface ExperienceItem {
company : string ;
position : string ;
duration : string ;
description : string ;
}
Lightning-fast build tool
Instant server start : ES modules in dev mode
Hot Module Replacement : Sub-millisecond updates
Optimized builds : Rollup-based production bundles
TypeScript : Native TS support without config
// vite.config.ts
export default defineConfig ({
plugins: [ react ()] ,
server: {
port: 5173 ,
proxy: {
'/api' : {
target: 'http://localhost:8080' ,
changeOrigin: true
}
}
}
}) ;
UI Libraries
Tailwind CSS 4.1 Utility-first CSS framework "@tailwindcss/postcss" : "^4.1.18" ,
"@tailwindcss/typography" : "^0.5.15"
< div className = "max-w-4xl mx-auto p-6 bg-white rounded-lg shadow-md" >
< h1 className = "text-2xl font-bold text-gray-800 mb-4" >
Resume Analysis
</ h1 >
</ div >
Framer Motion 12.23 Declarative animations < motion.div
initial = { { opacity: 0 , y: 20 } }
animate = { { opacity: 1 , y: 0 } }
transition = { { duration: 0.3 } }
>
{ /* Content */ }
</ motion.div >
Recharts 3.6 React charting library < RadarChart data = { skillsData } >
< PolarGrid />
< PolarAngleAxis dataKey = "skill" />
< Radar dataKey = "score" fill = "#8884d8" />
</ RadarChart >
Lucide React 0.468 Beautiful icon library import { FileText , Upload , Download } from 'lucide-react' ;
< Upload className = "w-5 h-5" />
Advanced Features
React Markdown 9.0
React Virtuoso 4.18
Axios 1.7.7
Markdown rendering with syntax highlighting "react-markdown" : "^9.0.1" ,
"react-syntax-highlighter" : "^16.1.0" ,
"remark-gfm" : "^4.0.0" ,
"remark-breaks" : "^4.0.0"
import ReactMarkdown from 'react-markdown' ;
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' ;
< ReactMarkdown
remarkPlugins = { [ remarkGfm , remarkBreaks ] }
components = { {
code ({ node , inline , className , children , ... props }) {
const match = /language- ( \w + ) / . exec ( className || '' );
return ! inline && match ? (
< SyntaxHighlighter language = { match [ 1 ] } PreTag = "div" >
{ String ( children ). replace ( / \n $ / , '' ) }
</ SyntaxHighlighter >
) : (
< code className = { className } { ... props } >
{ children }
</ code >
);
}
} }
>
{ content }
</ ReactMarkdown >
Virtual scrolling for chat history Efficiently renders large lists (1000+ messages): import { Virtuoso } from 'react-virtuoso' ;
< Virtuoso
data = { messages }
itemContent = { ( index , message ) => (
< ChatMessage key = { message . id } message = { message } />
) }
followOutput = "smooth" // Auto-scroll to bottom
initialTopMostItemIndex = { messages . length - 1 }
/>
Performance benefit : Renders only visible items, constant O(1) memoryHTTP client with interceptors // src/api/client.ts
import axios from 'axios' ;
const apiClient = axios . create ({
baseURL: '/api' ,
timeout: 30000
});
// Request interceptor
apiClient . interceptors . request . use ( config => {
// Add auth token if exists
const token = localStorage . getItem ( 'token' );
if ( token ) {
config . headers . Authorization = `Bearer ${ token } ` ;
}
return config ;
});
// Response interceptor
apiClient . interceptors . response . use (
response => response . data ,
error => {
if ( error . response ?. status === 401 ) {
// Redirect to login
}
return Promise . reject ( error );
}
);
Version Matrix
Backend Dependencies
Component Version Release Date Support Until Java 21 LTS Sep 2023 Sep 2031 (8 years) Spring Boot 4.0.1 Nov 2024 Nov 2026 Spring AI 2.0.0-M1 Milestone TBD PostgreSQL 14+ Sep 2021 Nov 2026 Redis 6+ May 2020 Active Redisson 4.0.0 2024 Active Apache Tika 2.9.2 Sep 2023 Active iText 8.0.5 2024 Commercial MapStruct 1.6.3 2024 Active Lombok 1.18.36 2024 Active
Frontend Dependencies
Component Version Release Date LTS Status React 18.3.1 Apr 2024 Stable TypeScript 5.6.2 Sep 2024 Stable Vite 5.4.10 Oct 2024 Stable Tailwind CSS 4.1.18 Jan 2025 Stable React Router 7.11.0 Jan 2025 Stable Framer Motion 12.23.26 Jan 2025 Stable
Next Steps
Architecture Overview Understand the overall system design and component interactions
Async Processing Deep dive into Redis Streams implementation patterns