# Sentry セットアップ手順

Parky 全レイヤー (Workers BFF / Flutter / 3 Portal / Astro Home) の例外を Sentry に転送するための初期設定手順。

> **状況** (2026-04-29 更新):
> - Sentry org `parky-72` 作成済 + 6 project 作成済 (commit `426919d3`)
> - dev Worker (`parky-api-dev`) DSN 投入済 / smoke test 通過 (Issue 7444016876)
> - **dev Web 4 portal (home/admin/owner/marketing) DSN 配線済** (commit `e7e3067f`、deploy workflow で 1Password から取得)
> - 6 DSN Item 全て 1Password `PJ｜Parky` vault に保管済 (kylthd/nvjge/rda3b/ttysnr/4kmt4/jp3r2)
> - 12 alert rules 配線済 (6 project × 2 rules / **email 通知のみ**)
> - **残**: prod Worker DSN / stg Worker DSN / Flutter DSN / **Discord/Slack 通知ルート (§9.1 / §9.2 手順あり)**
> 詳細は [.work/parky/2026-04-28_002_parky_manual_action_checklist.html](../../.work/parky/2026-04-28_002_parky_manual_action_checklist.html) M-02 参照

## 1. Sentry プロジェクト作成

[https://sentry.io](https://sentry.io) で `parky` Organization を作り、以下 6 プロジェクトを生成:

| プロジェクト名 | Platform | DSN 用途 |
|---|---|---|
| `parky-api` | `cloudflare-workers` | Workers BFF |
| `parky-flutter` | `flutter` | モバイルアプリ |
| `parky-home` | `javascript-astro` | parky.co.jp / dev.parky.co.jp |
| `parky-admin` | `javascript-react` | admin / dev-admin |
| `parky-owner` | `javascript-react` | owner / dev-owner |
| `parky-marketing` | `javascript-react` | marketing / dev-marketing |

各プロジェクトの DSN を 1Password の `HF｜開発` vault に Item として保管:

- `Sentry｜DSN｜parky-api`
- `Sentry｜DSN｜parky-flutter`
- `Sentry｜DSN｜parky-home`
- `Sentry｜DSN｜parky-admin`
- `Sentry｜DSN｜parky-owner`
- `Sentry｜DSN｜parky-marketing`

各 Item のフィールド: `dsn` (password 型) / `org_slug` (string) / `project_id` (string)。

## 2. Workers BFF への DSN 投入

```bash
# dev
OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.op/sa_token.txt) op item get \
  "Sentry｜DSN｜parky-api" --vault "HF｜開発" --fields "label=dsn" --reveal \
  | wrangler secret put SENTRY_DSN --env dev

# prod (本番 Worker 作成後)
OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.op/sa_token.txt) op item get \
  "Sentry｜DSN｜parky-api" --vault "HF｜開発" --fields "label=dsn" --reveal \
  | wrangler secret put SENTRY_DSN --env prod
```

`scripts/secret-keys.txt` に `SENTRY_DSN` / `SENTRY_RELEASE` を追記し、
`scripts/set-secrets.sh` 一括投入の対象にする。

## 3. Flutter への DSN 投入 (--dart-define)

`parky/mobileapp/prototype/flutter/.env.dev.json` に以下を追加:

```json
{
  "SENTRY_DSN": "https://...@oXXX.ingest.sentry.io/YYY",
  "SENTRY_ENVIRONMENT": "development"
}
```

VS Code launch.json の `--dart-define-from-file=.env.dev.json` で読み込む。
release ビルドは CI / fastlane で `--dart-define=SENTRY_DSN=$SENTRY_DSN_FLUTTER` を渡す。

## 4. Portal (admin / owner / marketing / home) への DSN 投入 ✅ 配線済 (2026-04-29)

各 portal の Vite / Astro 環境変数として DSN を投入する。
**dev 環境は 4 portal 全て deploy workflow で 1P から自動取得 → `.env` に書き込み済**。

deploy workflow と 1P Item の対応:

| Workflow | 環境変数 | 1P Item ID |
|---|---|---|
| `deploy-public-dev.yml` | `PUBLIC_SENTRY_DSN` | `kylthd2gcuqnenwtpmx7li2z7e` |
| `deploy-admin.yml` | `VITE_SENTRY_DSN` | `nvjgezrhw32lrmijj3piovfw4y` |
| `deploy-portal-owner-dev.yml` | `VITE_SENTRY_DSN` | `ttysnrtvz6l3oxsgzedagoyewu` |
| `deploy-portal-marketing.yml` | `VITE_SENTRY_DSN` | `rda3bpi3ka2brnp75jcn3dpr44` |

ビルド時に Vite が `import.meta.env.VITE_SENTRY_DSN` を、Astro が
`process.env.PUBLIC_SENTRY_DSN` を埋め込む。値が空なら Sentry SDK は no-op で
bundle にも含めない。

prod (本番カットオーバー後) は `deploy-admin-prod.yml` / `deploy-public-prod.yml` /
`deploy-portal-marketing-prod.yml` / `deploy-portal-owner-prod.yml` に同じ
load-secrets パターンを移植する。

## 5. Sentry Release tracking (任意)

GitHub Actions の deploy job で git short SHA を inject:

```yaml
- name: Set Sentry release
  run: echo "SENTRY_RELEASE=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Deploy worker with release
  run: echo "$SENTRY_RELEASE" | wrangler secret put SENTRY_RELEASE --env dev
```

source map upload は `@sentry/cli` で deploy 後に流す。Workers / Vite / Flutter
それぞれ別ワークフローで個別投入する (ノイズ回避のため `parky-flutter` のみ最初は手動)。

## 6. Astro Home の Sentry integration (将来作業)

`web/home/package.json` に `@sentry/astro` を追加し、`astro.config.mjs` で:

```ts
import sentry from "@sentry/astro";
export default defineConfig({
  integrations: [
    sentry({
      dsn: import.meta.env.VITE_SENTRY_DSN,
      environment: import.meta.env.VITE_SENTRY_ENVIRONMENT ?? "development",
      sourceMapsUploadOptions: {
        org: "parky",
        project: "parky-home",
        authToken: process.env.SENTRY_AUTH_TOKEN,
      },
    }),
  ],
});
```

DSN 空時は initialize されない (no-op)。

## 7. PII 保護とサンプリング

- Workers: `lib/sentry.ts` の `requestDataOptions.allowedHeaders` で送信ヘッダを限定。
  body / cookies / IP は redact 済 (デフォルト)。
- 5xx と unhandled だけ転送。4xx (validation / rate-limit) はノイズなので除外。
- production sampleRate = 1.0 (全送信)。トラフィック増えたら 0.1 等に絞る。
- Flutter: `beforeSend` で Sentry イベント送信前に email/phone をマスク。

## 8. 動作確認

1. dev に DSN 投入後、`/v1/healthz` 等を叩いて 200 を確認 (no-op パス)。
2. テスト用に dev だけ意図的に throw する endpoint を作って Sentry Issues に
   exception が届くことを確認。確認後 endpoint は削除。
3. Mobile / Portal は故意に `throw new Error("sentry test")` を init 直後に
   仕込んで本物が届いたら removed する。

## 9. Alert ルール

Sentry プロジェクトごとに以下 Alert を設定:

- New Issue → Slack `#parky-alerts` / Discord `#parky-alerts`
- Same Issue 100 events / hour → Slack / Discord
- Crash-Free Sessions < 99% (Flutter) → Slack / Discord
- Failure Rate > 1% / 5 min (Workers) → Slack / Discord

### 9.1 Discord 連携の段取り (2026-04-29 拡張)

Sentry → Discord は Sentry 側の Discord 公式 integration を使う。Slack と違って
1 サーバー認証で全 project に展開できるので、設定は **org 単位 1 回 + project 単位の Alert 配線** で済む。

**A. Org レベル: Discord integration のインストール**

1. Sentry 上で `parky-72` org を選択 → Settings → Integrations。
2. "Discord" を検索 → Add Installation → 認証ダイアログで Discord にログイン。
3. 通知先 Discord サーバー (Parky 運用サーバー) を選択し権限承認。
4. `#parky-alerts` テキストチャネルを作成 (まだなければ) して、Sentry bot を
   そのチャネルに `/invite @Sentry` で招待。

**B. Project レベル: Alert Rules 配線 (6 project x 4 rules = 24 rules)**

各 project の Settings → Alerts → "Create Alert" で以下を作る:

| 名前 | 条件 | アクション |
|---|---|---|
| New Issue | An issue is first seen | Send a Discord notification to channel `#parky-alerts` |
| Issue Spike | An issue is seen more than 100 times in 1h | Send a Discord notification to channel `#parky-alerts` |
| (Flutter のみ) Crash-Free < 99% | Crash-Free Session Rate < 99% in 1h | Send a Discord notification |
| (Workers のみ) Failure Rate > 1% | failure rate > 1% over 5 min | Send a Discord notification |

**C. 確認**

- 任意 project で `Sentry SDK` debug endpoint から throw して issue を起こす
- `#parky-alerts` に Sentry bot の embed が出れば成功

**D. 既存 email-only alert の併存**

email 通知ルールはそのまま残す (重要度 high のときに二重通知する設計)。
過剰 通知になったら Settings → Alerts で email rule を archive する。

### 9.2 Slack 連携の段取り (Discord と同一構造)

`Sentry` Slack app (公式) を Sentry org に Add → Slack workspace を選択 →
`#parky-alerts` チャネルを bot に invite。Alert Rules で `Send a Slack
notification to channel #parky-alerts` を選択。Discord と同じ 4 ルール推奨。

## 10. Cost / Quota 監視

Sentry の無料枠: Errors 5K / month、Performance 10K / month。超過時は subscription を
Team Plan ($26/mo) にアップグレード。月次で `Stats` ページを確認し、quota 80% 到達時に
sample rate を絞るか subscription 引き上げを判断する。

---

## 関連ファイル

- [parky/api/src/lib/sentry.ts](../../api/src/lib/sentry.ts) — Workers Sentry helper
- [parky/api/src/middleware/error-handler.ts](../../api/src/middleware/error-handler.ts) — 5xx capture 配線
- [parky/api/src/env/bindings.ts](../../api/src/env/bindings.ts) — `SENTRY_DSN` / `SENTRY_RELEASE` 型定義
- [parky/mobileapp/prototype/flutter/lib/main.dart](../../mobileapp/prototype/flutter/lib/main.dart) — Flutter 初期化
- [parky/web/packages/observability/src/sentry-init.ts](../../web/packages/observability/src/sentry-init.ts) — Portal 共通 init helper
