An enterprise tool,
built to spec.
An internal recruitment tool developed at Solutec, built from a specification, Figma mockups, and a fragile existing codebase. Architecture redesigned from scratch, complete full-stack development, functional V1 delivered with tests, CI/CD and documentation.

A real client. A documented need.
Solutec is a French IT consulting firm with 1,500 employees. Their Toulouse recruitment team was piloting every hire through Microsoft Planner. A tool never designed for that. Stages, candidates, interviews: all scattered across cards in a shared board. It worked. Barely.
Functional consultants gathered requirements directly from the recruitment team and produced the reference documents: a 7-module specification, a three-role permission matrix, Figma mockups. This wasn't a vague idea: it was a commission with a client, a deliverable, and expectations.
That's what gives GeReCo its weight. Every decision had to be justified by the need, not dictated by convenience.
Functional Requirements Spec.
Recruitment Management Tool
7 functional modules · 4 delivered in V1
Two teams. One shared process.
GeReCo coordinates two teams on the same pool of candidates: the Recruitment team, which drives the process end to end, and the Business Engineers, who only access candidate files from the technical evaluation stage onwards. Same data, distinct roles, differentiated access.
The Candidate
The central object of the application. Each candidate is tracked with their personal information, technical domains, and current stage in the selection process. Their file is shared between both teams, each with their own level of visibility.
Restricted — not visible to Business Engineers
Three roles
Recruiter
Full access. Manages the entire process from intake to decision: candidates, interviews, settings.
Business Engineer
Read-only. Candidates become visible from a certain stage in the process.
Admin
Recruiter rights plus user and account management.
Key stages
HR Interview
First interview conducted by the Recruiter. The candidate is not yet visible to the Business Engineer.
Technical Interview
The assigned Commercial assesses the candidate's technical fit and accesses their file for the first time.
Offer
The candidate has been selected. The Recruiter or the Commercial formalizes the salary offer.
The codebase was there. The architecture wasn't.
Taking on the project meant inheriting an implementation started a year earlier, never completed: a backend with fragile foundations, a frontend reduced to a login page. A few days of analysis were enough: fixing it would take more effort than starting over.
Structurally fragile from the ground up: not a question of polish, but of foundations.
- Data model unfit for the spec: candidates modeled as users, join table duplicated
- JWT bypassing Spring Security: volatile secret, no token expiry or revocation, business routes unprotected
- Structure without rigor: controllers wired directly to repositories, entities exposed raw, no separation of concerns
Same stack, entirely different architecture: every decision driven by the spec, not the legacy.
- Domain model redesigned with Merise: aligned with functional requirements, coherent relationships, extensible to V2 modules
- Spring Security properly integrated: global JWT filter, time-limited tokens with database revocation, @PreAuthorize-protected routes
- Layered architecture: controller → service → repository → mapper, each responsibility isolated, entities never exposed raw
Stack given. Architecture owned.
Making an app work and building it correctly are two distinct goals. From the data model to packaging, every layer was designed with the same rigor: the right tool, in the right place, for the right reason.
JPA Specifications — composable filtering
Filtering on stage, domain, and availability at once means dozens of combinations. Instead of one method per case, each filter is an autonomous block assembled at runtime. Typed queries, testable in isolation, without a line of hand-written SQL.
OpenAPI codegen — shared contract
Writing Angular HTTP services by hand means risking desynchronization at every backend change. The OpenAPI spec generated by Spring acts as the contract: ng-openapi-gen derives the TypeScript client services automatically. Zero drift, the API remains the single source of truth.
Angular modules — on-demand loading
Without lazy-loading, all Angular code loads on first access, including pages never visited. Four independent modules (candidates, calendar, settings, API) loaded only on navigation. Reduced initial bundle, each feature isolated.
Docker — portable stack in one command
Without containerization, reproducing the full stack requires a specific local setup. Multi-stage build (JDK → JRE, Node → Nginx), Docker Compose orchestrating Spring Boot, MariaDB, and Nginx. One docker compose up runs everything, identical on any machine.
The tool at work.
Engineering, end to end.
Tests
607
Test cases
281
Integration tests
92 %
Backend coverage
61 %
Frontend coverage
Every endpoint is tested end to end against an H2 database in MariaDB mode: JWT, authorization checks, business logic, persistence. On the frontend, Jasmine covers components across the three business modules. A CI pipeline that blocks on failure, a codebase that can evolve without fear of silent regressions.
CI/CD
Each application has its own dedicated GitLab CI pipeline: no code reaches the registry without having demonstrated a sufficient level of stability through its tests. The resulting Docker images are versioned and published directly to the GitLab registry on every run, ready to be pulled for deployment or integrated into a broader environment. Adding an automatic deployment stage would be the natural next step for this structure.
Documentation
Documentation covers every layer of the project. Compodoc certifies 100% JSDoc coverage across Angular components, pipes and interfaces. The OpenAPI spec lists 33 endpoints and 25 data schemas, all testable live from the Swagger UI. Two READMEs covering architecture, JWT flow and CI procedures. At delivery: installation guide, functional specification, and presentation to the business team.
Looking back.
What I learned
Spring Boot & Angular in a professional context
I had already taught myself Spring Boot and Angular: online courses, personal projects. GeReCo was the first time I applied them in a real professional project: an API integrated with an Angular client, complex business logic, real quality constraints. What self-study alone cannot provide, I gained here: a professional-grade command of this stack.
Building from a formal specification
In my other professional experiences, I developed, rarely designed. On personal projects, I design freely, without formal constraints. GeReCo combined both: designing the technical solution from a formal specification, as architect as much as developer.
Technical lead, mid-project
For most of the project, I handled every responsibility alone: technical breakdown, feature prioritization, client coordination. When a second developer joined in the final month, it was the real test of how readable the project was. His onboarding was fast, the collaboration natural.
What I'd do differently
Full-viewport layout
The mockups prescribed a full-viewport interface with no main scroll. I followed that approach without questioning it. In practice, it required JavaScript calculations to resolve what CSS alone could not, proof that the foundation was fragile. I would have proposed a natural scroll layout from the start: a mockup defines the what, not the how.
JWT in localStorage
In GeReCo, I stored the JWT token in localStorage: the most straightforward approach, and the most vulnerable to XSS attacks. It was while building StrivPath that I grasped the real risk and switched to httpOnly cookies instead. That choice, I would have made first.