Daily Leveling は、Cloudflare Workers + React で構成する習慣トラッカー MVP です。
現在は Today / Weekly / Monthly の集計、every_n_days 習慣、簡易レベル表示、達成時の軽いフィードバックまで含みます。
- React SPA
- Hono on Cloudflare Workers
- PostgreSQL + Cloudflare Hyperdrive
- pnpm
flowchart LR
user["ユーザー"]
browser["ブラウザ\nReact SPA"]
worker["Cloudflare Workers\nHono API / BFF\n+ Static Assets"]
google["Google OAuth / OIDC"]
hyperdrive["Cloudflare Hyperdrive\nHYPERDRIVE binding"]
db["PostgreSQL"]
wrangler["Wrangler\n開発・read/write・deploy"]
terraform["Terraform\nRoute / Custom Domain / Account-side Resource"]
user --> browser
browser --> worker
worker --> google
worker --> hyperdrive
hyperdrive --> db
wrangler -.-> worker
terraform -.-> worker
- 依存関係をインストールします。
pnpm install- ローカル用の Worker 環境変数ファイルを作成します。
cp .dev.vars.example .dev.vars- 以下の値を
.dev.varsに設定します。
DATABASE_URLAPP_BASE_URLGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET
- 環境変数を確認します。
pnpm run env:check- migration を PostgreSQL に適用します。
pnpm run db:migrate環境別に切りたい場合の example:
cp .dev.vars.staging.example .dev.vars.staging
cp .env.staging.example .env.staging推奨するフルスタック開発コマンドは以下です。
pnpm devこのコマンドで次の 2 つが同時に動きます。
vite build --watchdist/を継続更新します。wrangler devAPI とビルド済み SPA を同一オリジンで配信します。
個別に動かしたい場合は以下を使います。
pnpm dev:test
pnpm dev:staging
pnpm dev:production
pnpm dev:web
pnpm dev:worker
pnpm dev:worker:test
pnpm dev:worker:staging
pnpm dev:worker:production
pnpm run check
pnpm test
pnpm run test:e2e
pnpm run test:e2e:headed
pnpm run test:e2e:ui
pnpm run build
pnpm run env:check
pnpm run env:check:test
pnpm run env:check:staging
pnpm run env:check:production
pnpm run db:migrate:plan
pnpm run db:migrate:plan:test
pnpm run db:migrate:plan:staging
pnpm run db:migrate:plan:production
pnpm run db:migrate
pnpm run db:migrate:test
pnpm run db:migrate:staging
pnpm run db:migrate:production
pnpm run infra:fmt
pnpm run infra:validate
pnpm run deploy:dry-run:test
pnpm run deploy:dry-run:staging
pnpm run deploy:dry-run:production
pnpm run verify
pnpm run verify:full:test
pnpm run verify:full:staging
pnpm run verify:full:production
pnpm run release:check:test
pnpm run release:check:staging
pnpm run release:check:production- ローカル認証フローは
wrangler devによる same-origin 前提です。 APP_BASE_URLはローカル Worker の URL と一致させてください。- Worker 実行時の DB 接続は
HYPERDRIVE.connectionStringを優先し、未設定時だけDATABASE_URLに fallback します。 DATABASE_URLは local dev、migration、Hyperdrive 作成元として残します。- セッション Cookie は Worker 側で管理し、
HttpOnlyです。 - state-changing request は
Origin / Refererを Worker 側で検証します。 - API と静的 HTML の両方に
Content-Security-Policyなどのセキュリティヘッダを付与します。 - Google ID token は
tokeninfoではなく JWKS を使って Worker 内で署名検証します。 - auth route のレート制限は
AUTH_RATE_LIMITSKV binding を使い、local では binding 未設定時に no-op で動作します。 - auth rate limit 応答には
Retry-AfterとRateLimit-*header を付けます。 - JWKS 取得失敗、署名不正、rate limit 超過は構造化 security log として
wrangler tailから追えるようにします。 - ブラウザのログイン導線では、
/auth/google/startと/auth/google/callbackの rate limit 時にログイン画面へ戻し、再試行までの秒数を表示します。 - UI のフォントスタックは sans-serif のみを使用します。
Playwright CLI による E2E テストを tests/e2e に置いています。
初回だけ Chromium をインストールします。
pnpm exec playwright install chromiumローカル PostgreSQL に migration を適用したうえで、以下を実行します。
pnpm run test:e2epnpm run test:e2e は Playwright の webServer 経由で pnpm dev:e2e を起動します。
E2E 用 Worker は http://127.0.0.1:8788 で動き、.dev.vars と config/e2e.vars を読み込みます。
config/e2e.vars では E2E_TEST_MODE=true を設定し、/__e2e/* のテスト補助 API を有効化します。
この補助 API は E2E_TEST_MODE=true 以外では 404 を返し、通常の dev/staging/production では使いません。
確認範囲:
- ログイン画面の表示
- Google OAuth start URL の生成
- オンボーディングテンプレート適用
- 習慣作成
- Today view のログ更新
- Weekly view の集計表示
- Monthly view の集計表示
- レベル表示と達成時フィードバック
このプロジェクトは Cloudflare 環境を IaC 化できます。
推奨する責務分担は以下です。
- Wrangler ローカル開発、Worker の read/write、ビルド、コードのデプロイ
- Terraform Cloudflare 側の Worker サービス定義、Custom Domain、Route などの管理
Cloudflare 操作の標準経路:
- Worker の read/write は
wranglerを使う - account-side resource は Terraform を使う
- Cloudflare ダッシュボードや Codex プラグインは補助的な確認用途に留める
- Hyperdrive は環境ごとに
HYPERDRIVEbinding 名で固定する
よく使う Wrangler コマンド:
pnpm run cf:whoami
pnpm run cf:health:test
pnpm run cf:health:staging
pnpm run cf:health:production
pnpm run cf:deployments:test
pnpm run cf:deployments:staging
pnpm run cf:deployments:production
pnpm run cf:secrets:test
pnpm run cf:secrets:staging
pnpm run cf:secrets:production
pnpm run cf:status:test
pnpm run cf:status:staging
pnpm run cf:status:production
pnpm run cf:sync-secrets:staging
pnpm run cf:sync-secrets:production
pnpm run cloud:status
pnpm run deploy:test
pnpm run deploy:staging
pnpm run deploy:production
pnpm exec wrangler secret put DATABASE_URL --env production
pnpm exec wrangler tail --env productioncf:deployments:* は初回 deploy 前だと対象 Worker が存在せず失敗することがあります。
cf:health:* は公開 URL の疎通確認、cf:secrets:* は Cloudflare 側の secret 投入状況の確認に使います。
cf:status:* は deployments / healthz / secrets をまとめて確認します。
cf:sync-secrets:* は .env.<env> または .dev.vars.<env> から GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET を Cloudflare に同期します。
DATABASE_URL は Hyperdrive 障害時の fallback が必要な場合だけ同期します。
安全のため、環境別ファイルがない場合や DATABASE_URL が localhost / 127.0.0.1 の場合は同期を拒否します。
cloud:status は gcloud、Supabase CLI、Wrangler のインストールと認証状態をまとめて確認します。
Hyperdrive の config ID は wrangler.toml の [[env.<env>.hyperdrive]] に環境ごとに設定します。
新規 deploy 直後は workers.dev 側の反映に数秒かかり、一時的に 404 There is nothing here yet になることがあります。
クラウド操作は以下の CLI を使います。
gcloudGoogle OAuth client や GCP 側 resource の確認に使います。supabaseSupabase PostgreSQL を使う場合の project / DB connection 確認に使います。pnpm exec wranglerCloudflare Workers、secrets、deploy、Hyperdrive 連携の確認に使います。
状態確認:
pnpm run cloud:status初回ログイン:
gcloud auth login
gcloud config set project <PROJECT_ID>
supabase login
pnpm exec wrangler loginSupabase MCP が利用できる環境では MCP を補助確認に使って構いませんが、このリポジトリの標準手順は Supabase CLI とします。
Daily Leveling 用 Supabase project:
- project name:
daily-leveling - project ref:
djfqflkxsyzazuvtnqqm - region:
ap-northeast-1/ Northeast Asia (Tokyo) - 用途: production DB
- Hyperdrive production config:
5d5eb906286148e18f97904118daa682
Supabase Free plan では project 追加ができないため、DB は production のみ接続します。
test / staging / production の Worker、URL、cookie、Google OAuth redirect URI はコード上で分離し、将来 project を追加できる場合は環境別 Supabase project と Hyperdrive config に差し替えます。
Terraform の土台は infra/terraform にあります。
基本フローは以下です。
cd infra/terraform
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform plan
terraform applyWorker コード側は以下で検証・デプロイします。
pnpm run build
pnpm dev:worker
# 実デプロイは環境別 script を使うこのプロジェクトは以下の 3 環境を前提に分けます。
test接続確認や軽い検証用。Worker 名はdaily-leveling-teststagingmainの確認環境。Worker 名はdaily-leveling-stagingproduction本番環境。Worker 名はdaily-leveling
分離するもの:
- Cloudflare Worker 名
APP_BASE_URL- PostgreSQL Free plan の現時点では production のみ接続する。将来、環境別 project を作れる場合に分離する。
- Hyperdrive config
現時点では production のみ設定する。
test/stagingは DB binding を持たせない。 - Google OAuth client / redirect URI
- Cloudflare / GitHub Secrets
- Terraform の
tfvars
wrangler.toml には env.test, env.staging, env.production を定義しています。
ローカル開発用の top-level 名は daily-leveling-local です。
初期 bootstrap では各環境の APP_BASE_URL を workers.dev URL で持ち、custom domain 移行後に上書きします。
ローカルの環境ファイル読み込み順:
local.dev.vars->.env->.env.localtest.dev.vars.test->.env.test-> 共通ファイルstaging.dev.vars.staging->.env.staging-> 共通ファイルproduction.dev.vars.production->.env.production-> 共通ファイル
ローカルからの事前確認:
pnpm run env:check
pnpm run db:migrate:plan
pnpm run verify
pnpm run deploy:dry-run:staging環境別の事前確認例:
pnpm run env:check:staging
pnpm run db:migrate:plan:staging
pnpm run release:check:staging環境別の実デプロイ:
pnpm run db:migrate
pnpm run deploy:test
pnpm run deploy:staging
pnpm run deploy:productionGitHub Actions からの deploy も可能です。.github/workflows/deploy.yml を使い、手動実行で Worker を Cloudflare に配備できます。
実行時に test / staging / production を選択し、同名の GitHub Environment を使って secrets を解決します。
DB migration は .github/workflows/migrate.yml から手動実行できます。
plan と apply を選べるようにしてあり、まず plan で未適用 migration を確認し、その後 apply を実行する運用を想定しています。
Cloudflare Worker secret の同期は .github/workflows/sync-secrets.yml から手動実行できます。
dry-run で前提確認、apply で GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET と任意の DATABASE_URL を Cloudflare に反映します。
ローカル CLI から同期する場合は、対象環境ごとの .env.<env> または .dev.vars.<env> を作成してください。
.dev.vars だけに値がある状態では、ローカル DB URL の誤同期を防ぐため cf:sync-secrets:* は失敗します。
必要な GitHub Secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
Cloudflare Workers 側で最低限必要な環境変数:
APP_BASE_URLGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET
Cloudflare Workers 側で最低限必要な binding:
HYPERDRIVE
任意だが運用上は明示推奨の環境変数:
DATABASE_URL(fallback 用。migration では必須)SESSION_COOKIE_NAMESESSION_TTL_SECONDSDEFAULT_TIMEZONEOPENAI_API_KEY(AI 習慣提案を有効にする場合)
GitHub Actions の deploy で必要な Secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
GitHub Actions の secret sync で必要な Secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDDATABASE_URLGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET
GitHub Environments の推奨構成:
teststagingproduction
各 GitHub Environment に最低限設定するもの:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDDATABASE_URL(migration workflow 用)GOOGLE_CLIENT_ID(secret sync workflow 用)GOOGLE_CLIENT_SECRET(secret sync workflow 用)
Worker runtime 用の環境変数と secret は Cloudflare 側に環境ごとに設定します。
APP_BASE_URLGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETHYPERDRIVEbinding(現時点では production のみ)- fallback が必要な場合のみ
DATABASE_URL - AI 習慣提案を有効にする場合
OPENAI_API_KEY - 必要に応じて
SESSION_COOKIE_NAME,SESSION_TTL_SECONDS,DEFAULT_TIMEZONE
初期 bootstrap 時点では、以下の非秘密値は wrangler.toml に定義しています。
test:https://daily-leveling-test.hamakyoh.workers.devstaging:https://daily-leveling-staging.hamakyoh.workers.devproduction:https://daily-leveling.hamakyoh.workers.dev
そのため Cloudflare 側で最初に投入すべき secret は以下です。
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET
DATABASE_URL は Hyperdrive fallback が必要な場合だけ投入します。
加えて、production の Hyperdrive config ID を wrangler.toml の env.production.hyperdrive に設定します。
本番デプロイ前に確認すること:
APP_BASE_URLが本番の公開 URL と一致している- Google OAuth の redirect URI に
/auth/google/callbackを含む本番 URL が登録されている - PostgreSQL に
migrations/001_init.sqlが適用済みである - session cookie を
Secureで返せる HTTPS URL を使っている - Hyperdrive config ID が production 用の PostgreSQL を指している
- Cloudflare 側の Route または Custom Domain が Terraform で作成済みである
pnpm run verify:full:productionが通る
Wrangler で本番 secret を設定する例:
wrangler secret put DATABASE_URL --env production
wrangler secret put GOOGLE_CLIENT_ID --env production
wrangler secret put GOOGLE_CLIENT_SECRET --env productionstaging の例:
wrangler secret put DATABASE_URL --env staging
wrangler secret put GOOGLE_CLIENT_ID --env staging
wrangler secret put GOOGLE_CLIENT_SECRET --env stagingWrangler にログインしているかの確認:
pnpm run cf:whoamiGitHub Actions で以下を検証するようにしています。
- TypeScript 型チェック
- Vitest
- Vite build
- Terraform fmt
- Terraform validate
Playwright E2E はローカル PostgreSQL と .dev.vars を前提にするため、現時点ではローカル確認コマンドとして扱います。
ローカルで CI 相当の検証をまとめて回したい場合は以下を使います。
pnpm run verifyCloudflare/Terraform の確認まで含める場合は以下です。
pnpm run verify:full:staging本番投入前の総合チェックは以下です。
pnpm run release:check:production後続フェーズでログイン後の today view と monthly view のスクリーンショットを追加します。
migration は schema_migrations テーブルで管理します。
pnpm run db:migrate:plan未適用 migration の一覧だけ確認します。pnpm run db:migrate未適用 migration を順に適用します。pnpm run db:migrate:plan:stagingstaging 環境の未適用 migration を確認します。pnpm run db:migrate:productionproduction 環境に migration を適用します。
どのコマンドも、まず process.env を見て、不足分だけ環境別 .dev.vars / .env と共通ファイルから読み込みます。
migration コマンドで必須なのは DATABASE_URL のみです。
infra/terraform/environments/ に環境別の雛形を置いています。
test.tfvars.examplestaging.tfvars.exampleproduction.tfvars.example
例:
cd infra/terraform
cp environments/staging.tfvars.example staging.tfvars
terraform plan -var-file=staging.tfvars
terraform apply -var-file=staging.tfvarsGET /healthzが200を返す- Google ログインのリダイレクトが正しい
- 初回ログインでオンボーディングに遷移する
- テンプレート適用で習慣が作成される
- 手動で習慣を追加できる
- オンボーディング完了後のリダイレクトが切り替わる
- Today view でログをトグルできる
- Month view でグリッドと集計が表示される
- 並び替えと archive が動く
- Settings 更新で timezone/default view が保存される
- ログアウトで現在のセッションが失効する
- パッケージマネージャーは
pnpm - 習慣削除は物理削除ではなく
is_active = falseによる soft delete - 外部ユーザー識別子は
google_sub - 日付境界はユーザーのローカル timezone 基準
- Cloudflare 側のインフラは Terraform で管理できる
- Worker runtime の DB 接続は Hyperdrive を優先する
- Google OAuth は refresh token を保存しないため offline access を要求しない