Skip to content

データベース (ERD) ​

Generated by prisma-markdown

default ​

ShopGroup ​

Properties as follows:

  • id:
  • name:
  • iconUrl:
  • description:
  • isPrepaidEnable:
  • createdAt:
  • updatedAt:

PhoneBlocklist ​

店舗グループ単位で管理する、予約申込をブロックする電話番号のリスト

Properties as follows:

  • id:
  • shopGroupId:
  • phoneNumber: 数字のみに正規化された電話番号(ハイフン等は除去して保存する)
  • reason: 登録理由(任意・店舗内の管理用メモ)
  • createdAt:
  • updatedAt:

ShopGroupCorporateProfile ​

店舗グループの法人情報

Properties as follows:

  • id:
  • shopGroupId:
  • corporateNumber: 法人番号(13桁)
  • name: 法人名
  • address: 住所
  • invoiceNumber: インボイス番号(T + 法人番号)
  • createdAt:
  • updatedAt:

Shop ​

Properties as follows:

  • id:
  • publicId: 外部公開用の不変参照キー (21 文字 base62)。displayId はユーザーが変更できるため API キーには使えない。詳細は TYO-78。
  • displayId:
  • region:
  • contract:
  • name:
  • description:
  • catchCopy:
  • iconUrl:
  • address:
  • schedule:
  • paymentMethods:
  • shopGroupId:
  • createdAt:
  • updatedAt:
  • archivedAt: 閉店(論理削除)日時。null でない場合は閉店済みとして扱い、店舗管理者・メンバーからアクセス不可になる。
  • gameMasterId:
  • tel:
  • contactEmail

    店舗への問い合わせ先として公開面やユーザー向けメールに掲載するメールアドレス TODO: 将来的にはnon-nullにして、必須項目にすることも検討する

  • reservationNotificationEmail: 店舗向けの予約通知メールを受け取るメールアドレス。未設定時は通知先なしとして扱う
  • officialUrl:
  • businessHours:
  • defaultReservationDeadlineDays:
  • defaultReservationDeadlineTime:
  • defaultCancellationDeadlineDays: デフォルトのキャンセル締切日が何日前に設定されるか。
  • reservationCautions: 店舗レベルの「注意事項」の欄に表示される店舗からの文章
  • needConfirmationReservationCautions: 店舗レベルの「注意事項」の欄に表示される店舗からの文章
  • postBookingCautions: 店舗レベルの「予約確定後に表示する注意事項」の欄に表示される店舗からの文章。予約確定後にのみ表示される。未入力は null
  • reservationNoteInstructions: 店舗レベルの「店舗への連絡事項」の欄に表示される店舗からの指示文
  • reservationNoteRequired: 店舗レベルの「店舗への連絡事項」への回答は必須かどうか
  • rules:
  • cancellationPolicy:
  • googleAccessToken:
  • googleRefreshToken:
  • googleTokenExpiry:
  • googleCalendarId:
  • hideStaffAssignments:
  • hideRoomInformation

    true の場合、ユーザー向け予約詳細画面で部屋情報(ShopRoom)を表示しない。 スタッフ/管理画面側では引き続き表示される。デフォルトは公開(false)。

  • isPluginIntegrationEnabled

    WordPress 予約プラグイン連携の契約フラグ。ZIP 配布表示・API キー発行可否・プラグイン API 有効/無効の単一判定軸。 API キーの有無で契約判定はしない(キーは失効・再発行されるため、契約とキーは別概念)。変更は admin(運営)のみ。

ShopApiKey ​

WordPress 予約プラグイン連携の店舗 API キー。 平文は発行時のレスポンスでのみ返し、DB には SHA-256 ハッシュ(hex)だけを保存する(DB 漏洩時に全店キーが漏れるのを防ぐ)。 再発行は「旧キーを即失効させて新キーを作る」1 操作。有効なキー(revokedAt IS NULL)は店舗ごとに高々 1 本。 失効済みレコードは監査(いつ発行・失効したか)のために残す。

Properties as follows:

  • id:
  • shopId:
  • keyHash: API キー平文の SHA-256 ハッシュ(hex 64 文字)。認証時はリクエストのキーをハッシュ化して照合する。
  • createdAt:
  • revokedAt: 失効日時。null が有効なキー。再発行・連携解除で失効させる。

Properties as follows:

  • id:
  • url:
  • shopId:
  • createdAt:
  • updatedAt:

ShopGroupMember ​

Properties as follows:

  • id:
  • shopGroupId:
  • userId:
  • displayName

    権限管理でのみ表示する氏名。人材管理用で、消費者向けサイトには一切露出しない。 User.name は本人が自由に変えられる消費者向けニックネームで人材の同定に使えないため、 グループ単位で別に持つ。ShopStaff.name(消費者に公開される GM 名)とも別物。 NULL 許容: User.name が null のユーザーが実在し、必須にすると移行時に入れる値がないため。 招待受諾時は氏名を持たない人にのみ入力を必須化する。

  • isGroupAdmin:
  • order:
  • createdAt:
  • updatedAt:

ShopMember ​

