Cheikh Ali CheikhDéveloppeur Java · Angular Voir la démo

Projet client · pièces détachées automobiles

Auto Stock
Management

Une application web qui relie ce qui entre en stock, ce qui est vendu et ce qui reste à encaisser.

Je l’ai conçue et développée pour un magasin de pièces détachées : API Java / Spring Boot, interface Angular, base PostgreSQL. Elle a été déployée sur un VPS OVHcloud ; la démonstration ci-dessous tourne en local avec des données fictives.

  • Java 17 Spring Boot 3.5
  • Angular 20 TypeScript 5.9
  • PostgreSQL Flyway · 17 migrations
  • 474 tests backend
Tableau de bord d’Auto Stock : ventes du jour, créances ouvertes, produits sous le seuil et activité récente.

Dans ce magasin, une vente ne s’arrête pas à l’encaissement : une pièce peut être en surface ou en réserve, un client peut payer une partie et revenir plus tard.

  1. 01Réceptionnersaisie ou import CSV
  2. 02Rangersurface · réserve
  3. 03Vendrecomptant ou crédit
  4. 04Suivrecréance et remboursements
  5. 05Pilotertableau de bord

Démonstration

L’application, de la connexion au tableau de bord.

Enregistrement continu d’un vrai parcours dans le navigateur, en mode clair. Sans voix : des légendes décrivent chaque étape. Toutes les données sont fictives.

Enregistré le 17 septembre 2026 avec Playwright sur l’application réelle (API Spring Boot + interface Angular + PostgreSQL), à partir d’un jeu de données fictif. Télécharger la vidéo (MP4, 9 Mo)

Fonctionnalités

Ce que l’application permet de faire.

Chaque écran ci-dessous est une capture de l’application lancée localement.

Catalogue paginé avec prix, stock global et seuil par référence.

Catalogue et recherche

Recherche par nom ou référence, tolérante aux fautes de frappe et aux accents (PostgreSQL pg_trgm + unaccent). Pagination côté serveur, fiche produit avec stock par emplacement.

Réceptions

Saisie manuelle d’un produit nouveau ou existant, répartie entre surface et réserve. Import CSV jusqu’à 500 lignes : modèle, aperçu ligne par ligne, sélection, rapport téléchargeable.

Ventes

Panier multi-articles, prélèvement du stock par emplacement, refus si le stock est insuffisant. Paiement complet ou partiel rattaché à un client.

Créances

Solde calculé à partir du journal des versements, ancienneté et retard, remboursements successifs avec historique.

Stock et historique

Transferts entre réserve et surface, seuils d’alerte, journal des entrées, sorties et transferts regroupés par opération.

Accès

Rôles propriétaire et vendeur, mot de passe temporaire à changer à la première connexion, désactivation des comptes, familles de pièces.

Architecture

Un domaine métier qui ne dépend pas du framework.

Le backend est un seul déployable découpé en trois modules Maven. Les règles de vente et de paiement se testent sans démarrer Spring ni la base.

stock-infrastructure Spring Boot · REST · Security · JPA · Flyway stock-application cas d’usage · ports · transactions stock-domain Sale · Product · Money StorageLocation · règles contrôleurs REST adaptateurs JPA / SQL transactions Spring
Les dépendances Maven vont de l’extérieur vers le centre. Les modules domaine et application n’ont aucune dépendance de production à Spring ou JPA ; l’infrastructure implémente leurs ports.

RecordPaymentUseCase.javastock-application

// Verrou exclusif sur la vente : deux encaissements
// simultanés ne peuvent pas lire le même ancien solde.
private RecordPaymentResult doRecord(
        RecordPaymentCommand command) {
    Sale sale = saleRepository
            .findByIdForUpdate(command.saleId())
            .orElseThrow(() ->
                    new SaleNotFoundException(command.saleId()));

    Payment payment = sale.recordPayment(
            command.amount(),
            command.receivedBy(),
            LocalDateTime.now(clock));

    saleRepository.save(sale);
    ...
}

Le cas d’usage s’exécute dans un TransactionRunner (port) ; l’agrégat Sale refuse un versement si la vente est soldée ou si le montant dépasse le reste dû. Le commentaire est ajouté pour cette page.

Pourquoi le DDD sur un domaine de cette taille ?

