4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

高校の文化祭の整理券システムを作ったら色々勉強になった話

Last updated at Posted at 2025-12-13

はじめに

期末テスト期間中、電車に揺られているとGmailから1件の通知が来ました。

Gmailの通知 (Qiitaニュースメール)

「あれ、俺こんな記事書いたっけ」と一瞬思いました。というのも、私も今年の文化祭で整理券システムをワンオペした経験があるからです。

使用技術も学校の環境も全然違いましたが、同じような経験をしている高校生がいるんだなぁと思ったら少しうれしくなったので、私も体験談を書くことにしました。コメント欄で沢山の人から励ましの言葉やアドバイスを受けているのを見て羨ましくなったわけでは決してありません。

システム開発について周りに相談できる人がいないので、至らない点などご指摘いただけたらとても嬉しいです。

開発の経緯

「整理券システムって作れたりしない?」
文化祭実行委員会に所属している先輩から連絡があったのが始まりです。

どうやら過去、人気クラスの前に長蛇の列が発生して危険な状況になることが度々あったそう。人気になると予想されるクラスに整理券システムを貸し出し、解決を図りたいのだといいます。

数回話し合いを重ねた結果、

  • 整理券は各クラスに足を運んで取得する
  • 同時に一枚しか取れないようにする

という要件で開発を進めることになりました。

「あえて不自由さは残して、文化祭を回る時間を楽しんでほしい」という魂胆のようです。

作ったもの

来場者のLINE画面(LINE BOTからの呼び出し通知) 
↑ 来場者のLINE画面(呼び出し時)

Web呼び出し画面
↑ クラスの受付担当者が操作するWeb呼び出し画面

当日の紙整理券表示モニター
↑ 文化祭当日の紙整理券 表示画面

QR読み取りのイメージ 
↑ QRコード読み取りのデモ

特徴

  • 公式LINEから通知が飛んでくる
  • 友だち追加不要
  • クラスの受付に表示されているQRコードを読み込みメッセージを送信することで整理券を取得する

使用方法(来場者目線)

  1. クラスへ行く
  2. 受付でQRコードを読み取る
  3. LINE上に自動入力されたメッセージを送信して整理券を取得
  4. 順番を待っている間に他のクラスを回ったり休んだりする
  5. 呼び出しメッセージが来たらクラスへ行く

主な機能

  • QR更新による不正アクセス防止
  • 待ち人数から推定呼び出し時刻を表示する機能
  • カメラが破損していてQRコードが読み取れない時のためのワンタイムトークン
  • LINEやスマホが使えない場合の紙整理券登録、表示
  • DoS攻撃に対する警告と制裁
  • 文化祭終了後のアンケート用のメッセージ一斉送信(管理画面)

完成までの流れ

10月の文化祭まで、約4か月間の準備期間がありました。テストや部活と平行しながらコードを書くのは日課になっていたので、特に苦ではありませんでした。

  • 6月:話を持ち掛けられる、仕様決定
  • 7月:プロトタイプ完成
  • 8月:概ね完成
  • 9月:マニュアル制作、運用方針確認
  • 10月:対象クラスへの説明、本番環境へのデプロイ、直前の機能追加

1. 仕様決定

余計な情報を保存すると事故につながります。
取得するユーザー(来場者)の個人情報は最小限に留めたいものです。

メールアドレスや電話番号の入力は論外。ユーザー体験向上の観点から、アカウント登録などの作業は避けなければなりません。

【案1】 ネイティブアプリ(即没)

ネイティブアプリなら、デバイスIDを使ってユーザーを識別することができます。アカウント登録はスキップできるでしょう。
しかし、アプリをインストールするという行為は、ユーザーにとって非常にストレスになります。たかが文化祭のためだけに一介の高校生が作ったアプリを入れたいと思う物好きはいません。

他にも、2つの大きな壁があります。

1つ目は私がネイティブアプリ開発に慣れていないことです。Swiftを触ったことはないですし、クロスプラットフォーム対応は面倒です。React NativeやFlutterはアプリサイズが無駄に大きくなるのでユーザーのギガに優しくないでしょう。

2つ目はApple Developer Programに登録できないことです。つまりApp Storeでの公開ができません。年間約2万円の登録料と20歳以上の体が必要になります。

以上の理由から、この案は頭に浮かんだ5秒後に葬り去られました。

