AQ Tech Blog

インターン生による「POPダンス図鑑」開発の記録

作成者: yuto.yano|2026年04月27日

はじめに

はじめまして!私は2026年卒のアジアクエストのインターン生です。 現在は大分県の大学に在学しており、アジアクエストの別府オフィスにてインターン生として参加させていただいています。(執筆時)

本記事は、文系大学の私が、初めて本格的なWebアプリケーション開発に挑戦した約2ヶ月間にわたるデモプロジェクトの記録です。「一つのアプリができるまでの具体的な流れを知りたい」という方、及び開発を始める前の自分自身にとって役立つ内容を目指して、今回のプロジェクトを通じて得た学びをまとめました。

デモプロジェクトについて

開発した「POPダンス図鑑」とは

私がデモプロジェクトのテーマに選んだのは、私の趣味であるPOPダンスの技術を図鑑のようにまとめたWebアプリケーションです。

POPダンスとはストリートダンスの一種で、ロボットのような不思議な動きをしたりするのが特徴です。POPダンスには非常に多くの技やスタイルがあるため、自分なりに情報を整理できる場所があれば、より効率よく楽しく練習が進められると考え、今回のテーマにPOPダンス図鑑を選びました。

また、「今日は何を練習したら良いかわからない…」という時に、ランダムでお題を提案してくれる練習テーマルーレット機能も搭載することにしました。

今回学んだ技術

今回の開発では以下の技術スタックを採用しました。初めて触れるものばかりでしたが、AIのGeminiを利用しながら、一つひとつ内容を学習して進めるようにしました。

カテゴリ 技術・ツール 役割
Infrastructure Docker, Docker Compose, GitHub 環境構築の再現性、コード管理
Development Tools Visual Studio Code, DBeaver コード編集、DB操作の効率化
Backend Python, Flask アプリのロジック実装
Database PostgreSQL 技データ・練習テーマデータの蓄積
Frontend CSS, JavaScript デザイン、動きのある機能実装
Storage MinIO 画像のファイル管理
Design draw.io 設計図・画面遷移図の作成


開発の4つのフェーズ

プロジェクトは、以下の4つのステップで進めました。

フェーズ 期間 主な内容
1. 環境構築 2日間 Docker / Flask環境構築、GitHub連携
2. 設計 2日間 DB・API設計、画面遷移図の作成
3. 実装・開発 10日間 主要機能実装、UI/UX調整
4. テスト 4日間 テスト設計書作成、検証

1. 環境構築

プログラムを書く前に、まずはPC上でアプリが正しく動くための環境を整えました。

フォルダの作成

環境構築の第一歩として、まずはプロジェクトの核となるフォルダ(ディレクトリ)の作成から着手しました。PCのローカル環境にsrcというフォルダを作り、さらにその中にpopdance-appというフォルダを作成しました。以降に作成していくものはすべてこの中に入れます。

Dockerfileの作成

今回、環境構築にはDockerという最も主流なコンテナサービスを利用しました。

コンテナとはアプリの実行に必要なもの(コード、ライブラリ、設定など)をすべて一つに詰め込んだ仮想環境です。コンテナを利用することで、パソコンに直接様々なものをダウンロードせずとも開発を進めることができました。例えば、今回のケースでは、Pythonというプログラミング言語を使用したため、本来であればPCにPythonをインストールしてから開発をしなければいけないはずでした。しかし、Dockerを利用し、Pythonがインストールされた仮想環境を構築することでPCの設定には影響を与えずに開発が行えました。

また、コンテナを利用し、仮想環境を構築することでハードウェアごとの差を考慮しなくて良くなるため、複数人での開発や本番環境への移行も楽になります。

このDockerで仮想環境を動かすために、先ほど作ったpopdance-appフォルダの中に「Python実行環境」の作り方を記述したDockerfileを作成しました。作成には、エンジニアに広く愛用されているコードエディタ Visual Studio Code (VS Code) を使用しました。

