← Selected engineering work
CASE STUDY / 01

Go · AI integration · Concurrent services

JobGen

An AI-assisted job platform that aggregates remote roles, matches them to candidate profiles, and supports CV improvement workflows.

01

Overview

The system, not just the screen.

JobGen combines a Go backend with a React and TypeScript client. The backend coordinates job ingestion, matching, CV processing, AI calls, authentication, and storage behind REST APIs.

Problem

Remote roles are fragmented across sources, and early-career candidates need a clearer way to understand how their profile maps to each opportunity.

My work

Built the backend service structure and web product around job aggregation, profile-based matching, CV workflows, and AI-service integration.

02

Architecture

How data moves through the system.

  1. 01React + TypeScriptCV and job-search experience
  2. 02Go REST APIAuth, orchestration, validation
  3. 03Domain servicesAggregation, matching, CV workflows
  4. 04Data & integrationsMongoDB, Redis, MinIO, Gemini, job sources
03

Engineering

Decisions and constraints.

Selected decisions

  1. 01

    Run independent job-source adapters concurrently with goroutines and sync.WaitGroup, then collect failures without discarding successful sources.

  2. 02

    Keep source-specific scraping behind interfaces so sources can be registered or removed without rewriting the aggregation flow.

  3. 03

    Separate deterministic skill, experience, and location scoring from AI-assisted CV features.

  4. 04

    Use Redis for cache/session concerns and MongoDB for application data; keep object storage behind MinIO-compatible APIs.

Challenges

  • Normalizing inconsistent job descriptions and skill labels across multiple external sources.
  • Bounding slow external work with context deadlines and keeping partial source failures visible.
  • Balancing explainable matching rules with AI-assisted workflows.
representative_flow.go
group, failures := sync.WaitGroup{}, make(chan error, len(sources))
for name, source := range sources {
    group.Add(1)
    go func() {
        defer group.Done()
        if err := aggregate(ctx, source); err != nil {
            failures <- fmt.Errorf("%s: %w", name, err)
        }
    }()
}
04

Stack & evidence

What it was built with.

  • Go
  • Gin
  • MongoDB
  • Redis
  • MinIO
  • React
  • TypeScript
  • Docker
  • GitHub Actions