アーキテクチャ概要¶
KanjiIQは、Kubernetes上にデプロイされたマルチコンテナPodアーキテクチャに従っています。フロントエンドとバックエンドは同じPod内の別々のコンテナとして動作し、localhostで通信します。
システム図¶
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
ドメインアーキテクチャ¶
| ドメイン | サービス | 用途 |
|---|---|---|
kanjiiq.com |
Frontend (Nginx) | Flutter Webアプリケーション |
www.kanjiiq.com |
Frontend (Nginx) | メインドメインへのリダイレクト |
api.kanjiiq.com |
Backend (Dart Frog) | REST API |
admin.kanjiiq.com |
Backend (Dart Frog) | 管理ダッシュボードAPI |
docs.kanjiiq.app |
Docs (Nginx) | このドキュメントサイト |
マルチコンテナPod設計¶
アプリケーションは、2レプリカの単一Kubernetes Deploymentとして動作し、各レプリカに2つのコンテナが含まれます:
# 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
なぜマルチコンテナPodなのか?
- フロントエンドのNginxが
/api/リクエストをlocalhost:8080(バックエンド)にプロキシし、クロスオリジンの問題を回避 - 両コンテナが一緒にスケール — 各レプリカが完全で自己完結したユニット
- シンプルなネットワーキング:フロントエンドからバックエンドへの通信がPod内で完結
コンポーネント概要¶
フロントエンド¶
- フレームワーク: Material Design 3搭載のFlutter Web
- 配信: Nginx Alpine(非root、UID 1000)
- 状態管理: Provider
- ルーティング: GoRouter
- オフラインサポート: バックグラウンド同期付きローカルSQLiteキャッシュ
バックエンド¶
- フレームワーク: Dart Frog 1.1.0
- 認証: JWT(管理エンドポイント用)
- セキュリティ: 多層ミドルウェアスタック(IPブロッキング、パス検出、レート制限)
- 翻訳: 動的コンテンツ翻訳用OpenAI API
データベース¶
- エンジン: PostgreSQL 15
- ストレージ: Kubernetes PersistentVolumeClaim (10Gi)
- スキーマ: 多言語コンテンツ保存用JSONBカラム
- 主キー: UUID
インフラストラクチャ¶
- クラスター: Hetzner専用サーバー上のk3s
- Ingress: 自動HTTPS付きTraefik
- TLS: Let's Encrypt付きcert-manager
- CI/CD: Forgejo Actions(セルフホスト)
- レジストリ: Forgejo Container Registry
セキュリティレイヤー¶
KanjiIQは多層防御を複数のセキュリティレイヤーで実装しています:
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]
- インフラストラクチャレベル(Traefik):レート制限(パブリック100リクエスト/分、管理50リクエスト/分)およびセキュリティヘッダー(HSTS、X-Frame-Options、CSP)
- アプリケーションレベル(Dart Frogミドルウェア):IPブロックリスト、悪意のあるパス検出(.env、.php、設定ファイル)、SQLインジェクションパターン、パストラバーサル防止
- 分析レベル:24時間以内に3回の不審なリクエストで自動ブロックする地域別リクエストトラッキング
詳細はミドルウェアスタックのバックエンドアーキテクチャを参照してください。