Aller au contenu

Vue d'ensemble de l'architecture

KanjiIQ suit une architecture multi-conteneurs en pod déployée sur Kubernetes. Le frontend et le backend s'exécutent en tant que conteneurs séparés au sein du même pod, communiquant via localhost.

Diagramme du système

graph TB
    subgraph Internet
        U[User Browser]
    end

    subgraph Hetzner["Hetzner k3s Cluster"]
        subgraph NS["Namespace: jlpt-kanji"]
            T[Traefik Ingress Controller]

            subgraph Pod["Application Pod (x2 replicas)"]
                FE[Flutter Web<br/>Nginx :80]
                BE[Dart Frog API<br/>:8080]
            end

            PG[(PostgreSQL 15<br/>PVC)]

            subgraph Middleware["Traefik Middlewares"]
                RL[Rate Limiting]
                SH[Security Headers]
            end
        end

        CM[cert-manager<br/>Let's Encrypt]
    end

    U -->|HTTPS| T
    T --> Middleware
    Middleware -->|kanjiiq.com| FE
    Middleware -->|api.kanjiiq.com| BE
    FE -->|/api/ proxy| BE
    BE --> PG
    CM -->|TLS Certificates| T

Architecture des domaines

Domaine Service Fonction
kanjiiq.com Frontend (Nginx) Application Flutter Web
www.kanjiiq.com Frontend (Nginx) Redirection vers le domaine principal
api.kanjiiq.com Backend (Dart Frog) API REST
admin.kanjiiq.com Backend (Dart Frog) API du tableau de bord administrateur
docs.kanjiiq.app Docs (Nginx) Ce site de documentation

Conception multi-conteneurs en pod

L'application s'exécute en tant que Deployment Kubernetes unique avec 2 réplicas, chacun contenant deux conteneurs :

# Simplified view of k8s/05-deployment.yaml
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: backend    # Dart Frog API on :8080
        - name: frontend   # Nginx serving Flutter Web on :80

Pourquoi un pod multi-conteneurs ?

  • Le Nginx du frontend redirige les requêtes /api/ vers localhost:8080 (le backend), évitant les problèmes cross-origin
  • Les deux conteneurs évoluent ensemble — chaque réplica est une unité complète et autonome
  • Réseau simplifié : la communication frontend-backend reste au sein du pod

Résumé des composants

Frontend

  • Framework : Flutter Web avec Material Design 3
  • Serveur : Nginx Alpine (non-root, UID 1000)
  • Gestion d'état : Provider
  • Routage : GoRouter
  • Support hors ligne : Cache SQLite local avec synchronisation en arrière-plan

Backend

  • Framework : Dart Frog 1.1.0
  • Authentification : JWT (pour les endpoints administrateur)
  • Sécurité : Pile de middlewares multicouche (blocage IP, détection de chemins, limitation de débit)
  • Traduction : API OpenAI pour la traduction dynamique de contenu

Base de données

  • Moteur : PostgreSQL 15
  • Stockage : Kubernetes PersistentVolumeClaim (10Gi)
  • Schéma : Colonnes JSONB pour le stockage de contenu multilingue
  • Clés primaires : UUID

Infrastructure

  • Cluster : k3s sur serveur dédié Hetzner
  • Ingress : Traefik avec HTTPS automatique
  • TLS : cert-manager avec Let's Encrypt
  • CI/CD : Forgejo Actions (auto-hébergé)
  • Registre : Forgejo Container Registry

Couches de sécurité

KanjiIQ met en oeuvre une défense en profondeur avec plusieurs couches de sécurité :

graph LR
    R[Request] --> L1[Traefik<br/>Rate Limiting]
    L1 --> L2[Traefik<br/>Security Headers]
    L2 --> L3[App: IP<br/>Blocklist Check]
    L3 --> L4[App: Malicious<br/>Path Detection]
    L4 --> L5[App: SQL Injection<br/>Detection]
    L5 --> L6[App: Regional<br/>Analytics]
    L6 --> H[Request Handler]
  1. Niveau infrastructure (Traefik) : Limitation de débit (100 req/min public, 50 req/min admin) et en-têtes de sécurité (HSTS, X-Frame-Options, CSP)
  2. Niveau application (middleware Dart Frog) : Liste de blocage IP, détection de chemins malveillants (.env, .php, fichiers de configuration), motifs d'injection SQL, prévention de traversée de chemin
  3. Niveau analytique : Suivi régional des requêtes avec blocage automatique après 3 requêtes suspectes en 24 heures

Voir Architecture du backend pour les détails sur la pile de middlewares.