Imported from nishiokya/pokefuta-tracker (
AGENTS.md). Install upstream withnpx skills add nishiokya/pokefuta-tracker. Copyright stays with the author.
manhole_titles.jsonは手動で更新している
dataset/prefecture_events.json は手動更新(都道府県ページに出す開催中スタンプラリー等のリンク。end_date 過ぎは日次再生成で自動非表示)
pokefuta.ndjsonはapps/scraperで更新している
latest-manhole-photos.json と docs/api/*.json は import-manhole-photos.yml が Supabase から日次一括生成(画像DL込み。pokefuta.com アプリの /api/manholes・/api/site-stats は docs/api を読む。手動で回すときだけ /import-photos スキル)
都道府県ページは docs/latest-manhole-photos.json を生成時に読み、写真掲載率・投稿写真・写真募集状態を47都道府県共通テンプレートへ静的に埋め込む
都道府県ページから pokefuta.com への導線は from=data&pref=<県slug> を付ける(県がない場合は from=data のみ)。同一GA4プロパティ内の内部UTMは使わず、クロスドメインリンカーと着地側の source_app=tracker / p_data_referral で分析する。pref のGA4送信・投稿までの引き継ぎは写真館側の対応が別途必要。GA4の content_id・photo_state・surface はカスタムディメンションとして登録して分析する
GA4 は apps/web/assets/analytics.js から初期化し、data.pokefuta.com だけで送信する。各HTMLや生成スクリプトに gtag ローダーや独自の trackEvent を直書きしない
イベント発生箇所は surface で表し、GA4の流入元予約語 source をカスタムイベント引数に使わない
AdSense
AdSense はPVと検索流入の多い data.pokefuta.com を最初の導入先とする。
導入目的は収益最大化ではなく広告配信・計測の学習。
広告によってサイト本来の検索・閲覧体験や pokefuta.com への導線を損なわないことを優先する。
- 全画面広告、ビネット広告、画面固定アンカー広告は使わない。
- 広告は当初、都道府県ページと詳細ページの本文中に各1枠程度とし、トップページには原則置かない。
- AdSenseサイト確認コードと
ads.txtをdata.pokefuta.comで正しく配信し、デプロイ後に実サイトで確認する。 - 審査前にプライバシーポリシー、問い合わせ先、運営者情報を確認し、不足があれば整備する。
- 広告枠はレイアウトシフトを起こさないよう表示領域を予約し、Core Web Vitalsへの影響を確認する。
- GA4の既存イベント、
pokefuta.comへのクロスドメイン計測、同意・プライバシー方針を壊さない。 - Googleアカウントへのログイン、氏名・住所・支払い情報の入力、規約同意、審査リクエストの 最終操作はユーザー本人が行う。そこまで進んだら作業を止め、必要な操作を具体的に案内する。
共通About
pokefuta.com/aboutをpokefuta.comとdata.pokefuta.com共通のAbout・お問い合わせページの正本とする。- 両ドメインを「姉妹サイト」と表現せず、同じサービス内の「ポケふた写真館」と「ポケふた図鑑」として扱う。
- 運営者名は
nishiokyaと表記する。
ディレクトリ構成
apps/scraper/— GitHub Actions から自動実行されるスクリプト群(update-pokefuta.yml / pages-deploy.yml / import-manhole-photos.yml)address_parser.py/manhole_titles.pyは上記スクリプトの内部ライブラリ
apps/tools/— 手動実行ツール・初期化アーカイブ(例外: import_latest_manhole_photos.py は import-manhole-photos.yml からも呼ばれる)apps/web/— フロントエンド
バッチワークフロー規約
.github/workflows/ を新規作成・変更するときは以下に従うこと。過去に規約が無いまま各ワークフローが別々に育ち、timeout 未設定・依存の二重管理・クロスリポジトリ依存といった事故要因が溜まったため明文化した。
どの家系で作るかを最初に決める
| 家系 | 挙動 | 使いどころ | 例 |
|---|---|---|---|
| A: 自動マージ | ブランチ→PR作成→即 squash マージ→gh workflow run pages-deploy.yml で明示起動 |
毎日確実に本番へ出す必要があるデータ。人のレビューを待たない | import-manhole-photos.yml |
| B: レビュー待ち | peter-evans/create-pull-request@v8 で PR を作って放置 |
中身を人が見てからマージしたいデータセット更新 | update-pokefuta.yml / update-design-manholes.yml |
| C: 読み取り専用 | 何も書かない。異常時に失敗させるだけ | 監視・検証 | check-site-stats.yml / production-url-check.yml |
家系AとBが形式的にPRを作るのは main が「PR必須」ルールのため。家系Aは人の目を通らないので、壊れた出力がそのまま本番に出ることを踏まえて作ること。ワークフロー冒頭のコメントにどの家系かを明記する。
必ず守ること
timeout-minutesを必ず書く。 既定値は6時間で、ハングすると runner をその間占有する- Python は
actions/setup-python@v6+python-version: '3.11'で固定する。 ランナー既定の python に依存しない - 依存は
requirements.txtに集約する。 ワークフロー内でpip install <パッケージ名>を直接書かない(バージョン非固定で上流の破壊的変更をそのまま踏むため) - 定期実行するワークフローには
concurrencyを付ける。 手動実行と定時実行の衝突を防ぐ - 外部リポジトリを
actions/checkoutするときはref:をタグかコミットSHAに固定する。 以前nishiokya/pokefutaを HEAD で引いてスクリプトを実行しており、相手側の変更で日次ジョブが黙って壊れる状態だった(現在は tracker 側へ移管して解消済み) - 同じ Supabase テーブルを複数のワークフローから引かない。 取得は1ジョブに集約する。かつては写真取込とスナップショット生成が同じ
photo/visitを別々に引いていた - cron を変更するときは前後のワークフローとの順序を確認する。
import-manhole-photos.yml(05:30 JST)→ Pages デプロイ →check-site-stats.yml(08:00 JST)はこの順序に依存しており、崩すと検証が生成を追い越して毎日誤検知する
テストについて
テストファイルは20個以上あるが CI で走っているのはごく一部。ワークフローからスクリプトを呼ぶなら、対応するテストを実行するステップも同じワークフローに入れること。