Skip to content

Architecture Logicielle

Ce document décrit l'architecture technique de Bindr avec les technologies, versions et librairies principales.


Vue d'ensemble

Architecture: Client-serveur avec API REST

  • Backend: Java Spring Boot (API REST)
  • Frontend: Next.js (React, web uniquement)
  • Base de données: SQLite (V1) → PostgreSQL (V2)
  • Stockage: Infomaniak Object Storage (S3-compatible) + Cloudflare CDN
  • Paiements: Stripe Connect

Compatibilité & points de vigilance

Cette section liste les incompatibilités confirmées et contraintes importantes entre les librairies choisies. À consulter avant tout ajout de dépendance ou montée de version.

Backend (Java / Spring Boot)

Sévérité Librairie Problème Action
CRITIQUE iText7 8.0.3 Licence AGPLv3 — usage commercial sans licence payante interdit. Chaque PDF généré doit mentionner iText (producer line). Acheter une licence commerciale avant mise en production, ou remplacer par Apache PDFBox (Apache 2.0).
HAUTE Lombok + MapStruct 1.5.5 L'ordre des annotation processors doit être explicite : Lombok → lombok-mapstruct-binding → MapStruct. Sans cela, compilation échoue (Unknown property in result type). Configurer <annotationProcessorPaths> dans le plugin Maven compiler (voir snippet ci-dessous).
HAUTE jjwt 0.12.5 API cassante vs 0.11.x : parseClaimsJws()parseSignedClaims(), setSigningKey()verifyWith(). Les 3 modules sont requis : jjwt-api, jjwt-impl, jjwt-jackson. S'assurer que les 3 artifacts sont déclarés avec la même version 0.12.5.
MOYENNE Sentry 7.6.0 Utiliser sentry-spring-boot-starter-jakarta (et non la variante javax). La capture automatique des erreurs HTTP peut impacter le quota Sentry. Vérifier le nom de l'artifact ; ajuster sentry.traces-sample-rate si nécessaire.
BASSE Flyway 10.x Architecture modulaire : les drivers PostgreSQL/MySQL ne sont plus dans flyway-core. SQLite reste dans le core. Ajouter flyway-database-postgresql si migration vers PostgreSQL.
<!-- Configuration Maven requise pour Lombok + MapStruct -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <annotationProcessorPaths>
      <path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path>
      <path><groupId>org.projectlombok</groupId><artifactId>lombok-mapstruct-binding</artifactId><version>0.2.0</version></path>
      <path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId></path>
    </annotationProcessorPaths>
  </configuration>
</plugin>

Frontend (Next.js)

Sévérité Librairie Problème Action
HAUTE @stripe/react-stripe-js Les éléments Stripe nécessitent un contexte Elements wrappant la page de checkout. Incompatible avec React Server Components. Marquer la page checkout avec "use client".
MOYENNE next/image En développement local, l'optimisation d'image peut ralentir le chargement. En production sur Infomaniak Jelastic, configurer le domaine S3 dans next.config.js. Ajouter le domaine Infomaniak Object Storage dans images.remotePatterns.
BASSE react-dropzone Sur iOS Safari, le drag & drop n'est pas supporté. L'input <input type="file"> natif est utilisé en fallback automatique. Prévoir un bouton "Choisir des fichiers" visible sur mobile.

Backend - API REST

Technologies principales

Technologie Version Description
Java 21 LTS Langage principal
Spring Boot 3.3.x Framework application
Spring Data JPA Inclus ORM et repositories
Spring Security Inclus Authentification & autorisation
Spring Validation Inclus Validation des données

Base de données

Technologie Version Usage
SQLite 3.45+ V1 (développement, MVP)
PostgreSQL 16.x V2 (production, scalabilité)
Flyway 10.x Migrations de schéma

Librairies essentielles

Authentification & Sécurité

Problématique : Les utilisateurs (organisateurs, photographes) doivent pouvoir s'authentifier de manière sécurisée sans maintenir de session serveur. Les mots de passe stockés en base ne doivent jamais être lisibles en clair, même en cas de fuite.

<!-- JWT : génère et valide des tokens d'authentification stateless.
     Chaque requête API porte son propre token, sans état côté serveur. -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.5</version>
</dependency>

<!-- BCrypt : hache les mots de passe avec un salt aléatoire.
     Résistant aux attaques par dictionnaire et rainbow tables. -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
</dependency>

Stockage et traitement d'images

