マダミス.jp
マダミス.jp は、マーダーミステリーの情報提供と予約機能を持つ Web サイトで、店舗情報・イベント情報・シナリオ情報などを総合的に扱う。このページでは全体像(機能・業務・技術スタック・開発環境・設計方針)をまとめ、個々の機能の仕様は「機能」、開発の決まりは「開発」の各ページに置く。
主な機能
- 店舗検索・情報表示
- イベント予約システム
- シナリオデータベース
- レビュー・評価システム
- 決済処理
- メール通知
業務の基本
- マルチテナント: 各 ShopGroup に個別の請求と権限がある(権限管理)
- 手数料: ショッププランにより 0〜3%(MonthlyShopBilling で追跡)
- 決済: Stripe と fincode byGMO(決済システム)
技術スタック
- フロントエンド(
frontend/shop/admin): Next.js、React、TypeScript、Tailwind CSS - バックエンド(
backend): Hono、GraphQL(Apollo Server + Nexus)と REST、Prisma - データベース: 専用の PostgreSQL(データベース (ERD))
開発環境
bash
# 開発サーバー起動
task mdms_jp:dev
# テスト実行(Vitest。環境のセットアップが要るので必ず task 経由で実行する)
task mdms_jp:test
# 匿名化済みの本番環境データの復元
task mdms_jp:seedtask mdms_jp:seed は名前に反して 0 から seed を作る処理ではなく、mdms_jp-anon.sql または mdms_jp-sample.sql を取得してローカル DB に復元し、その後 dev 用の補正をかける。
設計方針
clientType によるレスポンス出し分け
バックエンドはリクエストヘッダー mdms_jp-client-type でクライアント種別(mdms_jp-frontend / mdms_jp-shop 等)を識別し、同一の GraphQL 型でもクライアントに応じて返すデータを切り替える。
ts
// context.ts でヘッダーから取得
const clientType = normalizeHeader(req.headers['mdms_jp-client-type']);
// field resolver で分岐
if (context.clientType === 'mdms_jp-frontend') {
// 公開ページ向けにマスキング
}このパターンは全面的に許可する。クライアントごとに別の query や型を定義する方式は採らない。
clientType で出し分けているのは画面の表示方針(OCCUPIED_HINT のシナリオ名の非表示、スタッフの非表示など)で、セキュリティの境界ではない。ヘッダーが無くて全情報が見えても(fail open)、個人情報の漏洩にはならない。表示の出し分けのために query や型を分けるのは、手間に見合わない。
利用箇所:
booking_slot/object.ts— OCCUPIED_HINT 詳細マスキング、スタッフ非表示shouldMaskOccupiedHintDetails.ts— マスキング判定ロジック