これにより、誰でも同じ開発環境を再現できる土台が整いました。

docker-compose.yml の作成

Dockerfileで定義した Python 実行環境に加え、アプリに必要なデータベースやストレージをまとめて管理するためにdocker-compose.ymlを作成しました 。

通常の場合、アプリ本体とデータベースなどは別々に起動して接続設定を行う必要がありますが、docker-compose.ymlを用意することで、複数のコンテナを一つのネットワーク内で連携させることができます。.ymlという部分はYAMLというファイル形式を示しています。

このアプリの構成には、システムを「プレゼンテーション層」「アプリケーション層」「データ層」の3層に切り分けて構成する3層アーキテクチャという設計手法を採用しました。それぞれ「見た目」「司令塔」「保管庫」の役割を果たします。

今回のプロジェクトでは、以下のサービスをdocker-compose.ymlに定義しました。

Flask

  • アプリケーション層(司令塔)
  • Pythonで書かれたWebアプリケーションフレームワーク


PostgreSQL

  • データ層(保管庫)
  • 信頼性の高いオープンソースのリレーショナルデータベース

 

MinIO

  • データ層(保管庫)
  • 画像や動画などを保存・管理するためのストレージ

MinIOというサービスは開発段階に入ってから途中で必要に駆られて開発用に設定しました。本番環境で使用したいAWSのストレージであるAmazon S3と互換性をもち、ローカル環境で扱えるため擬似的なS3として利用しました。

これらの設定を一つのファイルにまとめたことで、docker-compose upというコマンド一つで、複雑に連携し合う全サービスを一斉に起動できる環境が整いました 。

2. 設計

環境が整ったところで、具体的な設計に入りました。ユーザー側の視点から内部構造へと段階的に設計を固めていきました。

画面遷移の設計

まずはユーザーが画面をどう操作するかの仕様を固めました。

draw.io を使用し、以下のように画面遷移図を書き、必要な画面とそれらがどう繋がるかを可視化しました。

データ構造の設計

次に、システムで扱うデータベースの内容を整理しました。

  • テーブルの定義: Excelのような一つの表形式のデータベースの中に何を書き込むのかを定義します。今回のプロジェクトでは技の情報を管理するskillsテーブルと、練習テーマを管理する practice_item テーブルの2つを定義しました。
  • カラムの定義: カラム(表の縦項目)にどのような種類のデータをどのような形式で書き込むかを定義します。今回のプロジェクトのskillsテーブルでは、技名を記すcontentや技の概要を記すdescription、その技の解説をしている動画のURLを保存するvideo_urlなど計8つのカラムを定義しました。同様にpractice_item テーブルにおいても5つのカラムを定義しました。

 

詳細仕様の設計

最後に、プログラムとして実装できるレベルまでシステム内部の具体的な動きを定義しました。

ロジック設計

ここでは、ユーザーの操作に対してアプリがどう反応するか、主要な 3 つの仕組みを考えました。

  • ルーレットロジック: データ層のskillspractice_itemの両テーブルからFlaskを介して全データを取得します。その中からローカル環境で動くJavaScriptという言語で一つのデータを選び表示します。
  • 検索ロジック: 技の名前や解説文など、複数の項目を対象にキーワードを探しに行きます。以下のようなSQL文を利用して大文字・小文字を気にせず、一部の言葉が合っているだけでも見つけ出せる「あいまいな検索」ができるように設計しました。
SELECT * FROM (
SELECT 'skill' as type, id, content, content_jp, category, description, description_detail
FROM skills
UNION ALL
SELECT 'practice' as type, id, '' as content, content_jp, category, description, '' as description_detail
FROM practice_item
) AS combined_data
WHERE (content_jp LIKE %s OR content LIKE %s OR category LIKE %s OR description LIKE %s OR description_detail LIKE %s)
  • お気に入りロジック: ブラウザ側のローカルストレージに技のIDをリストに保存します。お気に入りページを開くとリストにあるIDを参照してデータベースから詳細を取得し、表示します。

