Skip to content

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:

  1. Build List<ChatMessage> with system + user prompts
  2. Call chatClient.GetResponseAsync(chatHistory)
  3. Parse response.Text as JSON (using CleanJsonResponse() 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)