開発者ブログ

みんなで麻雀帳などWEBアプリのアップデート情報や、開発で活用しているAIツールでの試行錯誤の記録を発信します。

※当ブログの内容や技術情報については、公開時点の情報や個人の見解・見識に基づくものであり、特定の組織や団体を代表するものではありません。また、掲載情報の利用については自己の責任においてお願いいたします。

AI/技術情報

【技術解説】WEBアプリをAWSで構築する際のほぼミニマムのシステム構成と裏側の技術スタック

🚀 はじめに:迅速な開発と安定稼働を両立する技術選定


いつも「みんなで麻雀帳」をご利用いただきありがとうございます。

本サイトは、ユーザーの皆様からのフィードバックをもとに週単位、日単位の新機能追加やUI改善を続けています。こうした迅速かつ安定した開発プロセスを支えているのが、シンプルながらも堅牢に設計されたシステム構成(システムアーキテクチャ)です。

今回は、普段はユーザーの皆様の目に見えない「みんなで麻雀帳」の裏側のシステム構成やデータベース設計、およびリアルタイムなデータ処理の流れについて、技術的に解説します。
(※記載の設計や構成の内容は2026年6月4日時点の情報になります。)


  • --



🌐 1. システムアーキテクチャとインフラ構成


本アプリケーションは、信頼性とメンテナンス性の高さを考慮し、業界標準のWebアーキテクチャを採用しています。インフラにはAWS(Amazon Web Services)を活用し、安全で高速な通信を実現しています。

以下は、ユーザーがブラウザでアクセスしてからデータが処理されるまでの全体像を示したシステム構成図です。

システム構成図

# 🛠️ なぜ「3つのサーバー・機能」に分けるのか?


システム構成図を見ると、インターネットの先から「ロードバランサー」「Webサーバー(Nginx)」「APサーバー(Gunicorn)」という3つの役割が登場しています。
Djangoだけで直接リクエストを受け取るのではなく、わざわざ3つの層に分ける「関心の分離(役割分担)」こそが、安定稼働と高速化の鍵になっています。それぞれの役割と必要性を整理します。

## ① ロードバランサー(ALB)


  • 役割:アクセスの整理、制御する役割

  • なぜ必要か?

  • 負荷分散(スケーラビリティ):アクセスが急増した際、後ろにある複数のサーバーへリクエストを均等に振り分けます。

  • SSL暗号化の処理(SSL終端):HTTPS通信に必要な「暗号化・復号」の重い処理をロードバランサーが引き受けることで、後ろのWebサーバーのCPU負荷を大幅に軽減します。

  • 可用性の向上:万が一、後ろのサーバーの1台がトラブルで停止しても、生存しているサーバーへと自動で通信を切り替えます(ヘルスチェック機能)。



## ② Webサーバー(Nginx)


  • 役割:画像やCSSなどの静的ファイルの高速配信

  • なぜ必要か?

  • 静的ファイルの高速配信:HTML、CSS、JavaScript、画像といった「プログラムによる計算を必要としないファイル」は、Nginxがメモリやキャッシュから直接配信します。Pythonプログラムを起動させる必要がないため、ミリ秒単位の超高速レスポンスが可能です。

  • リバースプロキシによるセキュリティ:動的処理を行うAPサーバーを直接インターネットにさらさないための「盾」になります。一時保存(バッファリング)機能により、低速なネットワーク接続からのアクセスによって後ろのサーバーのプロセスが占有されるのを防ぎます。



## ③ AP(アプリケーション)サーバー(Gunicorn)


  • 役割:Pythonプログラムを実行と、Djangoとの接続役

  • なぜ必要か?

  • WSGIによるPythonプログラムの実行:Nginxやロードバランサーは、HTTPというWebの通信規格しか理解できず、Pythonのプログラム(Django)を直接動かすことはできません。APサーバーは、Nginxから届いたリクエストをPythonが解釈できる共通規格「WSGI(Web Server Gateway Interface)」に翻訳し、Djangoを実行してデータベースの読み書きや動的なHTML・JSONの生成を行います。



## 💡 もし分けなかったらどうなる?