Properties as follows:

  • id:
  • shopId:
  • shopGroupMemberId:
  • shopStaffId:
  • role:
  • createdAt:
  • updatedAt:

ShopStaff ​

Properties as follows:

  • id:
  • shopId:
  • name:
  • iconUrl:
  • order:
  • createdAt:
  • updatedAt:
  • deletedAt:

ShopCatalog ​

Properties as follows:

  • id:
  • publicId: 外部公開用の不変参照キー (21 文字 base62)。URL 等に貼っても安全。詳細は TYO-78。
  • scenarioId:
  • title:
  • introduction:
  • portraitImageUrl:
  • landscapeImageUrl:
  • shopId:
  • minCapacity

    このカタログを扱う公演で必要な最小の人数

    • 未設定の場合には、募集人数固定(最大の人数Y人が必要)なカタログだと解釈される
    • 設定されている場合には、募集人数可変(最小の人数X人〜最大の人数Y人が必要)なカタログだと解釈される
    • scenario.minPeople とは独立に設定される。
  • maxCapacity

    このカタログを扱う公演に参加できる最大の人数

    • 最小の人数が未設定の場合には、最大の人数まで集める必要がある募集人数固定のカタログだと解釈される
    • 最大の人数と最小の人数がいずれも未設定の場合には、ユーザーはこのカタログを即時予約の貸切公演・仮予約の貸切リクエスト枠に指定できないことが想定される
    • scenario.maxPeople とは独立に設定される。
  • playMinutes

    このカタログを扱う公演を開催するために確保する必要がある目安のプレイ時間

    • 未設定の場合には、ユーザーはこのカタログを即時予約の貸切公演・仮予約の貸切リクエスト枠に指定できないことが想定される
    • 目安のプレイ時間が即時予約の貸切公演・仮予約の貸切リクエスト枠の開始時刻から最大終了時刻までの時間を超過する場合には、ユーザーはこのカタログを指定できないことが想定される
    • scenario.playMinutes とは独立に設定される。
  • comment:
  • reservationCautions: カタログレベルの「注意事項」の欄に表示される店舗からの文章
  • reservationNoteInstructions: カタログレベルの「店舗への連絡事項」の欄に表示される店舗からの指示文
  • reservationNoteRequired:
  • basePrice

    カタログの基本料金(円) - shopCatalogPriceに該当のruleがなければこの料金が適用される

    • 未設定の場合には、ユーザーはこのカタログを即時予約の貸切公演・仮予約の貸切リクエスト枠に指定できないことが想定される 未設定と無料であることは区別される、無料であるならば値は未設定ではなく0にする
  • order:
  • visibility:
  • unpublishAt:
  • createdAt:
  • updatedAt:

ShopPricingRule ​

店舗が設定することができる価格ルール 例えば「平日料金」「土日祝料金」「特別価格」などのルールを定義し、 条件を満たす公演スロットに自動適用される。

Properties as follows:

  • id:
  • shopId:
  • ruleName

    ルール名(例: "平日料金", "土日祝料金", "10/21以降", "年末年始特別料金") ショップが自由に設定できる。

  • startAt: ルールの適用開始日
  • endAt: ルールの適用終了日
  • dayCategory

    曜日

    • WEEKDAY: 平日(月〜金)に自動適用
    • WEEKEND: 土日祝日に自動適用
  • priority: ルール適用の優先度、0が最優先
  • createdAt:
  • updatedAt:

ShopCatalogPrice ​

特定のルールが適用された時のカタログの価格を定義 ShopCatalogのbasePriceとは別に、ルールごとの価格を設定できる 例: カタログAの基本料金は5000円だが、「土日祝料金」ルールでは6000円

Properties as follows:

  • id:
  • shopCatalogId:
  • shopPricingRuleId:
  • price

    このルールが適用された時の価格(円) 例: 土日祝は通常より1000円高い価格を設定

  • createdAt:
  • updatedAt:

ShopStaffCatalogSkill ​

Properties as follows:

  • id:
  • shopStaffId:
  • shopCatalogSkillId:
  • createdAt:
  • updatedAt:

ShopCatalogSkill ​

Properties as follows:

  • id:
  • skill:
  • shopCatalogId:
  • hidden:
  • requiredStaffCount:
  • createdAt:
  • updatedAt:

ShopHeaderImageUrl ​

Properties as follows:

  • id:
  • url:
  • shopId:
  • createdAt:
  • updatedAt:

BookingSlot ​

店舗の予約スロット このclassの配下に PublicBookingSlot と PrivateBookingSlot がある この Slot と並列に ExternalBookingSlot がある

