コンテンツにスキップ

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


本書は親SRSである。実装前に各機能単位で作成する子SRS(docs/SRS/features/*.md)の上位規範として機能する。

子SRSは以下を定義する。

  • 個別機能のユースケース
  • 画面仕様・API仕様(zodスキーマレベル)
  • 状態遷移・業務ルール
  • 受け入れ基準(テストケース)

親SRSは子SRS全体で共通するルール・制約・契約を定義し、各子SRSでの再記述を不要にする。各子SRSの冒頭で「本書はSRS-ROOT-001に従う」と明記する。


  • 実装者(自分・将来の協力者)
  • レビュー時の自己チェック
  • LLM に実装を依頼する際のコンテキスト
  • バージョンは Major.Minor
    • Major: アーキテクチャ変更
    • Minor: 要件追加・契約変更
  • 変更は必ず理由を変更履歴に残す
  • 子SRS作成時、親SRS更新が必要なら先に親を改訂してから子を書く
IDタイトル場所
DOC-ANALYSIS-001SALON BOARDクローン開発 基礎情報/outputs/SALON_BOARD_クローン開発_基礎情報.md
DOC-ERD-001ERD(Mermaid)/outputs/SALON_BOARD_ERD.md
DOC-DIR-001ディレクトリ構成/outputs/SALON_BOARD_DIRECTORY_STRUCTURE.md
DOC-SETUP-001セットアップガイド/outputs/SALON_BOARD_SETUP_GUIDE.md

用語定義
店舗(Store)本システムのマルチテナント単位
オペレーター(Operator)管理画面を操作する認証ユーザー
スタッフ(Staff)施術担当者の業務マスタ。Operator と 1:1 とは限らない
顧客(Customer)来店者・予約者
予約(Reservation)来店予定。Phase 1 では 10 状態の状態機械を持つ
来店(Visit)予約に紐づく実来店・会計の業務実体
返金(Visit Refund)visit に対する返金明細。visit_refund に記録する
設備グループ(Equipment Group)予約時に「同種設備から空きを自動割当」するための抽象グループ
レジ締め(Closed Date)日次締め済みとして後続改変を禁止する営業日
LIFFLINE Front-end Framework
MCPModel Context Protocol
RLSRow-Level Security

予約・顧客管理・会計・掲載を統合した美容サロン向け SaaS を構築する。SALON BOARD を参考にしつつ、価格・UX・AI ネイティブ・HPB 非依存で差別化する。

  • SALON BOARD: HPB 一体型
  • 本プロダクト: 自社顧客チャネル(LIFF)を内蔵した HPB 非依存運用
  • AI 差別化: MCP サーバー経由で Claude / ChatGPT から運営操作可能

In-scope(Phase 1〜4)

  • 予約管理(作成・編集・キャンセル・状態管理・カレンダー)
  • 顧客管理(基本情報・来店履歴・タグ・メモ)
  • レジ・会計(現金・カード・電子マネー・返金・締め)
  • メッセージング(メール・LINE・SMS)
  • スタッフ・設備・設備グループ・メニュー・営業時間管理
  • 売上集計・日報・月次レポート
  • HPB 掲載管理
  • LIFF 顧客アプリ
  • MCP サーバー(OAuth2.1)

Out-of-scope(Phase 1)

  • Smart Pay 実装本体
    • Phase 2 の SRS-PAY-001 で扱う
  • 物販EC
  • 勤怠・給与計算
  • ネイル・エステ業態特化機能
  • HPB 内部 API 連携
  • ネイティブアプリ

4. ステークホルダー / ペルソナ

Section titled “4. ステークホルダー / ペルソナ”
ペルソナ特徴主な関心
サロンオーナー複数店舗経営売上・会員・店舗横断数値
店長1 店舗運営予約・顧客・スタッフ・締め
スタイリスト自分の担当軸が中心自分のスケジュール、担当顧客
受付予約入力・会計中心カレンダー、レジ、来店導線

注記: スタイリスト向けの「自分関連のみ」権限は operator_staff_link を前提にする。リンクが存在しないオペレーターには self-scope を適用しない。

権限モデル: permission-based + プリセット role(RBAC ファサード)

  • owner
  • manager
  • staff
  • receptionist

詳細は §7.7。

  • 20〜50代女性が中心
  • LINE 利用率が高い
  • 予約チャネルは HPB / 電話 / LINE / 店頭 / 管理画面代理入力

IDコンテキスト主要エンティティ
BC-TENテナンシー・認証Store, Operator, Session, Passkey, TOTP, RecoveryCode
BC-MSTマスター・リソースStaff, Equipment, EquipmentGroup, Menu, BusinessHours, Shift
BC-CUS顧客・CRMCustomer, 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

  • 通常 API p95: 300ms 以下
  • 重い集計: 1s 以下
  • カレンダー初期表示: 100 予約規模で 1s 以下
  • 1 店舗あたり 10 オペレーター同時操作を想定
  • 通常ジョブは 5 秒以内に処理開始、最大 30 秒
  • 稼働率目標
    • Phase 1〜3: 99.5%
    • Phase 4 以降: 99.9%
  • メンテナンスウィンドウ: 月 1 回、03:00〜05:00
  • 無停止デプロイ最適化は Phase 3 以降
  • 通信: HTTPS 必須
  • 認証
    • Operator: Passkey 必須
    • TOTP: 補助要素
    • Customer: LINE Login
  • 認可: RLS + アプリ層 permission の二重ガード
  • セッション: JWT 不使用、サーバーサイドセッション
  • 監査: 書込系操作は operator_action_log に記録
  • 脆弱性対応: bun pm audit 相当を CI に組み込む
  • 緊急復旧
    • 未使用 recovery_code 1 個の提示を必須
    • 事前登録メールへの確認成功を必須
    • TOTP のみでの復旧は不可
    • 復旧成功時は当該 recovery code を即失効し、監査ログへ記録する
  • 毎晩 1 回 pg_dump を取得する
  • ダンプは age で暗号化する
  • 暗号化済みアーカイブは Cloudflare R2 に保管する
  • Phase 1 完了時に 1 回、手順書ベースの restore drill を実施する
  • 目標
    • RPO: 24h
    • RTO: 手動復旧 4h 以内を目安
  • restore drill は「空 DB への復元」「アプリ起動」「主要 read API 応答」まで確認する
Phase監視・観測の基準
Phase 1pino 構造化ログ、Sentry、/healthz/readyz
Phase 2OpenTelemetry 導入
Phase 3Prometheus メトリクス収集、ダッシュボード整備
  • アラート通知は Slack / Discord Webhook
  • pager 運用は Phase 1 スコープ外

6.6 プライバシー・コンプライアンス

Section titled “6.6 プライバシー・コンプライアンス”
  • 顧客データの管理者は店舗、本サービスは委託先
  • GDPR は現時点では非対象
  • クーポン・割引表示は店舗責任
  • 顧客削除要求は法令・会計要件と整合する範囲で論理削除を優先
  • 言語: 日本語のみ
  • タイムゾーン: Asia/Tokyo 固定
  • 通貨: JPY 整数固定

7. 共通制約(すべての子SRSに適用)

Section titled “7. 共通制約(すべての子SRSに適用)”

原則として、業務テーブルは store_id を持つ。

store_id を持たない例外テーブル

  • permission
  • operator
  • passkey_credential
  • totp_secret
  • recovery_code
  • operator_session
  • holiday(Phase 3 予定、全国共通カレンダー扱い)

明示注記

  • tax_rate は例外ではない。Phase 1/3 を通して store-scoped とする
  • 例外を増やす場合は親SRS改訂が必要
  • 参照は原則 (store_id, target_id) -> target(store_id, id) の複合 FK
  • 主キーが id 単独でも、参照先に UNIQUE(store_id, id) を必ず張る
  • tenant-scoped table は最初の migration から ENABLE ROW LEVEL SECURITY + FORCE ROW LEVEL SECURITY
  • RLS 後付けは禁止
  • postgres: bootstrap / migration 専用
  • app: API / worker 実行用
  • worker_runtime: graphile-worker 実行用(Phase 1 で bootstrap 作成)
  • リクエストごとに SET LOCAL app.current_store_id
  • ワーカーも tenant job 実行前に SET LOCAL
  • repository API は storeId 必須
  • tenant job の payload は storeId 必須

system-scope の scheduler 自体は storeId を持たなくてよい。ただし許されるのは以下のみ。

  1. 全 store の対象 ID を列挙する
  2. 各 store ごとに tenant-scoped job を enqueue する

system-scope の fan-out ループで業務 mutation を直接実行してはならない。

  • アプリ層からの cross-tenant 集計は禁止
  • 例外が必要なら専用管理クエリとして明示起票する
  • CI / レビューでブロック対象
  • 主キーは UUIDv7
  • API / URL / 外部露出の可能性がある業務実体は UUIDv7

以下を満たす内部用途のみ許容する。

  1. API トップレベルに露出しない
  2. 件数漏えいの業務影響が小さい
  3. 大量生成される

対象例

  • operator_action_log
  • reservation_event
  • message_delivery_log
  • customer_no: 店舗内採番
  • coupon_code: 人間共有用コード
  • salon_slug: 公開 URL 用、グローバル UNIQUE
  • UUIDv7 側に倒す
  • 金額は bigint(円)
  • amount_excl_tax / tax_amount / amount_incl_tax を分離保持
  • Phase 1 の visit_payments.methodcash / card / electronic の 3 値固定
  • Smart Pay は Phase 2 (SRS-PAY-001) まで契約から除外
  • 税率スナップショットは tax_rate_pct に保持
  • 端数処理ポリシーは store_settings.rounding_policy を参照する
  • DB: timestamptz
  • 保存: UTC
  • 表示: Asia/Tokyo
  • 予約の業務時刻は店舗タイムゾーン基準で扱う
  • 曜日番号は ISO DOW (1=Mon..7=Sun)、祝日可否は is_holiday boolean で別軸表現する
  • 原則、業務実体は物理削除しない
  • 論理削除は deleted_at を採る
  • 例外
    • セッション / トークン類
    • graphile-worker 管轄ジョブ
    • 一時ファイル
    • 未来の shiftstarts_at > now() に限る)
      • スタッフ退職・復職の同期調整でのみ許可
      • 過去 shift の物理削除は禁止
  • 論理削除行は RLS で隠さない。アプリ層で明示フィルタする
  • packages/contracts に zod スキーマを置く
  • apps/api がルートを結線する
  • 成功レスポンス: { data: ... }
  • エラーレスポンス: { error: { code, message, details? } }
  • ページングは cursor ベース
  • 小規模マスタ(staff, menu_category, equipment, equipment_group 等)は子SRSで明示した場合のみ全件返却可
  • /api/admin/*, /api/portal/*, /mcp, /webhooks/* を使い分ける
  • 全エンドポイントはデフォルト要認証
  • 認可は permission ミドルウェア + RLS の二重ガード
  • 実効権限 = role permission + operator override
  • permission: 全テナント共通マスタ
  • role: 店舗スコープ
  • role_permission: 中間
  • operator_permission_override: 個別 override
  • packages/auth
    • permission key 定義
    • pure resolver
    • resolveReservationTransitionPermission などの純関数
  • apps/api/src/middleware
    • Hono middleware
    • requirePermission(...)
    • requireReservationTransitionPermission(...)

packages/auth に Hono 依存を持ち込まない。

  • overrideoperator_permission_override を指す語としてのみ使う
  • 予約系の「警告を押し通す」権限は force_* で表現する
  • force_double_booking は廃止し、force_staff_concurrency を使う
  • force_staff_concurrencyスタッフ同時並行数のみ に効く
  • 設備重複の EXCLUDE 制約は force_staff_concurrency でも無効化しない
  • 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 のみを返す
  • split / merge / rename は新 key 追加 + backfill migration で行う
  • 既存 key の in-place rename はしない
  • 行可視性は RLS
  • 操作可否は permission
  • ABAC が必要になれば親SRS改訂

7.7.8 新 permission 追加時の backfill

Section titled “7.7.8 新 permission 追加時の backfill”

新 permission を追加する子SRSは、その migration の責務として以下を実施する。

  1. permission へ UPSERT
  2. 既存全店舗の preset role へ role_permission backfill
  3. テストで preset role matrix を検証
  • operator_action_log を共通監査ログとする
  • Phase 1 canonical columns
    • id bigserial
    • store_id uuid
    • actor_kind enum('operator','system')
    • operator_id uuid NULL
    • action varchar(80)
    • target_type varchar(40)
    • target_id text
    • diff jsonb
    • request_id varchar(64) NULL
    • created_at timestamptz
  • actor_kind='operator' のとき operator_id は NOT NULL
  • actor_kind='system' のとき operator_id は NULL
  • customer 起点の予約取消など、operator を持たないイベントは reservation_event 側に記録する

以下は operator_action_log 記録対象外とする。

  • seed 実行
  • bootstrap 実行
  • DB migration 実行
  • ドメインエラーは 4xx に変換
  • 予期しないエラーは 5xx + Sentry
  • ユーザーメッセージは日本語・短く・次アクションが分かる形
  • テストランナー: bun test
  • Unit: 純関数中心
  • Integration: shared Postgres(Docker Compose 上)+ helper cleanup
  • E2E: Phase 2 から Playwright
  • Testcontainers 導入は Phase 3 OQ とする
  • 境界バリデーションは zod
  • 生 SQL は prepared / parameterized
  • dangerouslySetInnerHTML はレビュー必須
  • レート制限
    • ログイン系: 10 回/分
    • 一般 API: 100 回/分
    • 予約 conflict-check 系: 600 回/分(専用 bucket)
  • デスクトップ優先
  • iPad 動作必須
  • スマホは PWA / LIFF 経由
  • 子SRS §4 は最低限粒度に留める
  • デザインシステム導入は別 SRS

Phase 1 の canonical fields は以下とする。

field型 / 既定用途
reservation_slot_minutessmallint, default 30予約枠刻み
max_concurrent_reservations_per_staffsmallint, default 1スタッフ並列上限
tentative_expire_hourssmallint, default 24, CHECK 1..168仮予約失効時間
no_show_grace_minutessmallint, default 30, CHECK 0..180no-show 判定猶予
customer_required_fieldsjsonb, default ["name"]顧客作成必須項目
customer_no_seqbigint, default 0, CHECK >= 0店舗内顧客番号採番カウンタ
rounding_policyjsonb, default {"method":"round","target":"line"}端数処理
cancel_policyjsonb, default {}キャンセルポリシー
updated_attimestamptz更新時刻

設備要件とスタッフ適格性は分離する。

  • 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 uuid
  • store_id uuid
  • name varchar(100)
  • display_order integer
  • terminated_at timestamptz NULL
  • version 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) にしない
  • 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 は migration 0011 以降で撤去する
  • visit は 7 年保存を原則とする
  • visit, visit_line, visit_payment, visit_refund の物理削除は禁止
  • 訂正は更新履歴・返金明細・supersede 列で表現し、削除で表現しない
  • visit_line / visit_payment の amend は superseded_at で旧行を無効化し、新行を INSERT する(SRS-REG-001 §7.8)
  • 共通関数 assertNotClosedDate(storeId, date) を repository 共通で使う
  • visit / cash_movement mutation は必ずこの関数を通る
  • Phase 1 はアプリ層強制
  • DB trigger 化は Phase 2 OQ とする

採用
ランタイムBun 1.3+
言語TypeScript(strict)
APIHono
契約zod + @hono/zod-openapi
型共有OpenAPI → openapi-typescript
ORMDrizzle ORM
DBPostgreSQL 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 / FormatBiome
実行環境Docker Compose 必須

9. フェーズ計画と子SRSカタログ

Section titled “9. フェーズ計画と子SRSカタログ”
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-001Worker ランタイム基盤cross
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-001Smart Pay 決済連携BC-PAY
SRS-PAY-002キャンセル料自動課金BC-PAY
SRS-RES-007複数チャネル予約統合BC-RES
Child SRS IDタイトルBC
SRS-CUS-003顧客セグメント・一斉配信BC-CUS
SRS-ANL-001売上日報・月次レポートBC-REG
SRS-ANL-002顧客分析BC-CUS
SRS-MCP-001MCP サーバーcross
SRS-MCP-002MCP ツールセットcross
SRS-PWA-001PWA 化cross
Child SRS IDタイトルBC
SRS-LIFF-001LIFF 基盤BC-CUS
SRS-LIFF-002LIFF 予約フローBC-RES
SRS-LIFF-003LIFF 会員証・履歴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

各子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. 変更履歴

  1. 子SRS起票
  2. レビュー
  3. Approved
  4. 実装
  5. テスト
  6. マージ
  7. 子SRSを Implemented へ更新
  • 親SRS違反の疑いがあれば先に親を直す
  • migration は code-first だが、RLS / GRANT / policy は必ず SQL で補完する
  • permission 追加は必ず backfill migration とセット
  • 子SRS全文をコンテキストに入れる
  • 実装と同時にテスト生成を要求する
  • 人間は親SRS違反の有無を最優先でレビューする
  • 実装で契約が変わったら SRS も同時更新
  • migration 番号、permission 表、OQ 状態は親SRSと整合させる

11.5 Phase 1 Definition of Done(28項目)

Section titled “11.5 Phase 1 Definition of Done(28項目)”
  1. Phase 1 対象の子SRSが全て Approved 以上である
  2. 00010020 の migration がクリーン DB に順適用できる
  3. infra/sql/bootstrap/001_roles_and_extensions.sql002_worker_runtime_role.sql が再実行可能である
  4. db:seed が冪等である
  5. tenant-scoped table すべてに RLS ENABLE + FORCE が入っている
  6. store_id 例外は §7.1.1 の一覧に限定されている
  7. API / worker ともに SET LOCAL app.current_store_id が徹底されている
  8. system-scope scheduler は fan-out のみを行い、直接業務 mutation しない
  9. canonical 47 permission が seed / backfill 済みである
  10. operator_permission_override の契約が親SRSと一致している(Phase 1 では DB 不在で OK)
  11. Passkey / TOTP / recovery code / email confirmation を含む Operator 認証導線が動作する
  12. operator_store_link が role assignment の正本として機能する
  13. operator_staff_link が self-scope の基盤として機能する
  14. store_settings の canonical fields が全て存在する
  15. equipment_group / menu_equipment_requirement / menu_staff_eligibility が契約どおり動作する
  16. validate_shift_breaks_jsonb(...) による shift CHECK が有効である
  17. 顧客登録・検索・メモ・タグ・顧客番号採番が動作する
  18. 予約カレンダー・作成・編集・状態遷移・競合判定が一連で動作する
  19. 設備自動割当が group 要件どおりに動作する
  20. 仮予約失効ジョブと no-show 猶予判定が動作する
  21. visit / visit_payment / visit_refund / cash_movement / register_closing が一連で動作する
  22. assertNotClosedDate(storeId, date) が全 visit / cash mutation で強制されている
  23. visit の物理削除禁止と 7 年保存方針がコードと文書で整合している
  24. 毎晩 pg_dump + age + R2 が構成済みである
  25. Phase 1 完了時の restore drill を 1 回実施済みである
  26. pino / Sentry / healthz / readyz が本番相当環境で確認済みである
  27. bun test が shared Postgres harness で green である
  28. 重大 OQ は明示 defer 分(kiosk, Testcontainers, DB trigger hardening)以外に残っていない

ID内容状態メモ
OQ-01顧客データの店舗間共有を許すかDeferredPhase 2+ (Phase 1 は店舗内 customer_no 個別管理で確定)
OQ-02スタッフ指名料の扱いDeferredSRS-MST-002 で別途検討、 Phase 1 は基本料金のみ
OQ-03Smart Pay の決済事業者選定DeferredPhase 2 SRS-PAY-001 (Phase 1 は cash/card/electronic 3 値固定)
OQ-04HPB 予約取り込み方式DeferredPhase 2 SRS-RES-007 (Phase 1 は admin_manual のみ)
OQ-05MCP write 系の解禁範囲DeferredPhase 2 SRS-MCP-002 (Phase 1 は read-only 設計のみ)
OQ-06本番デプロイ戦略DeferredPhase 2 完了時に再評価 (Phase 1 は dev/CI 環境のみ)
OQ-07Integration test に Testcontainers を採用するかDeferredPhase 3 OQ
OQ-08顧客必須項目 DSL / UI 編集をいつ入れるかDeferredPhase 2 (Phase 1 は customer_required_fields jsonb 既定値固定)
OQ-09Phase 1 permission 初期リスト確定Closed47 keys で確定
OQ-10緊急復旧の要素組合せClosed未使用 recovery code 1 個 + email confirmation 必須
OQ-11scheduler fan-out の system-scope 例外Closed§7.1.7 に明記
OQ-12operator_staff_link を Phase 1 に入れるかClosedPhase 1 に採用
OQ-13退職同期で future shift を物理削除してよいかClosedstarts_at > now() のみ許可
OQ-14tax_rate の持ち方と導入タイミングClosedstore-scoped master、Phase 1 空運用、Phase 3 実効期間検索
OQ-15共有端末モード / kiosk PIN 切替DeferredPhase 2 へ持越し
OQ-16worker 用 DB runtime role の分離Closedworker_runtime を bootstrap で作成
OQ-17assertNotClosedDate の DB trigger 化DeferredPhase 2 OQ (Phase 1 はアプリ層強制)
OQ-18restore drill 自動化の要否Deferredmanual drill 後に再判断 (Phase 2+)

Phase 1 完了時点で残る Open は無し (DoD-32)。 すべて Closed か Deferred (Phase 2/3) に明示済。


VersionDateAuthorChange
0.12026-04-21yudai初版作成
0.22026-04-22yudai権限モデルを permission-based + プリセット role に拡充。store_settings、UI粒度方針、OQ-09 追加
0.32026-04-25yudaisalon_slug のグローバル UNIQUE 化、permission backfill 規約、監査例外、menu_staff_eligibility / menu_equipment_requirement 分離、複合参照標準化
0.42026-05-04yudaioperator_action_log の先行導入を MST-001 ownership として同期、permission backfill 実装例を追加
0.52026-05-05yudai (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と整合している

  • Draft
  • Review
  • Approved
  • In Progress
  • Implemented
  • Deprecated

Appendix C. Phase 1 Migration 番号 canonical

Section titled “Appendix C. Phase 1 Migration 番号 canonical”
番号ファイル名所有 SRS内容
00010001_initial.sqlSRS-TEN-001store / store_settings / permission / role / role_permission 初期作成
00020002_enable_rls.sqlSRS-TEN-001BC-TEN 初期テーブルの RLS / policy / GRANT
00030003_staff.sqlSRS-MST-001staff 作成、RLS、DELETE 非付与
00040004_operator_action_log.sqlSRS-MST-001operator_action_log 先行導入
00050005_permissions_backfill_staff.sqlSRS-MST-001admin:staff:* 追加と preset role backfill
00060006_reservation.sqlSRS-RES-002, SRS-RES-004, SRS-RES-005placeholder customer / menu / equipmentreservations aggregate、reservation_menu_linesreservation_equipment_assignments
00070007_permissions_backfill_reservation.sqlSRS-RES-002, SRS-RES-005admin:reservation:read / write backfill
00080008_reservation_event.sqlSRS-RES-004reservation_event 追加
00090009_reservation_equipment_exclude.sqlSRS-RES-005concrete equipment_id に対する EXCLUDE 制約追加
00100010_permissions_backfill_reservation_transitions.sqlSRS-RES-004予約状態遷移 permission の backfill
00110011_store_settings_phase1_expansion.sqlSRS-TEN-001store.invoice_registration_numberstore_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 作成(空運用)
00120012_operator_auth_and_sessions.sqlSRS-TEN-002operator, passkey_credential, totp_secret, recovery_code, operator_session, operator_invitation 作成。operator_action_log.actor_kind 導入と operator_id 条件付き制約整備
00130013_operator_membership_and_staff_link.sqlSRS-TEN-003, SRS-CUS-004operator_store_linkoperator_staff_link 作成。admin:operator:* / admin:operator_store_link:write / admin:operator_staff_link:read/write backfill
00140014_menu_master_and_eligibility.sqlSRS-MST-002menu_category, menu placeholder を本番形へ昇格、menu_staff_eligibilitymenu_equipment_requirement(menu_id, equipment_group_id, quantity)staff_assignment_policy 追加
00150015_business_hours_and_day_overrides.sqlSRS-MST-003business_hours(weekday 1..7 + is_holiday)、day_override 作成
00160016_shift_management.sqlSRS-MST-004shift 作成、validate_shift_breaks_jsonb(jsonb,timestamptz,timestamptz) 定義、breaks CHECK 導入
00170017_equipment_master_and_groups.sqlSRS-MST-005equipment_group 作成、equipment.group_id 追加、設備 placeholder 昇格
00180018_customer_crm.sqlSRS-CUS-001, SRS-CUS-002customer placeholder を本番形へ昇格、customer_no、メモ、タグ、タグリンク、検索列追加。pg_trgm GIN
00190019_reservation_phase1_finalize.sqlSRS-RES-001/002/003/004/005reservation_menu_lines.menu_name_snapshotreservation.codechannel_code、編集/移動用整備、force_staff_concurrency permission rename、calendar query/index 最終化、reservation_event_actor_polymorphism CHECK 修正
00200020_visit_register_closing.sqlSRS-REG-001/002, SRS-WRK-001visit, visit_payment, visit_refund, cash_movement, register_closing, daily_sales_summaryassertNotClosedDate 連携、register 系 permission backfill
00220022_visit_amend_supersede.sqlSRS-REG-001 §7.8visit_lines.superseded_at / visit_payments.superseded_at 列を追加し、active 明細を WHERE superseded_at IS NULL で取り出せるよう partial index を作成。amend は supersede + INSERT で表現(DELETE 不可は維持)
00230023_reservation_menu_lines_supersede.sqlSRS-RES-003 §7.3reservation_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所有 SRSdescriptionownermanagerstaffreceptionistfeature_flagsensitive
admin:store:readTEN-001店舗情報の閲覧YYYY-N
admin:store:updateTEN-001店舗基本情報の更新YYNN-Y
admin:store_settings:readTEN-001店舗設定の閲覧YYYY-N
admin:store_settings:updateTEN-001店舗設定の更新YYNN-Y
admin:role:readTEN-001ロール一覧の閲覧YYYY-N
admin:operator:readTEN-002オペレーター一覧・詳細の閲覧YYNN-Y
admin:operator:createTEN-002オペレーター招待・作成YYNN-Y
admin:operator:updateTEN-002オペレーター更新YYNN-Y
admin:operator:retireTEN-002オペレーター無効化・復帰YYNN-Y
admin:operator_store_link:writeTEN-003オペレーターの店舗・ロール割当変更YYNN-Y
admin:staff:readMST-001スタッフ一覧・詳細の閲覧YYYY-N
admin:staff:createMST-001スタッフ新規作成YYNN-N
admin:staff:updateMST-001スタッフ編集・並び替えYYNN-N
admin:staff:retireMST-001スタッフ退職化・復職YYNN-Y
admin:menu:readMST-002メニュー一覧・詳細の閲覧YYYY-N
admin:menu:createMST-002メニュー新規作成YYNN-N
admin:menu:updateMST-002メニュー編集YYNN-N
admin:menu:retireMST-002メニュー停止・復帰YYNN-Y
admin:business_hours:readMST-003営業時間・定休日の閲覧YYYY-N
admin:business_hours:updateMST-003営業時間・定休日の更新YYNN-N
admin:shift:writeMST-004シフトの作成・更新・future deleteYYNN-N
admin:equipment:readMST-005設備・設備グループの閲覧YYYY-N
admin:equipment:createMST-005設備・設備グループ新規作成YYNN-N
admin:equipment:updateMST-005設備・設備グループ更新YYNN-N
admin:equipment:retireMST-005設備・設備グループ停止・復帰YYNN-Y
admin:customer:readCUS-001顧客一覧・詳細の閲覧YYYY-Y
admin:customer:createCUS-001顧客新規作成YYYY-Y
admin:customer:updateCUS-002顧客基本情報・メモ・タグ更新YYYY-Y
admin:operator_staff_link:readCUS-004operator/staff 紐付けの閲覧YYYN-Y
admin:operator_staff_link:writeCUS-004operator/staff 紐付けの更新YYNN-Y
admin:reservation:readRES-001予約一覧・詳細・カレンダー閲覧YYYY-N
admin:reservation:createRES-002予約作成YYYY-N
admin:reservation:updateRES-003予約編集・移動・所要時間調整YYYY-N
admin:reservation:read_timelineRES-004予約イベントタイムライン閲覧YYNY-Y
admin:reservation:force_business_hoursRES-002営業時間外予約を強制保存YYNN-Y
admin:reservation:force_staff_concurrencyRES-005スタッフ並列上限警告を強制通過YYNN-Y
admin:reservation:approve_tentativeRES-004tentative→confirmedYYNY-N
admin:reservation:declineRES-004tentative→declinedYYNN-Y
admin:reservation:cancel_by_storeRES-004confirmed/in_service→cancelled_by_storeYYNN-Y
admin:reservation:check_inRES-004confirmed→in_serviceYYYY-N
admin:reservation:complete_serviceRES-004in_service→service_completedYYYY-N
admin:reservation:finalize_paymentRES-004service_completed→paidYYNY-Y
admin:reservation:mark_no_showRES-004confirmed→no_showYYNN-Y
admin:reservation:cancel_by_customer_proxyRES-004顧客取消の代理入力YYNY-Y
admin:reservation:reopenRES-004中間状態の 1 段戻しYYNN-Y
admin:register:operateREG-001来店会計・返金・入出金操作YYNY-Y
admin:register:closeREG-002日次締め・締め解除相当操作YYNN-Y