Problématique : Chaque photo uploadée doit être déclinée en plusieurs variantes (thumbnail, medium, watermarked) pour servir le bon format selon le contexte (galerie, lightbox, achat). Les fichiers originaux haute résolution doivent être stockés séparément et accessibles uniquement après achat. Les métadonnées EXIF (date, GPS) sont utiles pour organiser et filtrer les photos.

<!-- AWS S3 SDK : upload, téléchargement et génération de liens signés
     temporaires (30 jours) pour les fichiers achetés. -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.x</version>
</dependency>

<!-- Thumbnailator : resize fluide avec API chaînée, watermark natif.
     Génère les variantes thumbnail/medium/watermarked à l'upload. -->
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.20</version>
</dependency>

<!-- TwelveMonkeys ImageIO : étend le support de formats de Java.
     Ajoute la lecture/écriture WebP et AVIF via le mécanisme ImageIO standard,
     utilisé de manière transparente par Thumbnailator. -->
<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-webp</artifactId>
    <version>3.12.0</version>
</dependency>

<!-- metadata-extractor : lit les données EXIF embarquées dans les fichiers
     JPEG/HEIC (date, heure, coordonnées GPS, modèle d'appareil). -->
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.19.0</version>
</dependency>

Paiements

Problématique : L'application doit encaisser les paiements clients et redistribuer une partie aux organisateurs, sans gérer directement les coordonnées bancaires. Stripe Connect permet de créer des flux de paiement multi-parties conformes PCI-DSS.

<!-- Stripe SDK : intégration complète PaymentIntent, webhooks,
     Stripe Connect pour les paiements vers les organisateurs. -->
<dependency>
    <groupId>com.stripe</groupId>
    <artifactId>stripe-java</artifactId>
    <version>25.x</version>
</dependency>

Processing asynchrone

Problématique : Le traitement des photos (resize, watermark, extraction EXIF) peut prendre plusieurs secondes par image. Bloquer la requête HTTP d'upload le temps du traitement dégraderait fortement l'expérience utilisateur, surtout lors d'uploads en masse.

<!-- Quartz : planificateur de jobs pour le processing asynchrone
     des photos et les tâches récurrentes (nettoyage, rapports). -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

Email

Problématique : Plusieurs événements déclenchent des emails automatiques : confirmation de commande, accès photographe, lien de téléchargement. Ces emails doivent être rendus en HTML avec des données dynamiques (nom, montant, lien signé).

<!-- JavaMail : envoi d'emails SMTP depuis Spring Boot. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<!-- Thymeleaf : moteur de templates HTML pour les emails transactionnels.
     Permet d'injecter des variables (nom, commande, lien) dans des templates. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Génération PDF

Problématique : Chaque commande payée doit générer une facture PDF conforme (numéro, TVA, coordonnées). Les organisateurs ont besoin d'attestations fiscales annuelles téléchargeables.

<!-- iText 7 : génération programmatique de PDFs (factures, attestations).
     Supporte la mise en page, les tableaux, les logos et les signatures. -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>8.0.3</version>
</dependency>

Validation & Utilities

Problématique : Le code Java Spring Boot génère beaucoup de boilerplate (getters, setters, constructeurs, equals/hashCode). Le mapping entre entités JPA et DTOs (objets exposés à l'API) est répétitif et source d'erreurs.

<!-- Lombok : génère automatiquement le boilerplate Java à la compilation
     (@Data, @Builder, @RequiredArgsConstructor, etc.). -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>

<!-- MapStruct : génère le code de mapping entité ↔ DTO à la compilation.
     Plus performant et sûr que le mapping manuel ou par réflexion. -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>

<!-- Apache Commons Lang : utilitaires courants (manipulation de chaînes,
     dates, tableaux) qui complètent la bibliothèque standard Java. -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

Tests

Problématique : L'API REST doit être testée à tous les niveaux : unitaire (services, logique métier), intégration (comportement des endpoints), et contrats (format des réponses JSON). Les dépendances externes (base de données, S3) doivent être mockées pour isoler les tests.

<!-- Spring Boot Test : contexte de test intégré, assertions, mocks
     et support JUnit 5 pour les tests unitaires et d'intégration. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<!-- Mockito : crée des doublures (mocks) des dépendances pour tester
     une classe en isolation, sans ses collaborateurs réels. -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>test</scope>
</dependency>

<!-- REST Assured : DSL fluide pour tester les endpoints HTTP.
     Permet de valider le status code, les headers et le corps JSON. -->
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>5.4.0</version>
    <scope>test</scope>
</dependency>

Monitoring & Logs

Problématique : En production, il faut pouvoir détecter les anomalies (erreurs, lenteurs) avant que les utilisateurs ne les signalent, et diagnostiquer rapidement les incidents. Les métriques métier (uploads, ventes) doivent aussi être visibles.

<!-- Actuator : expose des endpoints HTTP de santé (/health, /metrics)
     pour les checks de l'infrastructure et le monitoring. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- Sentry : capture et remonte les exceptions en production en temps réel,
     avec contexte (stack trace, utilisateur, requête). -->
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-spring-boot-starter</artifactId>
    <version>7.6.0</version>
</dependency>

Frontend - Next.js

Technologies principales

Technologie Version Description
Next.js 15.x Framework React (App Router)
React 19.x Bibliothèque UI
TypeScript 5.x Typage statique
Tailwind CSS 4.x Styling utilitaire

Plateformes cibles

  • Web (responsive, mobile-first) : application web accessible depuis tous navigateurs
  • Application mobile native : non prévu — la PWA (Progressive Web App) couvre les usages mobiles essentiels (V2 si besoin)

Librairies principales

Routing & State Management

Problématique : Next.js App Router gère le routing. L'état côté client (panier, session) doit être partagé entre composants sans prop drilling.

{
  "dependencies": {
    "next": "^15.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "zustand": "^5.0.0"
  }
}

Réseau & API

Problématique : Le frontend consomme l'API REST Java via fetch natif (Next.js Server Components) ou axios côté client. Les tokens JWT sont stockés en cookie httpOnly pour la sécurité.

{
  "dependencies": {
    "axios": "^1.7.0",
    "swr": "^2.2.0",
    "jose": "^5.0.0"
  }
}

UI Components

Problématique : La galerie photo est le cœur de l'UX — lazy loading, lightbox avec zoom/swipe, sélection multiple pour le panier, drag & drop pour l'upload.

{
  "dependencies": {
    "yet-another-react-lightbox": "^3.0.0",
    "react-dropzone": "^14.0.0",
    "react-hot-toast": "^2.4.0",
    "lucide-react": "^0.400.0",
    "clsx": "^2.0.0"
  }
}

Formulaires & Validation

{
  "dependencies": {
    "react-hook-form": "^7.50.0",
    "zod": "^3.22.0",
    "@hookform/resolvers": "^3.3.0"
  }
}

Paiement

{
  "dependencies": {
    "@stripe/stripe-js": "^4.0.0",
    "@stripe/react-stripe-js": "^2.4.0"
  }
}

Internationalisation

{
  "dependencies": {
    "next-intl": "^3.0.0"
  }
}

Tests

{
  "devDependencies": {
    "jest": "^29.0.0",
    "@testing-library/react": "^16.0.0",
    "@testing-library/jest-dom": "^6.0.0",
    "playwright": "^1.45.0"
  }
}

Points d'attention architecturaux

Galerie photo — performance & panier

La galerie est un composant central et critique. Elle doit être :

  • Responsive : expérience fluide sur desktop et mobile, avec layout adaptatif (grille masonry ou grid selon la taille d'écran)
  • Performante : chargement lazy des images, thumbnails servis depuis le CDN, virtualisation de la liste pour les grandes galeries
  • Compatible panier : sélection multi-photos directement depuis la galerie (overlay de sélection sur chaque photo), affichage du nombre d'éléments sélectionnés, ajout au panier sans quitter la galerie
  • Formats optimisés : WebP/AVIF avec fallback JPEG, srcset adapté à la résolution de l'écran

Solutions techniques retenues (Next.js)

Besoin Package Notes
Layout masonry/grid responsive CSS Grid natif + Tailwind Pas de dépendance externe
Lazy loading images next/image (natif Next.js) Optimisation automatique WebP/AVIF
Lightbox / zoom / galerie swipeable yet-another-react-lightbox Léger, accessible, swipe mobile
Sélection multiple (panier) Zustand (Set<photoId>) State global léger
{
  "dependencies": {
    "yet-another-react-lightbox": "^3.0.0",
    "zustand": "^5.0.0"
  }
}

CDN custom — gestion des assets photos

  • Toutes les images doivent transiter par le CDN (aucun accès direct au bucket S3)
  • 3 variantes générées à l'upload : thumbnail (300px), medium (1200px), full (original)
  • Une variante watermarkée pour la prévisualisation publique (logo Bindr en surimpression)
  • Les fichiers originaux (achetés) sont servis via liens signés temporaires (30 jours)
  • Invalidation de cache CDN automatique si une photo est supprimée ou masquée
  • Headers de cache agressifs sur les variantes statiques (Cache-Control: max-age=31536000, immutable)

Solutions techniques retenues (Java / Backend)

Resize + watermark

Librairie Maven Liens
Thumbnailator — resize fluide, watermark natif net.coobird:thumbnailator:0.4.20 GitHub · Doc
TwelveMonkeys ImageIO — support WebP/AVIF en lecture et écriture com.twelvemonkeys.imageio:imageio-webp:3.10.1 GitHub
// Exemple : resize + watermark avec Thumbnailator
Thumbnails.of(inputStream)
  .size(1200, 900)
  .watermark(Positions.BOTTOM_RIGHT, watermarkImage, 0.5f)
  .outputFormat("jpg")
  .toOutputStream(out);

Stockage — Infomaniak Object Storage (compatible S3) + Cloudflare CDN

Librairie Maven Liens
AWS SDK v2 for Java software.amazon.awssdk:s3:2.25.x Doc officielle · GitHub

L'Object Storage Infomaniak est compatible API S3 — le SDK AWS fonctionne tel quel avec un endpointOverride. Cloudflare (free tier) est utilisé en frontal CDN pour la distribution mondiale des images.

// Lien signé 30 jours (Infomaniak Object Storage via SDK AWS S3)
S3Presigner presigner = S3Presigner.builder()
    .endpointOverride(URI.create("https://s3.pub1.infomaniak.cloud"))
    .region(Region.of("dc3-a"))
    .credentialsProvider(StaticCredentialsProvider.create(
        AwsBasicCredentials.create(accessKey, secretKey)))
    .build();

PresignedGetObjectRequest req = presigner.presignGetObject(r -> r
    .signatureDuration(Duration.ofDays(30))
    .getObjectRequest(g -> g.bucket("bindr-photos").key(key)));

// Invalidation cache Cloudflare après suppression (via API Cloudflare)
// POST https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache

Upload de photos — mobile & desktop

  • Multiplateforme : drag & drop sur desktop, sélection native galerie/caméra sur mobile
  • Upload multipart : découpage en chunks pour les fichiers volumineux (résistance aux coupures réseau)
  • Upload parallèle : plusieurs photos uploadées simultanément (limite configurable, ex: 5 en parallèle)
  • Feedback en temps réel : barre de progression par photo + status global
  • Validation côté client : type MIME (JPEG, PNG, HEIC), taille max avant envoi
  • Retry automatique : en cas d'échec réseau, reprise de l'upload sans recommencer depuis zéro
  • Processing asynchrone : l'upload retourne immédiatement, la génération des variantes se fait en arrière-plan (status pendingprocessingcompleted)

Solutions techniques retenues (Next.js)

Besoin Package Notes
Drag & drop fichiers react-dropzone Gère la sélection fichiers + drag & drop
HTTP client — upload multipart + progression axios onUploadProgress natif
{
  "dependencies": {
    "react-dropzone": "^14.0.0",
    "axios": "^1.7.0"
  }
}
// Upload avec progression par fichier (axios)
await axios.post('/api/upload', formData, {
  onUploadProgress: (event) => {
    const progress = Math.round((event.loaded * 100) / event.total!);
    updateProgress(progress);
  },
});

// Upload parallèle (5 max simultanément)
await Promise.all(files.map((f) => uploadFile(f)));

Processing asynchrone côté backend

Besoin Solution Liens
V0 — processing simple post-upload Spring @Async + ThreadPoolTaskExecutor natif Spring Boot
V1+ — jobs robustes avec retry Spring Batch Doc

Infrastructure & DevOps

Hébergement & Cloud

Fournisseur retenu : Infomaniak — hébergement souverain suisse

Choix motivé par la souveraineté des données : data centers exclusivement en Suisse (Genève + Zurich), droit suisse (nFADP) + RGPD, société 100% employés, aucune exposition au CLOUD Act américain. ISO 27001, 27701.

Service Provider Usage Prix estimé
App hosting Infomaniak Jelastic Cloud (PaaS) Backend Java + Flutter Web (Docker/Node.js, auto-scaling) ~CHF 15–25/mois
Stockage S3 Infomaniak Object Storage Photos originales et traitées (API S3-compatible) ~CHF 0.02/Go/mois (~CHF 10/mois pour 500 Go)
Base de données Infomaniak Public Cloud PostgreSQL PostgreSQL managé (1 nœud v0, 3 nœuds HA en prod) ~CHF 22/mois (v0)
Egress réseau Inclus Infomaniak Sortie réseau gratuite jusqu'à 10 To/mois CHF 0
CDN Cloudflare (free tier) Distribution images mondiale en frontal de l'Object Storage Gratuit

Budget total estimé v0 (~500 Go d'images) : ~CHF 47–57/mois

Note SDK S3 : L'Object Storage Infomaniak est compatible API S3. Le SDK AWS (software.amazon.awssdk:s3) fonctionne sans modification en changeant l'endpoint vers https://s3.pub1.infomaniak.cloud. Les liens signés (PresignedGetObjectRequest) fonctionnent de la même manière.

// Configuration endpoint Infomaniak Object Storage (compatible S3)
S3Client s3 = S3Client.builder()
    .endpointOverride(URI.create("https://s3.pub1.infomaniak.cloud"))
    .region(Region.of("dc3-a")) // région Infomaniak
    .credentialsProvider(StaticCredentialsProvider.create(
        AwsBasicCredentials.create(accessKey, secretKey)))
    .build();

CI/CD

# GitHub Actions ou GitLab CI
Backend:
  - Build: Maven / Gradle
  - Tests: JUnit + REST Assured
  - Docker: Image Docker
  - Deploy: Infomaniak Jelastic Cloud (Docker container)

Frontend:
  - Build: flutter build web
  - Tests: flutter test
  - Deploy: Infomaniak Jelastic Cloud (Node.js container)

Monitoring & Logs

Service Usage
Sentry Erreurs applicatives (backend + frontend)
LogRocket Session replay frontend (optionnel V2)
Datadog / New Relic APM et monitoring infrastructure (V2)
CloudWatch Logs AWS (si AWS)

Services externes

Requis V1

Service Usage Plan
Stripe Paiements + Connect Standard (commission par transaction)
SendGrid / Mailgun Emails transactionnels Free tier puis payant
Printful / Gelato Print-on-demand Commission par produit

Optionnel V2

Service Usage Plan
Algolia Recherche photos avancée Payant
Cloudinary Traitement images (alternative) Free tier puis payant
Twilio SMS notifications Payant
Google Vision API Reconnaissance faciale, OCR dossards Pay-per-use

Architecture réseau

┌─────────────┐
│   Clients   │  (Browser, iOS, Android)
└──────┬──────┘
       │
       │ HTTPS
       │
┌──────▼──────────┐
│   Cloudflare    │  (CDN + WAF + DDoS protection — free tier)
└──────┬──────────┘
       │
       ├──────────────────┬──────────────────────┐
       │                  │                      │
┌──────▼──────┐   ┌───────▼────────┐  ┌──────────▼──────────┐
│ Flutter Web │   │  API REST      │  │  Object Storage S3   │
│  (Static)   │   │  Spring Boot   │  │  Infomaniak (CH)     │
│  Jelastic   │   │  Jelastic      │  │  (images, variantes) │
└─────────────┘   └────────┬───────┘  └──────────────────────┘
      Infomaniak            │                Infomaniak
      Suisse (CH)  ┌────────▼────────┐       Suisse (CH)
                   │   PostgreSQL    │
                   │   Infomaniak    │
                   │   Suisse (CH)   │
                   └─────────────────┘

Toutes les données (app, base, stockage) sont hébergées en Suisse chez Infomaniak. Cloudflare agit uniquement comme proxy/CDN edge sans stocker de données persistantes.


Versions & Compatibilité

Minimum requis - Développement

  • Java: JDK 21 (LTS)
  • Maven: 3.9+
  • Node.js: 20+ (LTS)
  • npm: 10+ (ou pnpm 9+)

Minimum requis - Production

  • JVM: OpenJDK 21 / Amazon Corretto 21
  • PostgreSQL: 16+

Standards de code

Backend Java

  • Style: Google Java Style Guide
  • Linting: Checkstyle
  • Formatting: Spotless
  • Coverage: JaCoCo (objectif: >80%)

Frontend Next.js

  • Style: Airbnb ESLint config
  • Linting: ESLint + TypeScript strict
  • Formatting: Prettier
  • Coverage: Jest (objectif: >70%)

Sécurité

Backend

  • HTTPS obligatoire (TLS 1.3)
  • JWT pour authentification (expiration: 24h)
  • Refresh tokens (expiration: 30j)
  • Rate limiting: 100 req/min par IP
  • CORS configuré strictement
  • Helmet headers (CSP, HSTS, etc.)
  • SQL injection prevention (JPA parameterized queries)
  • XSS prevention (output encoding)

Frontend

  • Tokens JWT en cookie httpOnly (pas de localStorage)
  • Input validation côté client (Zod) + serveur
  • Content Security Policy (CSP) via headers Next.js
  • Variables d'environnement côté serveur uniquement pour les secrets

Dernière mise à jour: 12 mars 2026