もし「APサーバー(Django)」だけで直接インターネットからの全アクセスを受け取ると、重い画像の送信処理やSSLの暗号化計算、大量のアクセス要求がすべてPythonのプロセスに直接のしかかり、CPUやメモリがすぐにパンクしてサイトがクラッシュしてしまう危険があります。
このように、各役割を完全に分けることで、システム全体のパフォーマンスとセキュリティを最大化しています。


  • --



🐍 なぜWebフレームワークに「Django」を採用しているのか?


本システムの中核(APサーバー)で動作しているのが、Python製のフルスタックWebフレームワークである 「Django(ジャンゴ)」 です。なぜ数あるフレームワークの中からDjangoを選んだのか、その特徴とメリットを解説します。


  • 「バッテリー内蔵 (Batteries Included)」の設計思想


Djangoは、ユーザー認証、管理画面、ORM(データベース連携)、セキュリティ対策、フォームバリデーションなど、Webアプリケーション開発に必要な標準的機能があらかじめすべてパッケージングされています。小規模開発において、これら高品質な機能をイチから実装する必要がないため、開発速度を極限まで引き上げることができます。

  • 標準搭載された堅牢なセキュリティ


Web開発で常に脅威となる「SQLインジェクション」「クロスサイトスクリプティング(XSS)」「クロスサイトリクエストフォージェリ(CSRF)」などの脆弱性対策が、標準機能として強力に組み込まれています。セキュリティ設計をフレームワーク側が担保してくれるため、安心安全な対局保存・ユーザー登録環境を素早く実装できました。

  • Pythonの強力なデータ処理能力


麻雀の成績集計は、「平均順位」「連対率」「ラス回避率」「順位ポイント」「祝儀チップ」などが複雑に絡み合う計算処理が必要です。将来的にユーザーごとの戦術傾向や対局の統計分析など、高度なデータ処理を導入する際、豊富なデータ分析エコシステムを持つPythonでシステム全体を統一しておけることは非常に大きなアドバンテージとなります。


  • --



🗄 2. 複雑な麻雀データを表現する「データベース設計」


麻雀の成績管理は、実はデータベースの設計において非常に複雑なモデル構成を必要とします。1つの「半荘(対局)」の中に複数の「プレイヤー」が紐付き、それぞれの「スコア」や「着順」、さらには「チップ(祝儀)の枚数」などが相互に連動するためです。

本サイトでは、Djangoのオブジェクト関係マッピング(ORM)を最大限に活用し、以下のようなデータリレーション(関係性)を構築しています。

データベース設計図

# 主要なデータモデルと設計の工夫


  • プレイヤー (Player) & グループ (Group)


プレイヤー情報は、アカウントを持つ「ユーザー」と、アカウントを持たない「ゲストプレイヤー(身内のメンバーなど)」のどちらでも柔軟に登録できるよう設計されています。グループオーナーがメンバーを登録すると、そのグループに属するすべてのプレイヤーが、お互いの大会記録や通算成績をシームレスに共有・閲覧できるリレーションを構成しています。

  • 大会セッション (Session) & 半荘 (Hanchan)


1回のイベント(セットや大会)を `Session` として定義し、その中に複数の `Hanchan` が時系列(対局順)で紐付きます。半荘ごとに「チップ精算フラグ」を持たせることで、「通常の素点計算」と「チップの枚数精算」を同一のテーブル構造の中でスッキリと表現する設計工夫を行っています。

  • 成績結果 (Result)


各半荘におけるプレイヤーごとの最終持ち点(スコア)や着順、チップ枚数を個別に管理します(主キー/PKと外部キー/FKで強固に紐付け)。この細分化されたデータ構造のおかげで、「平均順位」「連対率」「ラス回避率」といった高度な戦績スタッツをリアルタイムに集計・可視化することが可能になります。

# 💾 データベースに「SQLite」を採用している背景と今後の展望


現在、データベースには軽量な 「SQLite3」 を採用しています。開発や運用の初期段階において、SQLiteには非常に強力なメリットがあります。

## SQLiteのメリット


  • サーバーレスで超軽量:データベース専用のサーバーを用意・管理する必要がないため、運用コストやインフラの複雑さを最小限に抑えられます。

  • 導入初期の手軽さ:ユーザー数が少ないサービス初期段階においては、データベースサーバーとの通信レイテンシー(遅延)もなく、単一のファイル(`db.sqlite3`)で完結するため、開発とデプロイの手軽さが非常に有効に機能します。

  • バックアップの容易さ:データ全体が1ファイルとして保存されているため、ファイルのコピーと保護(ダンプ)が極めて簡単で、データ消失のリスクを手軽に回避できます。



