セーブポイント

特にジャンルの決まってない雑記です。

音ゲーのIRサイト作った

今月の頭くらいに、IRmaniaというWebサービスを公開しました。

github.com

初めてアカウント登録とデータベースへのアクセスという要素があるサービスを開発したので、せっかくなので記事を書いてみようと思います。

どういうサイト?

beatmania IIDXに今作から実装されたカジュアル大会機能を参考にして作られた、様々な音ゲーで大会を開くことのできるプラットフォームです。

使用するゲームタイトル・楽曲・難易度を指定して大会を作成することができ、大会は誰でも参加できるようにも、パスワードを使用して限られた人のみが参加できるようにも設定することが可能です。

Discordアカウントを使用してIRmaniaのアカウントを新規作成することができ、ログインすることで大会の新規作成と大会への参加(スコアの登録)ができるようになります。

現状としてはIRmaniaが持っている機能は以上の通りで、最小限の機能を持ったサービスになっています。

開発の経緯

去年の秋頃から大学のサークルの同期たちと、身内で弐寺の大会をやったりするようになりました。

このときはスコアの集計に友人がGoogle FormsとスプレッドシートにGASを使っていて、身内向けでのイベントなので正直別にこれで困ってもいなかったのですが、もっと気軽に大会を作れたらいいなあと考えていました。(自動化したくなりますよね)

自分が所属しているサークルでは定期的にIRという複数の機種を跨いで指定された楽曲のスコアを競うイベントがあり、そのときに利用しているサークル内向けのWebサイトのクローンのようなものを作りたいなあとぼんやり計画したりしていたのですが、いかんせん複雑なWebサービスを作った経験が無くあまり手を付けられていない状況がずっと続いていました。

そんなときにSupabaseというサービスを知り、「これでもう一回やってみるか」とやる気を出して今に至ります。Supabaseの話は以降の章でもう少し詳しく触れていきます。

技術選定

ここからは主に技術的な話になります。興味のある方はどうぞ。

Webサイトを作っていくのにあたって、使用するフレームワークはいつも通りNuxtにしました。個人的にNext.jsより好みです。

nuxt.com

どうも世間的にはNext.jsのシェアが圧倒的に広そうで逆張りみたいになってるんですが、普通にNuxtも開発しやすいと思うんですけどね。なんでなん。

で、今回のサービスはアカウントの登録の仕組みやデータベースが必要になるので、それらについても何を使うか決めないといけません。

元々は勉強もかねてGoogle Firebaseで実装しようと思っていたのですが、ドキュメント読んでもそもそもセットアップの部分がよく分からなかったりして、特に進展もないままプロジェクト自体保留になっていました。これが今年の年始とかくらいまでの話です。

そういう流れがあって「IRサイト作りたいなあ」とだけ言って放置していたのですが、今月になって先述したSupabaseというFirebaseの代替サービスを知りました。

supabase.com

話を聞くに、機能こそまだ限られてるけどFirebase本家よりも使いやすい?みたいな評価がされていたので気になり採用してみたところ、これが本当に使いやすい。
無料枠でもかなり色々なことができると確認できたので、今回はこのサービスをメインウェポンとして利用していくことにしました。

Supabaseのいいところ

最近は本当にSupabaseをかなり推しているので、個人的に嬉しかったポイントをいくつか書いていきます。

まず、公式ドキュメントが非常に整備されていて丁寧です。当たり前みたいなレベルのところから全て書いてくれていて、自分みたいな素人にはとても助かりました。

supabase.com

データベースからデータを取得する例

DatabaseやAuthなどのプロダクトごとの解説から、画像のような各言語のライブラリの使用例まで広く網羅されています。普段様々な言語やフレームワークのドキュメントを読んでいますが、Supabaseのドキュメントにはかなり感動しました。

また別の長所として、無料枠がかなり太っ腹です。

supabase.com

まず、Databaseに関しては無料でAPIリクエストの回数無制限です。データベースの容量としては500MBを使うことができて、ユーザーが爆発的に増えなければ十分足りる容量だと思います。画像とかを置く場所ではないので。

