Skip to content

NtwariGB/Akazi

Repository files navigation

Akazi — Job Application Tracker & AI Agent

Akazi (mot Kirundi signifiant "travail") est un outil full-stack de suivi de candidatures, augmenté d'un agent IA autonome qui recherche des offres d'emploi, les fait correspondre au profil de chaque utilisateur et remplit son dashboard automatiquement.

Ce projet sert aussi de démonstrateur technique : architecture cloud, CI/CD, Infrastructure as Code, systèmes agentiques (LangGraph) et bonnes pratiques DevOps.


Aperçu

Dashboard avec candidatures créées par l'agent Le dashboard : les candidatures badgées « Assistant » ont été trouvées et créées par l'agent autonome.

Chat avec l'assistant L'assistant conversationnel : recherche d'offres en langage naturel, avec scores de matching sémantique.

Page Paramètres Les paramètres : activation de l'agent, recherches sauvegardées, fréquence d'exécution, thème.

Stack technique :

Couche Technologies
Backend Java 21, Spring Boot 4, Spring Security, JWT, JPA/Hibernate
Frontend Next.js 15, TypeScript, React 18, Tailwind CSS v4
Agent IA Python 3.12, FastAPI, LangGraph, Mistral AI, pgvector, fastembed, APScheduler, python-jobspy
Base de données PostgreSQL 16 (AWS RDS) — 2 bases : métier + vectorielle (pgvector)
Infrastructure AWS (VPC, EC2, RDS, S3, CloudFront), Terraform
CI/CD GitHub Actions (tests, build, deploy — 3 images Docker)
Conteneurisation Docker, Docker Compose, Docker Hub
Emails Spring Mail + Brevo (SMTP), Mailpit en dev
Tests JUnit 5 + JaCoCo (backend), Jest + RTL (frontend) — coverage > 80%

Architecture cloud

                     Internet
                        │
                   Elastic IP (13.62.12.231)
                        │
        ┌─────────── VPC 10.0.0.0/16 ───────────┐
        │                                         │
        │  ┌─ Subnet public A ─────────────────┐  │
        │  │  EC2 t3.small (Docker Compose)     │  │
        │  │  ├─ Frontend Next.js     :3000     │  │
        │  │  ├─ Backend Spring Boot  :8080     │  │
        │  │  └─ Agent IA FastAPI     :8002     │  │
        │  └───────────────────────────────────┘  │
        │              │ port 5432                 │
        │              ▼                           │
        │  ┌─ Subnet privé A ──────────────────┐  │
        │  │  RDS PostgreSQL 16                 │  │
        │  │  ├─ candidature (métier)           │  │
        │  │  └─ akazi_agent (pgvector)         │  │
        │  └───────────────────────────────────┘  │
        └─────────────────────────────────────────┘
                        │
                  Brevo (SMTP) → emails de vérification

Points clés :

  • La base de données est isolée dans un subnet privé, accessible uniquement depuis le backend
  • Les security groups segmentent les accès : le SG de la BDD n'accepte que le SG du backend
  • L'Elastic IP garantit une adresse fixe même après redémarrage de l'instance
  • Le state Terraform est stocké dans un bucket S3 distant avec verrouillage
  • Procédure de bootstrap d'une nouvelle instance : voir docs/DEPLOY.md

L'agent IA

L'agent est un microservice FastAPI orchestré par LangGraph : un nœud gardien classifie l'intention (offres, profil, CV, entretien, hors-sujet) et route vers le bon pipeline. Le matching offres ↔ profil repose sur des embeddings (fastembed, BAAI/bge-small) stockés dans pgvector avec recherche par similarité cosinus.