## SQLiteのデメリットと課題


  • 同時書き込みの限界:ファイル全体をロックして書き込みを行う仕様上、多くのユーザーが同時にデータを送信・更新するようになると、処理待ち(データベースロック)が発生し、アクセス速度低下の原因になります。

  • サーバー冗長化の難しさ:複数のWebサーバーから同時に同じSQLiteファイルに書き込むことが難しいため、将来的にインフラ規模を拡張(サーバーの複数台構成化など)する際のボトルネックになります。



## 🚀 今後のロードマップ:フルマネージドDB(RDS)への移行

現在はアクセス規模に見合った手軽さを重視してSQLite3で安定運用していますが、今後のユーザー数や対局データ数のさらなる増加を見据え、AWSのフルマネージド関係データベースサービスである 「Amazon RDS(PostgreSQLまたはMySQL)」 へのシームレスな移行を予定しています。これにより、高い同時書き込み性能と、マルチAZ構成によるさらなる堅牢性を確保していく計画です。


  • --



📲 3. リアルタイムなスコア入力データフローとセキュリティ


麻雀の対局が終わった直後に、いかにストレスなくスコアを入力し、エラーを防ぐことができるか。これは「入力UX(ユーザー体験)」において最も重視したポイントです。

以下は、スマホ画面からのスコア入力から、データ検証、保存までの流れを表したデータフロー図です。

リアルタイムデータフロー図

# スコア入力から保存までの3ステップ

1. モバイル最適化された入力画面 (モバイル入力)
スマートフォンの小さな画面でも数字の入力ミスを防ぐため、OS標準のキーボードではなく、HTML5/JavaScriptで実装された「麻雀専用のテンキーボード」を採用しています。
2. リアルタイムな不一致検証 (リアルタイム検証)
ユーザーがスコアを入力するたびに、ブラウザ(JavaScript)側でリアルタイムに計算が走ります。プラスとマイナスの合計を瞬時に判定します。集計点数が0になっていない場合は赤文字でその差分を表示し、入力ミスがある状態での「誤送信」を未然に防ぎます。(ただ、あえて場所代やトップ賞を除いて計算する場合があるので、0にならない場合でも登録はできる仕様にしています。)

3. セキュアな保存とトークン保護 (データベース保存)
サーバー側でDjangoによる二重のバリデーションチェックをクリアしたデータのみが、暗号化されてデータベースに書き込まれます。
また、作成された対局データの共有用URLには、推測が不可能な「UUID(ユニークなID)」を採用しており、第三者が当てずっぽうのURLを入力して他人の対局データを盗み見たり改ざんしたりするリスクを徹底的に排除しています。


  • --



🛡 4. セキュリティと安定運用のための対策


小規模アプリであっても、セキュリティや悪用(乱用)防止には細心の注意を払っています。


  • レートリミット(アクセス制限)による保護


大量の自動プログラム(ボット)などによるサーバー負荷を防ぐため、一定時間内の対局作成数に制限(レートリミット)を設けています。

  • Google reCAPTCHA v3 の導入


フォーム送信時におけるスパム投稿を防ぐため、Google reCAPTCHAによるバックグラウンドでの信頼性評価システムを組み込んでいます。

  • SEOと検索エンジン最適化


`sitemap.xml` をDjango側で動的に自動生成する仕組みを実装し、一般公開された対局データやブログ記事がGoogle等の検索エンジンに正しく登録(インデックス)され、他の麻雀プレイヤーが検索からアクセスしやすいようにSEO対策を行っています。


  • --



🏁 まとめ


「みんなで麻雀帳」は、このようなシンプルで無駄のないシステム構成にすることで、サーバー負荷を極限まで抑えつつ、ページの表示速度を極めて高速に保つことに成功しています。

これからも、技術的なアプローチから「最も使いやすい麻雀スコア管理ツール」を目指して進化を続けていきます。
引き続き「みんなで麻雀帳」をよろしくお願いいたします!

← 次の記事 スマホでノンストレス入力!麻雀スコア入力用のカスタムテンキーUI/UXの設計と実装
前の記事 → 【機能紹介】アカウント作成で使える「成績ランキング」と「個人戦績分析」の魅力