コンテンツにスキップ

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 は不要。すべてコンテナ内で完結する。


2パターンを使い分ける。

用途コマンド中身
サーバー群の常駐起動docker compose upapi / worker / web / db を並走
単発コマンド(install、migrate、test、codegen等)docker compose run --rm <svc> <cmd>コンテナ1発動して終わり次第破棄

原則:ホストで bun xxx を直接叩かない。常に docker compose run --rm api bun xxx


Terminal window
# リポジトリ取得
git clone git@github.com:<org>/salon-clone.git
cd salon-clone
# 環境変数ひな形コピー
cp .env.example .env.local
# イメージビルド(初回のみ、以後もDockerfile/package.json変更時)
docker compose build
# 依存インストール(コンテナ内で実行、node_modulesはnamed volumeに永続化)
docker compose run --rm api bun install

.env.local で最低限書き換える:

変数用途初期値
DATABASE_URLアプリ用接続(**非superuser app**でつなぐ、RLS有効)postgres://app:app@db:5432/salon_dev
DATABASE_URL_MIGRATORマイグレーション用(superuser postgrespostgres://postgres:postgres@db:5432/salon_dev
AUTH_SECRETbetter-auth セッション暗号化openssl rand -hex 32 で生成
APP_URLAPI/Web の基点http://localhost:3000
LINE_CHANNEL_*LINE Messaging / LIFFPhase 2以降、空でOK
STRIPE_SECRET_KEYStripePhase 2以降、空でOK

DB接続を2本に分けるのは RLS強制のため(詳細は§5)。


Terminal window
# 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有効化。例外なし。

  • 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;

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()
})
Terminal window
docker compose run --rm db psql -U app -d salon_dev
SET app.current_store_id = 'store-dev-001';
SELECT * FROM reservation; -- そのテナントの行のみ見える

DISABLE ROW LEVEL SECURITY は絶対にやらない。事故の温床。


Terminal window
docker compose up

以下が並走:

ポートサービスコマンド
3000apibun --hot apps/api/src/index.ts
---workerbun apps/worker/src/index.ts
3001webbun --filter web dev
5432dbPostgres 16

ブラウザで http://localhost:3001 → オペレーターログイン画面。

Terminal window
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 で追加:

Terminal window
claude mcp add context7 -- npx -y @upstash/context7-mcp

プロンプト末尾に use context7 を足す:

“HonoでSSEストリーミングエンドポイント書きたい。use context7” “drizzle-ormで複合FK貼る方法を調べて実装して。use context7”

  1. hono / @hono/zod-openapi
  2. drizzle-orm / drizzle-kit
  3. better-auth
  4. graphile-worker
  5. zod
  6. @tanstack/react-router / @tanstack/react-query
  7. shadcn-ui
  8. @line/liff / @line/bot-sdk
  9. stripe
  10. openapi-typescript / openapi-fetch

LLM出力が古いAPIで落ちる事故を潰すため、実装時は積極的に use context7


8. よく使うコマンド(全部 docker compose run —rm 経由)

Section titled “8. よく使うコマンド(全部 docker compose run —rm 経由)”
Terminal window
# 型チェック
docker compose run --rm api bun run typecheck
# Lint / Format(Biome)
docker compose run --rm api bun run lint
docker compose run --rm api bun run format
# テスト
docker compose run --rm api bun run test
docker compose run --rm api bun --filter api test
docker compose run --rm api bun run test:watch
# Drizzle
docker 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 build
docker 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

頻出なので、ホストの ~/.bashrc / ~/.zshrc に置く:

Terminal window
alias dc='docker compose'
alias dcr='docker compose run --rm api'
# 使用例
dcr bun run test
dcr bun run db:migrate

Terminal window
# 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:4983

10. 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"
}
}

Claude Codeが Dev Container をサポートするので、.devcontainer/devcontainer.json を用意しておくとエディタ側もコンテナ内で動く:

{
"name": "salon-clone",
"dockerComposeFile": "../docker-compose.yml",
"service": "api",
"workspaceFolder": "/work"
}

症状対処
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 workergraphile_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

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。実装に入れる。