Descripción general de la arquitectura¶
KanjiIQ sigue una arquitectura de pod multi-contenedor desplegada en Kubernetes. El frontend y el backend se ejecutan como contenedores separados dentro del mismo pod, comunicándose a través de localhost.
Diagrama del sistema¶
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
Arquitectura de dominios¶
| Dominio | Servicio | Propósito |
|---|---|---|
kanjiiq.com |
Frontend (Nginx) | Aplicación Flutter Web |
www.kanjiiq.com |
Frontend (Nginx) | Redirección al dominio principal |
api.kanjiiq.com |
Backend (Dart Frog) | REST API |
admin.kanjiiq.com |
Backend (Dart Frog) | API del panel de administración |
docs.kanjiiq.app |
Docs (Nginx) | Este sitio de documentación |
Diseño de pod multi-contenedor¶
La aplicación se ejecuta como un único Deployment de Kubernetes con 2 réplicas, cada una conteniendo dos contenedores:
# 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
¿Por qué un pod multi-contenedor?
- El Nginx del frontend redirige las solicitudes
/api/alocalhost:8080(el backend), evitando problemas de cross-origin - Ambos contenedores escalan juntos — cada réplica es una unidad completa y autocontenida
- Red simplificada: la comunicación frontend-backend permanece dentro del pod
Resumen de componentes¶
Frontend¶
- Framework: Flutter Web con Material Design 3
- Servidor: Nginx Alpine (non-root, UID 1000)
- Gestión de estado: Provider
- Enrutamiento: GoRouter
- Soporte offline: Caché SQLite local con sincronización en segundo plano
Backend¶
- Framework: Dart Frog 1.1.0
- Autenticación: JWT (para endpoints de administración)
- Seguridad: Pila de middleware multicapa (bloqueo de IP, detección de rutas, limitación de velocidad)
- Traducción: OpenAI API para traducción dinámica de contenido
Base de datos¶
- Motor: PostgreSQL 15
- Almacenamiento: Kubernetes PersistentVolumeClaim (10Gi)
- Esquema: Columnas JSONB para almacenamiento de contenido multilingüe
- Claves primarias: UUID
Infraestructura¶
- Clúster: k3s en servidor dedicado Hetzner
- Ingress: Traefik con HTTPS automático
- TLS: cert-manager con Let's Encrypt
- CI/CD: Forgejo Actions (autoalojado)
- Registro: Forgejo Container Registry
Capas de seguridad¶
KanjiIQ implementa defensa en profundidad con múltiples capas de seguridad:
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]
- Nivel de infraestructura (Traefik): Limitación de velocidad (100 req/min público, 50 req/min admin) y cabeceras de seguridad (HSTS, X-Frame-Options, CSP)
- Nivel de aplicación (middleware Dart Frog): Lista de bloqueo de IP, detección de rutas maliciosas (.env, .php, archivos de configuración), patrones de inyección SQL, prevención de path traversal
- Nivel de analítica: Seguimiento regional de solicitudes con bloqueo automático después de 3 solicitudes sospechosas en 24 horas
Consulta Arquitectura del backend para más detalles sobre la pila de middleware.