Skip to content

Commit 4c19a72

Browse files
committed
docs: Global Club ID 設計文書を追加
Raspberry Pi Foundation の Clubs DB と CoderDojo Japan の Japan DB を 連携させるための設計文書。 主な内容: - global_club_id カラムの追加(string型、UUID、NOT NULL) - 一度きりのマッピング(継続的同期は不要) - 新規 Dojo は申請時に global_club_id を必須入力 - データ管理は db/dojos.yml で行う(既存の運用通り) Fix #1616
1 parent 280f829 commit 4c19a72

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

doc/global_club_id_design.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Global Club ID Design
2+
3+
## 概要
4+
5+
このドキュメントは、Raspberry Pi Foundation が管理する国際的な Clubs DB と CoderDojo Japan の Japan DB を連携させる機能の設計と実装について記載しています。
6+
7+
## 背景
8+
9+
### 現状
10+
11+
- Clubs DB(Global Clubs)と Japan DB(CoderDojo Japan)が独立している
12+
- 両者を紐付ける ID がない
13+
14+
### 解決策
15+
Clubs DB の ID(`global_club_id`)を Japan DB の Dojo と紐付ける。
16+
17+
## 設計決定
18+
19+
### 1. 命名規則
20+
21+
#### `global_club_id` を選択した理由
22+
- `club_id` では `dojo_id` との違いが不明瞭
23+
- `global_` プレフィックスにより、外部システムの ID であることが明確
24+
- 将来的に状況が変わっても、名前を変更する必要がない
25+
- 想定ケース: CoderDojo Foundation (Zen API) -> Raspberry Pi Foundation (Clubs API) -> ??? (FooBar API)
26+
27+
#### `GlobalClubs` モジュール名を選択した理由
28+
- 現在は Raspberry Pi Foundation が管理しているが、過去には CoderDojo Foundation (Zen) が管理していた
29+
- 将来的に同じような変更が行われる可能性を考慮 (想定例: GraphQL の廃止、REST API への回帰、など)
30+
- 実装は現在の API(Raspberry Pi)に直接接続するが、命名は抽象的に保つ
31+
32+
### 2. 実装方針
33+
34+
#### YAGNI 原則の適用
35+
当初はアダプターパターンを検討したが、以下の理由でシンプルな実装を選択:
36+
- API プロバイダーの変更は頻繁には起こらない(もしくは永遠に起こらない)
37+
- 過度な抽象化は開発速度を低下させる
38+
- 必要になったときにリファクタリングすればよい
39+
40+
#### API メソッドの命名
41+
```ruby
42+
def fetch_global_clubs(organization_slug: 'coderdojo', after: nil)
43+
```
44+
- `fetch_coderdojo_clubs` ではなく `fetch_global_clubs` を選択
45+
- API は CoderDojo 以外の組織のクラブも返すため、より正確な命名
46+
- `organization_slug` パラメータでフィルタリング可能
47+
48+
## 技術仕様
49+
50+
> **⚠️ 注意**: この節以降の内容は実装過程で変更される可能性があります。実際の実装とレビューを経て確定します。(2025-01-20時点)
51+
52+
### API エンドポイント
53+
- GraphQL: `https://clubs-api.raspberrypi.org/graphql`
54+
- 認証: 不要(読み取り専用)
55+
- レート制限: 60 req/min
56+
57+
### データモデル
58+
59+
#### Dojo モデルの拡張
60+
```ruby
61+
# マイグレーション(必要なのはこれだけ!)
62+
# UUID 文字列(例: "18704b53-1042-4464-9d49-8820c6ff8c97")
63+
add_column :dojos, :global_club_id, :string, null: false
64+
add_index :dojos, :global_club_id, unique: true
65+
```
66+
67+
### マッピング戦略
68+
69+
#### 初期マッピング(一度だけ実行)
70+
1. Clubs DB から全 CoderDojo を取得
71+
2. 既存の Dojo と手動で照合:
72+
- 名前は異なることが前提(Clubs DB は英語、Japan DB は日本語)
73+
- Japan DB には位置情報がないため、地理的照合は不可
74+
3. 人間が判断して `global_club_id` を設定
75+
76+
**重要な仕様理解**:
77+
- **名前の違いは正常**: Clubs DB(英語話者向け)と Japan DB(日本語話者向け)で名前が異なるのは仕様
78+
- **位置情報**: Japan DB にはなく、Clubs DB のみに存在
79+
- **用途例**: DojoMap アプリで global_club_id を使って英語名→日本語名の変換を行う
80+
81+
## 実装タスク(Issue #1616 より)
82+
83+
1. **Dojo モデルに `global_club_id` カラムを追加**
84+
```ruby
85+
class AddGlobalClubIdToDojos < ActiveRecord::Migration[8.0]
86+
def change
87+
# UUID 文字列(例: "18704b53-1042-4464-9d49-8820c6ff8c97")
88+
add_column :dojos, :global_club_id, :string, null: false
89+
add_index :dojos, :global_club_id, unique: true
90+
end
91+
end
92+
```
93+
94+
2. **db/dojos.yml の全 Dojo に `global_club_id` を追加**
95+
96+
3. **Clubs DB と Dojo ID を紐付ける仕組みを作成**
97+
98+
99+
100+
101+
102+
## セキュリティ考慮事項
103+
104+
- HTTPS 通信(読み取り専用 API)
105+
106+
## 運用上の注意点
107+
108+
### データの整合性
109+
- **ユニーク制約**: 同じ `global_club_id` を持つ複数の Dojo は作成できない
110+
- **NOT NULL 制約**: すべての Dojo に `global_club_id` が必須
111+
- **修正方法**: db/dojos.yml を編集して DB に反映(通常の運用通り)
112+
113+
114+
## 成功指標
115+
116+
1. **global_club_id カラムの追加完了**
117+
2. **既存 Dojo への ID 設定完了**
118+
3. **DojoMap への自動反映の実現**(Issue #1616 の目的)
119+
120+
## シンプルなワークフロー
121+
122+
### 新規 Dojo 追加時(申請フォームで対応)
123+
124+
```
125+
1. 申請時に Clubs DB での登録状況を確認してもらう
126+
2. global_club_id を申請フォームに記入(必須)
127+
3. db/dojos.yml に global_club_id 付きで追加
128+
```
129+
130+
### 初期マッピング(一度だけ実行するスクリプト)
131+
132+
```ruby
133+
# scripts/map_global_clubs.rb
134+
# 既存の全 Dojo に global_club_id を設定
135+
136+
clubs = GlobalClubs.fetch_all_coderdojo_clubs # 読み取り専用 API
137+
dojos = Dojo.active
138+
139+
puts "Clubs DB: #{clubs.count} clubs"
140+
puts "Japan DB: #{dojos.count} dojos"
141+
puts ""
142+
puts "Manual mapping needed:"
143+
puts "Clubs DB (English) | Japan DB (Japanese)"
144+
puts "---------------------------|--------------------"
145+
146+
clubs.each do |club|
147+
# club.id は UUID 文字列(例: "18704b53-1042-4464-9d49-8820c6ff8c97")
148+
puts "#{club.name.ljust(26)} | ???"
149+
end
150+
151+
# 手動で db/dojos.yml に global_club_id を追加
152+
# 例: global_club_id: "18704b53-1042-4464-9d49-8820c6ff8c97"
153+
```
154+
155+
156+
157+
## 更新履歴
158+
159+
- 2025-01-20: 初版作成(設計決定まで確定、技術仕様以降は暫定版)
160+
- 2025-08-18: YAGNI原則に基づく大幅簡素化
161+
- 不要なカラム削除(confidence, last_sync)
162+
- 継続的同期を削除(一度きりのマッピングに変更)
163+
- 複雑な監視・測定機能を削除
164+
- シンプルなワークフローに変更
165+
- CoderDojo運用の実態に合わせた現実的な設計に修正
166+
167+
## 実装チェックリスト
168+
169+
### 必要最小限の実装
170+
- [ ] `global_club_id` カラムの追加(string型、NOT NULL、UUID)
171+
- [ ] 読み取り専用の Clubs API クライアント実装
172+
- [ ] 既存 Dojo への一括マッピングスクリプト
173+
- [ ] 申請フォームに global_club_id 入力欄追加(必須)
174+
175+
### やらないこと(YAGNI)
176+
- ❌ APIトークン管理(読み取り専用なので不要)
177+
- ❌ 継続的な同期処理
178+
- ❌ null を許可(全 Dojo に必須)
179+
- ❌ 複雑な監視ダッシュボード
180+
- ❌ 自動マッチング(手動で確実に設定)

0 commit comments

Comments
 (0)