# Virtual Try-On Feature — Handoff Document

**For:** Team members continuing work on this feature (including Claude Code sessions)
**Branch:** `feature/virtual-tryon`
**PR:** https://github.com/ryo2gxo/moro/pull/5
**Last updated:** 2026-04-13

---

## TL;DR

バーチャル試着機能は**コード実装完了**。ローカルでモックモード全フロー動作確認済み。
本番デプロイには **Segmind APIキー + DigitalOcean Spaces + ウォーターマーク画像** が必要。

---

## What's Done

### Backend (Laravel)
- DB migrations: `user_face_photos`, `virtual_tryon_results`, `users.tryon_consent_at`
- Models: `UserFacePhoto`, `VirtualTryonResult`, `Laravue\User`にリレーション追加
- Services: `SegmindFaceSwapService`, `VirtualTryonImageService`
- Queue job: `ProcessVirtualTryon`
- Controller: `app/Http/Controllers/Api/Site/VirtualTryonController.php`（8エンドポイント）
- Artisan command: `tryon:clean-expired`（90日経過結果削除、daily 3:00）
- API rate limiting設定済
- セキュリティ対策（14件）適用済：path traversal, IDOR, image bomb, SVG XSS等

### Frontend (Vue 2)
- `components/VirtualTryon/` 配下4コンポーネント（Dialog, PhotoSelector, Processing, Result）
- `views/mypage/tryon-history.vue` — 試着履歴ページ
- `views/pages/virtual-fitting.vue` — ランディングページ
- 商品詳細ページにダイアログ統合済
- **おばあちゃん向けUI**: ステップ表示、IT用語排除、ボタン48-52px

### Tests
- `tests/Feature/VirtualTryonTest.php`（10ケース）
- `tests/Unit/SegmindFaceSwapServiceTest.php`（5ケース）
- `tests/Unit/VirtualTryonImageServiceTest.php`（4ケース）
- ローカル実行: 11パス / 4スキップ(GD未導入環境) / 0失敗

### Mock Mode
- `SEGMIND_API_KEY`未設定時は商品画像を結果として返す
- APIキー設定で自動的に本番Segmindに切替
- 実装: `SegmindFaceSwapService::isApiConfigured()`

---

## What's NOT Done (Blockers for Production)

| Item | Who | Notes |
|------|-----|-------|
| **Segmind APIキー取得** | Ryo | segmind.com登録、$10/月〜 |
| **DO Spacesバケット開設** | Ryo/Liem | sgp1リージョン推奨、月$5 |
| **ウォーターマーク画像** | Designer | `public/images/watermark-kirei.png`（PNG、透過、200-400px幅） |
| **本番 .env 設定** | Liem | SEGMIND_API_KEY, DO_SPACES_* を設定 |
| **本番DBマイグレーション** | Liem | `php artisan migrate`（3テーブル追加） |
| **Redisキューワーカー確認** | Liem | 既存インフラでOK |
| **動作確認** | All | docs/virtual-tryon-setup.md のチェックリスト |

---

## Files Changed (32 files, 3,400+ lines)

### Backend
- `database/migrations/2026_04_11_000001_create_user_face_photos_table.php`
- `database/migrations/2026_04_11_000002_create_virtual_tryon_results_table.php`
- `database/migrations/2026_04_11_000003_add_tryon_consent_to_users_table.php`
- `app/UserFacePhoto.php`
- `app/VirtualTryonResult.php`
- `app/User.php` + `app/Laravue/Models/User.php`（リレーション追加）
- `app/Services/SegmindFaceSwapService.php`
- `app/Services/VirtualTryonImageService.php`
- `app/Jobs/ProcessVirtualTryon.php`
- `app/Http/Controllers/Api/Site/VirtualTryonController.php`
- `app/Console/Commands/CleanExpiredTryonResults.php`
- `app/Console/Kernel.php`
- `config/faceswap.php`, `config/filesystems.php`
- `routes/api.php`
- `.env.example`

### Frontend
- `resources/js/frontend/api/virtual-tryon.js`
- `resources/js/frontend/components/VirtualTryon/` (4 files)
- `resources/js/frontend/views/mypage/tryon-history.vue`
- `resources/js/frontend/views/pages/virtual-fitting.vue`
- `resources/js/frontend/views/product/detail.vue`
- `resources/js/frontend/router/index.js`
- `resources/js/frontend/store/getters.js`, `store/modules/user.js`
- `resources/js/frontend/components/MyPageNav/index.vue`