【案2】 Webアプリ / PWA(没)

想定する流れは次の通りです。

  1. 来場者がクラスにやってくる
  2. 先客が多い場合はQRコードを読み取って、ブラウザで整理券を発券する
  3. 順番になったらプッシュ通知を受け取る

[デメリット1] ユーザーの特定が難しい

スマホに複数のブラウザを入れている人は少なくないと思います。複数のブラウザを使えるということは一人何役もできるので、整理券の不正取得が横行する可能性があります。

また、QRコードを読み取ってページを開いてもらう以上、沢山の懸念点が出てきます。

  • 「もしデフォルトのブラウザと普段使いのブラウザが違ったら...」
  • 「もしアプリ内ブラウザを実装しているQRコードリーダーを使っていたら...」

デジタルスキルの低い人にとって、ブラウザの違いを認識するのは困難です。

[デメリット2] 通知の許可がユーザーにとってストレス

私はここ数年間、スマホでWebサイトからの通知を許可した記憶はありません。ダイアログが出てきたら脊髄反射で拒否を押すレベルです。

私のようなユーザーは、通知許可を強要するシステムには嫌悪感を覚えるでしょう。

【案3】 LINE BOTを作る(採用)

LINE BOTに嗜みがあったからこそ思いついた案です。
LINEアカウントでユーザーを識別し、LINEのメッセージでユーザーを呼び出す手法です。

まず、日本人のLINE使用率は100%に近いので「スマホを持っている=LINEが使える」という認識でよさそうです。
そして、検証の結果「友だち追加をしなくてもメッセージのやり取りができる」ということが分かりました。友だち追加をしない状況だとBOT側が取得できる情報は識別IDのみで、アイコンや名前など余計な情報を取得できないという安心感があります。因みに、BOT側からメッセージを送信できるのは、最後にユーザーがメッセージを送った日から7日間だけのようです。

  • 個人情報:同一プロバイダ内でしか使えない識別IDのみ取得
  • 利便性:QRコードを読み取るだけ。友だち追加も不要
  • 不正防止:LINE複垢する猛者は中々いない

これまでのデメリットを全て解消する最良の方法です。強いてデメリットを挙げるなら、Messaging APIの使用料が高いことです。確実に200通の無料枠には収まりきらないので、課金することになってしまいそうですが、自分の金じゃないので関係ない!

2. 使用技術、環境

構成概略図.png

  • フロントエンド:Vite + Vue3 + TypeScript
  • バックエンド:Python3 + FastAPI + SQLModel
  • データベース:SQLite(開発) / PostgreSQL(本番)
  • ホスティング:自宅鯖(テスト) / Render(本番)

技術スタックは私が一番使い慣れているもので取り揃えました。フロントエンドはバニラJSにするかフレームワークを使うか迷いましたが、拡張性を考えて後者を選びました。

アプリ開発にお金をかけた経験のない私は先輩から「合計3万円くらいで足りるかな?」と言われ驚愕しました。予算があるって素晴らしい。
...とは言っても無駄遣いはしたくありません。ホスティングサービスを決めるのは、かなり迷いました。

  • PythonAnywhere:本番環境で使われている例を見たことがない
  • AWS Lamba:従量課金制こわい
  • Heroku:王道。割高な印象
  • Render:Herokuの上位互換らしい

それぞれのPaaSの特徴や料金形態を検討したうえで、Renderを採用しました。

料金

最終的な料金は以下の通りになりました。

用途 料金
LINE Messaging API (ライトプラン) 5,000円 (1ヶ月)
Render Webインスタンス (Starter) 4.9ドル (テスト~本番の20日)
Render Postgresインスタンス (Free) 0円
合計 5,714円 (開発~運用の3か月)

RenderのデータベースのFreeプランは1GB (Storage) | 256MB (RAM) | 0.1CPUというスペックです。1ヶ月経ったらデータベースが削除されてしまうという制約がありましたが、文化祭期間だけ使えればよいので問題ありません。(データベースはCSVに変換して削除前にちゃんと回収しました。)

Webインスタンスは、Freeの512MB (RAM) | 0.1CPUだと流石にレスポンスがもっさりしていたので、Starter(512MB (RAM) | 0.5CPU)に課金しました。

