【高校生が作ってみたシリーズ】高校生が体育祭向けのアプリをゼロから1ヶ月で作った話

# はじめに
はじめましての方は、はじめまして。以前、記事を見たことのある方は、お久方ぶりです。

この記事では、先日に行われた体育祭で使用した運営システムを制作したので、その備忘録的な記事になります。所々、変なことを書いてるかもしれませんが、そこはご愛嬌ということで...


# 運営システムを制作することになった経緯
なぜ、システムを制作することになったのか。

私が通っている学校では、生徒会が中心となって、各イベントの企画、準備、運営まで行っています。体育祭とか、文化祭とか、その他諸々のイベントのことですね。

私事にはなりますが、3年ほど生徒会に携わっておりまして、毎年、体育祭を運営している中で、感じていたことがありました。

**「得点の管理やらエントリーの管理が煩雑すぎ！！」**

そうなんです。管理担当といい、管理方法といい、すべてが複雑怪奇だったのです。

そんな思いもあったので、昨年度は、[Glide](https://www.glideapps.com)というノーコードでアプリを制作できるサービスを実験的に利用して、得点の管理部分のみをデジタル化しました。

 **そしたら、思った以上に良い。良すぎた。うん。**
 
 
じゃあ、今年度は、

**「すべてを集中管理できるツール(サービス?)を制作してやる！」**

と~~安易な考えの元~~、思い立ったのが~~地獄の~~始まりでした。

# 気合十分！よし、制作するぞ！
と気合いを入れて、作り始めたのが、ゴールデンウィーク(大型連休)中の出来事。

# なにで作っていくか問題
最初に問題になったのは、何で作っていくか。
これに尽きた。

結論としては、フロントエンド部分は、
　・HTML
　・CSS
　・JS
バックエンド部分は、
　・Python(Flask)
　・Jinja2
　・PostgreSQL
を利用して、制作しました。
(ちなみに、テンプレートとして「[Material Dashboard 2](https://www.creative-tim.com/product/material-dashboard)」を活用しています。)

なぜ、Pythonなのかといいますと、
 
**「使い慣れてる」かつ「制作時間が圧倒的にない」**

以上。
当初は、Flutterで作ろうかなと思ってた。(思ってたんですよ！！)
でも、ゼロから1ヵ月で作るのは厳しい。(しかも、途中で定期テストもある。)
なので、制作経験のあるFlaskにしました。(深い理由はない)
 
 # 必要な機能の洗い出し
 制作をするにあたって、必要な機能を洗い出して、進めていきました。
 制作をしていく中で、随時追加した機能もありますが、結果としては、
## ダッシュボード機能
機能としては、
　・リアルタイムでトップのチームが確認できる
　・現在、競技中のプログラムが確認できる
　・次に予定されているプログラムが確認できる
　・天気予報(降水確率/最高気温/最低気温)
などが挙げられます。
![](https://storage.googleapis.com/zenn-user-upload/268da9a0b605-20230611.png)

## エントリーシステム
エントリーシステムには、主に2つの機能に分類することができ、
　・競技に出場する人や補欠をエントリーすることができるシステム
　・エントリーした内容を確認することができるシステム
 があります。

「チームの管理」と「ログインシステム」と連携しており、チームを作成すると、自動的にそのチーム固有のユーザー名とパスワードが発行されます。発行されたアカウントでログインすることで、チームごとにエントリーすることができます。(管理者は、すべてのチームのエントリー情報を確認することができます)

管理者でログインした場合のエントリー画面
![](https://storage.googleapis.com/zenn-user-upload/fe0b68d8b591-20230611.png)
各チームに発行されたアカウントでログインした場合のエントリー画面(Aチーム)
![](https://storage.googleapis.com/zenn-user-upload/34641206c9fb-20230611.png)
エントリーを行う画面
![](https://storage.googleapis.com/zenn-user-upload/2eb4ee755a8c-20230611.png)
管理者は、エントリーを締め切ることができる機能もある(Aチーム)
![](https://storage.googleapis.com/zenn-user-upload/4b291d3ac8c5-20230611.png)

エントリーが完了すると、エントリーを確認することができるようになります。
現状、二つの画面に分かれていて、使っていて不便なので、一つの画面に統一するつもりです。
エントリーの確認だけでは、イマイチ、デジタルを活用する意味がないと思い、「欠席報告」機能と連動しており、当日に欠席報告がある生徒がエントリーされていると、自動的に赤くハイライトされるようになっています。

一見すると、エントリー画面と変わらない
![](https://storage.googleapis.com/zenn-user-upload/6104af4af056-20230611.png)
エントリーの確認画面(個人情報はスポイラーしています)
![](https://storage.googleapis.com/zenn-user-upload/9d316bae95d7-20230611.png)

## 得点の記録
名前の通り、各競技の得点を記録することができます。
![](https://storage.googleapis.com/zenn-user-upload/a8062685883f-20230611.png)

## チームの管理
チームの登録や削除などができます。
機能としては、
　・現在の総合得点
　・総合得点に基づいた、現在の順位
　・各チームのチームリーダー＆副リーダーを登録
　・ログインIDとパスワード
将来的には、チームメンバーの管理をこの画面に統合する予定です。(今回は、直接DBに登録した←制作時間が足りなかった)

チームの一覧画面
![](https://storage.googleapis.com/zenn-user-upload/d9b9f0c34615-20230611.png)
チームの編集画面(登録画面も同じような画面)
![](https://storage.googleapis.com/zenn-user-upload/89beb5c69130-20230611.png)


:::note warn
チームメンバーのデータは、すべて暗号化しており、万が一、漏洩しても秘密鍵(パスフレーズ)がないと、復号化できない設計になっています。
:::

## スケジュールの管理
当日のスケジュールを登録することができます。
機能としては、
　・当日のスケジュール(競技以外も含む。例えば、開会式とか休憩とか)の登録/削除
　・競技の場合、競技ごとの出場人数/補欠人数の登録(エントリーシステムの連携している)
　・時間の登録
などが挙げられます。

スケジュール一覧
![](https://storage.googleapis.com/zenn-user-upload/c6b043c6cd72-20230611.png)

編集画面
![](https://storage.googleapis.com/zenn-user-upload/a4564e520a41-20230611.png)

## 欠席報告
当日に欠席した生徒を教員が報告することで、エントリーの確認画面で欠席している人が赤くハイライトされるようになります。すぐに、欠席している人を把握できるので、補欠メンバーを入れなければいけないかどうかの判断がすぐできるようになりました。
![](https://storage.googleapis.com/zenn-user-upload/a870afec7d92-20230611.png)

## アカウント管理(ログインシステム)
教員向けだったり、生徒会向けだったり、必要に応じて、組織ごとのアカウントの発行ができます。「権限もいじれるので、割とあると便利な機能だよね。」という理由から、導入しました。

アカウント一覧
![](https://storage.googleapis.com/zenn-user-upload/e87c38b71d8a-20230611.png)

いーーじょう！結構、盛沢山になってしまいました。
~~これを一か月で制作した自分、すごいと思う()~~

# テーブル設計
と、書こうと思ったのですが、そんな大層なことはしておりません。制作していく中で、必要なテーブルやカラムを随時、追加してました。(後々、自分の首を締めることになるのは、後の祭り...)

# インフラ関連
この記事の主軸とは少しずれてしまいますが、本校では、昼休憩の時間に生徒からリクエストのあった曲をランダムで選曲して、放送する校内放送を行っています。その活動(?)の中で、「リクエスト曲からランダムに選曲するシステム」を既に開発して、実際に活用しています。そのシステムが、Docker環境内で動作しているので、この校内放送システムに統合しました。

また、外部ネットワークからアクセスできるように、[Ngrok](https://ngrok.com)を活用して、外部からアクセスできるようにしました。

### 動作環境
　・RaspberryPi 4(4GBモデル)←学校の
　・Ubuntu22.04.01LTS
　・Docker
 
# コード管理
コードの管理は、自宅のローカルネットワーク内にセルフホスト型の「[Gitea](https://gitea.io/en-us/)」を構築していたので、こちらですべて管理しました。
![](https://storage.googleapis.com/zenn-user-upload/6639545b9116-20230611.png)
![](https://storage.googleapis.com/zenn-user-upload/63b2c73d4378-20230611.png)
![](https://storage.googleapis.com/zenn-user-upload/ca932d86d4af-20230611.png)


# 苦労したところとか、後日談的な何か
### SQL文が複雑。
条件が複雑に絡み合うので、割と苦戦しました。ほとんどのSQL文は、最近、話題の「対話型AI」にテーブル設計と取得したい内容及び条件をぶん投げて、AIにSQL文を生成してもらってました。AIの活用もあってか、大幅な開発期間の短縮には繋がってると思います。(やはり、AIは使い方次第で、物凄い威力を発揮することがわかった。)

:::details 実際に使ったプロンプト
```
下記の条件に合うように、SQL文を生成してください。

# テーブル設計
## user
　・user_id(serial)
　・user_name(text)
　・user_password_hash(text)
　・user_permission(text)
## schedules
略

# 取得したい条件
　・users.user_permissionとcurent_user.permissionが一致するuser_id
略

# 追加条件
　・ORDER BY句を使って、user_idで並べ替えること
```
:::

### 権限別に表示内容を変えることの大変さ
ログインシステムがあるのだから、アカウントごとに権限制御できたら、いいよねという理由から、権限を制御できる機能を導入しました。(そのせいで、)権限ごとに表示する内容だったり、例外処理だったりが、複雑になってしまいました。参考に、Discordの権限管理ってどのように制御しているのかなと調べてみたのですが、ちんぷんかんぷんでした... やはり、複雑になってくると、メンテナンス性や可読性が失われていってしまうので、どうにか改善していきたいところ。最適解があれば、教えて下さい。勉強します。

### メンテナンス性と可読性をどう維持するか(これからの話)
そうなんです。実際、コードが冗長化してしまい、途中からFlaskのblueprintを使って、機能ごとに切り出して、別のファイルに書くように仕様変更しています。でもやはり、機能が増えると、複雑化してしまうので、メンテナンス性と可読性の維持・担保が難しくなっています。(特にSQL文の部分)

この問題を、如何に解決していくかが、今後の課題の一つです。

### やっぱり、一人はキツイ。
コーディング作業から、デバッグ作業、インフラの整備(OSの準備から、DBの構築などなど)まで、一人で請け負うことになるので、当然と言われれば、当然なのですが、やはり、**1人はキツかった**です。二人ほどいると、もう少し楽にできたのかもしれませんが、学校内でここまでガッツリコーディングできる人がいなかったので、仕方がないのかなと思っています。(一緒に開発してみたい！！という同じ志のある方、是非一緒にやりましょう！TwitterのDMまでお待ちしております)

### 1ヵ月の突貫開発をやってみて
もうやりたくないです。(結構ガチで)

でも、勉強にはなりました。実際、SQL文の書き方だとか、Flaskの構文だとか、今まで知らなかったことが多かったので、(キツイですが、)楽しかったのが正直なところ。

**でも、もう一回やりたくはないです！**

# 今後の展望
今回、導入してみて、色々と課題の洗い出しができたので、その課題を一つずつ解決していこうと思っています。今は、リファクタリングを兼ねて、v2の開発を進めているので、ちょこちょこ進捗記事を出すかもしれません。その時は、有識者の皆さん、どしどしアドバイスを頂ければ...！と思っています。

# さいごに
長々とお読みいただき、ありがとうございました。
そして、協力していただいた先生方に、この場をお借りして、感謝申し上げます。

この記事だけでは伝わりきらない点があると思いますので、是非是非コメントで質問して頂ければと思います。ではでは。