# Sentry / Logpush ロールアウト手順

`sentry-setup.md` (仕様 / 設計) と `logpush-setup.md` (仕様 / 設計) を補完する **実行手順 doc**。
本書は「何を順にどう叩くか」「検証して通ったか」「ダメなとき何を戻すか」だけを書く。

> **状況** (2026-04-27): どちらもコード側 skeleton は配線済み。Sentry プロジェクトと Logpush job が
> まだ未作成のため、本書を順に実行することで稼働状態に持ち込む。

---

## Phase 1: Sentry プロジェクト作成 + DSN 投入

### 1-1. Sentry org 確認 / 作成

- 既存の Anthropic / High-Field など共有 org が使えるかまず確認。
  [https://sentry.io/organizations/](https://sentry.io/organizations/) で参加済み org を一覧化。
- **TODO**: 共有 org に parky team を切るか、parky 専用 org を新規作成するかを決定。
- 専用 org にする場合: `parky` slug で作成 (Free Plan で開始、Errors 5K / mo まで OK)。

### 1-2. project x6 作成

`sentry-setup.md` §1 の表どおりに 6 project 作成 (`parky-api` / `parky-public` /
`parky-admin` / `parky-owner` / `parky-marketing` / `parky-mobile`)。

各 project の **Client Keys (DSN)** ページから DSN 文字列を取得。

### 1-3. DSN を 1Password に保存

[feedback_1password_sa_only](.memory/feedback_1password_sa_only.md) に従い `op` は SA token 経由のみ。

```bash
export OP=$(cat ~/.op/sa_token.txt)

OP_SERVICE_ACCOUNT_TOKEN=$OP op item create \
  --category=password \
  --title="Sentry｜DSN｜parky-api" \
  --vault="HF｜開発" \
  password="https://...@oXXX.ingest.sentry.io/YYY" \
  org_slug=parky \
  project_id=YYY
# 6 project 分繰り返し
```

### 1-4. `scripts/secret-keys.txt` に追加

```
SENTRY_DSN_API
SENTRY_DSN_PUBLIC
SENTRY_DSN_ADMIN
SENTRY_DSN_OWNER
SENTRY_DSN_MARKETING
SENTRY_RELEASE
```

[parky/api/scripts/secret-keys.txt](../../api/scripts/secret-keys.txt) に上記 6 行を append (べき等。
重複 grep してから追加)。

### 1-5. set-secrets.sh で wrangler secret put

```bash
cd parky/api
./scripts/set-secrets.sh dev
# prod は本番 Worker 作成後
./scripts/set-secrets.sh prod
```

`set-secrets.sh` が secret-keys.txt を読み、1Password から値を引いて `wrangler secret put` を
全件流す (べき等)。

### 1-6. dev Sentry test

dev 環境の意図的 throw endpoint で疎通確認:

```bash
curl https://dev-api.parky.co.jp/v1/_internal/sentry-test
# expect: 500 + Sentry Issues に新規 issue 作成
```

- **TODO**: `_internal/sentry-test` endpoint がまだ無ければ 1 つだけ追加して、確認後 PR で削除。
- Sentry Issues に上がってきた issue の `release` / `environment` / `request.url` が正しく入って
  いることをチェック。
- Mobile / Portal は `lib/main.dart` / `sentry-init.ts` 直後に `throw` を一時挿入して同様確認。

---

## Phase 2: Logpush job 作成

### 2-1. R2 bucket 作成

```bash
wrangler r2 bucket create parky-logs-dev
wrangler r2 bucket create parky-logs-prod
```

### 2-2. Lifecycle rule (30 / 90 日 auto-delete)

`logpush-setup.md` §1 の lifecycle JSON を流用:

```bash
# dev: 30 日
wrangler r2 bucket lifecycle set parky-logs-dev --file infra/r2-lifecycle-30d.json
# prod: 90 日
wrangler r2 bucket lifecycle set parky-logs-prod --file infra/r2-lifecycle-90d.json
```

- **TODO**: `infra/r2-lifecycle-30d.json` / `r2-lifecycle-90d.json` をリポジトリに commit
  (`logpush-setup.md` §1 の inline JSON をファイル化)。

### 2-3. Logpush job 作成 (Cloudflare API)

`logpush-setup.md` §2 のテンプレに沿って `curl POST` で job 作成。R2 destination の
access-key-id / secret-access-key は dashboard `R2 → Manage R2 API Tokens` で発行 → 1Password
(`Cloudflare｜R2｜parky-logs アクセスキー`) に保管。

dev / prod 各 1 job ずつ:
- `parky-workers-logs-dev` → `r2://parky-logs-dev/dev/{DATE}`
- `parky-workers-logs-prod` → `r2://parky-logs-prod/prod/{DATE}`

dataset = `workers_trace_events` を必ず指定 (Cloudflare Workers Logs)。

### 2-4. 30 / 90 日 lifecycle 動作確認

```bash
wrangler r2 bucket lifecycle get parky-logs-dev
# expect: 30d expire ルールが返る
wrangler r2 bucket lifecycle get parky-logs-prod
# expect: 90d expire ルールが返る
```

### 2-5. R2 への落下確認

dev に通常リクエストを 5 分流した後:

```bash
wrangler r2 object list parky-logs-dev --prefix dev/2026-04-27/
# expect: NDJSON gzip object が 1 個以上
```

ダウンロードして DuckDB で query (`logpush-setup.md` §3 参照)。
`Outcome != 'ok'` の行を 1 つ以上発見できれば疎通 OK。

---

## ロールバック手順

### Sentry 側

- `wrangler secret delete SENTRY_DSN --env {dev|prod}` で DSN を消すと全レイヤーが no-op に戻る。
  → Mobile / Portal は再ビルド (env 経由) が必要なので、緊急時は Sentry 側で project の
     **Disable** トグルで rate-limit 0 にするほうが早い。
- Sentry プロジェクト自体を消すと Issue 履歴も消えるため、まず Disable で運用継続を保つ。

### Logpush 側

```bash
# job を一時無効化 (削除はしない)
curl -X PATCH "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/logpush/jobs/${JOB_ID}" \
  -H "Authorization: Bearer ${CF_TOKEN}" \
  --data '{"enabled": false}'
```

R2 bucket は消さない (過去ログ保持のため)。bucket 削除は最低 30 / 90 日経過後。

---

## 関連 docs

- [parky/docs/ops/sentry-setup.md](./sentry-setup.md) — Sentry 仕様 / 設計 (PII / sample rate / Alert)
- [parky/docs/ops/logpush-setup.md](./logpush-setup.md) — Logpush 仕様 / 設計 (dataset / filter / cost)
- [parky/docs/ops/logging.md](./logging.md) — 構造化ログスキーマ
- [parky/docs/ops/incident-response.md](./incident-response.md) — Sentry / Logpush の調査用途
- [parky/docs/ops/secret-rotation.md](./secret-rotation.md) — DSN / R2 access key の rotation