2クライアント × 5クラスで最低10クライアントがWebSocketで同時接続する計算になります。どれくらいのスペックがあればこの不可に耐えられるのか分からなかったので負荷テストを実施したかったのですが、できませんでした。協力者が集まらずLINEアカウントの数が足りなかったのと、直前になって機能追加に追われていたからです。

3. 先生方の反応

笑っちゃうほど薄かったです。

月に一度の先生方との会議で整理券システムが議題に上がったとき、

先輩「かくかくしかじかの様なシステムを構築する予定です。」
先生「それってホントにできるの?」
先輩「技術に長けている生徒に依頼をして、既に具体的なプランも決定済みです」
先生「ふ~ん」
自分「...」

安全面や技術面で突っ込まれたときのために完璧な回答を用意して挑んだ会議でしたが、拍子抜けでした。

いくら生徒主体で運営する方針の学校とはいえ、まさかここまですんなり通るとは思いませんでした。言及するのが面倒な分野ということもあったのかもしれません。
何はともあれ、新しいものを取り敢えず否定する先生がいなかったのはありがたかったです。

4. コロナ過の遺産を活用

万が一、LINEを使えない人が来た場合に備えて紙整理券という制度を導入しています。しかしこれの問題は呼び出し機能がないことです。定期的にクラスまでやってきて順番が回ってきたか確認させるのはあまりにも酷です。

解決策を考えていた時に現れたのは懐かしさを感じるアイツです。