注意点として、APIリクエストは無制限ですが帯域が毎月5GBという制約があります。まあそんなに連打しなければ気にする必要もなさそうです。
参考までに、今月の帯域の使用料は今のところ9MBです。自分が確認用などで割と頻繁にアクセスしてこれなので、1つのサイトで使うくらいならしばらく上限にひっかかることは無いでしょう。

Authについては、まず合計ユーザー数は無制限です。 ←どういうこと?

ただしMAUでの制限があって、毎月5万人までいけるということになっています。いや、それでも多すぎだろ。

5万人ユーザーがいるサイトって普通にもう結構大規模ですからね。VaddictでもMAU5万はいないだろ。

そういうわけで、認証に関しては無料枠で実質的に制限は無いものと思っていいと思います。一応セッションのタイムアウトができないとか細かい制約はありますが、無料枠でもソーシャルログイン(Googleアカウントでのログインとか)が利用できるので、あんまり困ってないです。

やはり個人開発は基本的にお金を発生させたくはないので、これだけ無料で便利だと助かりまくりです。

開発ログ

Commits · 3kanAlpha/kbd-mini-ir · GitHub

1日目

使うフレームワークやサービスを決めたので、実際に作っていきます。リポジトリを作成したのは4月5日らしいです。

上で触れるのを忘れましたが、今回開発にはbunを使っています。肉まん。

bun.sh

フロントエンド開発を始める前に、Supabaseの方で今回のサービスで使うテーブルを作成しておきます。

テーブルとその関係

あまり深く考えずに必要そうなカラムを思いつきで載せた感じなので良し悪しはよく分からないのですが、とりあえず現状はこのような設計になっています。

右上のusersテーブルはAuthで利用しているものとは別で、emailカラムは実際には空になっています。他のユーザーから読まれても大丈夫なデータしか載せていません。

それぞれのカラムに入る値はほとんど名前から想像される通りです。最新のものなので、一部リリースされているサイトには未実装の機能用のものも含まれます。

Supabaseはダッシュボードから各プロジェクトを開くと、ブラウザ上からGUIでデータベースに行を挿入したり編集したりできます。これがとても便利です。

とりあえず初日にはデータベースに既に登録されている大会とスコアの情報を読み出すだけの機能を実装しました。

フロントエンドのUIはVuetifyを利用して作成しました。VuetifyのData tableというコンポーネントを利用するとテーブルの表示が簡単にできて助かりました。(ただしモバイル対応はいまいち……)

2日目

サインアップ・サインインの仕組みを実装しました。実装したといってもフロントエンド側に数行のコードを追加するだけで実現でき、実際作ってみるととても簡単でした。

これまではユーザー認証の仕組みというとかなりめんどくさいのだろうと思っていたので、とても驚きです。(自分でバックエンドを実装しなくていい!)

アカウント登録の仕組みとしては、Discordによるログインを採用しました。一般的なメールアドレス・パスワードによる認証は使う側としてもめんどくさいし、サークルのメンバーならみんなDiscordのアカウントを既に持っているという前提があったので、こうしました。実際楽だと思います。

3日目

結構がっつり開発しました。

まず、ユーザーに各大会ページで表示される表示名を設定してもらう機能。(現在のアカウント情報ページ)

これを開発するときに、本当はAuth側のユーザーのテーブルにユーザーが追加されたら(Discordで誰かが新規登録したら)自動で自分で定義したusersの方に行を挿入するということをやりたかったのですが、トリガーを調べた通りに設定してみてもなぜかユーザーの新規登録ができなくなり、断念。
今でも解決できておらず、最初に表示名を更新してもらったときにusersにユーザーが登録される仕様になっています。

追記:解決できました。今は新規ユーザー登録と同時にpublic.usersにも新しく行が挿入されるようになっています。

また、アカウントの作成機能は既に実装したので、スコアの登録機能を作り、この時点で仮完成としてとりあえずリリース(α版)しました。

リリースした

