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/verslocalhost: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]
- 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)
- 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
- 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.