SALON BOARD クローン — 親SRS(System Requirements Specification)
SALON BOARD クローン — 親SRS(System Requirements Specification)
Section titled “SALON BOARD クローン — 親SRS(System Requirements Specification)”Document ID: SRS-ROOT-001 Version: 0.5 Status: Draft Last Updated: 2026-05-05 Owner: yudai
0. このドキュメントの役割
Section titled “0. このドキュメントの役割”本書は親SRSである。実装前に各機能単位で作成する子SRS(docs/SRS/features/*.md)の上位規範として機能する。
子SRSは以下を定義する。
- 個別機能のユースケース
- 画面仕様・API仕様(zodスキーマレベル)
- 状態遷移・業務ルール
- 受け入れ基準(テストケース)
親SRSは子SRS全体で共通するルール・制約・契約を定義し、各子SRSでの再記述を不要にする。各子SRSの冒頭で「本書はSRS-ROOT-001に従う」と明記する。
1. ドキュメント管理
Section titled “1. ドキュメント管理”1.1 対象読者
Section titled “1.1 対象読者”- 実装者(自分・将来の協力者)
- レビュー時の自己チェック
- LLM に実装を依頼する際のコンテキスト
1.2 変更管理
Section titled “1.2 変更管理”- バージョンは
Major.Minor- Major: アーキテクチャ変更
- Minor: 要件追加・契約変更
- 変更は必ず理由を変更履歴に残す
- 子SRS作成時、親SRS更新が必要なら先に親を改訂してから子を書く
1.3 関連ドキュメント
Section titled “1.3 関連ドキュメント”| ID | タイトル | 場所 |
|---|---|---|
| DOC-ANALYSIS-001 | SALON BOARDクローン開発 基礎情報 | /outputs/SALON_BOARD_クローン開発_基礎情報.md |
| DOC-ERD-001 | ERD(Mermaid) | /outputs/SALON_BOARD_ERD.md |
| DOC-DIR-001 | ディレクトリ構成 | /outputs/SALON_BOARD_DIRECTORY_STRUCTURE.md |
| DOC-SETUP-001 | セットアップガイド | /outputs/SALON_BOARD_SETUP_GUIDE.md |
2. 用語集
Section titled “2. 用語集”| 用語 | 定義 |
|---|---|
| 店舗(Store) | 本システムのマルチテナント単位 |
| オペレーター(Operator) | 管理画面を操作する認証ユーザー |
| スタッフ(Staff) | 施術担当者の業務マスタ。Operator と 1:1 とは限らない |
| 顧客(Customer) | 来店者・予約者 |
| 予約(Reservation) | 来店予定。Phase 1 では 10 状態の状態機械を持つ |
| 来店(Visit) | 予約に紐づく実来店・会計の業務実体 |
| 返金(Visit Refund) | visit に対する返金明細。visit_refund に記録する |
| 設備グループ(Equipment Group) | 予約時に「同種設備から空きを自動割当」するための抽象グループ |
| レジ締め(Closed Date) | 日次締め済みとして後続改変を禁止する営業日 |
| LIFF | LINE Front-end Framework |
| MCP | Model Context Protocol |
| RLS | Row-Level Security |
3. システム概要
Section titled “3. システム概要”3.1 目的
Section titled “3.1 目的”予約・顧客管理・会計・掲載を統合した美容サロン向け SaaS を構築する。SALON BOARD を参考にしつつ、価格・UX・AI ネイティブ・HPB 非依存で差別化する。
3.2 ビジネス上の位置付け
Section titled “3.2 ビジネス上の位置付け”- SALON BOARD: HPB 一体型
- 本プロダクト: 自社顧客チャネル(LIFF)を内蔵した HPB 非依存運用
- AI 差別化: MCP サーバー経由で Claude / ChatGPT から運営操作可能
3.3 スコープ
Section titled “3.3 スコープ”In-scope(Phase 1〜4)
- 予約管理(作成・編集・キャンセル・状態管理・カレンダー)
- 顧客管理(基本情報・来店履歴・タグ・メモ)
- レジ・会計(現金・カード・電子マネー・返金・締め)
- メッセージング(メール・LINE・SMS)
- スタッフ・設備・設備グループ・メニュー・営業時間管理
- 売上集計・日報・月次レポート
- HPB 掲載管理
- LIFF 顧客アプリ
- MCP サーバー(OAuth2.1)
Out-of-scope(Phase 1)
- Smart Pay 実装本体
- Phase 2 の
SRS-PAY-001で扱う
- Phase 2 の
- 物販EC
- 勤怠・給与計算
- ネイル・エステ業態特化機能
- HPB 内部 API 連携
- ネイティブアプリ
4. ステークホルダー / ペルソナ
Section titled “4. ステークホルダー / ペルソナ”4.1 オペレーター
Section titled “4.1 オペレーター”| ペルソナ | 特徴 | 主な関心 |
|---|---|---|
| サロンオーナー | 複数店舗経営 | 売上・会員・店舗横断数値 |
| 店長 | 1 店舗運営 | 予約・顧客・スタッフ・締め |
| スタイリスト | 自分の担当軸が中心 | 自分のスケジュール、担当顧客 |
| 受付 | 予約入力・会計中心 | カレンダー、レジ、来店導線 |
注記: スタイリスト向けの「自分関連のみ」権限は operator_staff_link を前提にする。リンクが存在しないオペレーターには self-scope を適用しない。
権限モデル: permission-based + プリセット role(RBAC ファサード)
ownermanagerstaffreceptionist
詳細は §7.7。
4.2 顧客
Section titled “4.2 顧客”- 20〜50代女性が中心
- LINE 利用率が高い
- 予約チャネルは HPB / 電話 / LINE / 店頭 / 管理画面代理入力
5. バウンデッドコンテキスト
Section titled “5. バウンデッドコンテキスト”| ID | コンテキスト | 主要エンティティ |
|---|---|---|
| BC-TEN | テナンシー・認証 | Store, Operator, Session, Passkey, TOTP, RecoveryCode |
| BC-MST | マスター・リソース | Staff, Equipment, EquipmentGroup, Menu, BusinessHours, Shift |
| BC-CUS | 顧客・CRM | Customer, CustomerNote, CustomerTag |
| BC-RES | 予約 | Reservation, ReservationMenuLine, ReservationEvent |
| BC-REG | 会計・締め | Visit, VisitPayment, VisitRefund, CashMovement, RegisterClosing |
| BC-MSG | メッセージング | Message, AutoMessageRule, Coupon |
| BC-PAY | 決済連携 | SmartPayTxn, Settlement |
| BC-LST | 掲載 | SalonListing, MenuListing, Photo, Blog, Review |
6. 非機能要件(NFR)
Section titled “6. 非機能要件(NFR)”6.1 性能
Section titled “6.1 性能”- 通常 API p95: 300ms 以下
- 重い集計: 1s 以下
- カレンダー初期表示: 100 予約規模で 1s 以下
- 1 店舗あたり 10 オペレーター同時操作を想定
- 通常ジョブは 5 秒以内に処理開始、最大 30 秒
6.2 可用性
Section titled “6.2 可用性”- 稼働率目標
- Phase 1〜3: 99.5%
- Phase 4 以降: 99.9%
- メンテナンスウィンドウ: 月 1 回、03:00〜05:00
- 無停止デプロイ最適化は Phase 3 以降
6.3 セキュリティ
Section titled “6.3 セキュリティ”- 通信: HTTPS 必須
- 認証
- Operator: Passkey 必須
- TOTP: 補助要素
- Customer: LINE Login
- 認可: RLS + アプリ層 permission の二重ガード
- セッション: JWT 不使用、サーバーサイドセッション
- 監査: 書込系操作は
operator_action_logに記録 - 脆弱性対応:
bun pm audit相当を CI に組み込む - 緊急復旧
- 未使用
recovery_code1 個の提示を必須 - 事前登録メールへの確認成功を必須
- TOTP のみでの復旧は不可
- 復旧成功時は当該 recovery code を即失効し、監査ログへ記録する
- 未使用
6.4 バックアップ・リストア
Section titled “6.4 バックアップ・リストア”- 毎晩 1 回
pg_dumpを取得する - ダンプは
ageで暗号化する - 暗号化済みアーカイブは Cloudflare R2 に保管する
- Phase 1 完了時に 1 回、手順書ベースの restore drill を実施する
- 目標
- RPO: 24h
- RTO: 手動復旧 4h 以内を目安
- restore drill は「空 DB への復元」「アプリ起動」「主要 read API 応答」まで確認する
6.5 可観測性
Section titled “6.5 可観測性”| Phase | 監視・観測の基準 |
|---|---|
| Phase 1 | pino 構造化ログ、Sentry、/healthz、/readyz |
| Phase 2 | OpenTelemetry 導入 |
| Phase 3 | Prometheus メトリクス収集、ダッシュボード整備 |
- アラート通知は Slack / Discord Webhook
- pager 運用は Phase 1 スコープ外
6.6 プライバシー・コンプライアンス
Section titled “6.6 プライバシー・コンプライアンス”- 顧客データの管理者は店舗、本サービスは委託先
- GDPR は現時点では非対象
- クーポン・割引表示は店舗責任
- 顧客削除要求は法令・会計要件と整合する範囲で論理削除を優先
6.7 国際化
Section titled “6.7 国際化”- 言語: 日本語のみ
- タイムゾーン:
Asia/Tokyo固定 - 通貨: JPY 整数固定
7. 共通制約(すべての子SRSに適用)
Section titled “7. 共通制約(すべての子SRSに適用)”7.1 マルチテナント規律
Section titled “7.1 マルチテナント規律”7.1.1 store_id 原則と例外
Section titled “7.1.1 store_id 原則と例外”原則として、業務テーブルは store_id を持つ。
store_id を持たない例外テーブル
permissionoperatorpasskey_credentialtotp_secretrecovery_codeoperator_sessionholiday(Phase 3 予定、全国共通カレンダー扱い)
明示注記
tax_rateは例外ではない。Phase 1/3 を通して store-scoped とする- 例外を増やす場合は親SRS改訂が必要
7.1.2 外部キー
Section titled “7.1.2 外部キー”- 参照は原則
(store_id, target_id) -> target(store_id, id)の複合 FK - 主キーが
id単独でも、参照先にUNIQUE(store_id, id)を必ず張る
7.1.3 RLS
Section titled “7.1.3 RLS”- tenant-scoped table は最初の migration から
ENABLE ROW LEVEL SECURITY+FORCE ROW LEVEL SECURITY - RLS 後付けは禁止
7.1.4 接続分離
Section titled “7.1.4 接続分離”postgres: bootstrap / migration 専用app: API / worker 実行用worker_runtime: graphile-worker 実行用(Phase 1 で bootstrap 作成)
7.1.5 app.current_store_id
Section titled “7.1.5 app.current_store_id”- リクエストごとに
SET LOCAL app.current_store_id - ワーカーも tenant job 実行前に
SET LOCAL
7.1.6 repository / job 契約
Section titled “7.1.6 repository / job 契約”- repository API は
storeId必須 - tenant job の payload は
storeId必須
7.1.7 scheduler fan-out 例外
Section titled “7.1.7 scheduler fan-out 例外”system-scope の scheduler 自体は storeId を持たなくてよい。ただし許されるのは以下のみ。
- 全 store の対象 ID を列挙する
- 各 store ごとに tenant-scoped job を enqueue する
system-scope の fan-out ループで業務 mutation を直接実行してはならない。
7.1.8 テナント跨ぎクエリ禁止
Section titled “7.1.8 テナント跨ぎクエリ禁止”- アプリ層からの cross-tenant 集計は禁止
- 例外が必要なら専用管理クエリとして明示起票する
7.1.9 DISABLE ROW LEVEL SECURITY 禁止
Section titled “7.1.9 DISABLE ROW LEVEL SECURITY 禁止”- CI / レビューでブロック対象
7.2 識別子
Section titled “7.2 識別子”7.2.1 原則
Section titled “7.2.1 原則”- 主キーは UUIDv7
- API / URL / 外部露出の可能性がある業務実体は UUIDv7
7.2.2 bigserial 例外
Section titled “7.2.2 bigserial 例外”以下を満たす内部用途のみ許容する。
- API トップレベルに露出しない
- 件数漏えいの業務影響が小さい
- 大量生成される
対象例
operator_action_logreservation_eventmessage_delivery_log
7.2.3 表示用 ID
Section titled “7.2.3 表示用 ID”customer_no: 店舗内採番coupon_code: 人間共有用コードsalon_slug: 公開 URL 用、グローバル UNIQUE
7.2.4 迷ったら
Section titled “7.2.4 迷ったら”- UUIDv7 側に倒す
7.3 金額表現
Section titled “7.3 金額表現”- 金額は
bigint(円) amount_excl_tax/tax_amount/amount_incl_taxを分離保持- Phase 1 の
visit_payments.methodはcash/card/electronicの 3 値固定 - Smart Pay は Phase 2 (
SRS-PAY-001) まで契約から除外 - 税率スナップショットは
tax_rate_pctに保持 - 端数処理ポリシーは
store_settings.rounding_policyを参照する
7.4 時刻
Section titled “7.4 時刻”- DB:
timestamptz - 保存: UTC
- 表示:
Asia/Tokyo - 予約の業務時刻は店舗タイムゾーン基準で扱う
- 曜日番号は ISO DOW (1=Mon..7=Sun)、祝日可否は
is_holiday booleanで別軸表現する
7.5 削除
Section titled “7.5 削除”- 原則、業務実体は物理削除しない
- 論理削除は
deleted_atを採る - 例外
- セッション / トークン類
- graphile-worker 管轄ジョブ
- 一時ファイル
- 未来の
shift行(starts_at > now()に限る)- スタッフ退職・復職の同期調整でのみ許可
- 過去 shift の物理削除は禁止
- 論理削除行は RLS で隠さない。アプリ層で明示フィルタする
7.6 API 契約
Section titled “7.6 API 契約”packages/contractsに zod スキーマを置くapps/apiがルートを結線する- 成功レスポンス:
{ data: ... } - エラーレスポンス:
{ error: { code, message, details? } } - ページングは cursor ベース
- 小規模マスタ(
staff,menu_category,equipment,equipment_group等)は子SRSで明示した場合のみ全件返却可 /api/admin/*,/api/portal/*,/mcp,/webhooks/*を使い分ける
7.7 認可
Section titled “7.7 認可”7.7.1 基本方針
Section titled “7.7.1 基本方針”- 全エンドポイントはデフォルト要認証
- 認可は permission ミドルウェア + RLS の二重ガード
- 実効権限 = role permission + operator override
7.7.2 permission モデル
Section titled “7.7.2 permission モデル”permission: 全テナント共通マスタrole: 店舗スコープrole_permission: 中間operator_permission_override: 個別 override
7.7.3 実装責務の分離
Section titled “7.7.3 実装責務の分離”packages/auth- permission key 定義
- pure resolver
resolveReservationTransitionPermissionなどの純関数
apps/api/src/middleware- Hono middleware
requirePermission(...)requireReservationTransitionPermission(...)
packages/auth に Hono 依存を持ち込まない。
7.7.4 用語・命名規則
Section titled “7.7.4 用語・命名規則”- override は
operator_permission_overrideを指す語としてのみ使う - 予約系の「警告を押し通す」権限は
force_*で表現する force_double_bookingは廃止し、force_staff_concurrencyを使うforce_staff_concurrencyは スタッフ同時並行数のみ に効く- 設備重複の EXCLUDE 制約は
force_staff_concurrencyでも無効化しない
7.7.5 override の運用規律
Section titled “7.7.5 override の運用規律”- override UI は effective permission viewer と同時リリース
- Phase 1 では UI 非公開可だがスキーマは保持する
operator_permission_overrideテーブルは Phase 1 では作成しない(DB なし)。Phase 2 で feature flag 連動で作成する。Phase 1 の effective permission viewer は role 由来 permission のみを返す
7.7.6 粒度変更規約
Section titled “7.7.6 粒度変更規約”- split / merge / rename は新 key 追加 + backfill migration で行う
- 既存 key の in-place rename はしない
7.7.7 RLS との境界
Section titled “7.7.7 RLS との境界”- 行可視性は RLS
- 操作可否は permission
- ABAC が必要になれば親SRS改訂
7.7.8 新 permission 追加時の backfill
Section titled “7.7.8 新 permission 追加時の backfill”新 permission を追加する子SRSは、その migration の責務として以下を実施する。
permissionへ UPSERT- 既存全店舗の preset role へ
role_permissionbackfill - テストで preset role matrix を検証
7.8 監査
Section titled “7.8 監査”operator_action_logを共通監査ログとする- Phase 1 canonical columns
id bigserialstore_id uuidactor_kind enum('operator','system')operator_id uuid NULLaction varchar(80)target_type varchar(40)target_id textdiff jsonbrequest_id varchar(64) NULLcreated_at timestamptz
actor_kind='operator'のときoperator_idは NOT NULLactor_kind='system'のときoperator_idは NULL- customer 起点の予約取消など、operator を持たないイベントは
reservation_event側に記録する
7.8.1 監査の例外
Section titled “7.8.1 監査の例外”以下は operator_action_log 記録対象外とする。
- seed 実行
- bootstrap 実行
- DB migration 実行
7.9 エラー処理
Section titled “7.9 エラー処理”- ドメインエラーは 4xx に変換
- 予期しないエラーは 5xx + Sentry
- ユーザーメッセージは日本語・短く・次アクションが分かる形
7.10 テスト
Section titled “7.10 テスト”- テストランナー:
bun test - Unit: 純関数中心
- Integration: shared Postgres(Docker Compose 上)+ helper cleanup
- E2E: Phase 2 から Playwright
- Testcontainers 導入は Phase 3 OQ とする
7.11 セキュリティチェック
Section titled “7.11 セキュリティチェック”- 境界バリデーションは zod
- 生 SQL は prepared / parameterized
dangerouslySetInnerHTMLはレビュー必須- レート制限
- ログイン系: 10 回/分
- 一般 API: 100 回/分
- 予約 conflict-check 系: 600 回/分(専用 bucket)
7.12 UI/UX
Section titled “7.12 UI/UX”- デスクトップ優先
- iPad 動作必須
- スマホは PWA / LIFF 経由
- 子SRS §4 は最低限粒度に留める
- デザインシステム導入は別 SRS
7.13 店舗設定(store_settings)
Section titled “7.13 店舗設定(store_settings)”Phase 1 の canonical fields は以下とする。
| field | 型 / 既定 | 用途 |
|---|---|---|
reservation_slot_minutes | smallint, default 30 | 予約枠刻み |
max_concurrent_reservations_per_staff | smallint, default 1 | スタッフ並列上限 |
tentative_expire_hours | smallint, default 24, CHECK 1..168 | 仮予約失効時間 |
no_show_grace_minutes | smallint, default 30, CHECK 0..180 | no-show 判定猶予 |
customer_required_fields | jsonb, default ["name"] | 顧客作成必須項目 |
customer_no_seq | bigint, default 0, CHECK >= 0 | 店舗内顧客番号採番カウンタ |
rounding_policy | jsonb, default {"method":"round","target":"line"} | 端数処理 |
cancel_policy | jsonb, default {} | キャンセルポリシー |
updated_at | timestamptz | 更新時刻 |
7.14 リソース適格性マスタ
Section titled “7.14 リソース適格性マスタ”設備要件とスタッフ適格性は分離する。
menu_staff_eligibility(store_id, menu_id, staff_id)menu_equipment_requirement(store_id, menu_id, equipment_group_id, quantity)
設備要件は concrete equipment_id ではなく equipment_group_id を持つ。
予約作成 / 編集時は「要件 N 台」に対して、group 内の空き equipment_id を N 個自動割当する。
設備重複防止の EXCLUDE 制約は concrete equipment_id に対して維持する。
equipment_group canonical schema:
id uuidstore_id uuidname varchar(100)display_order integerterminated_at timestamptz NULLversion integer
equipment.group_id uuid NULL を持つ。
メニュー側にスタッフ適格性のホワイトリスト適用要否を menu.staff_assignment_policy varchar CHECK IN ('any','whitelist') で制御する。
7.15 業務実体テーブルの複合参照標準
Section titled “7.15 業務実体テーブルの複合参照標準”- 主キーは
id単独 - 追加で
UNIQUE(store_id, id)を張る - 参照は
(store_id, foreign_id) - PK を
(store_id, id)にしない
7.16 消費税率管理
Section titled “7.16 消費税率管理”tax_rateは store-scoped master とする- Phase 1 は空運用を許容する
- 予約 / 来店では
tax_rate_pctスナップショットを直接保持 - 実効期間検索は行わない
- 予約 / 来店では
- Phase 3 で
service_dateを基準にeffective_from/effective_toから検索する - 法改正対応時も既存
visit/reservation_menu_lineのスナップショットは不変 reservation_menu_lines.tax_rate_pct CHECK IN (8,10)のハードコード CHECK は migration0011以降で撤去する
7.17 visit 法定保存
Section titled “7.17 visit 法定保存”visitは 7 年保存を原則とするvisit,visit_line,visit_payment,visit_refundの物理削除は禁止- 訂正は更新履歴・返金明細・supersede 列で表現し、削除で表現しない
visit_line/visit_paymentの amend はsuperseded_atで旧行を無効化し、新行を INSERT する(SRS-REG-001 §7.8)
7.18 締め後改変禁止
Section titled “7.18 締め後改変禁止”- 共通関数
assertNotClosedDate(storeId, date)を repository 共通で使う - 全
visit/cash_movementmutation は必ずこの関数を通る - Phase 1 はアプリ層強制
- DB trigger 化は Phase 2 OQ とする
8. 技術スタック(確定)
Section titled “8. 技術スタック(確定)”| 層 | 採用 |
|---|---|
| ランタイム | Bun 1.3+ |
| 言語 | TypeScript(strict) |
| API | Hono |
| 契約 | zod + @hono/zod-openapi |
| 型共有 | OpenAPI → openapi-typescript |
| ORM | Drizzle ORM |
| DB | PostgreSQL 16 |
| 認証 | better-auth |
| ジョブキュー | graphile-worker |
| リアルタイム | SSE(Phase 2 採用、Phase 1 は polling) |
| フロント | Vite + React + TanStack Router + Tailwind |
| 監視 | Phase 1: pino + Sentry + healthz / readyz、Phase 2: OTel、Phase 3: Prometheus |
| テスト | bun test、shared Postgres、helper cleanup、Playwright(Phase 2)、Testcontainers は Phase 3 OQ |
| モノレポ | Bun workspaces |
| Lint / Format | Biome |
| 実行環境 | Docker Compose 必須 |
9. フェーズ計画と子SRSカタログ
Section titled “9. フェーズ計画と子SRSカタログ”9.1 Phase 1:基幹
Section titled “9.1 Phase 1:基幹”| Child SRS ID | タイトル | BC |
|---|---|---|
| SRS-TEN-001 | 店舗作成・初期設定 | BC-TEN |
| SRS-TEN-002 | オペレーター登録・Passkey 登録 | BC-TEN |
| SRS-TEN-003 | ロールと店舗アサイン | BC-TEN |
| SRS-MST-001 | スタッフ管理 | BC-MST |
| SRS-MST-002 | メニュー管理 | BC-MST |
| SRS-MST-003 | 営業時間・定休日 | BC-MST |
| SRS-MST-004 | シフト管理 | BC-MST |
| SRS-MST-005 | 設備管理 | BC-MST |
| SRS-CUS-001 | 顧客登録・検索 | BC-CUS |
| SRS-CUS-002 | 顧客詳細・メモ・タグ | BC-CUS |
| SRS-CUS-004 | 顧客担当スタッフリンク(operator_staff_link) | BC-CUS |
| SRS-RES-001 | 予約カレンダー表示 | BC-RES |
| SRS-RES-002 | 予約作成 | BC-RES |
| SRS-RES-003 | 予約編集・移動 | BC-RES |
| SRS-RES-004 | 予約状態遷移 | BC-RES |
| SRS-RES-005 | 二重予約判定 | BC-RES |
| SRS-REG-001 | レジ会計 | BC-REG |
| SRS-REG-002 | 日次締め | BC-REG |
| SRS-WRK-001 | Worker ランタイム基盤 | cross |
9.2 Phase 2:接客導線
Section titled “9.2 Phase 2:接客導線”| Child SRS ID | タイトル | BC |
|---|---|---|
| SRS-MSG-001 | 手動メッセージ送信 | BC-MSG |
| SRS-MSG-002 | 予約リマインダー自動送信 | BC-MSG |
| SRS-MSG-003 | クーポン発行・適用 | BC-MSG |
| SRS-RES-006 | オンライン予約受付 | BC-RES |
| SRS-PAY-001 | Smart Pay 決済連携 | BC-PAY |
| SRS-PAY-002 | キャンセル料自動課金 | BC-PAY |
| SRS-RES-007 | 複数チャネル予約統合 | BC-RES |
9.3 Phase 3:分析・連携
Section titled “9.3 Phase 3:分析・連携”| Child SRS ID | タイトル | BC |
|---|---|---|
| SRS-CUS-003 | 顧客セグメント・一斉配信 | BC-CUS |
| SRS-ANL-001 | 売上日報・月次レポート | BC-REG |
| SRS-ANL-002 | 顧客分析 | BC-CUS |
| SRS-MCP-001 | MCP サーバー | cross |
| SRS-MCP-002 | MCP ツールセット | cross |
| SRS-PWA-001 | PWA 化 | cross |
9.4 Phase 4:LIFF・メディア
Section titled “9.4 Phase 4:LIFF・メディア”| Child SRS ID | タイトル | BC |
|---|---|---|
| SRS-LIFF-001 | LIFF 基盤 | BC-CUS |
| SRS-LIFF-002 | LIFF 予約フロー | BC-RES |
| SRS-LIFF-003 | LIFF 会員証・履歴 | BC-CUS |
| SRS-LST-001 | サロン基本情報掲載 | BC-LST |
| SRS-LST-002 | メニュー・クーポン掲載 | BC-LST |
| SRS-LST-003 | フォトギャラリー | BC-LST |
| SRS-LST-004 | ブログ・特集 | BC-LST |
| SRS-LST-005 | 口コミ返信 | BC-LST |
| SRS-LST-006 | スタッフ掲載情報 | BC-LST |
10. 子SRSのテンプレート
Section titled “10. 子SRSのテンプレート”各子SRSは最低限以下の構造を持つ。
# {Feature Name}
**Document ID**: SRS-{BC}-{NNN}**Parent**: SRS-ROOT-001 v0.X**Status**: Draft / Review / Approved / Implemented**Depends on**: [SRS-XXX-YYY, ...]
## 1. 目的## 2. ユーザーストーリー## 3. ユースケース## 4. UI仕様## 5. API仕様## 6. データモデル影響## 7. 業務ルール## 8. 非機能要件## 9. セキュリティ・認可## 10. 受け入れ基準## 11. テスト計画## 12. 関連ジョブ## 13. Open Questions## 14. 変更履歴11. 実装フロー
Section titled “11. 実装フロー”11.1 基本フロー
Section titled “11.1 基本フロー”- 子SRS起票
- レビュー
- Approved
- 実装
- テスト
- マージ
- 子SRSを Implemented へ更新
11.2 実装順序の原則
Section titled “11.2 実装順序の原則”- 親SRS違反の疑いがあれば先に親を直す
- migration は code-first だが、RLS / GRANT / policy は必ず SQL で補完する
- permission 追加は必ず backfill migration とセット
11.3 LLM 利用時の原則
Section titled “11.3 LLM 利用時の原則”- 子SRS全文をコンテキストに入れる
- 実装と同時にテスト生成を要求する
- 人間は親SRS違反の有無を最優先でレビューする
11.4 文書同期
Section titled “11.4 文書同期”- 実装で契約が変わったら SRS も同時更新
- migration 番号、permission 表、OQ 状態は親SRSと整合させる
11.5 Phase 1 Definition of Done(28項目)
Section titled “11.5 Phase 1 Definition of Done(28項目)”- Phase 1 対象の子SRSが全て Approved 以上である
0001〜0020の migration がクリーン DB に順適用できるinfra/sql/bootstrap/001_roles_and_extensions.sqlと002_worker_runtime_role.sqlが再実行可能であるdb:seedが冪等である- tenant-scoped table すべてに RLS
ENABLE + FORCEが入っている store_id例外は §7.1.1 の一覧に限定されている- API / worker ともに
SET LOCAL app.current_store_idが徹底されている - system-scope scheduler は fan-out のみを行い、直接業務 mutation しない
- canonical 47 permission が seed / backfill 済みである
operator_permission_overrideの契約が親SRSと一致している(Phase 1 では DB 不在で OK)- Passkey / TOTP / recovery code / email confirmation を含む Operator 認証導線が動作する
operator_store_linkが role assignment の正本として機能するoperator_staff_linkが self-scope の基盤として機能するstore_settingsの canonical fields が全て存在するequipment_group/menu_equipment_requirement/menu_staff_eligibilityが契約どおり動作するvalidate_shift_breaks_jsonb(...)による shift CHECK が有効である- 顧客登録・検索・メモ・タグ・顧客番号採番が動作する
- 予約カレンダー・作成・編集・状態遷移・競合判定が一連で動作する
- 設備自動割当が group 要件どおりに動作する
- 仮予約失効ジョブと no-show 猶予判定が動作する
visit/visit_payment/visit_refund/cash_movement/register_closingが一連で動作するassertNotClosedDate(storeId, date)が全 visit / cash mutation で強制されているvisitの物理削除禁止と 7 年保存方針がコードと文書で整合している- 毎晩
pg_dump + age + R2が構成済みである - Phase 1 完了時の restore drill を 1 回実施済みである
- pino / Sentry /
healthz/readyzが本番相当環境で確認済みである bun testが shared Postgres harness で green である- 重大 OQ は明示 defer 分(kiosk, Testcontainers, DB trigger hardening)以外に残っていない
12. Open Questions 棚卸し
Section titled “12. Open Questions 棚卸し”| ID | 内容 | 状態 | メモ |
|---|---|---|---|
| OQ-01 | 顧客データの店舗間共有を許すか | Deferred | Phase 2+ (Phase 1 は店舗内 customer_no 個別管理で確定) |
| OQ-02 | スタッフ指名料の扱い | Deferred | SRS-MST-002 で別途検討、 Phase 1 は基本料金のみ |
| OQ-03 | Smart Pay の決済事業者選定 | Deferred | Phase 2 SRS-PAY-001 (Phase 1 は cash/card/electronic 3 値固定) |
| OQ-04 | HPB 予約取り込み方式 | Deferred | Phase 2 SRS-RES-007 (Phase 1 は admin_manual のみ) |
| OQ-05 | MCP write 系の解禁範囲 | Deferred | Phase 2 SRS-MCP-002 (Phase 1 は read-only 設計のみ) |
| OQ-06 | 本番デプロイ戦略 | Deferred | Phase 2 完了時に再評価 (Phase 1 は dev/CI 環境のみ) |
| OQ-07 | Integration test に Testcontainers を採用するか | Deferred | Phase 3 OQ |
| OQ-08 | 顧客必須項目 DSL / UI 編集をいつ入れるか | Deferred | Phase 2 (Phase 1 は customer_required_fields jsonb 既定値固定) |
| OQ-09 | Phase 1 permission 初期リスト確定 | Closed | 47 keys で確定 |
| OQ-10 | 緊急復旧の要素組合せ | Closed | 未使用 recovery code 1 個 + email confirmation 必須 |
| OQ-11 | scheduler fan-out の system-scope 例外 | Closed | §7.1.7 に明記 |
| OQ-12 | operator_staff_link を Phase 1 に入れるか | Closed | Phase 1 に採用 |
| OQ-13 | 退職同期で future shift を物理削除してよいか | Closed | starts_at > now() のみ許可 |
| OQ-14 | tax_rate の持ち方と導入タイミング | Closed | store-scoped master、Phase 1 空運用、Phase 3 実効期間検索 |
| OQ-15 | 共有端末モード / kiosk PIN 切替 | Deferred | Phase 2 へ持越し |
| OQ-16 | worker 用 DB runtime role の分離 | Closed | worker_runtime を bootstrap で作成 |
| OQ-17 | assertNotClosedDate の DB trigger 化 | Deferred | Phase 2 OQ (Phase 1 はアプリ層強制) |
| OQ-18 | restore drill 自動化の要否 | Deferred | manual drill 後に再判断 (Phase 2+) |
Phase 1 完了時点で残る Open は無し (DoD-32)。 すべて Closed か Deferred (Phase 2/3) に明示済。
13. 変更履歴
Section titled “13. 変更履歴”| Version | Date | Author | Change |
|---|---|---|---|
| 0.1 | 2026-04-21 | yudai | 初版作成 |
| 0.2 | 2026-04-22 | yudai | 権限モデルを permission-based + プリセット role に拡充。store_settings、UI粒度方針、OQ-09 追加 |
| 0.3 | 2026-04-25 | yudai | salon_slug のグローバル UNIQUE 化、permission backfill 規約、監査例外、menu_staff_eligibility / menu_equipment_requirement 分離、複合参照標準化 |
| 0.4 | 2026-05-04 | yudai | operator_action_log の先行導入を MST-001 ownership として同期、permission backfill 実装例を追加 |
| 0.5 | 2026-05-05 | yudai (with Codex co-design) | Phase 1 SRS finalization 反映。pg_dump + age + R2 のバックアップ方針と restore drill を追加。可観測性年表を更新。store_id 例外一覧、scheduler fan-out 例外、future shift delete 例外を明文化。override/force_* 命名規則を整理し force_staff_concurrency へ改名。equipment_group / menu_equipment_requirement(quantity, equipment_group_id) を親規範化。store_settings canonical fields、tax_rate 管理、visit 7 年保存、assertNotClosedDate 共通化、worker_runtime 分離、Phase 1 DoD 28 項目、OQ 棚卸しを反映。Permission 47-key canonical を確定(OQ-09 closed) |
Appendix A. 子SRS作成チェックリスト
Section titled “Appendix A. 子SRS作成チェックリスト”- Document ID を採番した
- Parent version を明記した
- 依存 SRS を列挙した
-
store_id例外を勝手に増やしていない - tenant table に RLS
ENABLE + FORCEを入れた -
app/worker_runtimeへの必要 GRANT を明示した - request / job で
SET LOCAL app.current_store_idが走る - bigserial を API トップレベルへ露出していない
- 金額が整数 + 税抜/税込分離になっている
- 時刻が
timestamptzである - 物理削除例外が §7.5 に収まっている
- permission 追加時に backfill migration を伴っている
- 予約系の例外権限が
force_*命名になっている - 監査対象かどうか判定した
- Given-When-Then を 3 件以上書いた
- 関連ジョブの有無を書いた
- Open Questions が親SRSと整合している
Appendix B. 子SRSステータス
Section titled “Appendix B. 子SRSステータス”DraftReviewApprovedIn ProgressImplementedDeprecated
Appendix C. Phase 1 Migration 番号 canonical
Section titled “Appendix C. Phase 1 Migration 番号 canonical”| 番号 | ファイル名 | 所有 SRS | 内容 |
|---|---|---|---|
| 0001 | 0001_initial.sql | SRS-TEN-001 | store / store_settings / permission / role / role_permission 初期作成 |
| 0002 | 0002_enable_rls.sql | SRS-TEN-001 | BC-TEN 初期テーブルの RLS / policy / GRANT |
| 0003 | 0003_staff.sql | SRS-MST-001 | staff 作成、RLS、DELETE 非付与 |
| 0004 | 0004_operator_action_log.sql | SRS-MST-001 | operator_action_log 先行導入 |
| 0005 | 0005_permissions_backfill_staff.sql | SRS-MST-001 | admin:staff:* 追加と preset role backfill |
| 0006 | 0006_reservation.sql | SRS-RES-002, SRS-RES-004, SRS-RES-005 | placeholder customer / menu / equipment、reservations aggregate、reservation_menu_lines、reservation_equipment_assignments |
| 0007 | 0007_permissions_backfill_reservation.sql | SRS-RES-002, SRS-RES-005 | admin:reservation:read / write backfill |
| 0008 | 0008_reservation_event.sql | SRS-RES-004 | reservation_event 追加 |
| 0009 | 0009_reservation_equipment_exclude.sql | SRS-RES-005 | concrete equipment_id に対する EXCLUDE 制約追加 |
| 0010 | 0010_permissions_backfill_reservation_transitions.sql | SRS-RES-004 | 予約状態遷移 permission の backfill |
| 0011 | 0011_store_settings_phase1_expansion.sql | SRS-TEN-001 | store.invoice_registration_number、store_settings.tentative_expire_hours / no_show_grace_minutes / customer_no_seq / rounding_policy 追加。reservation_menu_lines.tax_rate_pct CHECK IN (8,10) を撤去。tax_rate master 作成(空運用) |
| 0012 | 0012_operator_auth_and_sessions.sql | SRS-TEN-002 | operator, passkey_credential, totp_secret, recovery_code, operator_session, operator_invitation 作成。operator_action_log.actor_kind 導入と operator_id 条件付き制約整備 |
| 0013 | 0013_operator_membership_and_staff_link.sql | SRS-TEN-003, SRS-CUS-004 | operator_store_link、operator_staff_link 作成。admin:operator:* / admin:operator_store_link:write / admin:operator_staff_link:read/write backfill |
| 0014 | 0014_menu_master_and_eligibility.sql | SRS-MST-002 | menu_category, menu placeholder を本番形へ昇格、menu_staff_eligibility、menu_equipment_requirement(menu_id, equipment_group_id, quantity)、staff_assignment_policy 追加 |
| 0015 | 0015_business_hours_and_day_overrides.sql | SRS-MST-003 | business_hours(weekday 1..7 + is_holiday)、day_override 作成 |
| 0016 | 0016_shift_management.sql | SRS-MST-004 | shift 作成、validate_shift_breaks_jsonb(jsonb,timestamptz,timestamptz) 定義、breaks CHECK 導入 |
| 0017 | 0017_equipment_master_and_groups.sql | SRS-MST-005 | equipment_group 作成、equipment.group_id 追加、設備 placeholder 昇格 |
| 0018 | 0018_customer_crm.sql | SRS-CUS-001, SRS-CUS-002 | customer placeholder を本番形へ昇格、customer_no、メモ、タグ、タグリンク、検索列追加。pg_trgm GIN |
| 0019 | 0019_reservation_phase1_finalize.sql | SRS-RES-001/002/003/004/005 | reservation_menu_lines.menu_name_snapshot、reservation.code、channel_code、編集/移動用整備、force_staff_concurrency permission rename、calendar query/index 最終化、reservation_event_actor_polymorphism CHECK 修正 |
| 0020 | 0020_visit_register_closing.sql | SRS-REG-001/002, SRS-WRK-001 | visit, visit_payment, visit_refund, cash_movement, register_closing, daily_sales_summary、assertNotClosedDate 連携、register 系 permission backfill |
| 0022 | 0022_visit_amend_supersede.sql | SRS-REG-001 §7.8 | visit_lines.superseded_at / visit_payments.superseded_at 列を追加し、active 明細を WHERE superseded_at IS NULL で取り出せるよう partial index を作成。amend は supersede + INSERT で表現(DELETE 不可は維持) |
| 0023 | 0023_reservation_menu_lines_supersede.sql | SRS-RES-003 §7.3 | reservation_menu_lines.superseded_at 列を追加し、 既存 (store_id, reservation_id, sort_order) UNIQUE を partial unique index (WHERE superseded_at IS NULL) に置換。 PATCH /reservations/:id の menu_lines 全置換は supersede + INSERT で履歴維持 |
worker_runtime ロール自体は packages/db/migrations ではなく infra/sql/bootstrap/002_worker_runtime_role.sql で作成する。
Appendix D. Phase 1 Permission 47-key Canonical
Section titled “Appendix D. Phase 1 Permission 47-key Canonical”| key | 所有 SRS | description | owner | manager | staff | receptionist | feature_flag | sensitive |
|---|---|---|---|---|---|---|---|---|
admin:store:read | TEN-001 | 店舗情報の閲覧 | Y | Y | Y | Y | - | N |
admin:store:update | TEN-001 | 店舗基本情報の更新 | Y | Y | N | N | - | Y |
admin:store_settings:read | TEN-001 | 店舗設定の閲覧 | Y | Y | Y | Y | - | N |
admin:store_settings:update | TEN-001 | 店舗設定の更新 | Y | Y | N | N | - | Y |
admin:role:read | TEN-001 | ロール一覧の閲覧 | Y | Y | Y | Y | - | N |
admin:operator:read | TEN-002 | オペレーター一覧・詳細の閲覧 | Y | Y | N | N | - | Y |
admin:operator:create | TEN-002 | オペレーター招待・作成 | Y | Y | N | N | - | Y |
admin:operator:update | TEN-002 | オペレーター更新 | Y | Y | N | N | - | Y |
admin:operator:retire | TEN-002 | オペレーター無効化・復帰 | Y | Y | N | N | - | Y |
admin:operator_store_link:write | TEN-003 | オペレーターの店舗・ロール割当変更 | Y | Y | N | N | - | Y |
admin:staff:read | MST-001 | スタッフ一覧・詳細の閲覧 | Y | Y | Y | Y | - | N |
admin:staff:create | MST-001 | スタッフ新規作成 | Y | Y | N | N | - | N |
admin:staff:update | MST-001 | スタッフ編集・並び替え | Y | Y | N | N | - | N |
admin:staff:retire | MST-001 | スタッフ退職化・復職 | Y | Y | N | N | - | Y |
admin:menu:read | MST-002 | メニュー一覧・詳細の閲覧 | Y | Y | Y | Y | - | N |
admin:menu:create | MST-002 | メニュー新規作成 | Y | Y | N | N | - | N |
admin:menu:update | MST-002 | メニュー編集 | Y | Y | N | N | - | N |
admin:menu:retire | MST-002 | メニュー停止・復帰 | Y | Y | N | N | - | Y |
admin:business_hours:read | MST-003 | 営業時間・定休日の閲覧 | Y | Y | Y | Y | - | N |
admin:business_hours:update | MST-003 | 営業時間・定休日の更新 | Y | Y | N | N | - | N |
admin:shift:write | MST-004 | シフトの作成・更新・future delete | Y | Y | N | N | - | N |
admin:equipment:read | MST-005 | 設備・設備グループの閲覧 | Y | Y | Y | Y | - | N |
admin:equipment:create | MST-005 | 設備・設備グループ新規作成 | Y | Y | N | N | - | N |
admin:equipment:update | MST-005 | 設備・設備グループ更新 | Y | Y | N | N | - | N |
admin:equipment:retire | MST-005 | 設備・設備グループ停止・復帰 | Y | Y | N | N | - | Y |
admin:customer:read | CUS-001 | 顧客一覧・詳細の閲覧 | Y | Y | Y | Y | - | Y |
admin:customer:create | CUS-001 | 顧客新規作成 | Y | Y | Y | Y | - | Y |
admin:customer:update | CUS-002 | 顧客基本情報・メモ・タグ更新 | Y | Y | Y | Y | - | Y |
admin:operator_staff_link:read | CUS-004 | operator/staff 紐付けの閲覧 | Y | Y | Y | N | - | Y |
admin:operator_staff_link:write | CUS-004 | operator/staff 紐付けの更新 | Y | Y | N | N | - | Y |
admin:reservation:read | RES-001 | 予約一覧・詳細・カレンダー閲覧 | Y | Y | Y | Y | - | N |
admin:reservation:create | RES-002 | 予約作成 | Y | Y | Y | Y | - | N |
admin:reservation:update | RES-003 | 予約編集・移動・所要時間調整 | Y | Y | Y | Y | - | N |
admin:reservation:read_timeline | RES-004 | 予約イベントタイムライン閲覧 | Y | Y | N | Y | - | Y |
admin:reservation:force_business_hours | RES-002 | 営業時間外予約を強制保存 | Y | Y | N | N | - | Y |
admin:reservation:force_staff_concurrency | RES-005 | スタッフ並列上限警告を強制通過 | Y | Y | N | N | - | Y |
admin:reservation:approve_tentative | RES-004 | tentative→confirmed | Y | Y | N | Y | - | N |
admin:reservation:decline | RES-004 | tentative→declined | Y | Y | N | N | - | Y |
admin:reservation:cancel_by_store | RES-004 | confirmed/in_service→cancelled_by_store | Y | Y | N | N | - | Y |
admin:reservation:check_in | RES-004 | confirmed→in_service | Y | Y | Y | Y | - | N |
admin:reservation:complete_service | RES-004 | in_service→service_completed | Y | Y | Y | Y | - | N |
admin:reservation:finalize_payment | RES-004 | service_completed→paid | Y | Y | N | Y | - | Y |
admin:reservation:mark_no_show | RES-004 | confirmed→no_show | Y | Y | N | N | - | Y |
admin:reservation:cancel_by_customer_proxy | RES-004 | 顧客取消の代理入力 | Y | Y | N | Y | - | Y |
admin:reservation:reopen | RES-004 | 中間状態の 1 段戻し | Y | Y | N | N | - | Y |
admin:register:operate | REG-001 | 来店会計・返金・入出金操作 | Y | Y | N | Y | - | Y |
admin:register:close | REG-002 | 日次締め・締め解除相当操作 | Y | Y | N | N | - | Y |