Skip to content

環境戦略 (dev / stg / prd) ​

UZU は GCP プロジェクト単位で 3 環境を分けている。本ドキュメントは「どこまで本番同等構成を取るか、どこはコストや運用簡素化のため割り切るか」のチーム合意を残し、議論が蒸し返されないようにするためのもの。

基本方針 ​

"本番同等性" は絶対原則ではなく、目的に応じて選択する。 各インフラ要素ごとに以下 3 段階のいずれかを選ぶ:

レベル意味例
F. フル同等prd と同一構成・同一データFirebase Auth、Redis、GraphQL schema
D. 縮小同等構成は同じだが規模・データ量を削減Postgres / AlloyDB (後述)
S. prd 共有dev/stg は prd のリソースを cross-project 参照BigQuery のアプリ読み取りデータ

判断基準:

  1. 書き込みがあるか(あるなら環境分離は必須)
  2. 再現性の価値(本番障害の再現、破壊的実験の必要性)
  3. コスト
  4. 運用負荷(Datastream のような daily DB reset と衝突する技術の扱い)

インフラ要素ごとの選択 ​

Postgres / AlloyDB(アプリ DB) ​

Level: D. 縮小同等

環境実体備考
devCloud SQL (uzu-postgresql in uzu-dev)AlloyDB ではなくコスト重視の Cloud SQL
stgAlloyDB (uzu-shared in uzu-stg)prd 同等
prdAlloyDB

日次データ同期: .github/workflows/db_import_backend.yml が 05:00 JST(20:00 UTC)に prd dump を匿名化して dev/stg に import:

prd dump → postgresql_anonymizer でマスキング → (dev は sampling 縮小) → drop database app → import

マスク範囲: backend/scripts/mask_rules.sql で定義。PII(email / 住所 / 支払情報 / chatroom 本文 等)のみ書き換え。PK / FK は prd と同じ値のまま保持される。つまり users.id=12345 は prd と dev で同一ユーザー(ただし dev の sampling で一部が抜ける)。

BigQuery ​

Level: 用途ごとに分かれる

BigQuery は一つの dataset を複数用途で使わない。以下 3 種類に分類する:

用途例Level書き込み元
アプリ読み取り元(学習・分析用)uzu-prd.app_public.*、uzu-prd.mdmsjp_public.*S. prd 共有Datastream (prd AlloyDB → prd BQ)
行動ログ / イベントログmobile_events.scenario_views、mobile_events.recommendation_assignments 等F. フル同等各環境のクライアント / backend
KPI / 分析用中間テーブルapp_kpi、app_opt 等F. フル同等(prd のみ運用)prd のバッチ

なぜアプリ DB データ (app_public) は prd 共有で OK か ​

  1. BigQuery は OLAP 設計で cross-project read 想定。Postgres のようにプロセス単位の接続ではなく、IAM 単位の read-only SELECT。dev が prd BQ を参照しても prd Postgres や prd アプリには一切影響しない
  2. ID 整合性がすでに取れている。dev/stg は prd の匿名化ダンプを毎日 import しているので、user.id / scenario.id は prd と一致。dev Postgres の ent 行と prd BQ の該当行は同一主体
  3. コスト差はあるが決定打ではない
    • S の場合: dev/stg からの BQ クエリ課金のみ(月 $0-5、on-demand 1 TiB 無料枠内で収まる規模)
    • F の場合: 環境ごとに Datastream + BQ storage が必要。dev/stg も毎日 drop database があるので replication slot が毎日吹き飛ぶ → Datastream 再初期化 + backfill が毎日発生するなど運用破綻
  4. 書き込み事故のリスクはゼロ。IAM で dataset level の roles/bigquery.dataViewer のみ付与する

なぜ行動ログ (mobile_events.*) は環境別か ​

  1. 書き込みがある → 環境混在は禁止(dev テストデータが prd KPI を汚染する)
  2. A/B 実験割付 は環境ごとに独立した ID 空間を持つ必要がある
  3. PII 流出リスク軽減: dev クライアントから生の PII が prd BQ に流れない

実装上のルール ​

Backend のレコメンデーション学習ジョブ(spec)は:

環境変数値用途
GCP_PROJECT_ID各環境(uzu-dev / uzu-stg / uzu-prd)書き込み先(mobile_events.recommendation_assignments)および AlloyDB/pgvector 接続
RECOMMENDATION_BQ_READ_PROJECT全環境で uzu-prd読み取り元(app_public.*、学習データソース)

この分離により、dev の学習ジョブでも本番データで実際に動作検証できる。

Redis / AlloyDB pgvector(推論の state) ​

Level: F. フル同等

scenario_embeddings / user_embeddings は各環境の AlloyDB に日次学習で書き込む。dev でも学習ジョブが動く(BQ は prd 共有で読むが、pgvector への書き込みは環境別)。

Firebase Auth ​

Level: F. フル同等

各環境で独立 Firebase プロジェクト。テストユーザーは環境ごとに作る。

Cloud Tasks / Pub/Sub ​

Level: F. フル同等

各環境で独立エンドポイント。

Cross-project 参照の IAM 原則 ​

dev/stg の SA(サービスアカウント)が uzu-prd の BigQuery を read する場合:

  • 付与する権限は dataset level の roles/bigquery.dataViewer のみ(project 全体には付けない)
  • 対象 dataset は uzu-prd.app_public と uzu-prd.mdmsjp_public に限定
  • 書き込み権限は絶対に付与しない(IAM レベルで保証)
  • 設定は Terraform infra/terraform/modules/iam/ に集約する

破壊的実験の原則 ​

「prd データを破壊する実験」は dev/stg では不可能になる(S レベルの共有のため)。それでも問題ない理由:

  • スキーマ変更は ent migration で PR レビュー経由
  • 破壊的な SQL を試したいときは dev Postgres ローカルコピーで試す
  • BQ スキーマを壊す実験は BQ の sandbox dataset を別途作る

変更時の参考 ​

この方針を変える場合:

  • 影響範囲: backend 学習ジョブ / BI ダッシュボード / KPI 集計クエリ
  • 移行手順: Datastream 新設 → dual-read 期間 → 旧ソース廃止
  • 過去の議論: レコメンデーション spec の §8 および関連 PR

FAQ ​

Q. dev でも prd 同等の Datastream を立てたら整合性が綺麗では? ​

  • 毎日の drop database app で replication slot が消える → stream が毎日 FAILED → 再初期化運用
  • 再初期化のたびに backfill が発生 → 月額コストが不定に跳ねる
  • メリットより運用負荷が大きいため却下(2026-04 合意)

Q. prd BQ が落ちたら dev も落ちる? ​

  • Yes、ただし稀。BigQuery 自体の SLA は 99.99%
  • dev で学習ジョブが失敗しても dev アプリは継続動作する(pgvector の古い embedding が残っているため)

Q. 個人情報の扱いは大丈夫? ​

  • dev SA は uzu-prd.app_public の read only
  • 匿名化は Postgres dump 時点で実施済み
  • さらに詳細な取り扱いは別途 security doc で管理