SALON BOARD クローン — セットアップガイド
SALON BOARD クローン — セットアップガイド
Section titled “SALON BOARD クローン — セットアップガイド”Claude Code + Docker Compose前提。ホストにBunすら入れない運用で、すべての実行は docker compose 経由。
- macOS / Linux / WSL2
- Git
- Docker Desktop(Compose v2 同梱、v2.20+推奨)
- Claude Code(実装の主作業場)
ホスト側にBun / Node は不要。すべてコンテナ内で完結する。
1. 実行モデル
Section titled “1. 実行モデル”2パターンを使い分ける。
| 用途 | コマンド | 中身 |
|---|---|---|
| サーバー群の常駐起動 | docker compose up | api / worker / web / db を並走 |
| 単発コマンド(install、migrate、test、codegen等) | docker compose run --rm <svc> <cmd> | コンテナ1発動して終わり次第破棄 |
原則:ホストで bun xxx を直接叩かない。常に docker compose run --rm api bun xxx。
2. インストール
Section titled “2. インストール”# リポジトリ取得git clone git@github.com:<org>/salon-clone.gitcd salon-clone
# 環境変数ひな形コピーcp .env.example .env.local
# イメージビルド(初回のみ、以後もDockerfile/package.json変更時)docker compose build
# 依存インストール(コンテナ内で実行、node_modulesはnamed volumeに永続化)docker compose run --rm api bun install3. 環境変数
Section titled “3. 環境変数”.env.local で最低限書き換える:
| 変数 | 用途 | 初期値 |
|---|---|---|
DATABASE_URL | アプリ用接続(**非superuser app**でつなぐ、RLS有効) | postgres://app:app@db:5432/salon_dev |
DATABASE_URL_MIGRATOR | マイグレーション用(superuser postgres) | postgres://postgres:postgres@db:5432/salon_dev |
AUTH_SECRET | better-auth セッション暗号化 | openssl rand -hex 32 で生成 |
APP_URL | API/Web の基点 | http://localhost:3000 |
LINE_CHANNEL_* | LINE Messaging / LIFF | Phase 2以降、空でOK |
STRIPE_SECRET_KEY | Stripe | Phase 2以降、空でOK |
DB接続を2本に分けるのは RLS強制のため(詳細は§5)。
4. データベース初期化
Section titled “4. データベース初期化”# 1) DBコンテナだけ先に起動docker compose up -d db
# 2) 初期スキーマ&ロール作成(postgres.sql)docker compose run --rm api bun run db:bootstrap# └─ app ユーザー作成、graphile_worker スキーマ、拡張有効化(pgcrypto等)
# 3) Drizzleマイグレーション生成(スキーマ変更時のみ)docker compose run --rm api bun run db:generate
# 4) マイグレーション適用(RLSポリシーも含む)docker compose run --rm api bun run db:migrate
# 5) シード投入docker compose run --rm api bun run db:seed- 開発用店舗:
store-dev-001 - オペレーター:
owner@example.com(初回アクセスでPasskey/TOTP登録誘導) - スタッフ3名、メニュー5種、設備2台
- サンプル顧客10名、予約数件
5. Row-Level Security(初回からONで運用)
Section titled “5. Row-Level Security(初回からONで運用)”方針:Phase 1の最初のマイグレーションから全テナント対象テーブルでRLS有効化。例外なし。
5-1. DBユーザー分離
Section titled “5-1. DBユーザー分離”postgres:superuser。マイグレーション・Drizzle Studio専用app:通常ユーザー。アプリ/ワーカーがつなぐ。RLSが必ず適用されるpostgresはsuperuserなのでRLSを貫通してしまう- アプリが
appユーザーで繋ぐことで、policy違反 = 見えない/書けない が保証される
5-2. テーブル作成テンプレ(Drizzleマイグレーション末尾に必ず付ける)
Section titled “5-2. テーブル作成テンプレ(Drizzleマイグレーション末尾に必ず付ける)”ALTER TABLE reservation ENABLE ROW LEVEL SECURITY;ALTER TABLE reservation FORCE ROW LEVEL SECURITY; -- ★ FORCEでテーブル所有者にも適用
CREATE POLICY tenant_isolation ON reservation USING (store_id = current_setting('app.current_store_id'));
GRANT SELECT, INSERT, UPDATE, DELETE ON reservation TO app;5-3. リクエスト毎の設定
Section titled “5-3. リクエスト毎の設定”Hono middleware で SET LOCAL を発行(トランザクション内で有効、コネクションプール安全):
app.use('*', async (c, next) => { const storeId = c.get('storeId') // 認可middlewareで解決済み await db.execute(sql`SET LOCAL app.current_store_id = ${storeId}`) await next()})5-4. デバッグ
Section titled “5-4. デバッグ”docker compose run --rm db psql -U app -d salon_devSET app.current_store_id = 'store-dev-001';SELECT * FROM reservation; -- そのテナントの行のみ見えるDISABLE ROW LEVEL SECURITY は絶対にやらない。事故の温床。
6. 開発サーバー起動
Section titled “6. 開発サーバー起動”docker compose up以下が並走:
| ポート | サービス | コマンド |
|---|---|---|
| 3000 | api | bun --hot apps/api/src/index.ts |
| --- | worker | bun apps/worker/src/index.ts |
| 3001 | web | bun --filter web dev |
| 5432 | db | Postgres 16 |
ブラウザで http://localhost:3001 → オペレーターログイン画面。
個別起動・ログ追跡
Section titled “個別起動・ログ追跡”docker compose up api web # 欲しいサービスだけdocker compose up -d # バックグラウンドdocker compose logs -f api # 特定サービスのログ追跡docker compose ps # 状態確認7. Context7 MCP(Claude Code側で設定)
Section titled “7. Context7 MCP(Claude Code側で設定)”Context7はホスト側のClaude Codeに登録する(コンテナ内に入れる必要はない)。
プロジェクトルートの .mcp.json(チーム共有):
{ "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp"] } }}または claude mcp add で追加:
claude mcp add context7 -- npx -y @upstash/context7-mcpプロンプト末尾に use context7 を足す:
“HonoでSSEストリーミングエンドポイント書きたい。use context7” “drizzle-ormで複合FK貼る方法を調べて実装して。use context7”
常用ライブラリ
Section titled “常用ライブラリ”hono/@hono/zod-openapidrizzle-orm/drizzle-kitbetter-authgraphile-workerzod@tanstack/react-router/@tanstack/react-queryshadcn-ui@line/liff/@line/bot-sdkstripeopenapi-typescript/openapi-fetch
LLM出力が古いAPIで落ちる事故を潰すため、実装時は積極的に use context7。
8. よく使うコマンド(全部 docker compose run —rm 経由)
Section titled “8. よく使うコマンド(全部 docker compose run —rm 経由)”# 型チェックdocker compose run --rm api bun run typecheck
# Lint / Format(Biome)docker compose run --rm api bun run lintdocker compose run --rm api bun run format
# テストdocker compose run --rm api bun run testdocker compose run --rm api bun --filter api testdocker compose run --rm api bun run test:watch
# Drizzledocker compose run --rm api bun run db:generate # マイグレーション生成docker compose run --rm api bun run db:migrate # 適用docker compose run --rm api bun run db:reset # drop→migrate→seed(破壊的、devのみ)docker compose run --rm --service-ports api bun run db:studio # GUI、port公開必要
# OpenAPI → 型生成docker compose run --rm api bun run codegen# └─ 内部で openapi:write → openapi-typescript を直列実行
# ビルドdocker compose run --rm api bun run builddocker compose run --rm api bun --filter api build
# 依存監査docker compose run --rm api bun pm audit
# パッケージ追加docker compose run --rm api bun add <pkg> # ルートdocker compose run --rm api bun --filter api add <pkg> # 特定app/packageエイリアス推奨
Section titled “エイリアス推奨”頻出なので、ホストの ~/.bashrc / ~/.zshrc に置く:
alias dc='docker compose'alias dcr='docker compose run --rm api'
# 使用例dcr bun run testdcr bun run db:migrate9. PostgreSQLへの直接アクセス
Section titled “9. PostgreSQLへの直接アクセス”# psql(superuser)docker compose exec db psql -U postgres salon_dev
# psql(アプリユーザー、RLS有効)docker compose exec db psql -U app salon_dev
# Drizzle Studio(portを公開して起動)docker compose run --rm --service-ports api bun run db:studio# → http://localhost:498310. IDE設定(Claude Code外でも触る場合)
Section titled “10. IDE設定(Claude Code外でも触る場合)”.vscode/settings.json(リポジトリ同梱想定)
Section titled “.vscode/settings.json(リポジトリ同梱想定)”{ "editor.formatOnSave": true, "editor.defaultFormatter": "biomejs.biome", "editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" }}Dev Container(任意)
Section titled “Dev Container(任意)”Claude Codeが Dev Container をサポートするので、.devcontainer/devcontainer.json を用意しておくとエディタ側もコンテナ内で動く:
{ "name": "salon-clone", "dockerComposeFile": "../docker-compose.yml", "service": "api", "workspaceFolder": "/work"}11. トラブルシュート
Section titled “11. トラブルシュート”| 症状 | 対処 |
|---|---|
bun install が失敗 | docker compose run --rm api rm -rf node_modules bun.lockb && docker compose run --rm api bun install |
| Postgres接続拒否 | docker compose ps で db コンテナ起動確認、docker compose logs db |
| マイグレーション重複 | docker compose run --rm api bun run db:reset |
| ジョブが処理されない | docker compose logs worker と graphile_worker.jobs テーブル確認 |
| 型エラーがapp横断で出る | docker compose run --rm api bun --filter <上流> build |
| Context7が効かない | Claude Code側のMCPログ確認、npx @upstash/context7-mcp を直接実行 |
| RLSで行が見えない | app ユーザーで current_setting('app.current_store_id') が期待店舗IDになってるか確認。middlewareのSET LOCALもれ疑え |
| volume の node_modules が古い | docker compose down -v && docker compose build && docker compose run --rm api bun install |
12. 本番デプロイ(MiniPC)
Section titled “12. 本番デプロイ(MiniPC)”docs/DEPLOY.md(Phase 1完了時に書く)参照。概要:
- systemd unit で
docker compose -f docker-compose.prod.yml up -dを起動時実行 - Tailscaleで外部アクセス、Caddyでリバースプロキシ
- 毎晩
pg_dumpをgraphile-workerジョブで取得、NAS/S3へpush /healthzをUptimeRobotで外形監視
13. チェックリスト(初回セットアップ完了確認)
Section titled “13. チェックリスト(初回セットアップ完了確認)”-
docker --version/docker compose version動作確認 -
docker compose build成功 -
.env.local用意 -
docker compose up -d dbでPostgres起動 -
docker compose run --rm api bun install成功 -
docker compose run --rm api bun run db:bootstrap && bun run db:migrate && bun run db:seed成功 -
docker compose upでAPI/worker/web起動 -
http://localhost:3001でログイン画面表示 - Claude Code から Context7 MCP が使える
-
docker compose run --rm api bun run test成功 -
docker compose run --rm api bun run codegen成功 -
appユーザーでの接続でRLSが機能している(擬似テナント切替で確認)
ここまで通ればOK。実装に入れる。