### Tests & Docs
- `tests/Feature/VirtualTryonTest.php`
- `tests/Unit/SegmindFaceSwapServiceTest.php`
- `tests/Unit/VirtualTryonImageServiceTest.php`
- `tests/RefreshDatabaseWithoutSeeds.php`
- `docs/virtual-tryon-setup.md`（英語手順書）
- `docs/virtual-tryon-handoff.md`（このファイル）

---

## Architecture Notes

### Authentication
- 実際に使われるUserモデルは `App\Laravue\Models\User`（`App\User`ではない）
- リレーション追加は両方のクラスに必要
- 2段階認証（verify → code送信 → login）

### Storage Fallback
- DO Spaces設定あり → `do_spaces`ディスク
- なし → `public`ディスク（`storage/app/public`、symlink経由）
- `SegmindFaceSwapService::diskName()` と `VirtualTryonImageService::diskName()` で判定

### Route Parameters
- ルート定義は `/product/:code` だが、検索ページ等は `params: {id}` で渡している
- `detail.vue` で両対応: `this.$route.params.code || this.$route.params.id`

### Security
- Segmind APIキー未設定時でもモックモードで動作
- `is_deleted=0` チェック必須
- `basename()` でpath traversal防止
- レート制限: upload 5/min, start 10/min, status 60/min, download 20/min

---

## Local Development (Docker)

```bash
cd /path/to/moro
git checkout feature/virtual-tryon
docker compose up -d
```

**Important local-only tweaks (do NOT commit):**
- If port 8000 is taken, change `docker-compose.yml` and `docker/docker.env` to another port
- `composer.lock` was deleted to avoid PHP 8.1/8.2 compat issues on some environments. Regenerate with `composer install --ignore-platform-reqs` if needed
- `docker/entrypoint.sh` may need `sed -i 's/\r$//'` on Windows hosts (CRLF issue)

### Test Credentials
- Regular user: `test@kirei.local` / `test1234`
- Admin: `admin@admin.dev` / `AtIlUbFaPyotos47oX9U`
- Mailpit (for verify code): `http://127.0.0.1:8025/`

### End-to-End Test Flow
1. Login at `/login` (use Mailpit for verify code)
2. Browse to any product via `/search`
3. Click "バーチャル試着する" on product detail
4. Upload any face photo
5. Wait 2 seconds (mock mode)
6. Save or download result
7. Check history at `/mypage/tryon-history`

---

## Known Issues

1. **Product images missing in DB**: The imported SQL dump references image files like `9197befd3aa0cd5ce281606eeae50fb6.png` that don't exist. For local testing, generate a placeholder:
   ```bash
   docker exec moro-laravel-1 php -r "..."  # see handoff session for full command
   ```

2. **GD extension required** for `Intervention\Image`. Skipped in tests when missing, but production must have GD enabled.

3. **Frontend API URL is build-time embedded** via `MIX_BASE_API`. Must rebuild frontend (`npm run dev` or `dev-all`) after changing `APP_URL`.

---

## Claude Code Continuation

If you're a Claude Code agent picking up this work:

1. **Read first**: `docs/virtual-tryon-setup.md`, `docs/virtual-tryon-handoff.md`, PR #5 description
2. **Check branch**: `git log --oneline origin/develop..feature/virtual-tryon` — should show ~10 commits
3. **Test locally**: `docker compose up -d` then run end-to-end flow above
4. **Known good commit**: `ccfd096a` (2026-04-13) — mock mode fully working

Key context for AI agents:
- Mock mode exists for local dev (no Segmind key needed)
- Laravue User model is used, not App\User
- Security audit passed (see commits `6c869660`, `f57defa8`)
- UX was audited for grandma-friendly use (see commit `1507b329`)

---

## Next Actions (Priority Order)

1. **Ryo**: Open Segmind account, get API key
2. **Ryo**: Open DO Spaces bucket (sgp1 region), get credentials
3. **Designer**: Create `watermark-kirei.png` (KIREI logo, transparent PNG)
4. **Liem**: Review PR #5 code
5. **Liem**: Configure production `.env` with Segmind + DO Spaces
6. **Liem**: Merge to develop, deploy, run migrations
7. **All**: E2E test with real Segmind API on production