Properties as follows:

  • id:
  • publicId: 外部公開用の不変参照キー (21 文字 base62)。URL 等に貼っても安全。詳細は TYO-78。
  • shopId:
  • reservationDeadline

    このスロットの予約締切日 この予約締切時間をもって、開催判断が行われる

  • cancellationDeadline: ユーザーの予約がキャンセル可能な締め切り日時
  • canceledAt

    公開公演で、deadline までに予約が埋まらない場合、自動でキャンセルされる(canceledAtの値は入る) リクエスト貸切公演で、店側がdeclineした場合もキャンセルされる その他運営都合でキャンセルが可能。 reservation が一つも入っていない場合は、 canceledAt で削除するのではなく、物理削除で対応

  • cancelReason:
  • startAt:
  • isDraft

    一括公開ワークフロー維持のマスターフラグ true の間は問答無用で非公開 publishBookingSlots mutation により false 化される

  • listing

    情報開示レベル(一覧掲載と詳細閲覧権限を統合した 1 軸) UNLISTED: 一覧×・詳細はリンク保持者のみ / OCCUPIED_HINT: 一覧に「予定あり」のみ / LISTED: 一覧○・詳細○

  • bookingOpensAt

    予約開始日時 null / 過去 = 予約可、未来 = 予約受付前(ティーザー表示)

  • paymentMethod

    決済方法 これは一度でも予約を受け付けした後は変更してはならない。

  • linkToken: 認証用トークン。isHidden や privateBookingSlot で一人目が予約した時等に使う
  • memo: 公演に対して店舗がかけるメモ
  • reservationCautions

    slotごとの「注意事項」の欄に表示される店舗からの文章 デフォルト値よりslot生成時に設定される。

  • postBookingCautions

    slotごとの「予約確定後に表示する注意事項」の欄に表示される店舗からの文章。予約確定後にのみ表示される。未入力は null デフォルト値よりslot生成時に設定される。

  • reservationNoteInstructions

    slotごとの「店舗への連絡事項」の欄に表示される店舗からの指示文 デフォルト値よりslot生成時に設定される。

  • reservationNoteRequired

    slotごとの「店舗への連絡事項」への回答は必須かどうか デフォルト値よりslot生成時に設定される。

  • autoCancellationCheckedAt: reservationDeadline 時点で予約が埋まっていない場合、自動でキャンセルされるが、そのチェックが行われた時刻。
  • googleCalendarEventId:
  • shopRoomId

    このスロットが公演される店舗の部屋 ここには確定情報が入り、部屋A or 部屋B みたいな状態は入らない。 部屋機能を特に使わない店舗はここを空のままにしておく

  • createdByUserId

    この枠を作成した店舗管理の操作者(User.id)。複製で作られた枠は複製を実行した人が入る。 記録を始める前に作られた枠は null。 User への外部キーは張らない。退会で参照を空にすると、記録を始める前の枠と区別できなくなる

  • createdBySystemAdmin

    作成者が運営(システム管理者)として操作したか。 運営かどうかは後から変わるため、操作した時点の立場を保存する

  • lastEditedByUserId

    店舗管理から最後に枠を手動変更した操作者(User.id)。外部キーを張らない理由は createdByUserId と同じ。 予約の操作と自動処理(Google カレンダー連携等)では変わらない

  • lastEditedBySystemAdmin: 最後に手動変更した人が運営(システム管理者)として操作したか
  • lastEditedAt

    店舗管理から最後に枠を手動変更した日時。 updatedAt は予約の操作や自動処理でも進むため、人の操作の日時としては使えない

  • createdAt:
  • updatedAt:

PublicBookingSlot ​

店舗の公開募集予約スロット(オープン公演)

Properties as follows:

  • id:
  • bookingSlotId:
  • endAt:
  • minCapacity

    このオープン公演が開催されるのに必要な人数

    • 未設定の場合には、受付可能な最大の人数まで集めることで開催できると解釈される
  • maxCapacity

    このオープン公演で受付可能な最大の人数

    • 無限人で開催することは現実的ではないため、この値は必須となっている
  • price:
  • shopCatalogId:
  • createdAt:
  • updatedAt:

PrivateBookingSlot ​

店舗の貸切予約スロット(即時予約の貸切公演・仮予約の貸切リクエスト枠)

Properties as follows:

  • id:
  • bookingSlotId:
  • maximumEndAt: 最長の場合の終了時刻、これを超える時間のカタログは予約できない
  • shopCatalogId

    [shopCatalogId] が指定されているときは、このslotは特定のカタログ専用のスロットになる。 指定されていないときは、[staffAssignments]からカタログが決定される。 また初回予約が入った瞬間に確定される。

  • catalogFixedByShopAt

    店舗が作品を事前指定した日時

    • null でなければ、この枠の [shopCatalogId] は店舗による事前指定であり、 予約が全てキャンセルされても [shopCatalogId] をリセットしない(作品固定のまま再募集する)
    • null であれば、[shopCatalogId] は予約時にユーザーが選んだ作品(全キャンセルでリセットされる)
  • shopConfirmedAt

    仮予約の貸切リクエスト枠が店舗によって承認された時間 (即時予約の貸切公演の場合は、この値がnullであると変なので予約時の時刻を入れることを想定している)

    • これがnullであれば、仮予約の貸切リクエスト枠は店舗からの承認がないと解釈される
  • needShopConfirmation

    即時予約の貸切公演か仮予約の貸切リクエスト枠かを区別するためのフラグ

    • これが true であれば、仮予約の貸切リクエスト枠であると解釈される (このとき店舗の承認が必要になり、shopConfirmedAtがnullでなければ承認されたと解釈される)
  • shopConfirmationMessage

    店舗からの確認メッセージ(許可・拒否時に店舗が入力する任意メッセージ) ユーザーへの通知メールに含まれる

  • createdAt:
  • updatedAt:

ShopEventSlot ​

店舗で公演以外のカレンダー情報を管理するモデル

Properties as follows:

  • id:
  • shopId:
  • title:
  • startAt:
  • endAt:
  • createdAt:
  • updatedAt:

ExternalBookingSlot ​

マダミス.jp shops を使ってない店舗の予約スロット 基本的にスクレイピングして取得したデータ

Properties as follows:

  • id:
  • scenarioId:
  • shopId:
  • startAt:
  • duration:
  • price:
  • url:
  • currentCapacity:
  • createdAt:
  • updatedAt:

ShopRoom ​

Properties as follows:

  • id:
  • publicId: 外部公開用の不変参照キー (21 文字 base62)。URL 等に貼っても安全。詳細は TYO-78。
  • shopId:
  • name:
  • order:
  • createdAt:
  • updatedAt:

ShopCatalogRoom ​

カタログと部屋の紐付け(どの部屋でどのカタログが公演可能か)

Properties as follows:

  • id:
  • shopCatalogId:
  • shopRoomId:
  • createdAt:
  • updatedAt:

BookingSlotStaffAssignment ​

Properties as follows:

  • id:
  • bookingSlotId:
  • shopStaffId:

Reservation ​

予約情報 将来的に予約時質問等を追加することを考えると、ReservationPaymentとは別に Reservation クラスを持つのは理にかなっている。

Properties as follows:

  • id:
  • bookingSlotId:
  • customerId:
  • source

    この予約が ユーザーから / 店舗から 入ったかを示すフラグ 店舗から入った場合、仮に事前決済slotで決済完了していなくても、自動キャンセルされない。

  • reservationNotes: 「店舗への連絡事項」への回答項目
  • usedCouponId:
  • createdAt:
  • updatedAt:
  • canceledAt:
  • confirmationEmailSentAt:
  • campaignId: 予約ごとに一意のトークン。非会員向けメールリンクのゲストアクセス(?reservation={campaignId})や、ログイン後の予約紐付け(linkGuestReservation)に使用される。
  • sourceUrl: 予約が発生した外部ページの URL(WP プラグイン設置ページ等)。ゲスト決済導線の「サイトに戻る」リンクに使う。書き込み時に http(s) のみ許可
  • sessionRecordSkippedAt: この予約情報に対するプレイ記録をつけないことが意思表明された場合に値を入れる

ReservationTransaction ​

予約の変更履歴 予約の変更があった場合、その時点の予約状態(絶対値)を記録する transaction は未確定、確定、キャンセルの3つの状態を持つ。一つのReservationに対して、常に一つ以上存在し、また未確定は常に1つ以下存在することが想定される。 未確定または確定のtransactionが存在する場合、その [totalQuantity] の在庫は確保されなければならない。 状態遷移は 未確定 -> 確定, 未確定 -> キャンセル の2パターンである。

Properties as follows:

  • id:
  • reservationId:
  • totalQuantity: その時点の予約人数(絶対値)
  • totalAmount

    このTransactionでの支払い金額。 クーポンが考慮されている。 事前決済の場合は、基本的には Payment.amount の初期値と一緒になる。

  • source: この変更を行ったソース(USER: ユーザー、SHOP: 店舗スタッフ、UNKNOWN: 不明)
  • createdAt:
  • updatedAt:
  • acceptPayment

    顧客からの支払いを受け付けるかどうか。 これが true の時は、支払いを受け付ける。

  • paymentCheckoutExpiresAt

    支払い期限 この値を過ぎていて、かつpaymentが存在しない場合は、自動でキャンセルされる。 この値がnullであれば、支払い期限がなく、自動でキャンセルされないことを意味する。 [acceptPayment] が true の時のみ、この値は意味をなす。 [paymentCheckoutExpiresAt]、[activatedAt]、[invalidatedAt]のいずれかは必ず非nullであることが想定される。(永久に在庫を確保することは許されない。)

  • activatedAt

    決済等が確定し、このtransactionが有効になった日時。 決済が不要なTransactionの場合(現地決済の予約や、店舗管理からの予約)は、最初からこの値は入っている。 店舗管理から予約を入れた場合、acceptPayment=true,payment=null,activatedAt=予約作成日時 となるパターンがあることに注意。

  • invalidatedAt

    決済失敗/タイムアウト等でこのトランザクションが無効化された日時。 事前決済のslotをユーザー側から予約した時のみ値が入りうる。

Customer ​

Properties as follows:

  • id:
  • shopGroupId:
  • userId:
  • name:
  • email:
  • phoneNumber:
  • memo:
  • createdAt:
  • updatedAt:

User ​

ウズアカウントを持っているユーザー

Properties as follows:

  • id:
  • firebaseUid:
  • name:
  • iconUrl:
  • twitterId:
  • description:
  • termsAcceptedAt:
  • createdAt:
  • updatedAt:

UserContact ​

ユーザーの連絡先情報

