ビジネスソリューション
Rosterly:仮想空間ビジネス向け マルチテナント型予約・シフト管理システム
仮想空間で急成長する有償サービス市場において、バーチャル店舗向けの自由シフト制かつ安価な「予約・シフト管理システム」が不足しているという課題を解決するため、実店舗レベルの高度な運用や権限管理にも耐えうるSaaS型予約基盤をゼロから独自開発しました。
SaaS予約システムシフト管理DjangoマルチテナントDiscord OAuthアーキテクチャ設計
メタバース向け・マルチテナント予約管理SaaS
*本番リリースに向けて、現在TEST運営中
技術スタック、開発体制
- 技術スタック:Python / Django、JavaScript、HTML/CSS、Docker、Nginx、Discord OAuth
- 開発体制:個人開発
- 概要:仮想空間店舗向けに、予約管理・シフト管理・店舗情報管理を一元化するB2B SaaSを開発しました。要件定義、設計、実装、デプロイまで一貫して担当し、実際の店舗運営者からのフィードバックをもとに改善を続けています。
役割・担当
- サービス全体の要件定義、機能設計、画面設計、実装、デプロイを担当
- 店長・スタッフ・顧客の3種類のロールに応じたUIと権限制御を設計
- 予約管理、スタッフのシフト管理、店舗情報管理、認証・権限管理などの主要機能を実装
開発内容
マルチテナント設計
店舗ごとに独立した運営環境を提供し、各店舗の予約情報・シフト情報・スタッフ情報を分離して管理できる構成を実装しました。
RBACによる権限制御
店長・スタッフ・顧客ごとに操作できる範囲を分け、スタッフは自身のシフトや担当予約のみ操作できるようにしました。
Discord OAuthによる認証
仮想空間ユーザーとの親和性を考慮し、Discord OAuthを用いたログイン機能を実装しました。
予約フォームのスパム対策
公開予約フォームに対して、IPベースのレートリミットやハニーポットを導入し、不正アクセスやスパム予約への対策を行いました。
運用・リスク管理を意識した設計
通報・監査ログ、利用規約上の責任範囲、外部プラットフォームの規約遵守などを考慮し、B2B SaaSとして安全に運用できる設計を意識しました。
システム全体アーキテクチャー図
システム論理アーキテクチャと設計思想
アクセス経路と権限の明確な分離:
店長・スタッフが利用する「管理画面」と、顧客が利用する「公開予約ページ」の入口を物理的・論理的に分離。外部サービスからの流入は必ずSSO認証や専用フロントを経由させることで、管理機能への越権アクセスを構造的に防いでいます。
責務に応じた基盤の分割:
予約受付やシフト管理といった「同期的に処理すべきコアロジック」と、メール送信やWebhook連携といった「非同期で処理すべきタスク」を分割。Redis / Celeryを用いた非同期基盤を導入することで、外部APIの遅延に引きずられない高いレスポンス性能とUXを実現しています。
外部連携を前提とした疎結合設計:
Discord OAuthによる安全な認証連携や、Stripe決済・Webhook通知など、外部のエコシステムと容易に連携できるよう、コア機能と外部連携モジュールを疎結合に設計しています。
インフラストラクチャ・デプロイメント構成図
📌 アーキテクチャの重要ポイント
- 厳格なネットワーク境界 : システムをPublic / Privateサブネットに完全分離しています。外部からの全トラフィック(ユーザー操作、Webhookコールバック等)は、Public領域の Nginx を単一の入り口として受け、TLS暗号化を解除した上でPrivate領域へプロキシします。
- セキュアな閉域網運用 (Private Environment):
ビジネスロジックを担う Django アプリケーション、PostgreSQL (DB)、Redis/Celery (非同期ワーカー) は全てPrivateサブネット内の Docker コンテナとして稼働し、パブリックインターネットから完全に隠蔽されています。
ER図
📌 設計の重要ポイント
- マルチテナントの絶対的隔離 (Tenant Isolation):
全ての主要テーブル(サブテーブルを含む)に tenant_id を伝播させる「冗長化設計」を採用しています。これにより、Django ORMのCustom Managerにて全てのクエリにテナントフィルターを強制適用でき、データ漏洩リスクをアーキテクチャレベルで排除するとともに、JOIN処理を減らしクエリパフォーマンスを最大化しています。
- 悲観的ロックと排他制御 (Pessimistic Locking for Concurrency):
「シフト枠 (Availability)」と「予約 (Booking)」の関係を厳格な 1 対 0..1 に設計しています。顧客の予約処理時には、対象の Availability レコードに対してデータベースレイヤーで select_for_update() による行ロック(悲観的ロック)をかけ、ダブルブッキングを完全に防ぐ仕組みを構築しています。