3日でWebサービスが作れるなんて気楽でいいですね。3日かかったとはいえ別に朝から晩までコードを書いていたわけでもないので、実際には10時間もかかっていないと思います。一人アジャイル開発

ただしリリースしたときはusersemailカラムに間違えてunique制約を付けていて、2人目以降がemailカラムをnullにすることができず登録に失敗するという重大なバグがありました。大変申し訳ありません。

しかしながらこれ以降はサービスの運営に関わる重大なバグは出ていないので、今のところ安心です。まあコーナーケースみたいなやつは今でもいくつか残っているんですが……。

この日はこのあと不具合を直すついでにスコア提出時にコメントをつけれるようにしました。これはサークル内のIRサイトの真似です。

この時点ではスコアを提出するときに写真は直接添付できず、外部サイトのURLを貼るという仕組みにしていました。本当は最初から画像を投稿できるようにしたかったのですが、やはり画像はサイズが大きかったりするので、置き場所に困ります。Supabaseにストレージのサービスはあるのですが、無料枠だと1GBまでで写真を投稿していくとなるとあまり安心できる容量とは言えませんでした。

4日目

仮リリース時点で実装していなかった大会作成機能を作り、とりあえず当初想定していた機能を全て実装しました。

このときに、誰でも参加できる大会ではなく、スコア提出時にパスワードが必要となる「プライベート大会」作成機能も実装しました。

パスワードは送信時にSHA-256を使用してハッシュ化して、データベース側にはハッシュ値のみ保持されるようにしています。(一般的なWebサイトのパスワードの管理方法と同じでしょう)

こういう仕様にしているので、パスワードを忘れた場合管理者側からもパスワードを通知したりすることはできません。データベースを直接編集することでリセットをしたり異なるパスワードに再設定することは可能です。

5日目以降

主要な機能を実装したあとも、UI/UX面でのアプデやリファクタリングをちまちまやっています。マイナーチェンジみたいな変更がほとんどですが、たまに新規機能を追加したりもしています。

例えば、4月14日には実装を見送っていたスコア提出時の写真添付機能を追加しました。

この機能には、Cloudflare R2を使用しています。AWS S3互換のストレージサービスです。

www.cloudflare.com

無料で10GBまで利用することができ、書き込み操作が月100万回まで、読み取り操作が月1000万回までできます。データの転送に料金がかかりません。画像の配信が目的なので、転送に料金がかからないのがかなり嬉しいです。

その分、ストレージとしては本当に最小限の機能しか有していませんが、画像のリサイズなどはフロントエンド側で頑張ればなんとかできそうな感じがします。今はまだ画像を直接アップロードしているだけですが、今後改善できたらいいなーと考えています。

また、もう少し小さい新規機能として数日前にスコアの値が小さい方が順位の高い大会も作成できるようにしました。弐寺のミスカンアリーナなどで使えます。別にマリオパーティとかでもいい。

UI/UXの面などで不便があれば改善していきたいと思ってるので、何か不都合あれば連絡ください。新規機能の案でもいいです。実装できそうなら考えます。

現在のトップ画面

今後の展望

個人的にはもう十分実装したかったものは作ったのですが、一応以下のような機能を追加しようかどうか考えています。

  • 大会の開始日時の指定(今の実装だと作成した瞬間からスタートなので) 実装した
  • 大会終了時まで他の人のスコアが見えない大会 実装した
  • 各ユーザーのページ?(これまでの提出スコアが確認できるとか)

あとは身内向けにDiscordのWebhookを使用したbotとかでしょうか。

スコア一覧のテーブルの読み取りはanon keyさえあれば誰でも閲覧できるようになっているので、実は簡単に作れてしまいます。

スコアが更新されたときに通知を送ったりするのはEdge Functionがやってくれるはずなのですが、ちょっと今この機能についてよく分かってなくて無理やり実装になりそう。


まあ、とりあえずIRmaniaを使って色々遊んでくれたら嬉しいです。自分としても、せっかく作ったので今後も色んなゲームで定期的にカジュアルな大会を開けたらいいなーと考えています。

それではまた~👋