Skip to content

Commit d7bcb7e

Browse files
yasulabrakuda-san-desu
authored andcommitted
📝 Global Clubs連携機能の設計ドキュメントを追加
Raspberry Pi FoundationのClubs APIとCoderDojo Japanのデータベースを 連携させる機能の設計と実装計画をドキュメント化。 主な内容: - 背景と現状の課題 - 命名規則の決定理由(global_club_id, GlobalClubsモジュール) - YAGNI原則に基づくシンプルな実装方針 - 技術仕様(暫定版)と実装計画 refs #1616
1 parent 4a0616a commit d7bcb7e

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

docs/global_clubs_integration.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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

Comments
 (0)