Properties as follows:

  • id:
  • userId:
  • name:
  • email:
  • phoneNumber:
  • stripeCustomerId: Stripe Customer ID(カード情報を保存して次回以降の決済で再利用するために使用)
  • fincodeCustomerId: fincode Customer ID(カード情報を保存して次回以降の決済で再利用するために使用)
  • createdAt:
  • updatedAt:

Scenario ​

Properties as follows:

  • id:
  • scenarioGlobalId:
  • title: 作品タイトル
  • titleFurigana: 作品タイトル(ふりがな)
  • portraitImageUrl: タテ型作品キービジュアルURL
  • landscapeImageUrl: ヨコ型作品キービジュアルURL
  • minPeople: プレイ人数(最小)
  • maxPeople: プレイ人数(最大)
  • manCount: プレイ人数(男性キャラクター)
  • womanCount: プレイ人数(女性キャラクター)
  • otherCount: プレイ人数(その他キャラクター)
  • playMinutes: プレイ時間(分)
  • price

    料金体系

    具体的な価格ではない

  • gameMasterRequired

    ゲームマスターの有無

    nullの場合は不明として扱う

  • releasedAt: 公開日
  • releasedAtAccuracy: 公開日(年月日のいずれまで正確か)
  • introduction: ストーリー/物語のあらすじ
  • explanation: 作品の説明
  • videoUrl: 動画埋め込みURL
  • flagHideRating: 表示設定(評価の数値が表示されないようにする)
  • flagHideReview: 表示設定(感想一覧が表示されないようにする)
  • flagHideTags: 表示設定(シナリオタグの一覧が表示されないようにする)
  • flagRestrictedGameMaster

    表示設定(管理者以外のゲームマスターを非表示にする)

    trueならばシナリオ情報の管理者以外のGM情報が取得されない ただしスクレイピングしている公演情報は制限していないため、そこでは管理者以外のGMの情報が表示されることがある

    制限するのは作品ページ側の表示だけ(権利者が意図しない GM を作品ページに並べさせない)。 GM が自分のプロフィールで「依頼されれば公演できる」と対応可能作品に載せることは制限しない。 GM 側の保存(rest/game_master_compose、GraphQL の createPlayableScenario)や GM 詳細ページで このフラグを見て弾かないこと(2026-10 に一度入れかけて取りやめた)

  • flagExcludeFromMadaan

    マダアン(毎月マダミスアンケート)の集計対象から除外する

    主催・運営関係者の作品など、企画の趣旨上ランキングに載せない作品に立てる。 除外は集計時に効くので、既に凍結済みの MadaanResult は遡って変わらない。

  • isEditedByUser:
  • createdAt:
  • updatedAt:

ScenarioRightsHolder ​

Properties as follows:

  • id:
  • scenarioId:
  • userId:
  • requestedAt:
  • acceptedAt:
  • rejectedReason:
  • confirmationImageUrl:
  • createdAt:
  • updatedAt:
  • シナリオの公式ページへのリンク

Properties as follows:

  • id:
  • scenarioId:
  • url:

ScenarioTagCategory ​

Properties as follows:

  • id:
  • name:
  • createdAt:
  • updatedAt:

ScenarioTag ​

Properties as follows:

  • id:
  • scenarioTagCategoryId:
  • name:
  • createdAt:
  • updatedAt:

ScenarioTagRelation ​

Properties as follows:

  • id:
  • scenarioId:
  • scenarioTagId:
  • createdAt:
  • updatedAt:

ScenarioTagRelationVote ​

Properties as follows:

  • id:
  • scenarioTagRelationId:
  • userId:
  • vote:
  • createdAt:
  • updatedAt:

Author ​

Properties as follows:

  • id:
  • name:
  • nameFurigana:
  • iconUrl:
  • description:
  • userId:
  • playerMypageLinkEnabled:
  • createdAt:
  • updatedAt:

ScenarioPosition ​

Properties as follows:

  • id:
  • position:
  • scenarioId:
  • createdAt:
  • updatedAt:

ScenarioAuthor ​

Properties as follows:

  • id:
  • scenarioPositionId:
  • authorId:
  • createdAt:
  • updatedAt:

GameMaster ​

Properties as follows:

  • id:
  • name:
  • iconUrl:
  • displayId:
  • comment:
  • providableArea:
  • reservationLink:
  • email:
  • userId:
  • createdAt:
  • updatedAt:

GameMasterPhoto ​

Properties as follows:

  • id:
  • gameMasterId:
  • photoUrl:

PlayableScenario ​

Properties as follows:

  • id:
  • comment:
  • fee:
  • priority:
  • reservationLink:
  • scenarioId:
  • gameMasterId:
  • createdAt:
  • updatedAt:

SessionRecord ​

プレイ記録

  • プレイ未確定状態(playedConfirmedAtがnullである※プレイ予定として扱う予定だったが現状必要なくなった)
  • プレイ済み状態(playedConfirmedAtがnullでない)
  • レビュー済み状態(playedConfirmedAtがnullでないかつrecommendedCommentあるいはspoilerCommentがnullでない)

