Skip to content

マダミス.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:seed

task 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 — マスキング判定ロジック