|
| 1 | +# Global Clubs Integration |
| 2 | + |
| 3 | +## 概要 |
| 4 | + |
| 5 | +このドキュメントは、Raspberry Pi Foundation が管理する国際的な Clubs API データベースと CoderDojo Japan のデータベースを連携させる機能の設計と実装について記載しています。 |
| 6 | + |
| 7 | +## 背景 |
| 8 | + |
| 9 | +### 現状の課題 |
| 10 | +- 新しい Dojo が追加されるたびに、DojoMap に表示させるために手動で CSV を更新する必要がある |
| 11 | +- この手動作業は時間がかかり、エラーが発生しやすい |
| 12 | + |
| 13 | +### 解決策 |
| 14 | +Global Clubs データベースの ID(`global_club_id`)を CoderDojo Japan の Dojo と紐付けることで、データの同期を自動化する。 |
| 15 | + |
| 16 | +## 設計決定 |
| 17 | + |
| 18 | +### 1. 命名規則 |
| 19 | + |
| 20 | +#### `global_club_id` を選択した理由 |
| 21 | +- `club_id` では `dojo_id` との違いが不明瞭 |
| 22 | +- `global_` プレフィックスにより、外部システムの ID であることが明確 |
| 23 | +- 将来的に状況が変わっても、名前を変更する必要がない |
| 24 | + - 想定ケース: CoderDojo Foundation (Zen API) -> Raspberry Pi Foundation (Clubs API) -> ??? (FooBar API) |
| 25 | + |
| 26 | +#### `GlobalClubs` モジュール名を選択した理由 |
| 27 | +- 現在は Raspberry Pi Foundation が管理しているが、過去には CoderDojo Foundation (Zen) が管理していた |
| 28 | +- 将来的に同じような変更が行われる可能性を考慮 (想定例: GraphQL の廃止、REST API への回帰、など) |
| 29 | +- 実装は現在の API(Raspberry Pi)に直接接続するが、命名は抽象的に保つ |
| 30 | + |
| 31 | +### 2. 実装方針 |
| 32 | + |
| 33 | +#### YAGNI 原則の適用 |
| 34 | +当初はアダプターパターンを検討したが、以下の理由でシンプルな実装を選択: |
| 35 | +- API プロバイダーの変更は頻繁には起こらない(もしくは永遠に起こらない) |
| 36 | +- 過度な抽象化は開発速度を低下させる |
| 37 | +- 必要になったときにリファクタリングすればよい |
| 38 | + |
| 39 | +#### API メソッドの命名 |
| 40 | +```ruby |
| 41 | +def fetch_global_clubs(organization_slug: 'coderdojo', after: nil) |
| 42 | +``` |
| 43 | +- `fetch_coderdojo_clubs` ではなく `fetch_global_clubs` を選択 |
| 44 | +- API は CoderDojo 以外の組織のクラブも返すため、より正確な命名 |
| 45 | +- `organization_slug` パラメータでフィルタリング可能 |
| 46 | + |
| 47 | +## 技術仕様 |
| 48 | + |
| 49 | +> **⚠️ 注意**: この節以降の内容は実装過程で変更される可能性があります。実際の実装とレビューを経て確定します。(2025-01-20時点) |
| 50 | +
|
| 51 | +### API エンドポイント |
| 52 | +- GraphQL: `https://clubs-api.raspberrypi.org/graphql` |
| 53 | +- 認証: Bearer token (OAuth flow) |
| 54 | +- レート制限: 60 req/min |
| 55 | + |
| 56 | +### データモデル |
| 57 | + |
| 58 | +#### Dojo モデルの拡張 |
| 59 | +```ruby |
| 60 | +# マイグレーション |
| 61 | +add_column :dojos, :global_club_id, :bigint |
| 62 | +add_index :dojos, :global_club_id, unique: true, where: 'global_club_id IS NOT NULL' |
| 63 | +``` |
| 64 | + |
| 65 | +#### 同期管理テーブル |
| 66 | +```ruby |
| 67 | +create_table :global_club_syncs do |t| |
| 68 | + t.bigint :global_club_id, null: false |
| 69 | + t.datetime :last_seen_at |
| 70 | + t.string :sync_status |
| 71 | + t.timestamps |
| 72 | +end |
| 73 | +``` |
| 74 | + |
| 75 | +### 同期戦略 |
| 76 | + |
| 77 | +#### 増分同期 |
| 78 | +- `updatedAt` フィールドを使用して、前回の同期以降に更新されたクラブのみを取得 |
| 79 | +- 全データを毎回取得するのではなく、効率的な差分更新を実現 |
| 80 | +- 冪等性を保証(同じ操作を複数回実行しても結果が同じ) |
| 81 | + |
| 82 | +#### マッチングアルゴリズム |
| 83 | +1. `global_club_id` で既存の Dojo を検索 |
| 84 | +2. 見つからない場合は、名前の類似度 + 地理的距離(1km 以内)で自動マッチング |
| 85 | +3. 曖昧な場合は手動レビューキューに追加 |
| 86 | + |
| 87 | +## 実装計画 |
| 88 | + |
| 89 | +### フェーズ 1: 基盤整備 |
| 90 | +1. データベーススキーマの更新(`global_club_id` カラム追加) |
| 91 | +2. YAML ファイルの構造更新 |
| 92 | +3. モデルのバリデーション追加 |
| 93 | + |
| 94 | +### フェーズ 2: API 統合 |
| 95 | +1. `GlobalClubs::Client` クラスの実装 |
| 96 | +2. GraphQL クエリの実装 |
| 97 | +3. 認証設定(Rails credentials) |
| 98 | + |
| 99 | +### フェーズ 3: 同期機能 |
| 100 | +1. `GlobalClubs::SyncService` の実装 |
| 101 | +2. マッチングロジックの実装 |
| 102 | +3. エラーハンドリングとリトライ機構 |
| 103 | + |
| 104 | +### フェーズ 4: 運用 |
| 105 | +1. 定期実行ジョブの設定 |
| 106 | +2. 監視とアラートの実装 |
| 107 | +3. 手動レビュー機能(将来的に) |
| 108 | + |
| 109 | +## セキュリティ考慮事項 |
| 110 | + |
| 111 | +- Bearer token は Rails credentials に保存 |
| 112 | +- API 通信は HTTPS のみ |
| 113 | +- レート制限に対応(指数バックオフでリトライ) |
| 114 | + |
| 115 | +## 運用上の注意点 |
| 116 | + |
| 117 | +### データの整合性 |
| 118 | +- ソフトデリート: Global Clubs API から削除されたクラブは `global_club_id = nil` に設定(Dojo レコードは削除しない) |
| 119 | +- 重複チェック: ユニーク制約により、同じ `global_club_id` を持つ複数の Dojo は作成できない |
| 120 | + |
| 121 | +### エラー処理 |
| 122 | +- ネットワークエラー: 自動リトライ(最大 3 回) |
| 123 | +- API エラー: エラーログに記録し、次回の同期で再試行 |
| 124 | +- マッチング失敗: 手動レビューキューに追加 |
| 125 | + |
| 126 | +## 今後の拡張可能性 |
| 127 | + |
| 128 | +- DojoMap との直接連携 |
| 129 | +- リアルタイム同期(Webhook 対応) |
| 130 | +- 他の組織のクラブとの連携 |
| 131 | + |
| 132 | +## 更新履歴 |
| 133 | + |
| 134 | +- 2025-01-20: 初版作成(設計決定まで確定、技術仕様以降は暫定版) |
0 commit comments