この段階では、「ルーレットロジック」と「お気に入りロジック」をどう作るかで頭を悩ませました。

ルーレットロジックでは、ページ遷移時に全データを読み込む「事前一括取得方式」と、ボタンを押すごとにサーバーへ問い合わせる「都度リクエスト方式」を比較しました。最終的には、ダンス練習中のリズムを損なわないUIを優先し、前者の「事前一括取得方式」を採用しました。データの数が膨大になった時に画面取得に時間がかかったり、端末が重くなったりするのではないかと考えましたが、今回のアプリではそこまでデータの数が多くなることは考えにくく、通信回数を減らすメリットの方が大きいと判断しています。

また、お気に入り機能についても「ユーザー登録制」にするか、今回の「ローカルストレージ保存」にするかで迷いました。本格的なアプリならサーバー側にユーザー情報を保存するのが一般的ですが、今回は「利用のハードルを下げること」を優先し「ローカルストレージ保存」を採用しました。

API 設計

API(Application Programming Interface)とは、プレゼンテーション層であるブラウザとアプリケーション層であるサーバーをつなぐ窓口のようなものです。今回は、以下の 2 つの形式(メソッド)を使い分けました。

  • GET メソッド:サーバーから情報を「取得」するときに使います。
  • POST メソッド:サーバーへ情報を「送信」するときに使います。

このルールに基づき、3 つのAPIを用意しました。

APIエンドポイント メソッド 役割
/api/roulette GET skillsとpractice_itemの全データを一括取得
/api/search GET キーワードに基づき、複数カラムを対象とした「あいまい検索」を実行
/api/favorites POST ローカルストレージのIDリストを送信し、データベースから詳細データを一括取得

以上が本アプリの設計指針です。これらの設計はREADME.MDというファイルにマークダウン形式という書き方でまとめました。

実際の開発では状況に応じた他の機能も作成していくことになりましたが、この基本設計を軸に据えることで、一貫性を持った「実装・開発」フェーズへと移行することができました。

3.実装

実装フェーズにおいて、設計を具体的な形にするために作成したものは以下の3つです。

  • main.py:Flask(python)で作成した アプリケーションの「司令塔」であり、全ロジックを制御する中心的なファイルです。
  • templates フォルダ: ユーザーが実際に目にする「画面」を構成する HTMLファイルがすべてここに入っています。
  • init.sql: データベースの構造と初期データを管理するための設定ファイルです。skillsテーブルやpractice_itemテーブルの定義、および初期データを投入するための SQL 文をここにまとめたファイルです。

 

main.py

ユーザーがブラウザからこのWebアプリにアクセスした際、そのリクエストを真っ先に受け取るのがこのmain.pyです。今回のプロジェクトではFlaskフレームワークを通じて、以下の 3つの重要な役割を一手に担っています。

  • 外部サービスとの連携: 画面からの要望に応じてPostgreSQLから技データを引き抜いたり、MinIOに保存された画像を呼び出したりするための接続管理を行っています。
  • ルーティング(交通整理): ユーザーが「トップ画面を見たい」「ルーレットを回したい」といった要求(URL)に対して、どの HTMLを表示するか、どのデータを準備するかを判断し、適切に誘導します。例えば、ユーザーのアクセスを受け、トップページ(top.html)を表示するために、次のようなルーティングを設定しました。
@app.route('/')
def top():
return render_template('top.html')
  • APIの定義: 設計段階で定義したAPIをこのファイルに具体的なプログラムとして記述します。たとえば、お気に入り一覧を表示するためのデータ取得 APIは以下のように記述しました。
@app.route('/api/favorites', methods=['POST'])
def get_favorites():
data = request.get_json()
fav_ids = data.get('ids', [])
if not fav_ids:
return jsonify([])
query = "SELECT id, content, content_jp, category FROM skills WHERE id = ANY(%s)"
fav_skills = execute_query(query, (fav_ids,), fetch="all")
return jsonify(fav_skills)


