コンテンツにスキップ

アーキテクチャ概要

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]
  1. インフラストラクチャレベル(Traefik):レート制限(パブリック100リクエスト/分、管理50リクエスト/分)およびセキュリティヘッダー(HSTS、X-Frame-Options、CSP)
  2. アプリケーションレベル(Dart Frogミドルウェア):IPブロックリスト、悪意のあるパス検出(.env、.php、設定ファイル)、SQLインジェクションパターン、パストラバーサル防止
  3. 分析レベル:24時間以内に3回の不審なリクエストで自動ブロックする地域別リクエストトラッキング

詳細はミドルウェアスタックのバックエンドアーキテクチャを参照してください。