Properties as follows:

  • id:
  • userId:
  • scenarioId: 遊んだ作品
  • reservationId: 紐付いている予約情報
  • shopId: 遊んだ店舗
  • private

    SessionRecord を他人から閲覧できない状態にする。 シナリオの Rating の計算には現状利用される。

  • hideRating

    SessionRecord の項目のうち、Rating について他人から表示されないようにする。 [private] が true であれば、この値は無視される。

  • hidePlayedAt

    SessionRecord の項目のうち、プレイ日時について他人から表示されないようにする。 これが false でも 年月までしか表示されない。 [private] が true であれば、この値は無視される。

  • rating

    評価(0〜5) ⚠️非公開にすることができる

  • playedAt

    プレイ時期として記録する日時、ユーザーが選んで入力する ⚠️プライバシーを考慮するためにXXXX年Y月という形式で表示する ⚠️非公開にすることができる

    • プレイ未確定状態の場合、この値はプレイ予定の日時として表示される
    • プレイ済み状態の場合、この値はプレイ時期として表示される
  • playedConfirmedAt: プレイ済み状態に変更された日時
  • privateMemo

    自分用メモ ⚠️許可なく公開されることはない

  • recommendedComment: おすすめコメント
  • spoilerComment: ネタバレコメント
  • createdAt:
  • updatedAt:

SessionRecordPerson ​

プレイ記録("ゲームマスター"・"プレイヤー")用に作成される人物情報 ⚠️自分が作成した人物情報は他人から参照されることがないようにしている

Properties as follows:

  • id:
  • name:
  • iconUrl:
  • belongingUserId:
  • userId:
  • createdAt:
  • updatedAt:

SessionRecordPlayer ​

Properties as follows:

  • id:
  • sessionRecordId:
  • sessionRecordPersonId:

SessionRecordGameMaster ​

Properties as follows:

  • id:
  • sessionRecordId:
  • sessionRecordPersonId:

SessionRecordFavorite ​

Properties as follows:

  • id:
  • userId:
  • sessionRecordId:
  • createdAt:
  • updatedAt:

InterestedScenario ​

Properties as follows:

  • id:
  • userId:
  • scenarioId:
  • createdAt:
  • updatedAt:

MadaanAnswer ​

マダアン(月刊マダミスアンケート)の 1 回答 = 1 シナリオ。 投票は対象月の翌月 1〜7 日に受け付けるため、createdAt の月は targetMonth の翌月になる。

Properties as follows:

  • id:
  • xId:
  • scenarioId:
  • type:
  • targetMonth

    遊んだ月(YYYY-MM)。投票した月ではない。 「あなたが N 月に遊んだ作品」という設問への回答なので、集計も結果表記もこの月をそのまま使う。

  • createdAt:
  • updatedAt:

MadaanResult ​

マダアンの発表単位。発表時点の集計を凍結する。

集計自体はオンデマンドでも性能上問題ないが、公開済みの結果は告知・被リンクから 参照される確定情報なので、後から動いてはいけない。mergeScenarios による scenarioId の付け替え・除外シナリオの追加・DB migration はいずれも過去月の順位を変えうる。

Properties as follows:

  • id:
  • targetMonth: 対象月(YYYY-MM)。MadaanAnswer.targetMonth と同じ概念
  • voterCount

    回答者数。重複投票を除外した後のユニーク xId 数

    flagExcludeFromMadaan の除外はランキングにだけ効かせ、この参加人数からは引かない (除外シナリオへの投票も回答そのものは実在するため)。現行スプレッドシートの 「回答人数」= countUNIQUE(データ!A:A) と同じ数え方。

  • answerCount: 回答件数。重複投票を除外した後の行数。voterCount と同じくシナリオ除外の前で数える
  • aggregatedAt: 集計を確定した時刻。「いつ時点の集計か」を説明可能にする
  • publishedAt: null = 未公開(admin プレビューのみ)
  • createdAt:
  • updatedAt:

MadaanResultItem ​

発表 1 件ぶんの行。票が入った作品を順位付きで全部持つ。

上位だけでなく全順位を保存するのは、Google Sites 時代に部門ごとの別スプレッドシート (「全票」×4)とスライド(×4)へ手作業でコピーしていた内容を、発表ページの中に そのまま出せるようにするため。

Properties as follows:

  • id:
  • resultId:
  • type:
  • rank: 同率を潰さない順位(1,2,2,4...)
  • voteCount:
  • scenarioId:
  • featured: 発表ページの上位として大きく載せるか。false でも全票一覧には出る

ScenarioPlayFormat ​

Properties as follows:

  • id:
  • scenarioId:
  • playFormat:

Properties as follows:

  • id:
  • token:
  • expiresAt:
  • shopGroupId:
  • shopId:
  • createdAt:
  • updatedAt:

BookingSlotNotification ​

Properties as follows:

  • id:
  • bookingSlotId:
  • subject:
  • body:
  • sentAt:
  • createdAt:
  • updatedAt:

CustomerNotification ​

お客さんに対して送ったメールの履歴