templatesフォルダ

templatesフォルダには、アプリの全画面に対応する HTML ファイルが格納されています。今回見た目を指定するCSSファイル、ブラウザ上の動きを作るJavaScriptファイルは作らず、ページ毎にHTMLファイルを作りその中にCSSもJavaScriptも書き込んでいます。

はじめに、webアプリの入口として、トップページを作成しました。top.htmlファイルをtemplatesフォルダ内に作成し、そこに最低限のHTML、CSSをそれぞれ書き込み次のようなトップページを作成しました。

作成したページをブラウザで確認するために、自分の PC 内で動いているサーバーに接続する必要があります。通常、インターネットでWebサイトを見るときは、ブラウザからサーバーと呼ばれる世界中のどこかにある他のコンピューターへデータを取りに行きます。しかし開発中は、とりあえず自分のPCをサーバーとして動かし、ブラウザから自分のPCにアクセスして見た目や動作などを確認します。

今回、ブラウザの URL 欄に http://localhost:8080と入力してアクセスしました。これはローカルホストのポート番号8080番にアクセスしてという意味です。

  • ローカルホスト(localhost): 操作しているコンピュータ自身を指す住所です。
  • ポート番号: そのハードウェアの中でどのアプリ(プログラム)が通信するかを仕分けるためのドアの番号です。

http://localhost:8080にアクセスしたところ、以下のような画面が表示されました。


その後も、同様にページを増やしていき、設計段階の画面遷移図の際に定義した必要な画面6つを作成しました。

init.sql

システムの土台となるデータを管理するためのinit.sqlを作成しました。これは、データベースの「設計図」と「初期の中身」を一つにまとめたファイルです。

このファイルには、主に以下の3つの内容を記述しています。

  • 元あるデータの削除: 実行時に一度テーブルを削除、あるいは中身を空にする SQL 文を記述します。これにより、古いデータや重複データが残るのを防ぎ、何もない状態からセットアップを開始できます。
  • テーブル定義(スキーマ): skills(技情報)やpractice_item(練習メニュー)といった表の枠組みを作成するSQL文です。
  • 初期データの投入: アプリを立ち上げた瞬間に、すでにいくつかの技や練習テーマが登録されている状態にするためのSQL文です。

このファイルを作った段階で、すでにDockerの中でデータベースは動いていました。しかし、このファイルがあることによってこのファイルに定義したデータベースを自分のPC、または他の人のPCの中でコマンド一つで再現することができます。

実際、開発中にデータをいじっているとデータベースが汚くなっていくことがありました。そのような時に次のコマンドを一度入力するだけで初期状態に戻すことができます。

docker exec -i postgres_db psql -U user -d popdance_db < init.sql


追加機能・デザイン

基本的な骨組みができた後、設計段階の計画(画面遷移図)にはなかった以下の要素を追加実装しました。

データ追加機能

データベースを直接操作しなくても、ブラウザ上の管理パネルから「新しいデータの登録」や「既存データの修正・削除」ができる仕組みを構築しました。技用のパネル、練習テーマ用のパネルからそれぞれ、追加、更新、削除ができるようにしました。MinIOを利用した画像のアップロードや、YouTube動画のURL紐付けもここから簡単に行えるよう工夫しています。

サイドバー

全ページ共通の土台となるlayout.htmlを作成し、サイドバーを導入しました。これにより、どの画面からでも一瞬で目的のページへ移動できる直感的な操作性を実現しました。

デザインの更新

アプリ全体の統一感を持たせるためにデザインの全面的な更新を行いました。layout.htmlやそれぞれのページのCSSを利用しすべてのページを黒や金を基調としたシックなデザインに変更しました。


ルーレットのフィルター機能

当初の設計では全データをランダムに選ぶだけのシンプルな仕様でしたが、特定のカテゴリーに集中して練習ができるようにするためにフィルター機能を追加しました。JavaScriptを用いて対象データをブラウザ側で抽選するという処理を書きました。