Deux modes :

  • Conversationnel — chat intégré au dashboard (drawer) : recherche d'offres en langage naturel avec suivi de contexte, conseils CV et préparation d'entretien ancrés sur des offres réelles (garde-fous : jamais d'expérience inventée)
  • Autonome — un scheduler (tick horaire) exécute pour chaque utilisateur, à la fréquence qu'il a choisie (6h à 7 jours) : scraping ciblé (métier/lieu/séniorité extraits par LLM) → matching sémantique → création des candidatures dans son dashboard (source=AGENT, badge « Assistant »)

Sécurité — délégation par utilisateur :

Utilisateur                 Backend                       Agent (service)
───────────────────────────────────────────────────────────────────────
active l'assistant ──►  crée un grant (révocable)
+ recherches + fréquence

                        GET /assistant/grants  ◄──  secret de service
                        renvoie, par grant actif,
                        un JWT scopé (actor=AGENT)
                                                ──►  agit pour chaque user
                                                     avec SON token
désactive          ──►  grant inactif → plus de token émis
  • L'agent ne détient aucun mot de passe utilisateur ; chaque token est scopé à un seul utilisateur et révocable indépendamment
  • Le backend force source=AGENT côté serveur (claim actor du JWT → ROLE_AGENT)
  • Les endpoints /chat et /profile de l'agent valident le JWT Akazi (profil par utilisateur)

Fonctionnalités

  • Authentification sécurisée (inscription, connexion, token JWT)
  • CRUD complet : candidatures et notes
  • Isolation des données par utilisateur (chaque user ne voit que ses propres candidatures)
  • Suivi par statut : À postuler · Postulé · Entretien · Offre · Refus
  • Priorités : Haute · Moyenne · Basse
  • Statistiques par utilisateur (taux de réponse, répartition par statut)
  • Validation des données entrantes avec messages d'erreur en français
  • DTOs et mappers pour sécuriser les réponses API (aucune donnée sensible exposée)
  • Gestion d'erreurs centralisée (GlobalExceptionHandler)

Architecture

src/main/java/com/emploi/candidature/
├── configuration/     # SecurityConfig, JwtFilter, SwaggerConfig
├── controller/        # AuthController, CandidatureController, NoteController, UserController
├── dto/               # Request & Response DTOs
├── entity/            # User, Candidature, Note, Statut, Priorite
├── exception/         # GlobalExceptionHandler
├── mapper/            # UserMapper, CandidatureMapper, NoteMapper
├── repository/        # JPA Repositories
└── service/           # UserService, CandidatureService, NoteService, JwtService

Prérequis

  • Java 21+
  • Docker & Docker Compose
  • Maven (ou utiliser le wrapper ./mvnw)

Lancement

1. Cloner le projet

git clone https://github.com/NtwariGB/Candidature.git
cd Candidature

2. Lancer la base de données

docker compose up -d

3. Configurer les variables d'environnement

Copier le fichier d'exemple et adapter :

cp application.properties.example src/main/resources/application.properties

4. Lancer l'application

# Lancer PostgreSQL
docker compose up postgres -d

# Lancer le backend
./mvnw spring-boot:run

5. Accéder à Swagger

http://localhost:8080/swagger-ui.html

Utilisation de l'API

Inscription

docker compose up --build -d

Lancer les tests

Backend :

curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.com","password":"123456"}'

Frontend :

curl -X POST http://localhost:8080/api/candidatures \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <votre_token>" \
  -d '{"entreprise":"Doctolib","poste":"Cloud Engineer","salaire":"62K€","statut":"POSTULE","priorite":"HAUTE"}'

Endpoints principaux

Méthode Route Description
POST /api/auth/register Inscription
POST /api/auth/login Connexion
GET /api/users/me Mon profil
GET /api/candidatures Mes candidatures
POST /api/candidatures Créer une candidature
GET /api/candidatures/{id} Détail d'une candidature
PUT /api/candidatures/{id} Modifier une candidature
PATCH /api/candidatures/{id}/statut Changer le statut
DELETE /api/candidatures/{id} Supprimer une candidature
GET /api/candidatures/stats Mes statistiques
GET /api/candidatures/statut/{statut} Filtrer par statut
POST /api/notes/candidature/{id} Ajouter une note
GET /api/notes/candidature/{id} Notes d'une candidature

Auteur

Guy Béni NtwariGitHub

About

Plateforme de suivi de candidatures (Spring Boot · Next.js · PostgreSQL) déployée sur AWS via Terraform et CI/CD GitHub Actions, avec un assistant IA (FastAPI + LangGraph) pour le matching sémantique d'offres et des suggestions d'amélioration de CV

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors