share facebook facebook facebook twitter twitter menu hatena pocket slack

2021.07.29 THU

エンジニア夫婦が自分たちの結婚式用にプロフィールサイトとウェブアプリを作った話

西田 駿史

WRITTEN BY 西田 駿史

はじめに

私事ですが今年の6/27に結婚式を挙げました。

私も奥さんもエンジニアなので何か二人らしいおもてなしができないかと思い、よくある席次表プロフィール代わりのプロフィールサイトと披露宴のレクリエーション用にクイズウェブアプリを作成しました。

作ったもの

分担は、奥さん(@tasopi)が主にプロフィールサイトのコーディングとデザイン作成を担当し、私(@danishi)はアプリのフロントエンドとバックエンド、AWSインフラ周りを担当しました。

結婚式の準備の合間を縫って工期は2ヵ月くらい。

実際作ったものの当日の写真が以下です。

プロフィールサイト

席次表に印刷しておいたQRコードから遷移して見てもらうようにしました。
トップページとプロフィール紹介、自分年表のようなページで構成されています。

クイズアプリ(出題側)

予めURLを伝えたスタッフさんに操作してもらうPC用画面で、順番に問題を出題、最後に問題の正解とランキングの発表ができます。
プロジェクターに映してゲストには見てもらいます。
事前に操作手順書を作って司会者さん、スタッフさんにお渡ししました。

クイズアプリ(回答側)

ゲストに操作してもらうスマホ用画面です。
出題側の初回画面で映したQRコードから遷移してもらいます。
初回のニックネーム登録を終えると、後は画面に出ている問題に合わせて三択を押すだけです。

アーキテクチャ

AWSを使って流行のサーバーレス構成で作っています。
利用者は結婚式の出席者だけなので同接60人にも満たない規模でしたが笑。披露宴中も負荷に耐えきり、心配してたエラーやダウンもなく使えました。
ランニングコストもドメイン代抜いて$10いかないくらい。

AWSインフラ構成図

フロントエンド

プロフィールサイト(React)、クイズアプリ(Nuxt.js)ともにフロントエンドはCloudFrontでS3に置いた静的ファイルを配信しています。
公開当日まではWAFでIP制限をかけていました。
出題者の画面は決まった人しかアクセスできないようにLambda@EdgeでBasic認証をかけています。
GitHub Actionsを使って、GitへのPushを契機にソースのビルド、S3へのデプロイができるようにしています。

バックエンド

クイズアプリに必要なバックエンドはAWS Chaliceフレームワークを使っています。
chalice deployコマンドでAPI Gateway、Lambdaをデプロイできます。
DynamoDBの操作には、PynamoDBを利用しています。

クイズアプリの設計

バックエンドが必要なクイズアプリはそこそこ気合を入れて設計しました。
なるべくゲストの操作を簡単にして老若男女が遊べるように工夫しています。

テーブル設計

DynamoDBを使っているもののそんなにベストプラクティスに沿ってはいません…。
ユーザーがそんなにいないのである程度力押しで手抜きしてる部分があります。

ユーザーテーブル

回答するゲストの情報と成績をセットするためのテーブルです。
回答画面でゲストにニックネームを初回登録してもらいます。

属性 説明
user_id(パーティションキー) String 回答するゲストを識別するUUID。
nickname String ゲストに入力してもらう名前。結果発表に使います。
before_question_id Number 同じ問題を二度回答させないために前回回答した問題IDを保存。
score Number 回答成績。初期値はゼロ。正解するとカウントアップします。

クイズテーブル

予めセットしておく問題のテーブルです。
出題画面で内容を表示。
ゲストが答えた回答の答え合わせにも使います。

属性 説明
question_id(パーティションキー) Number 問題のID。
description String 問題文。
correct_answer_id Number 正解の選択肢の番号。
answers List (String) 選択肢のリスト。
stat1 Number 選択肢1を選択したユーザーの数
stat2 Number 選択肢2を選択したユーザーの数
stat3 Number 選択肢3を選択したユーザーの数

現在クイズテーブル

現在出題画面でどの問題を出しているかをセットするためのテーブルです。

属性 説明
key(パーティションキー) String 固定値をセット。ホットスポットになるのであまりよくない使い方です。
question_id Number 現在の問題IDが入る。

API設計

使うAPIは全部で5本。
フロントエンドのNuxt.jsではVuexストアに情報を保存しながらaxiosでAPIを呼び出します。

回答側

POST /user/register

初回のユーザー登録の処理を行います。
ニックネームをパラメータにユーザーテーブルに登録。
ユーザーIDとしてUUIDを払い出します。

GET /user/answer/{user_id}/{answer}

ユーザーの回答を受け取るためのAPIです。
現在出題されている問題を取得し、答え合わせ、自身の成績に反映します。

出題側

GET /admin/question/{question_id}

出題画面に出す問題を取得するためのAPIです。
これを呼びだすことで現在の問題を設定します。

GET /admin/score

出題画面で最後のランキング発表に使います。
ユーザーテーブルをスキャンして成績順に並び替えて返します。

GET /admin/correct_answers

出題画面で最後の正解の発表に使います。
クイズテーブルをスキャンしてそれぞれの問題の答えを返します。

実際のクイズの流れ

  1. 出題画面を開いて初期画面をプロジェクターに投影。
  2. 表示されているQRコードを読み取るよう司会者からアナウンス。
  3. 読み取ったゲストは回答画面の指示に従ってニックネームを登録して待機。
  4. 司会者がゲストの準備が整ったことを確認して出題開始。
  5. 司会者がプロジェクターに表示された問題を読み上げ、ゲストはそれを見て回答。
  6. これを10問繰り返す。
  7. 最後に結果を発表して上位3名に景品をプレゼント

改善点

あとでゲストに感想を聞いた結果以下のような改善点がありました。

  • プロジェクターで写すことを十分想定していなかったので文字が若干小さく読みづらかった
  • プロジェクターの問題に対して回答するというルールが十分に周知されておらず、自分がどこの問題を回答してるかわからなかったというゲストがいた。一本APIを増やしても回答側に問題を表示していた方が分かりやすかったかもしれない。

私たちはもうやり直しはできないですが笑、似たようなことをやろうと思った方は参考にしてみてください。

やってよかったこと

お互い経験のある言語や領域が異なっていたので、それぞれの得意なところをカバーしながらお互いのスキルアップが図れたのがよかったです。
結婚式の準備に加えて開発は大変でしたが、出来上がったときの達成感はひとしおで、当日無事みんなに喜んでもらえたのは嬉しかったです。

謝辞

最後に、コロナ禍の結婚式にもかかわらず足を運んでくださった親族、友人。画面の操作やクイズの司会進行にご協力いただいた会場の表参道TERRACEのスタッフの皆様への感謝とともに、本記事の締めくくりとさせて頂きます。

元記事はこちら

https://qiita.com/danishi/items/6f0f2b3052bb1a841d11

西田 駿史

西田 駿史

2019年4月入社。第四開発事業部グループリーダー。海岸オフィス所属

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。