Properties as follows:

  • id:
  • customerId:
  • reservationId:
  • subject:
  • body: htmlメールの場合は、htmlを入れる
  • sendgridStatus: メールの送信ステータス(Event Webhookで更新)
  • failedDetail

    失敗詳細(SendGrid Event Webhook 由来の構造化フィールド)。 型は src/lib/emailFailureClassification.ts の EmailFailureDetail を参照。 failedDetail->>'classification' = 'Reputation' のように構造化検索できる。

  • sendgridMessageId: SendGridのメッセージID(x-message-id)
  • sentAt: SendGridキューに入った日時
  • sendgridDeliveredAt: 実際に配信された日時(Event Webhook)
  • shopFailureNotifiedAt

    予約者向けメールが送信失敗(FAILED_ADDRESS_INVALID / FAILED_REJECTED)となった際に、店舗管理者へ失敗通知メールを送った日時。 SendGrid Webhook が同一イベントを重複送信した場合や、失敗後に別イベントが来た場合の二重送信を防ぐために使う。

  • createdAt:
  • updatedAt:

ShopNotification ​

Shopに対して送ったメールの履歴

Properties as follows:

  • id:
  • shopId:
  • slotId:
  • subject:
  • body: htmlメールの場合は、htmlを入れる
  • sendgridStatus: メールの送信ステータス(Event Webhookで更新)
  • failedDetail

    失敗詳細(SendGrid Event Webhook 由来の構造化フィールド)。 型は src/lib/emailFailureClassification.ts の EmailFailureDetail を参照。

  • sendgridMessageId: SendGridのメッセージID(x-message-id)
  • sentAt: SendGridキューに入った日時(従来のsentAtと同じ役割)
  • sendgridDeliveredAt: 実際に配信された日時(Event Webhook)
  • createdAt:
  • updatedAt:

BookingSlotBilling ​

Properties as follows:

  • id:
  • startedAt:
  • totalGuests:
  • totalAmount:
  • prepaidTransferAmount:
  • onSiteCommissionAmount:
  • monthlyShopBillingId:
  • createdAt:
  • updatedAt:

MonthlyShopBilling ​

Properties as follows:

  • id:
  • shopId:
  • year:
  • month:
  • fixedCommissionAmount:
  • plan:
  • paymentAgencyFee:
  • createdAt:
  • updatedAt:

Payment ​

=============================== ReservationTransactionに紐ずくPayment情報を持つ。 将来的にはこの Payment に紐付いて StripePayment, GMOPayment と増やしていく想定だが、現状はStripeしか対応せず、適切に抽象化するのは困難なため、一旦Paymentに直接stripeIdを保存する。 正常系では、REFUND は行われない。 ここで CanceledAt や lastRefundedAt があっても、それは店舗等の手動でのキャンセルや返金等も考えられる。 Paymentモデルはあくまで決済状況を保持するためのモデルであり、これらのステータスが、ReservationやBookingSlotのStatusには影響出ないように独立して考える。 ​

Properties as follows:

  • id:
  • reservationTransactionId:
  • paymentProvider

    決済プロバイダー(Stripe または fincode) 既存データは全て Stripe なのでデフォルトは STRIPE

  • externalPaymentId

    マダミス.jp では外部決済サービスを必ず使う。 将来的には paymentProvider カラムを追加して、Stripe以外の決済サービスも扱えるようにする可能性がある。 その際、各決済サービスでのPaymentモデルに該当するObject の ID を保存するカラムとして利用する。 決済サービス横断のカラムなので、uniqueは保証されないが、実害が出てくるまで、uniqueをつけておく。

    stripe: 管理画面でいう取引オブジェクトのid https://docs.stripe.com/api/payment_intents

  • stripePaymentIntentClientSecret

    ===== Stripe 関連フィールド ===== Payment Element用のクライアントシークレット フロントエンドで決済フォームを表示するために使用

  • fincodeAccessId

    ===== fincode 関連フィールド ===== fincode の Access ID 決済実行時に使用するアクセスID

  • amount

    決済金額 例えば、オーソリの金額から決済の金額が減額された場合、amountは決済時の金額に書き変わる。 一度決済されたら金額が書き変わることなく、それ以降の返金は refundedAmount に加算される。

  • currency: マダミス.jp の仕様上、この値は常に JPY になる
  • captureMethod

    決済方法によって変わる。カードの場合は MANUAL、PayPayの場合は AUTOMATIC。 captureBefore が入っているかどうかで判断可能なので、captureMethod は不要。

  • authorizedAt

    オーソリ完了日時 決済実行前に、Paymentモデルは作成されるので初期状態は null。 Webhookでオーソリ成功時に設定される

  • capturedAt: capture 完了日時
  • captureBefore

    キャプチャの期限日時 Stripeのcapture_beforeパラメータから取得 通常はオーソリから7日間(最大30日間)

  • canceledAt

    AUTHORIZED 状態で Payment をキャンセルしたら canceledAt が入る 一度でも CAPTURED したら canceledAt 値が入ることはなくなる

  • refundedAmount

    今まで返金した金額の総額 オーソリからの減額決済はこれに含まれない。

  • lastRefundedAt

    最後に返金した日時 最終日時以外は、重要度が低いので持たない。

  • paymentMethodType

    決済方法 過去データのデフォルトはカードだが、将来的には、default値は削除したい。

  • createdAt:
  • updatedAt:

Coupon ​

=============================== クーポンテーブル ​

Properties as follows:

  • id:
  • code:
  • title: クーポンのタイトル、ユーザーに表示される。
  • internalDescription: クーポンの管理用説明、ユーザーには表示されない。
  • discountType: 割引タイプ。UNIT=各人から円割引、TOTAL=総額から円割引、PERCENTAGE=N% 割引
  • discountAmount: 円割引額。UNIT/TOTAL のときのみ値あり(PERCENTAGE では NULL)
  • discountPercentage: 割引率(%、5〜100、5 の倍数)。PERCENTAGE のときのみ値あり
  • applyToCount: 適用人数。UNIT/PERCENTAGE で意味あり: NULL=予約全体に適用、N=N 名分のみに適用。TOTAL は人数非依存のため常に NULL
  • validFrom:
  • validUntil:
  • issuedByUserId:
  • maxUsageCount:
  • perUserUsageCount:
  • disabledAt

    無効化日時。非 null の場合、以降の新規クーポン適用を弾く(既存予約には影響しない)。 店舗がトグルで無効化⇄再有効化を切り替える(再有効化時は null に戻す)。物理削除ではないので 既存予約の usedCoupon リレーション・金額再計算・利用履歴は一切壊れない。

  • createdAt:
  • updatedAt:

CouponScopeShop ​

=============================== クーポン利用範囲テーブル(店舗対象) ​

Properties as follows:

  • id:
  • couponId:
  • shopId:
  • createdAt:

CouponScopeShopCatalog ​

=============================== クーポン利用範囲テーブル(カタログ対象) ​

Properties as follows:

  • id:
  • couponId:
  • shopCatalogId:
  • createdAt:

UserSessionRecordCommentMute ​

プレイ記録のコメントに関するミュート設定

Properties as follows:

  • id:
  • sourceUserId: このミュート設定を行ったユーザーのID
  • targetUserId: このミュート設定の対象のユーザーのID
  • createdAt:

Survey ​

Survey の本体メタデータ statusカラムは持たず、starts_at/ends_atで有効期間を管理する

Properties as follows:

  • id:
  • slug: 公開URL用途など。任意
  • title: 表示名
  • description: 説明
  • startAt: 有効期間開始。NULLなら非公開
  • endAt: 有効期間終了。NULLなら制限なし
  • createdAt:
  • updatedAt:

SurveyVersion ​

Survey のバージョン 質問定義のスナップショット単位。公開後の変更や履歴を安全に扱うために導入

  • publishedAt IS NULL: 下書き
  • publishedAt IS NOT NULL: 公開済み(最も新しい publishedAt のものがアクティブ)

Properties as follows:

  • id:
  • surveyId:
  • publishedAt: 公開時にセット。NULLなら下書き、最も新しいものがアクティブ
  • createdAt:
  • updatedAt:

SurveyQuestion ​

Survey Version に属する質問定義

Properties as follows:

  • id:
  • surveyVersionId:
  • key

    version内で一意。API/集計で使う安定キー version間での同一性の担保にはこのkeyを使う。

  • title: 質問文
  • description: 補足説明
  • type:
  • isRequired: 必須かどうか
  • position: 表示順
  • config: 型ごとの追加設定(minLen, maxLen, min, max, maxSelections, allowedScenarioIds等)
  • createdAt:
  • updatedAt:

SurveyResponse ​

1回の回答提出(ヘッダ) レコード作成 = 提出完了

Properties as follows:

  • id:
  • surveyVersionId:
  • respondentId: ログインユーザーID。未ログインの回答ならNULL
  • createdAt:
  • updatedAt:

SurveyAnswer ​

Response × Question の回答(1質問=1行) scenario_single は value_scenario_id に、scenario_multi は SurveyAnswerScenario に保存

Properties as follows:

  • id:
  • responseId:
  • questionId:
  • valueBoolean: type=BOOLEAN で使用
  • valueString: type=STRING で使用
  • valueInteger: type=INTEGER で使用
  • valueScenarioId: type=SCENARIO_SINGLE で使用
  • createdAt:
  • updatedAt:

SurveyAnswerScenario ​

scenario_multi 専用。複数選択の回答値を保持

Properties as follows:

  • answerId:
  • scenarioId:
  • createdAt:

ReceiptIssueLog ​

=============================== 領収書発行履歴 ​

領収書発行 (generateReceiptDownloadUrl mutation) の履歴。 同一 payment に対する発行回数のカウントと、再発行表記 (連番 + 「再発行日」) を実現するための補助テーブル。

shop (店舗管理画面) からの領収書発行導線は削除済み (お客様にマイページからセルフ発行してもらう運用)。 よってこのテーブルは「お客様による全領収書発行」のログとして機能する。

recipientName は再生成時の根拠データとして平文保存する。サニタイズ済み。

Properties as follows:

  • id:
  • paymentId:
  • issuanceCount: 同一 payment 内での発行回数 (1 から開始)
  • recipientName: 入力された宛名 (サニタイズ済み、写し再生成の根拠データ)
  • issuedAt:
  • issuedByUserId: 発行操作したユーザー (お客様本人)