# curumi-corp ↔ curumi-ops 疎結合連携仕様

curumi の2つのリポジトリの**役割境界・共有点・分離点**を整理する。境界が曖昧だと修正範囲が膨らみ、片方の変更が他方を壊すリスクが上がる。

## 全体像

```
curumi-corp (集客サイト)              curumi-ops (社内運用)
┌─────────────────────┐             ┌─────────────────────┐
│ admin.curumi.co.jp   │             │ ops (port 3311)       │
│  - 記事管理          │             │  - 広告管理         │
│  - 編集方針         │             │  - レポート          │
│  - cron (記事生成)   │             │  - ナレッジ          │
│ curumi.co.jp         │             │  - ペルソナ          │
│  - 記事閲覧          │             │ knowledge-base       │
│  - sitemap/llms.txt  │             │  - マーケ知識収集   │
└──────────┬──────────┘             └──────────┬──────────┘
           │                                    │
           │  read/write                        │  read
           └─────────┬──────────────────────────┘
                     ▼
           ┌────────────────────┐
           │   Turso (libSQL)   │ ← 単一の真実
           │  - articles        │
           │  - keywords        │
           │  - personas        │
           │  - editorial cfg   │
           └────────────────────┘
```

## 役割境界

| 領域 | curumi-corp | curumi-ops |
|------|-----------|-----------|
| **記事管理（CRUD）** | ★ Owner | — |
| **記事閲覧（公開）** | ★ Owner | — |
| **記事生成 cron** | ★ Owner | — |
| **キーワード管理** | ★ Owner（管理画面） | ○ 参照のみ |
| **編集方針 / ブランド設定** | ★ Owner（`*.config.ts`） | ○ 参照のみ |
| **広告データ収集（Google/Meta API）** | — | ★ Owner |
| **広告レポート生成** | — | ★ Owner |
| **クライアント別レポート閲覧** | — | ★ Owner |
| **ペルソナ定義** | ○ 参照（記事生成で使用） | ★ Owner（管理画面） |
| **マーケ知識収集（articles/x/youtube）** | — | ★ Owner（GHA cron） |
| **戦略ドキュメント** | — | ★ Owner（`docs/strategy/`） |

★ = 一次責任、○ = 二次参照

## 共有しているもの

### Turso DB

**1つの DB を両方が使う**。テーブル単位で「書き手は誰か」が決まっている。

```
articles, keywords, editorial_*  → corp が書き手
personas, ad_*, report_*         → ops が書き手
```

**rule**:
- 自分のテーブルしか書かない
- 他方のテーブルは read のみ、SQL で直接更新しない
- スキーマ変更は drizzle-kit generate → migrate（手動 ALTER 禁止、ops の CLAUDE.md 参照）

### 環境変数の管理

| 変数 | 管理場所 | 共有 |
|-----|--------|-----|
| `TURSO_DATABASE_URL` | 1Password vault `curumi` | 両方が参照 |
| `TURSO_AUTH_TOKEN` | 1Password vault `curumi` | 両方が参照 |
| アプリ固有のキー | `apps/*/.env.local` (corp/ops それぞれ) | 各repo独立 |

**重要なインシデント教訓**（corp CLAUDE.md より）:
- 過去に staging DB の URL を本番 GitHub Secrets に上書き → 全記事消失
- **`.env`（staging）と GitHub Secrets（本番）を絶対に混ぜない**

## 分離しているもの（独立性）

- ✅ **デプロイ**: corp = Cloudflare Workers / ops = Vercel
- ✅ **CI**: 各repoでGitHub Actions独立
- ✅ **依存ライブラリ**: 各repoで独立管理（共通化しない）
- ✅ **認証**: 各repo独自（corp = 公開・認証なし or 軽い、ops = withAuth + Google OAuth + ドメイン制限）
- ✅ **ブランチ運用**: 各repoでstaging/main 独立

→ **片方が落ちても他方は稼働可能**。これが疎結合の意味。

## 連携が発生するケース

| ケース | 連携手段 | 注意 |
|------|--------|------|
| corp で記事生成時にペルソナを参照 | DB read（personas テーブル） | personas のスキーマ変更時は事前共有 |
| ops で記事の閲覧数を集計 | DB read（articles テーブル） | articles のスキーマ変更時は事前共有 |
| ブランド設定変更 | corp の `brand.config.ts` を編集 → 必要なら ops 側で同等の設定を更新 | 二重管理。将来は DB に集約検討 |

**API 経由の連携は現時点では無し**。すべて DB 経由。

## 障害時の独立性チェックリスト

### corp が落ちた場合

- [ ] ops は稼働可能? → ✅（記事配信に依存していない）
- [ ] ops の管理画面でレポート閲覧可能? → ✅
- [ ] 営業は料金表・FAQ を見られる? → ✅（curumi-ops/docs/strategy/adbuddy/ で）

### ops が落ちた場合

- [ ] corp は稼働可能? → ✅（広告データに依存していない）
- [ ] 記事閲覧は継続? → ✅
- [ ] 記事生成 cron は動く? → ✅（corp 側で完結）

### Turso が落ちた場合

- [ ] corp は稼働可能? → ❌（記事閲覧不可）
- [ ] ops は稼働可能? → ❌（レポート閲覧不可）
- [ ] 緊急対応 → Turso の status 確認 + 復旧待ち、あるいは静的フォールバック検討

## 設計原則

1. **DB を共有してもアプリは疎結合**: コード共有はしない、依存もしない
2. **テーブルの書き手は1つ**: 同じテーブルを両方から書くと整合性が崩れる
3. **スキーマ変更は事前共有**: 影響範囲を見てから migrate
4. **片方の障害は他方に伝播させない**: API直接依存を作らない
5. **設定の二重管理は許容するが、いずれDBに集約**: 現状は許容、整理は将来課題

## 将来の検討事項

- [ ] `personas` を corp と ops の双方が書く運用への対応
- [ ] ブランド設定の DB 集約（現状 corp の `*.config.ts` のみ）
- [ ] 共通スキーマの packages 化（現状は drizzle-orm 重複問題で各アプリ定義）
- [ ] 監視・障害連絡の統一（現状は各repo独立）
