100日チャレンジ day47

昨日
100日チャレンジに感化されたので、アレンジして自分でもやってみます。
やりたいこと
- 世の中のさまざまなドメインの簡易実装をつくり、バックエンドの実装に慣れる(dbスキーマ設計や、関数の分割、使いやすいインターフェイスの切り方に慣れる
- 設計力(これはシステムのオーバービューを先に自分で作ってaiに依頼できるようにする
- 生成aiをつかったバイブコーティングになれる
- 実際にやったことはzennのスクラップにまとめ、成果はzennのブログにまとめる(アプリ自体の公開は必須ではないかコードはgithubにおく)
できたもの
TBD

CDN つくる

了解しました!Day47は「コンテンツ配信ネットワーク (CDN) シミュレータ」で進めましょう。早速ですが、プロジェクトの仕様を以下にまとめます。
Day47: コンテンツ配信ネットワーク (CDN) シミュレータ 仕様書
1. アプリケーション概要
本アプリケーションは、コンテンツ配信ネットワーク (CDN) の基本的な動作原理をシミュレートするWebアプリケーションです。ユーザーはオリジンサーバーにコンテンツを登録し、複数の設定可能なエッジサーバーを通じて、クライアント(シミュレートされたユーザー)からのリクエストに応じてコンテンツがどのように配信されるかを視覚的に確認できます。キャッシュ戦略やリクエストルーティングの基本的な概念を学ぶことを目的とします。
デザインテーマ: ニューモーフィズム (Neumorphism) を採用し、柔らかい影と光の表現で、モダンかつ触覚的なインターフェースを目指します。
2. 主要機能
-
オリジンサーバー管理:
- コンテンツの登録:
- コンテンツID (文字列、ユニーク)
- コンテンツデータ (テキストエリアで入力、または事前に用意したサンプルテキスト)
- コンテンツタイプ (例:
text/html
,application/json
,image/jpeg
- Picsum Photos の URL を直接使用)
- 登録済みコンテンツの一覧表示・削除。
- コンテンツの登録:
-
エッジサーバー設定:
- 複数のエッジサーバーを動的に追加・設定可能。
- 各エッジサーバーの設定項目:
- エッジサーバーID (文字列、ユニーク)
- 地域 (例: 日本、アメリカ西海岸、ヨーロッパ中央など、選択式)
- キャッシュ容量 (数値、キャッシュできるコンテンツアイテム数で表現)
- キャッシュポリシー:
- TTL (Time To Live): キャッシュ有効期間 (秒単位)。0の場合はキャッシュしない。
- キャッシュアルゴリズム: LRU (Least Recently Used) のみ実装。
- 設定済みエッジサーバーの一覧表示・削除。
-
クライアントリクエストシミュレーション:
- クライアントの地域を選択 (エッジサーバーの地域と対応)。
- リクエストするコンテンツIDを指定。
- リクエスト実行ボタンを押下。
-
配信プロセス視覚化:
- リクエストが発生すると、以下の情報をログ形式で表示:
- クライアントの地域とリクエストされたコンテンツID。
- 選択されたエッジサーバー (最も近い地域、または簡易的なロジック)。
- キャッシュヒット/ミス:
- ヒットの場合: 該当エッジサーバーから配信されたことを表示。LRUアルゴリズムに基づき、キャッシュ内のアイテム順序が更新される様子を内部的に処理。
- ミスの場合:
- オリジンサーバーにフォールバックされたことを表示。
- オリジンサーバーからコンテンツを取得し、エッジサーバーにキャッシュされたことを表示 (TTL設定とキャッシュ容量を考慮)。
- キャッシュがいっぱいの場合、LRUに基づいて最も古いアイテムが削除されることを表示。
- クライアントに配信されたことを表示。
- 各エッジサーバーの現在のキャッシュ内容 (コンテンツIDと残りTTL) を表示。
- リクエストが発生すると、以下の情報をログ形式で表示:
-
統計情報 (簡易版):
- システム全体、およびエッジサーバーごとのキャッシュヒット率。
- 配信された総リクエスト数。
3. 技術要素
- フレームワーク: Next.js (App Router)
- 言語: TypeScript
- データベース: SQLite (better-sqlite3)
- スタイリング: Tailwind CSS (ニューモーフィズムデザイン)
- 状態管理: React Context API または Zustand (必要に応じて判断)
4. データモデル (DBスキーマ)
-
origin_contents
: オリジンサーバーのコンテンツ-
id
: INTEGER PRIMARY KEY AUTOINCREMENT -
content_id
: TEXT UNIQUE NOT NULL (ユーザー指定のID) -
data
: TEXT NOT NULL (コンテンツ本体 or Picsum URL) -
content_type
: TEXT NOT NULL -
created_at
: TEXT DEFAULT CURRENT_TIMESTAMP
-
-
edge_servers
: エッジサーバー定義-
id
: INTEGER PRIMARY KEY AUTOINCREMENT -
server_id
: TEXT UNIQUE NOT NULL (ユーザー指定のID) -
region
: TEXT NOT NULL -
cache_capacity
: INTEGER NOT NULL -
default_ttl
: INTEGER NOT NULL (秒単位、0はキャッシュしない) -
created_at
: TEXT DEFAULT CURRENT_TIMESTAMP
-
-
edge_cache_items
: エッジサーバーのキャッシュアイテム (LRUとTTLを考慮)-
id
: INTEGER PRIMARY KEY AUTOINCREMENT -
edge_server_id_ref
: INTEGER NOT NULL (FK toedge_servers.id
) -
content_id_ref
: INTEGER NOT NULL (FK toorigin_contents.id
) -
cached_at
: TEXT NOT NULL (キャッシュされた時刻 ISO8601) -
last_accessed_at
: TEXT NOT NULL (LRU用、最後にアクセスされた時刻 ISO8601) -
expires_at
: TEXT NOT NULL (TTL用、失効時刻 ISO8601)
-
-
request_logs
: リクエストログ (統計情報用、簡易)-
id
: INTEGER PRIMARY KEY AUTOINCREMENT -
requested_at
: TEXT DEFAULT CURRENT_TIMESTAMP -
client_region
: TEXT NOT NULL -
content_id_requested
: TEXT NOT NULL -
served_by_edge_server_id
: INTEGER (FK toedge_servers.id
, NULLable if direct from origin) -
cache_hit
: BOOLEAN NOT NULL -
delivered_from_origin
: BOOLEAN NOT NULL
-
5. ディレクトリレイアウトと作成するファイル一覧 (主要なもの)
day47_cdn_simulator/
├── app/
│ ├── api/
│ │ ├── origin-contents/
│ │ │ └── route.ts континентов CRUD
│ │ ├── edge-servers/
│ │ │ └── route.ts эдж серверов CRUD
│ │ ├── request-simulation/
│ │ │ └── route.ts リクエスト処理、キャッシュロジック
│ │ └── stats/
│ │ └── route.ts 統計情報取得
│ ├── (pages)/
│ │ ├── dashboard/
│ │ │ ├── page.tsx メインの操作・表示ページ
│ │ │ └── components/
│ │ │ ├── OriginContentsManager.tsx
│ │ │ ├── EdgeServerManager.tsx
│ │ │ ├── RequestSimulator.tsx
│ │ │ ├── VisualizationLog.tsx
│ │ │ └── StatsDisplay.tsx
│ ├── _lib/
│ │ ├── cdn-logic.ts キャッシュ戦略、ルーティングロジックなどサーバーサイド処理
│ │ └── types.ts 共通の型定義
│ ├── layout.tsx
│ ├── globals.css
│ └── page.tsx (ランディングページ、今回は dashboard へリダイレクトでも可)
├── components/
│ └── ui/ (ニューモーフィズム用ボタン、カードなど共通コンポーネント)
│ ├── NeumorphicCard.tsx
│ ├── NeumorphicButton.tsx
│ └── NeumorphicInput.tsx
├── lib/
│ └── db.ts SQLite 初期化、スキーマ定義、クエリ関数
├── db/
│ └── dev.db
├── public/
├── PROGRESS.md
├── README.md
├── package.json
... (その他設定ファイル)
6. 作業手順 (ステップごとのテストとコミットを含む)
-
プロジェクト初期化 (Step 1/10)
-
template
からday47_cdn_simulator
ディレクトリへコピー。 -
package.json
のname
をday47_cdn_simulator
に変更。 -
README.md
にこの仕様書の概要を記載。 -
PROGRESS.md
に作業工程を記載。 - 基本レイアウト作成 (
app/layout.tsx
,app/page.tsx
からapp/(pages)/dashboard/page.tsx
へのリダイレクトまたは直接表示)。 - Tailwind CSS でニューモーフィズムの基本的なカラースキームとスタイルを
globals.css
に設定。 -
テスト:
npm run dev
で起動し、基本ページが表示されることを確認。 -
コミット:
day47: step 1/10 Initialize project, basic layout, and neumorphism setup
-
-
データモデリングとDB設定 (Step 2/10)
-
lib/db.ts
にinitializeSchema
を作成し、上記DBスキーマのCREATE TABLE
文を記述。 - オリジンコンテンツ、エッジサーバー、キャッシュアイテム、リクエストログの型定義を
app/_lib/types.ts
に作成。 -
db/dev.db
があれば削除。 -
テスト: サーバー起動時に
db/dev.db
がスキーマ通りに自動生成されることを確認。簡単な CRUD 関数 (例: オリジンコンテンツ追加・取得) をlib/db.ts
に作成し、node で直接実行してテスト。 -
コミット:
day47: step 2/10 Define DB schema and initialize database
-
-
APIエンドポイント実装: オリジンコンテンツ管理 (Step 3/10)
-
app/api/origin-contents/route.ts
を実装:-
POST /api/origin-contents
: 新規コンテンツ登録 -
GET /api/origin-contents
: 全コンテンツ取得 -
DELETE /api/origin-contents?id={id}
: コンテンツ削除 (実際には content_id で削除)
-
-
テスト:
curl
や Postman などで各エンドポイントの動作確認。 -
コミット:
day47: step 3/10 Implement API for origin content management
-
-
APIエンドポイント実装: エッジサーバー管理 (Step 4/10)
-
app/api/edge-servers/route.ts
を実装:-
POST /api/edge-servers
: 新規エッジサーバー登録 -
GET /api/edge-servers
: 全エッジサーバー取得 -
DELETE /api/edge-servers?id={id}
: エッジサーバー削除 (実際には server_id で削除)
-
-
テスト:
curl
や Postman などで各エンドポイントの動作確認。 -
コミット:
day47: step 4/10 Implement API for edge server management
-
-
UIコンポーネント実装: マネージャー系 (Step 5/10)
-
app/(pages)/dashboard/components/OriginContentsManager.tsx
: オリジンコンテンツの登録フォームと一覧表示。 -
app/(pages)/dashboard/components/EdgeServerManager.tsx
: エッジサーバーの設定フォームと一覧表示。 - ニューモーフィズムスタイルの汎用コンポーネント (
NeumorphicCard.tsx
,NeumorphicButton.tsx
,NeumorphicInput.tsx
) をcomponents/ui/
に作成。 - 上記マネージャーコンポーネントを
app/(pages)/dashboard/page.tsx
に配置。 - テスト: ブラウザでUIの表示と基本的なフォーム操作(API連携前でOK)を確認。
-
コミット:
day47: step 5/10 Implement UI components for content and edge server management
-
-
APIエンドポイント実装: リクエストシミュレーション (Step 6/10)
-
app/api/request-simulation/route.ts
を実装:-
POST /api/request-simulation
: クライアント地域とコンテンツIDを受け取り、配信プロセスを実行。- 最適なエッジサーバーを選択するロジック (地域ベースの単純なもの)。
-
app/_lib/cdn-logic.ts
にキャッシュヒット/ミス判定、LRU に基づくキャッシュ更新/削除、オリジンへのフォールバック処理、TTL管理ロジックを実装。 -
edge_cache_items
テーブルを更新。 -
request_logs
テーブルに記録。 - 処理結果 (配信元、キャッシュ状態など) を返す。
-
-
テスト:
curl
や Postman で様々なシナリオ (キャッシュヒット、ミス、容量超過など) をテスト。DBのedge_cache_items
とrequest_logs
の状態を確認。 -
コミット:
day47: step 6/10 Implement API for request simulation and core CDN logic
-
-
UIコンポーネント実装: シミュレータと可視化 (Step 7/10)
-
app/(pages)/dashboard/components/RequestSimulator.tsx
: クライアント地域選択、コンテンツID入力、リクエスト実行ボタン。 -
app/(pages)/dashboard/components/VisualizationLog.tsx
: リクエストシミュレーションAPIからの応答と、エッジサーバーのキャッシュ状態をリアルタイム (またはリクエストごと) に表示。 -
app/(pages)/dashboard/page.tsx
に上記コンポーネントを配置し、API連携。 - テスト: ブラウザで実際にリクエストをシミュレートし、ログとキャッシュ状態が期待通りに表示・更新されることを確認。
-
コミット:
day47: step 7/10 Implement UI for request simulation and visualization
-
-
APIエンドポイント実装 & UIコンポーネント実装: 統計情報 (Step 8/10)
-
app/api/stats/route.ts
を実装:-
GET /api/stats
:request_logs
を集計し、キャッシュヒット率などの統計情報を返す。
-
-
app/(pages)/dashboard/components/StatsDisplay.tsx
: 統計情報を表示。 -
app/(pages)/dashboard/page.tsx
に配置し、API連携。 - テスト: 複数のリクエストをシミュレートした後、統計情報が正しく計算・表示されることを確認。
-
コミット:
day47: step 8/10 Implement API and UI for statistics display
-
-
デバッグとテスト、リファクタリング (Step 9/10)
- 全体の動作確認、UIの調整 (ニューモーフィズムの微調整など)。
- Playwright を用いたE2Eテストケースをいくつか作成し実行:
- オリジンコンテンツ登録 → エッジサーバー設定 → キャッシュミスとキャッシュ作成 → キャッシュヒット → キャッシュ期限切れ → LRUによるキャッシュ追い出し。
- 不要なファイルやコードの削除。
- Linter (Biome) の警告修正。
- テスト: Playwrightテストが全て通ること。手動での一通りの動作確認。
-
コミット:
day47: step 9/10 Debugging, E2E testing, and refactoring
-
ドキュメント作成 (Step 10/10)
-
README.md
を更新し、アプリケーションの概要、起動方法、使い方などを記述。 -
.cursor/rules/knowledge.mdc
に今回のアプリ情報を追記。 - テスト: ドキュメントに記載された手順でアプリが利用できることを確認。
-
コミット:
day47: step 10/10 Finalize documentation
-
以上が CDN シミュレータの仕様と開発手順です。
ご確認いただき、問題なければこの内容で進めさせていただきます。
特にUIのデザインやインタラクションで、ニューモーフィズムを活かしたアイデアがあれば、実装段階で取り入れていきましょう。
では、最初のステップ「プロジェクト初期化」から開始します。はい、この仕様で問題ありません。最初のステップから進めてください。