Architecture Overview¶
High-Level Architecture¶
Recron (Blue Braces) is a microservices-based application for interview preparation, job search management, and CV portfolio building, orchestrated by .NET Aspire.
C4Context
title System Context Diagram
Person(user, "User", "Job seeker preparing for interviews")
System_Boundary(recron, "Recron Platform") {
System(webapp, "Web Application", "SolidJS SPA")
System(gateway, "API Gateway", "YARP Reverse Proxy")
System(questions, "Questions API", "Interview questions management")
System(organizer, "Organizer API", "Job offers & interviews tracking")
System(portfolio, "Portfolio API", "CV portfolio builder")
System(users, "Users API", "User profiles & auth")
}
System_Ext(keycloak, "Keycloak", "Identity Provider")
System_Ext(openai, "OpenAI", "AI-powered features")
Rel(user, webapp, "Uses")
Rel(webapp, gateway, "API calls")
Rel(gateway, questions, "Routes /questions/*")
Rel(gateway, organizer, "Routes /organizer/*")
Rel(gateway, portfolio, "Routes /portfolio/*")
Rel(gateway, users, "Routes /users/*")
Rel(questions, keycloak, "Authenticates")
Rel(questions, openai, "Generates answers")
Rel(organizer, openai, "Parses offers, matches CVs")
Rel(portfolio, openai, "Imports from LinkedIn/PDF")
Project Structure¶
├── Questions.Api/ # Interview questions management
├── Organizer.Api/ # Job offers & interviews tracking
├── Portfolio.Api/ # CV portfolio builder
├── Users.Api/ # User profiles & auth
├── Recron.AppHost/ # .NET Aspire orchestration
├── recron-web/ # SolidJS frontend
└── docs/ # MkDocs documentation
Shared libraries are consumed as NuGet packages from GitHub Packages:
| Package | Description |
|---|---|
Extensions.Application |
CQRS abstractions (ICommand, IQuery, handlers) |
Extensions.Domain |
Entities, domain abstractions, exceptions |
Extensions.Infrastructure |
Database, auth, caching, exception handling, cross-cutting concerns |
Architectural Patterns¶
CQRS (Command Query Responsibility Segregation)¶
Custom implementation without MediatR:
// Abstractions from Extensions.Application NuGet package
public interface ICommand { }
public interface ICommand<TResponse> { }
public interface IQuery<TResponse> { }
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
Task ExecuteAsync(TCommand command, CancellationToken ct = default);
}
public interface IQueryHandler<TQuery, TResponse> where TQuery : IQuery<TResponse>
{
Task<TResponse> ExecuteAsync(TQuery query, CancellationToken ct = default);
}
ICommand<TResponse> is used when a mutation must return data (e.g., AI calls that write and return results).
Vertical Slices¶
Each feature in /Features/{Feature}/{Action}/:
Features/
├── Questions/
│ ├── ProposeQuestion/
│ │ ├── ProposeQuestionEndpoint.cs
│ │ ├── ProposeQuestionCommand.cs
│ │ ├── ProposeQuestionHandler.cs
│ │ └── ProposeQuestionRequest.cs
│ ├── ApproveQuestion/
│ ├── PromoteQuestion/
│ ├── AddToLearning/
│ ├── AskAi/
│ └── GetQuiz/
├── Categories/
│ └── GetCategories/
Clean Architecture¶
Layer dependencies (inner layers have no dependencies on outer). Extensions are consumed as NuGet packages:
graph TB
A[API Projects] --> B[Extensions.Infrastructure NuGet]
B --> C[Extensions.Domain NuGet]
B --> D[Extensions.Application NuGet]
style D fill:#e1f5fe
style C fill:#b3e5fc
style B fill:#81d4fa
style A fill:#4fc3f7
| Layer | Responsibility |
|---|---|
| Extensions.Application (NuGet) | CQRS interfaces only, no dependencies |
| Extensions.Domain (NuGet) | Entities, domain abstractions, exceptions |
| Extensions.Infrastructure (NuGet) | Database, auth, caching, logging, exception handling |
| API Projects | Endpoints, handlers, feature-specific logic |
NuGet packages from GitHub Packages
Extensions are maintained in a separate repository and consumed as NuGet packages.
Extensions.Application and Extensions.Domain are independent — neither references the other.
Only Extensions.Infrastructure references both, and API projects reference Extensions.Infrastructure.
Infrastructure Components¶
| Component | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL | Data persistence (separate DB per service) |
| Cache | HybridCache (in-memory) | In-process caching (configured, no distributed provider) |
| Identity | Keycloak | OIDC authentication, role management |
| Gateway | YARP | Reverse proxy, route aggregation |
| AI | OpenAI (gpt-4o-mini) | Answers, offer parsing, CV matching, CV import |
| Observability | OpenTelemetry + Serilog | Tracing, metrics, logging |
API Services¶
Questions API (14 endpoints)¶
Interview question management with categories, voting, learning lists, and quiz.
Key Features:
- Hierarchical categories
- Question proposal & moderation workflow (approve/reject)
- Promote (upvote) questions
- Personal learning lists
- AI-generated answers
- Quiz / flashcard sessions
Organizer API (23 endpoints)¶
Job application tracking with offers, interview scheduling, AI parsing, and statistics.
Key Features:
- Job offer management (New → Considered → Sent → Rejected)
- Interview scheduling with stages (Screening, Technical, HR, Offer, Onboarding)
- Reference data dictionaries via single dynamic endpoint (
/dictionaries/{route}) - AI offer parsing from URL or text
- AI CV-to-offer matching, scoring, and cover letter generation
- Offer comparison
- Offer duplication and drag & drop reordering
- Dashboard statistics
- Google Calendar OAuth integration for interview events
Portfolio API (7 endpoints)¶
CV portfolio builder with multiple variants and AI-powered import.
Key Features:
- Full CV structure (personal info, summary, experience, projects, skills, education, certifications, languages)
- Multiple named portfolio variants per user
- AI import from LinkedIn profile URL
- AI import from CV PDF upload
- AI ATS compatibility check
- JSONB document storage for flexible schema
Users API (3 endpoints)¶
User profile management and authentication details.
Key Features:
- Token details endpoint for debugging claims
- User profile (display name, bio, role, experience, skills, URLs)
- Profile get/save operations
AI Integration¶
Three services use AI via IChatClient from Microsoft.Extensions.AI:
| Service | Feature | Pattern | Description |
|---|---|---|---|
| Questions.Api | Ask AI | IQuery |
Generates answers for interview questions |
| Organizer.Api | Parse Offer AI | IQuery |
Extracts structured offer data from URL/text |
| Organizer.Api | Match CV | IQuery |
Scores CV-to-offer compatibility |
| Organizer.Api | Score Offer | ICommand<T> |
Rates offer attractiveness and fit |
| Organizer.Api | Generate Cover Letter | ICommand<T> |
Generates tailored cover letter for offer |
| Portfolio.Api | Parse LinkedIn | IQuery |
Imports portfolio from LinkedIn profile |
| Portfolio.Api | Parse CV PDF | IQuery |
Extracts portfolio data from PDF upload |
| Portfolio.Api | Check ATS | IQuery |
Checks CV compatibility with ATS systems |
All AI features follow the same implementation pattern:
- Build
List<ChatMessage>with system + user prompts - Call
chatClient.GetResponseAsync(chatHistory) - Parse
response.Textas JSON (usingCleanJsonResponse()to strip markdown fences)
Service Communication¶
sequenceDiagram
participant W as Webapp
participant G as Gateway (YARP)
participant Q as Questions API
participant O as Organizer API
participant P as Portfolio API
participant K as Keycloak
participant AI as OpenAI
participant DB as PostgreSQL
W->>K: Login (OIDC Authorization Code)
K-->>W: Access Token + Refresh Token
W->>G: GET /questions/categories (Bearer token)
G->>Q: Forward request
Q->>K: Validate JWT
Q->>DB: Query categories
DB-->>Q: Results
Q-->>G: JSON response
G-->>W: Categories data
Note over W,AI: AI Answer Generation
W->>G: GET /questions/ask-ai?questionId=xxx
G->>Q: Forward request
Q->>AI: Generate answer
AI-->>Q: Completion
Q->>DB: Save answer
Q-->>W: Answer response
Note over W,AI: AI Offer Parsing
W->>G: POST /organizer/offers/parse-ai
G->>O: Forward request
O->>AI: Parse offer from URL/text
AI-->>O: Structured offer data
O-->>W: ParseOfferResponse
Note over W,AI: Portfolio AI Import
W->>G: POST /portfolio/portfolios/parse-linkedin
G->>P: Forward request
P->>AI: Parse LinkedIn profile
AI-->>P: PortfolioData JSON
P-->>W: Imported portfolio data
Gateway Routes¶
| Route Pattern | Target Service |
|---|---|
/questions/** |
Questions API |
/organizer/** |
Organizer API |
/portfolio/** |
Portfolio API |
/users/** |
Users API |
/** |
Scalar API Reference (docs) |