この機能では、技のカテゴリー(ベーシック、スタイル等)や練習メニュー(リズム、縛り等)を自由に組み合わせて抽選対象に含めることができます。特にこだわったのは「お気に入りモード」との連携です。「お気に入り技のみ抽選」をONにすると他の設定を一時的に無視し、LocalStorageに保存された特定の技だけを抽出するようにしました。

検索のフィルター機能

技の数が増えても、ユーザーが目的のデータにすぐ辿り着けるよう、フィルター機能を検索結果ページに実装しました。ルーレットフィルターと同様に、特定のカテゴリーやお気に入りに限定して検索をかけられるような機能になります。

また、検索ページでは「オリジネーター検索機能」を実装しました。POPダンスにおけるオリジネーターとは、そのダンススタイルや特定の技を「創始した人」や「形作った先駆者」を指します。技の解説文に含まれる「Boogaloo Sam」や「Mr. Wiggles」などの名前をキーワードとして検知し、該当する技だけを抽出します。

スマホ対応

スマホからでも快適に操作できるよう、レスポンシブデザインになるようにデザインを変更しました。レスポンシブデザインとは、画面サイズに応じて、ページのレイアウトやデザインを自動的に最適化する制作手法のことです。

スマホから見た各ページのレイアウトなどをブラウザの開発者ページから確認し、少しずつフォントなどをしながら画面を整えます。また、実際に自分のスマホからもこのPCのIPアドレスに接続し、動きやレイアウトを確認しました。

タイマー機能

一つのテーマに集中して取り組めるようにという意図で、練習時間を計るためのタイマー機能をルーレットページに実装しました。ローカルストレージを用いて、ページが遷移してもタイマーがリセットされないように工夫しました。

しかし完成後、IT業界にはYAGNI原則という原則があることを知り、このタイマー機能の必要性について再検討しました。YAGNI原則とは、「You Ain't Gonna Need It(そんなものは必要にならない)」の頭文字をとった言葉で、「将来必要になるかもしれない」という予測だけで機能を追加せず、「今まさに必要な機能」だけを実装すべきという考え方です。

ほとんどのデバイスには、時計機能がついている上にダンスの練習は曲単位で行うことが多いので、重要度は低いと感じました。そのため、UIをシンプルに保ち、不具合の原因となることを防ぐため、今回はこの機能の削除することにしました。
 

4.テスト

開発の最終段階として、作成した機能が設計通りに動くかを確認するためのテストを行いました。今回のプロジェクトでは、当初設計していた機能が揃った段階と、最終段階の2回にわたって検証作業を実施しました。

テスト段階では、プログラムの最小単位を検証する「単体テスト」や、システム間の連携を細かく見る「結合テスト」といった厳密な分類は行いませんでした。

まず、スプレッドシートでテスト設計書を作成します。正常なページ遷移などを確認する項目や検索欄にでたらめな文字列を入れて挙動を確認する項目など約50項目のテストを作成しました。そして、実際にアプリを動かし、テストを行った結果をスクリーンショットで保存して、テストエビデンスとして別のスプレッドシートにまとめました。

テストを通じて、細かいレイアウトの崩れやバリデーション(入力チェック)の不足を早期に発見・解消することができました。

まとめと今後の展望

今回のデモプロジェクトを通じて、環境構築や設計からテストまでのWeb開発の流れをつかむことができました。また、様々な技術やツールに触れ、役割や使い方を学ぶことができたのは自分の中で大きな収穫でした。

このあとは、開発したWebアプリを多くの人がアクセスできるサーバー上に配置し、実際のユーザーが使える状態にするデプロイという作業に移っていきます。また、この「POPダンス図鑑」を実際にダンサー仲間に使ってもらい、フィードバックをもとにさらにUI/UXを磨き上げていきたいです。

本記事を通して、読んでいただいた方のWeb開発を始めるハードルを少しでも下げることができれば嬉しいです。
最後まで読んでいただき、ありがとうございました。