github-reporadar
v0.11.0
Published
自分のGitHub活動を一晩ぶん眺める計器盤。npx github-reporadarでローカルに開く
Downloads
1,566
Readme
GitHub RepoRadar
多数の個人リポジトリを並行開発する人のための「どこで何を作っていたか」想起ダッシュボード。 GitHub の活動(commit / PR / issue)を期間指定で集約し、Web UI とターミナルの両方から確認できます。
毎日の使い方(自分用の早見表)
平日11:00-19:00は自動で動きます。詳しくは docs/毎日の運用.md。
最初に1回だけ。
echo "alias radar='~/dev/env/github-reporadar/ops/reporadar-workday.sh'" >> ~/.zshrc && source ~/.zshrc以後打つのは3つだけ。
| 打つもの | いつ |
|---|---|
| radar start | 土日・深夜・時間外に見たいとき |
| radar status | 動いているか |
| radar stop | 止めるとき |
見る場所は2つだけ。
| 見るもの | 場所 |
|---|---|
| 画面 | http://127.0.0.1:5177/ |
| うまくいかないとき | tail -20 ~/.local/state/github-reporadar/workday.log |
新しいPCではこの3行。gh auth loginが済んでいれば、設定ファイルも自動で作られます。
git clone https://github.com/BoxPistols/github-reporadar.git ~/dev/env/github-reporadar
cd ~/dev/env/github-reporadar
./ops/install.shはじめての起動だけ、同期が終わるまで1分ほど画面が開きません。2回目からは1秒で開き、同期は裏で走ります。
機能
Web UI はヘッダーでモードを切り替えます。
- ダッシュボード: 日次×repo ヒートマップ + repo カード/テーブル。期間(7/30/90日)・ソート(活動量/最終push/放置)・キーワード検索・タグ・Bookmark(★)。 絞り込みは「活動量(期間内 commit 数の下限)」×「最終push(N日以内 / N日以上放置)」の2軸と、 よく使う組み合わせのプリセット(🔥 活発 × 30日以内 / ⚡ 直近7日 / 💤 30日以上放置)。カードから「次にやること」メモ。 モバイルではカードがアコーディオンになり、既定は全て閉じた状態。単一展開/複数展開の切替と「全て開く/全て閉じる」で開き方を選べる。
- ボード: 総合 Projects。Backlog/Active/Review/Done/Dormant の列に repo や自由タスクのカードを DnD で並べる。
- 検索: 全 repo の open issue/PR を横断全文検索(日本語対応)+ type/repo/label ファセット + ラベル別件数。
- Wiki: 自分が関わったConfluenceのページを更新順に並べる一覧。タイトルとスペースでの検索、スペース・「他人が更新」・「要確認」での絞り込み。ローカル版だけで、Atlassianの設定が無ければモード自体を出しません。
User data(タグ/Bookmark/ボード/メモ)の保存先は既定でブラウザローカル(IndexedDB)。ヘッダーの 「☁ 同期フォルダを接続」で OneDrive/iCloud/Dropbox 等の同期フォルダを選ぶと、端末間で共有できます (BE/DB レス、同期は OS のクラウドクライアント任せ)。
必要なもの
- Node.js 20+ / pnpm
- gh CLI でログイン済みであること(
gh auth login)
トークンは実行時に gh auth token から読むだけで、ファイルには一切保存しません。
npxで使う(インストール不要)
npx github-reporadar # 同期してからローカルで開く
npx github-reporadar brief # 端末に要約を出す
npx github-reporadar --help # フラグの一覧- 前提は
gh auth login済みのgh CLIだけ。トークンは実行時にgh auth tokenから読み、保存しない - データは
$XDG_CACHE_HOMEか~/.cacheのgithub-reporadar/data/に置く。カレントディレクトリには落とさない(private repo名とコミット文が入るため)。--data-dirで変えられる - 待ち受けは
127.0.0.1だけ。ポートは既定5177で、使用中なら次を探す --no-syncで手元のデータだけで開く。--days 30で取得期間を変える--org <組織名>で組織のrepoも足せる(繰り返し可)。組織では自分がauthorのコミットと、自分が作ったか担当のopen issue/PRだけを数える。読むだけで、組織側には何も書かない。一覧では組織名/repo名で出る
npmには実データを含めない。filesでdist/dataを除外し、prepublishOnlyでも消し、npm pack --dry-runに/data/が無いことをテストで固定している。
業務での使い方(組織のrepoをまたいで働く人向け)
例として、example-companyという組織でexample-company/storefrontとexample-company/billingを触りながら、個人のexample-user/notesも動かしている人の1日で書きます。名前はすべて架空です。
前提と境界
| 項目 | 中身 |
|---|---|
| 動かす場所 | 自分のPCだけ。npx github-reporadar --org example-company。公開版(github-reporadar.vercel.app)は個人repoだけで、組織は出ない |
| なぜ公開版に組織を出さないか | 組織のprivateなrepo名・コミット文・PRタイトルがVercelのサーバーを通ることになる。それを避けるため、組織のデータはあなたのPCとGitHubの間だけで動かす |
| 組織への影響 | 読むだけ(GET)。組織側には何も書かない。組織の管理者の許可が要る操作は無い |
| 数えるもの | 組織のrepoでは自分がauthorのコミットと、自分が作ったか担当のissue/PRだけ。他人の作業は数に入らない |
| データの置き場 | ~/.cache/github-reporadar/data/。共有端末では使わない。消したいときはそのフォルダを削除する |
| トークン | gh auth tokenを実行時に読むだけ。ファイルには保存しない。組織がSSOなら、先にgh auth refresh -h github.com -s read:orgで組織を認可しておく |
朝、今日やることを決める
npx github-reporadar --org example-company --days 30ブラウザが開いたら、フィルターバーの上段を左から見ます。
| 札 | 意味 | 次の一手 | |---|---|---| | レビュー待ちの自分のPR 3 | 自分が出して、ドラフトでなく、まだ承認されていないPRが3件 | 放置されているものはレビュアーに声をかける。「要修正」の札が付いていれば指摘に対応する | | Draftの自分のPR 2 | 自分のDraft PRが2件 | 仕上げてReady for reviewにするか、閉じる | | 自分がレビューするPR 1 | レビューを頼まれているPRが1件 | 他人を待たせているのはこれ。先に片付ける | | 手を付けていない自分のissue 5 | 自分が作ったopen issueで、自分のopen PRがまだ閉じる予定になっていないもの | 今日やるものを1つ選んでブランチを切る |
札を押すと、その仕事があるrepoだけが一覧に残ります。もう一度押すと外れます。
昼、1つのrepoに集中する
一覧でexample-company/storefrontを選ぶと、右の詳細ペインに出ます。
| 節 | 中身 |
|---|---|
| レビュー待ちの自分のPR | 番号と題名。番号を押すとGitHubのPRが開く。CHANGES_REQUESTEDのものには「要修正」の札 |
| 自分がレビューするPR | 依頼されているPR。番号からGitHubへ |
| 直近のコミット | 自分のコミットの1行目。(#1419)のような番号はそのissue/PRへのリンク |
| 次にやること | このrepoのメモ。ブラウザの中に保存され、「メモを他のPCと共有」を押していれば選んだフォルダにも書かれる |
キーワードで探すときはCmd+K(Windows/LinuxはCtrl+K)か/で検索欄に飛びます。Escapeで消して離れます。
夕、端末で振り返る
npx github-reporadar brief --org example-company --days 7 --private直近7日のコミット数、最終push、最新コミットの1行目をrepoごとに1行で出します。日報の下書きに使えます。
個人と組織を分けて見る
--orgを付けなければ個人repoだけです。組織だけを見たいときは、フィルターバーの検索欄にexample-company/と入れると、その組織のrepoだけに絞れます。一覧では別ownerのrepoがexample-company/storefrontのように組織名つきで出るので、個人のnotesと見分けられます。
一日中開いておく(受信箱)
npx github-reporadar --org example-company --watch 1m--watchを付けると、開いたままその間隔でopen issue/PRを取り直します。同期のたびに前回との差分から「自分に起きたこと」をevents.json(データdir)に足していきます。
毎回はopen issue/PRとレビュー状態だけを取り、コミットは30分ごとにまとめて取ります。GitHubのAPIは認証済みで5000回/時なので、実測にもとづく目安はこうです。
| 間隔 | 1時間の消費(完全同期を含む) | 上限に対して |
|---|---|---|
| 30s | 4,430 | 89%。ghコマンドを併用する余裕が少ない |
| 1m | 2,390 | 48%。おすすめ |
| 5m | 700 | 14% |
実測値は1回あたり、軽い同期がREST 34回で6秒、完全同期がREST 175回で13秒(42 repo、うち組織5)。repo数が増えると完全同期の側が伸びます。30秒未満は受け付けません。
| 出来事 | 条件 | |---|---| | レビュー依頼が来た | 他人のPRで、レビューを頼まれた人に自分が新しく入った | | 要修正が付いた / 承認された / コメントが付いた | 自分のPRに他人のレビューが1つ増えた。自分自身のレビューは数えない | | 対応済み、再レビュー待ち | 要修正の自分のPRに、最後のレビューより新しい自分のコミットが載った | | 閉じられた | 自分のopen PRが一覧から消えた(マージかクローズ) |
初回の同期では何も出しません。溜まっていた分を一斉に出すと、新しく起きたことが埋もれるためです。画面のバッジと通知は次の版で入ります。
既定では組織のrepoの出来事だけを出します。個人repoのbotレビューが「あなたの番」を埋めるためです。ConfluenceとSlackは仕事の側なので残ります。「組織だけ」を押すと個人repoも出ます。
出す順は「誰が止まっているか」で分け、同じ組の中では組織のrepoを先に置きます。Confluenceの更新は「Wikiの更新」として独立した組にし、「あなたの番」の下、「知らせ」の上に置きます。GitHubの知らせと同じ組に混ぜると、他人が直したデザインルールが数十行の下に沈んで見えなくなります。個人のrepoは下にまとまります。依存更新のPRのように、botが起こしたレビュー依頼は「他人を待たせている」には入れません。人は止まっていないためです。
一覧は「何が起きたか」ではなく「どこで起きたか」で1行にします。同じPRにレビューが7回付いても1行で、見出しは最新のもの、残りは「ほか6」と添えます。1つのPRを7行に割ると、1行ずつ既読にしても同じPRの別の行が残り、読んでも減らないように見えるためです。
読んだものはその場で一覧から消えます。1件ずつの「既読」と、リンクを開いたときの既読があり、どちらもその行にまとまっている出来事をまとめて消します。それより古い未読は残ります。「すべて既読」は時刻で一気に消します。消えたものは「履歴」で見られます。
平日の勤務時間だけ動かす(macOS)
launchdで平日11:00に起動し、19:00に停止します。土日は動きません。
git clone https://github.com/BoxPistols/github-reporadar.git
cd github-reporadar
mkdir -p ~/.config/github-reporadar
cat > ~/.config/github-reporadar/workday.env <<'ENV'
RR_ORGS="example-company"
RR_WATCH=20m
RR_PORT=5177
ENV
./ops/install.sh設定ファイルはリポジトリの外(~/.config/github-reporadar/workday.env)に置きます。組織名を含むので、リポジトリには入れません。
| コマンド | 中身 |
|---|---|
| ./ops/install.sh | launchdに登録。平日11:00起動 / 19:00停止 |
| ./ops/install.sh uninstall | 登録を解除 |
| ./ops/reporadar-workday.sh start / stop / status | 手で起動・停止・確認 |
ログは~/.local/state/github-reporadar/workday.logです。二重起動はしません。ghにログインしていなければ起動せず、理由をログに残します。
20分間隔なら、1時間あたりのGitHub APIの消費は約313回で上限の6%です(軽い同期が約1.5回、完全同期が約1.5回)。8時間動かしても上限には触れません。
launchdは対話シェルのPATHを継がないので、install.shが実行時のPATHをplistに焼き込みます。nodeやghの場所を変えたら登録し直してください。
毎日の運用
登録したあとは、こちらから何もしなくても動きます。
| 時刻 | 起きること | |---|---| | 平日11:00 | 起動して完全同期を1回。以後20分ごとにopen issue/PRを取り直す | | 20分ごと | 受信箱に差分が溜まる。ブラウザを開いていれば通知が出る | | 30分ごと | コミットも含めた完全同期 | | 平日19:00 | 停止 | | 土日 | 動かない |
自分でやることはこれだけです。
- 朝、http://127.0.0.1:5177/ を開く。ブックマークしておく
- フィルターバーの札で今日やることを決める(レビュー待ちの自分のPR、自分がレビューするPR、Draft、手を付けていないissue)
- 受信箱に未読が付いたら開く。番号を押すとGitHubへ飛び、その1件は一覧から消える。まとめて消すときは「すべて既読」、振り返るときは「履歴」
- 迷ったら壁打ちで「今日の作業順を決めたい」と聞く
初回だけ、受信箱の「通知を許可」を1回押してください。ブラウザを閉じている間の出来事もevents.jsonに溜まるので、翌朝に開けば読めます。
様子がおかしいとき
| 症状 | 見るところ |
|---|---|
| 画面が開かない | ./ops/reporadar-workday.sh status。動いていなければstart |
| 数字が古い | ログの末尾。tail -20 ~/.local/state/github-reporadar/workday.log |
| 受信箱が空のまま | 差分は前回の同期との比較で出る。初回同期の直後は必ず空。1回目の20分を待つ |
| 「gh にログインしていません」 | gh auth login。組織がSSOならgh auth refresh -h github.com -s read:orgも |
| 組織のrepoが出ない | 設定のRR_ORGS。cat ~/.config/github-reporadar/workday.env |
| 通知が来ない | ブラウザの通知許可。受信箱を開いて「通知を許可」が出ていないか |
| 起動しなくなった | nodeやghの場所が変わった可能性。./ops/install.shで登録し直す |
更新とやめかた
./ops/reporadar-workday.sh restart # 新しい版に入れ替える(npxが@latestを取り直す)
./ops/install.sh uninstall # 自動起動をやめる
./ops/reporadar-workday.sh stop # いま動いているものを止める新しい版は次の11:00の起動から自動で使われます。すぐ入れ替えたいときだけrestartします。
Confluenceとの齟齬を出す(Atlassian連携)
ページを書いたあとに実装が進んだものを「Wiki要確認」として出します。本文と題に出てくるrepo名を拾い、そのrepoのpushがページ更新より新しければ挙げます。自分が関わったページと、見張っているフォルダの配下が対象です。他人が書いたページには「他人のページ」と添えます。
前提はこうです。値そのものは実装が正で、ページはその意図と使い方を書く場所です。だから食い違いが出たときに直す先はページのほうです。押すとそのページが開きます。
1ページ1行です。1枚のページが4つのrepoに触れていれば、repoは遅れの大きい順に並べて「ほか3」と添えます。repoごとに行を割ると、同じ題が何度も並びます。
「確認」を押すとその行は消え、数が減ります。押した時点でいちばん新しかったpushを覚えていて、そのあとに実装が進めばまた出ます。スプリントの記録のように一度読んだら読み直さない文書には「もう見ない」を使います。こちらはpushが来ても二度と出しません。Wikiのページは閉じることがなく残り続けるので、GitHubのPRのように「解決したら終わり」になりません。だから人が見て「いまは直さない」と決めたものを数から外せるようにしています。消したものは「履歴」で見られます。
トークンはファイルに置かず、macOSのキーチェーンから実行時に取ります(ghと同じ考え方)。JiraとConfluenceは同じサイトと同じトークンを使います。
# 1. Atlassianでトークンを作る
open https://id.atlassian.com/manage-profile/security/api-tokens
# 2. キーチェーンに入れる(<>は置き換える)
security add-generic-password -s github-reporadar-atlassian -a "<メールアドレス>" -w "<APIトークン>"
# 3. 設定に足す
cat >> ~/.config/github-reporadar/workday.env <<'ENV'
RR_ATLASSIAN_SITE=example.atlassian.net
[email protected]
ENVRR_CONFLUENCE_SPACES="EXAM OTHER"でスペースを絞れます。省略すると自分が関わった全ページです。
決まった場所を見張る
RR_CONFLUENCE_FOLDERS="2149875783"(--confluence-folder)を足すと、そのフォルダの配下は自分が関わっていないページも取ります。誰かが足したページは「Confluenceにページが追加」、直したページは「Confluenceのページが更新」として受信箱に出ます。IDの代わりにフォルダのURLをそのまま貼っても通ります。
自分が関わったページだけを取る既定では、他人が新しく作ったページは取得の対象にすら入りません。設計やUIのルールのように、置き場所は決まっているが書き手が自分とは限らないものは、場所のほうを指定します。
追加として出すのは、前回の同期より後に作られたページだけです。見張る場所を足した日に、過去のページが一斉に鳴るのを避けるためです。齟齬(Wiki要確認)の対象は今までどおり自分が関わったページだけで、見張っている場所のページは件数に混ざりません。
拾うのは、そのPCが取得しているrepoの名前だけです。知らない語をrepo名として扱うことはありません。名前だけで拾うのは、記号か数字を含むもの(sdpf-thing)か8文字以上のものです。uiやdesignのように普通の単語と同じ綴りのrepoは、owner付き(example-org/design)かGitHubのURLで書かれているときだけ拾います。本文の地の文に当たるのを避けるためです。
別のownerに同じ名前のrepoがあるときも、名前だけでは決めずowner付きを求めます。
ページ更新からpushまで24時間未満のものは出しません。書いた直後の手直しを齟齬として数えないためです。
リンクのURLはタグの属性に入るので、リンクの文字が「リポジトリ」でも中のGitHubのURLからrepoを拾います。
自分が関わったページを誰かが更新したら、受信箱にも出します。自分の更新では鳴りません。
Slackのメンションを受信箱に出す
自分あてのメンションが付いたら受信箱に出します。残すのは、どのチャンネルで誰が呼んだかと発言へのリンクだけです。発言の本文は保存しません。壁打ちへも渡しません。
security add-generic-password -s github-reporadar-slack -a slack -w "<ユーザートークン>"要るスコープはsearch:readだけです。トークンが無ければ何もしません。
トークンはSlackアプリを作って自分のアカウントに入れる形で取ります。手元のslack CLI(v4.6.0)のトークンでは足りません。認証は通りますが検索がmissing_scopeで弾かれます(実測)。企業のワークスペースではアプリの導入に管理者の承認が要ることがあります。
取りに行くのは自分が関わったページの最大200件です。更新の新しい順に並ぶので、50件ずつ続きを取って最後まで辿ります。1回で打ち切ると、長く放置されたページから先に落ちます。
Jiraの課題も見る
自分が担当か報告者の未完了課題を取り込み、壁打ちの文脈に入れます。GitHubのPRと並べて「今日の作業順」を相談できます。
Confluenceと同じ設定(RR_ATLASSIAN_SITE / RR_ATLASSIAN_EMAIL)で動きます。RR_JIRA_PROJECTS="EXAM OTHER"でプロジェクトを絞れます。省略すると自分に関わる全プロジェクトです。
設定かトークンが無ければ、JiraもConfluenceも何もしません。取得に失敗しても同期そのものは止まらず、GitHub側の結果は残ります。
壁打ちの範囲を「個人開発」にしているときは、Jiraの課題もConfluenceの齟齬も文脈に入れません。仕事のものなので前提が混ざります。
運用の方針
| 方針 | 理由 |
|---|---|
| 「リアルタイム」はポーリング(--watch)で作る | GitHubのWebhookは受け口のサーバーが要り、ローカル完結と矛盾する。毎回の同期をopen issue/PRだけに絞ってREST 34回にしたので、1分間隔でも上限の半分で収まる(実測)。コミットは30分ごと |
| 出来事は前回との差分から作る | GitHubの通知APIは組織の全件が混ざり、自分のPRに関することだけを取り出しにくい。前回のissues.jsonと比べるだけなら追加のAPIも権限も要らない |
| 組織はローカルだけ | 上の「前提と境界」のとおり。公開版に足すなら組織管理者への説明と明示同意の画面が先 |
| 通知はブラウザのNotification API(次の版) | ページを開いている間に出る。OSの通知センターまで欲しい場合はCLI側から出す案があるが、まずはブラウザで足りるかを見る |
| 受信箱を壁打ちに渡す(その次の版) | 「今日の作業順」「この指摘への対応の優先度」を、受信箱と仕事の状態を文脈にして相談する |
よくある疑問
| 疑問 | 答え |
|---|---|
| 組織のコミット数が少ない | GitHubはコミットのメールアドレスをアカウントに結んで数える。会社のメールで作業しているなら、GitHubのSettings → Emailsにそのアドレスを足す。過去分も結び付く |
| 「レビュー待ち」なのに承認されているPRが出る | 同期が古い。npx github-reporadar --org example-companyを打ち直す。画面は同期のたびに作り直される |
| 公開版でも組織を見たい | 現状は対象外(上の「前提と境界」)。要望があれば、組織の管理者への説明と明示同意の画面を先に作る |
| 他の人にこの画面を見せたい | 見せない。データには組織のprivateな情報が入っている。共有するなら、briefの出力から必要な行だけ写す |
使い方
pnpm install
pnpm sync # GitHub から直近90日の活動を取得して public/data/ にキャッシュ
pnpm dev # Web UI (http://localhost:5173)
pnpm brief # ターミナルで簡易確認CLI オプション
pnpm brief --days 7 --sort stale --limit 20
# --days 7|30|90 (default 30)
# --sort active(活動量順) | recent(最終push順) | stale(放置順)
# --limit 表示件数 (default 15)
# --private private repo も表示 (既定は public のみ。Web UI はヘッダーのチェックボックスで切替)
pnpm sync --days 30 # 取得期間の変更構成
scripts/sync.ts collector: repo ごとの REST commits API → public/data/*.json
scripts/brief.ts CLI: キャッシュを読んでターミナルに要約表示
src/ viewer: Vite + React + Tailwind v4 (キャッシュを読むだけの純フロント)
src/lib/aggregate.ts 期間集計の純関数 (vitest でテスト)データソースについて
GraphQL contributionsCollection は使いません。private リポジトリの内訳を
restrictedContributionsCount に集約して返す (repo 別内訳から欠落する) ため、
repo ごとの REST commits API を一次ソースにしています。
対象: 期間内に push があった 自分が owner の repo のみ(組織・共同 repo は収集しない)
bot (
author.type === 'Bot') を除く全コミットを集計。期間内にコミットの無い repo は除外private repo はローカルキャッシュにのみ保存し、表示は既定オフ (Web はトグル、CLI は
--private)。 公開ホスト版は既定では private を取得しない(下の「private を含める」参照)日付は実行環境のローカルタイムゾーンで日別化 (UTC 境界ずれを回避)
制約: デフォルトブランチのみ (未マージのブランチ作業は反映されない)
キャッシュ (
public/data/) には private リポジトリ名・コミットメッセージ・issue/PR タイトルが含まれるため gitignore 済みviewer はネットワークアクセスなし。GitHub API を叩くのは collector のみ
ローカル版のデプロイ注意
ローカル版(VITE_HOSTED 無し)は公開ホストにデプロイしないこと。public/data/ のキャッシュに
private リポジトリ名・コミット文・issue タイトルが入るため。public/data/ と dist/ は
gitignore + .vercelignore 済み(git 連携デプロイにはデータが入らない=空画面になる)。
公開したい場合は下の「公開ホスト版(GitHub OAuth)」を使う(各ユーザーが自分のデータを見る方式で安全)。
公開ホスト版(GitHub OAuth + Vercel)
各ユーザーが自分の GitHub でログインし、自分の public リポジトリの活動を見られる公開版
(api/ の Vercel Functions)。VITE_HOSTED=1 のときこのモードになる。他人がアクセスしても
その人自身の public データしか見えず、あなたのデータは見えない。
仕組み / セキュリティ
- OAuth トークンは httpOnly + Secure Cookie(ブラウザ JS から読めない=XSS 耐性)。
client_secretは Vercel Function のみ - OAuth
stateで CSRF 対策、最小権限(空スコープ) - 各ユーザーのデータはそのユーザーのトークンで 実行時に GitHub API から取得(
/api/data)。静的キャッシュは持たない - User data(タグ/ボード/メモ)は各ブラウザの IndexedDB(端末ローカル)
- 既定は public のみ(空スコープ)。private は明示同意した人だけ(下記)
private を含める(明示同意)
既定のサインインは空スコープなので、public しか見えない。private も見たい場合は
サインイン画面の「private も含めてサインイン」か、ヘッダーの「🔒 private を有効化」から
/api/auth/login?private=1 に進み、GitHub の認可画面で repo スコープを許可する。
- 許可の意思は OAuth の
stateに載せて往復し、セッション(暗号化 cookie)にprivateOptInとして残す /api/dataが private を取るのはprivateOptInかつ 実際に付与されたスコープにrepoがあるときだけ。 OAuth App のスコープはユーザーごとに累積する(一度repoを許可すると、以後は空スコープを要求してもrepo付きのトークンが返る)ため、「読めること」を同意の証拠にしない- 許可すると private の repo 名・コミット文・issue タイトルがこのホストを経由する(表示されるのは本人のデータのみ)
- 取り消したいときはサインアウトする。サインアウトは認可自体を revoke するので、 次回は public だけのサインインを選び直せる
デプロイ Runbook(この repo の本番: github-reporadar.vercel.app)
この repo は private のため、実際の URL・手順をここに記載する(secret は記載しない)。
現在の状態(2026-08-31)
- 本番 URL: https://github-reporadar.vercel.app
- Git連携は接続済み。mainへのpushで本番へ自動デプロイされる(手動デプロイは不要)
- 環境変数(Production)設定済み:
VITE_HOSTED=1/APP_URL=https://github-reporadar.vercel.app - 未設定(あなたの操作待ち):
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET/SESSION_SECRET - 未設定の間、
/api/auth/loginは503の「サーバー未設定」ページを返す。これは正しい状態 - 3つのうち1つでも欠けると503のまま。
getConfig()は4つ揃って初めて設定済みと見なす (APP_URLを含む)。SESSION_SECRETはセッションcookieの暗号鍵で、手順2で自分で作る
注意: 2026-08-31まで、本番の
/api/*は全て500(FUNCTION_INVOCATION_FAILED)だった。 原因はenv未設定ではなく、ESMの相対importに拡張子が無かったこと。 ローカル検証(tsx/vite)は拡張子なしを解決するため再現せず、Vercel上のNode ESMだけで落ちていた。 修正済み。api/esmImports.test.tsが同じ壊れ方を止める。
GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRETはどこかに存在する値ではなく、下の手順1で OAuth App を作った瞬間に GitHub が発行する。 Client Secret は発行直後の1回しか表示されない (控え損ねたら、同じ画面で新しい secret を再発行して古い方を失効させる)。
残りの手順
GitHub OAuth App を作成 → https://github.com/settings/applications/new (一覧は https://github.com/settings/developers の "OAuth Apps")
- Application name: 任意(例
RepoRadar)。GitHubはGitHubで始まる名前を拒否する - Homepage URL:
https://github-reporadar.vercel.app - Authorization callback URL:
https://github-reporadar.vercel.app/api/auth/callback - Allow wildcard matching / Enable Device Flowはオフのまま
- 「Expire user access tokens」という項目は探さなくてよい。これはGitHub Appのラベルで、 OAuth Appの設定画面には無い。OAuthアプリのアクセストークンは既定で無期限に発行される
- 作成後の画面に Client ID が表示される。Client Secret は 「Generate a new client secret」を押して発行し、その場でコピーする
- Application name: 任意(例
Vercelに3つの環境変数を追加(Production) → https://vercel.com/asagiri/github-reporadar/settings/environment-variables
GITHUB_CLIENT_ID= 上のClient IDGITHUB_CLIENT_SECRET= 上のClient Secret(secretはここ(Vercel)にのみ入れる。gitやチャットに貼らない)SESSION_SECRET= 自分で生成する乱数。セッションcookieをAES-GCMで封じる鍵で、 GitHubから貰う値ではない。openssl rand -base64 32の出力をそのまま貼る (この値を変えると全員が一斉にサインアウトする。復旧手段は再サインインのみ)
再デプロイ(
VITE_HOSTEDと違いGITHUB_CLIENT_*は実行時変数だが、 env追加だけでは既存のデプロイに反映されないので再ビルドする)- Git連携は接続済みなので、mainへpushすれば自動デプロイされる
- 手元から流すなら
vercel --prod --yes(要vercel login) - 最新デプロイがgit由来になったので、ダッシュボードのRedeployも使える
これで https://github-reporadar.vercel.app が「GitHub でサインイン」画面になり、ログイン後に各自の
public 活動が見える。設定前にアクセスすると「このサーバーは OAuth 未設定です」と表示される
(サインインを押して行き止まりにならないよう、未設定を検知して案内を出す)。
マージ前ゲート(CIが止まっている間の代替)
GitHub ActionsはFreeプランだとprivateリポジトリで月2000分の枠がある。使い切ると
ジョブが起動せず、PRのチェックは「テスト失敗」ではなく未実行のまま赤くなる。
その間は手元のpnpm verify(test → typecheck → build)が唯一の関門になる。
pnpm verify.githooks/pre-pushが同じものをpush前に走らせる。クローン直後は1度だけ紐付けが要る。
git config core.hooksPath .githooks飛ばしたい時はgit push --no-verify。実Chromeのe2e(pnpm e2e)はpublic/data/が
要るのでこのゲートには入れていない。
ローカル ⇔ 本番の切替
- ローカル(
pnpm dev/preview):VITE_HOSTED無し → 静的/data/*.json(pnpm syncで生成)を読む - 本番(Vercel):
VITE_HOSTED=1→ OAuth +/api/data(実行時 GitHub 取得)
開発
pnpm test # vitest
pnpm typecheck # tsc -b --noEmit
pnpm build # 型チェック + ビルド(ローカル版)
pnpm e2e # 本番ビルドを実 Chrome で開き、メモがリロード後も残るかを検証pnpm test / pnpm typecheck / pnpm build は PR と main への push で CI(.github/workflows/ci.yml)が実行する。
pnpm e2e は public/data/ のキャッシュ(生成に gh トークンが必要)を前提とするため CI では回さない。
UI を変える PR は、CI 緑だけでなく実ブラウザでの表示確認までをマージ条件にする。