コロナ過の体温計
(画像: デルフトハイテック株式会社

2つの出入り口に設置されたサーマルカメラ付きノートパソコンは、確かにそこに存在しているのに誰の視界にも入らない、石ころぼうしを被った悲しい置物になっていました。

これに目を付け、先生や事務所の人に協力していただきながら「紙整理券 表示モニター」として蘇らせました。
「目を付け」とは言ったものの、この存在に気付いたのはICT支援員の方です。私の学校には廊下の天井から生えている謎のテレビがあるのですが、最初はそれを表示用ディスプレイにしようと考えて話を持ち掛けていました。しかし調査をしてみると、どうやらソレはガラパゴス化されたレガシーシステムを使用しているようで、技術的に厳しいことが分かりました。頭を悩ませていたところ「サーマルモニターを使ったらどうか」と提案してくださったのです。

長いことインターネットから隔絶されていたPCではブラウザが更新されておらず、新しいCSSプロパティが使えずに表示が崩れる、といった面白い現象が起こりました。

結果的にLINEを使えない来場者は来なかったようですが、後述するシステム障害時に少しだけ活用されたようです。

運用してみての感想

試験導入ということで、一部のクラス(5クラス)での運用の予定でした。
しかし、あるクラスは整理券システムを使うほど人が来ず、あるクラスは必要な時だけ使用し、あるクラスはそもそも出し物自体が破綻してしまい(?)、常時運用していたのは実質2クラスでした。
この整理券システムはあくまで補助システムであり、無くても成り立つのだなと感じました。結構頑張って作ったのに必要じゃないと思うと少し悲しくなりますが、既存の仕組みを変えることなく必要な時にだけ使えるシステムというのは寧ろ理想形なのではないかと考え直し、今では作って良かったなと思っています。

当日は、クラスのシフトや委員会の仕事をしながらも、問題が発生したら駆け付けられるように準備していました。呼び出しは時々ありましたが、(1度を除いて)大きな問題はなく無事に終わることができました。

反省点

1. バグを残して本番で大爆発

一番やってはいけないことをやらかしました。
クラスからやってくる問い合わせの殆どは操作側のミスでしたが、1件だけプログラムのバグが原因で発生した事件がありました。

「QRコードを読み取ってもエラーが出て整理券を取得できない」

原因は独自の暗号化方式にありました。
整理券を取得するとき、QRコードを読み取ると次のようなメッセージが入力されます。

簡易暗号化の説明

このBase64みたいな文字の羅列は、クラスIDとダミー文字列を暗号化したものです。文字列の順序を入れ替えたりASCIIコードをコネコネしたりする程度の簡易的な古典暗号ですが、文化祭のシステムごときを全力で解析してくる人がいるとも思えなかったので、そこまでの強度はなくても良いと考えていました。

各クラスごとに暗号鍵復号鍵を発行してサーバーのメモリ上で保持し、QRコード生成時に更新される仕組みとなっています。復号時は各クラスが持つ復号鍵を順番に試していって、正しく復号できた場合にクラスIDを返すという処理をしていました。しかし正しく復号できた時、復号鍵のクラスと、復号して出てきたクラスIDが一致するか確認する処理が抜けていました。要は、存在しないクラスIDが復号されてしまい、エラーが発生したのです。

発生頻度は非常に低く、QRコードを表示しているブラウザをリロードするだけで直るものでしたが、欠陥に気付かずデプロイし、さらに本番で事故が発生しているので重く受け止めるべき事態です。

念入りに暗号復号テストを行っておくべきだったと反省するとともに、信頼されている暗号化方式を使うべきだと感じました。

2. クラスへの説明が十分にできなかった

「どれだけ優れたプログラムでも、上手く使えなければそのシステムはゴミ」
最初から分かってはいましたが、現実はどうにも上手くいかないようです。そもそもプログラムがバグバグのゴミだったけど!(大反省)

どのクラスも直前まで出し物の準備に精一杯で、まともに話を聞いてくれる状況ではありませんでした。その結果、開場5分前に校内を走り回る羽目になってしまいました。

使用方法を説明した3分弱の動画を作って公開していましたが、3分に詰め込める情報量だけでは全ての事態に対応できません。

様々なシナリオを想定し、私が来場者になって各クラスへ確認に行こうとも思いましたが、時間の関係上できませんでした。
項目
シチュエーション 1人で行く、複数人で行く、カメラが動かない、スマホがない
確認事項 適切な説明をしているか、待ち時間を適切に表示しているか、全画面表示をしているか、完了ボタンを押しているか
質問対応 「今の順番を確認したい」「取得後にやっぱりキャンセル」「ふざけて連打してたらブロックされちゃった」「友だち追加はしたくない」「個人情報は大丈夫?」

文化祭が始まってしばらくの間はやはりゴタゴタが何件か発生していたようで、事後アンケートで来場者から「受付担当の理解が甘い」との指摘も見受けられました。

3. テストが形骸化した

チーム開発をしたことがない私は、今まで大量のウンコードを生成してきました。

文化祭のシステムということで今後開発に携わる人が増える可能性が高いため、独りよがりなコード構成をやめ、Gitのコミットメッセージもきちんと書くように心掛けました。

その一環でpytestによるテストを導入することにしました。ライブラリのバグに振り回されてモック開発にかなりの時間を要しましたが、十数件のテストが全て通った瞬間はとても気持ちよかったです。

しかし、次々と折り重なる機能追加にテストコードを書くのが追い付かなくなっていきました。バックエンドはテスト基盤があったのでまだマシでしたが、問題はフロントエンドです。Playwrightによるブラウザ操作はそれなりに心得があるつもりですが、自分で作ったUIを自分で解析してコードを書くのが馬鹿らしくなり放棄しました。

最終的にテストは使われなくなり、GitHubのストレージを無駄にするジャンクコードと化して今もリポジトリに残されています。

4. UIがダサい

つい数年前まで「赤青緑黄を使ってカラフルにすればイイ感じになるでしょ!」と本気で思っていた私のデザインセンスはお察しの通りです。

「使用者の目線に立って、よく使う機能と使わない機能を分類して、配色を考えて...」
デザインに関する記事を読んで身に着けた知識も所詮は付け焼刃。

来場者が触るインターフェースはLINEだけなので今回は特に問題になりませんでしたが、クラスの受付担当が操作するWeb画面、前日に急いで作った紙整理券表示画面は、自分的にしっくりくるものではありませんでした。
画像は載せていませんが、「どうせ自分しか見ないから」と手抜きで作ったAdmin画面は目も当てられません。

使いづらさを感じた部分についてのアンケートを取って今後改善していけたら良いなと思います。

5. 後任がいない

(留年しなければ)再来年には私は卒業してしまいます。
内製システムに属人化は付き物ということを改めて実感しました。
生徒会でエンジニアチームを結成するなんていう話もあるとかないとか。チーム開発ならではの新たな課題が生まれる予感がして楽しみです。

おわりに

初の試みとしては割と成功したほうではないかと思います。
文化祭終了後に実施したアンケートでも概ね好評で、「使用するクラスを増やしてほしい」との要望も多くありました。
プログラム面でも運用面でも改善を施して、来年以降も継続していく予定です。

拙い文章でしたが、最後まで読んでいただきありがとうございました!

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?