Le domaine est modeste : une architecture en couches classique aurait suffi pour livrer. J’ai choisi le DDD tactique et l’architecture hexagonale en connaissance de cause, aussi pour pratiquer sur un vrai besoin client ce que j’étudiais en master.

Ce que j’y gagne
Les règles sensibles (reste dû, crédit sans client, stock insuffisant) sont écrites une seule fois et testées sans Spring.
Ce que ça coûte
Plus de classes et de mappings qu’une application CRUD. En équipe sur un projet plus simple, je commencerais par des couches classiques.
Ce que je n’ai pas fait
Pas de DDD stratégique (plusieurs contextes délimités) : le domaine ne le justifie pas.

Choix techniques

Un monolithe modulaire

Vente, stock et paiements changent ensemble : une seule base PostgreSQL et une transaction suffisent, sans transactions distribuées. Les modules séparent les responsabilités à la compilation.

pom.xml

Un solde jamais stocké deux fois

Le montant payé est recalculé à partir du journal des versements. Money associe un BigDecimal à une devise et refuse les opérations entre devises.

Sale.java

Concurrence traitée selon le risque

Verrou optimiste (@Version) sur les emplacements de stock, verrou pessimiste pour les remboursements, clé Idempotency-Key pour rejouer sans doublon une vente, une réception ou un transfert.

IdempotencyFilter.java

Sessions dans des cookies HttpOnly

JWT d’accès de 15 minutes et jeton de renouvellement de 7 jours dont seule l’empreinte SHA-256 est stockée. Cookies HttpOnly et SameSite=Strict, mots de passe BCrypt.

AuthController.java

Erreurs exploitables par l’interface

Les exceptions métier deviennent des réponses ProblemDetail (RFC 9457) avec un code stable, que l’interface Angular traduit en messages clairs.

web/handler

Une interface Angular par fonctionnalité

Composants standalone, formulaires réactifs et signals. Des intercepteurs renouvellent la session après un 401 ; une garde protège un import CSV en cours.

refresh.interceptor.ts

Tests

Tester chaque risque au bon niveau.

Rapports Maven Surefire du 17 septembre 2026 : 474 tests exécutés, aucun échec, aucune erreur, aucun test ignoré.

100 domaine
Invariants des agrégats et objets-valeurs, en Java pur.
126 application
Orchestration des cas d’usage avec des doublures des ports.
248 infrastructure
Contrats HTTP et autorisations (MockMvc), migrations, contraintes SQL et transactions sur PostgreSQL via Testcontainers.
  • Exemple : un échec après la création d’un produit annule aussi cette création (ReceiveStockAtomicityTest).
  • Frontend : 39 fichiers de tests Jasmine / Karma (pages, gardes, intercepteurs, services).
  • Travail par branches et pull requests : 34 PR fusionnées côté backend, 36 côté frontend.
  • CI GitHub Actions sur chaque pull request : mvn verify côté backend, build et tests côté frontend.
  • Pas encore de tests de bout en bout dans le navigateur : la vidéo ci-dessus a été produite avec Playwright, mais ce n’est pas une suite de tests.

Stack

Versions vérifiées dans le code.

Backend
Java 17 · Spring Boot 3.5.13 (Web, Security, Data JPA) · Flyway · JJWT 0.12.6 · Commons CSV 1.14.1
Frontend
Angular 20.3 · TypeScript 5.9 · RxJS 7.8 · SCSS
Données
PostgreSQL (17 en local, 16 dans les tests) · 17 migrations Flyway · pg_trgm, unaccent, index GIN
Tests
JUnit 5 · AssertJ · Mockito · MockMvc · Testcontainers · Jasmine / Karma
Livraison
Dockerfiles multi-étapes · Nginx · Docker Compose · Caddy (HTTPS) · GitHub Actions

Statut du projet

Ce qui est vrai aujourd’hui.

  • Développée pour un client du secteur des pièces détachées : conception, backend, interface et mise en production.
  • Déployée par le passé sur un VPS OVHcloud que j’ai financé (Docker Compose, Caddy, déploiement par GitHub Actions). Ce serveur n’est plus actif.
  • Aucune instance en ligne aujourd’hui. Cette page présente le projet et une démonstration enregistrée en local, avec des données fictives.
  • Limites connues : un seul magasin, pas de tests de bout en bout automatisés, événements publiés dans le processus uniquement.