LT運営者必見！タイムキーパー代わりサービスのリリースと、それを支える技術

この記事は[Ateam Brides Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam-brides)　1日目の記事です。

# サンプル
https://lightning-talks-timer.web.app/events/iYSl2bwnQWPM5WmWgnIdTn0aTbj2
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/63fe1cd1-eed1-3d3b-4ae1-010eb52f8aab.png" width="500">

トップページ
https://lightning-talks-timer.web.app/

LT（ライトニングトーク）のように、定刻進行するイベント用のタイマーです。
1アカウントにつき1イベントのタイムテーブルを作ることができます。

URLを共有すれば、ユーザー登録していない人にも、同イベントのタイムテーブルが共有できます。

**※このサービスは私個人のプロダクトです。アドベントカレンダーの記事ですが、弊社とは一切関係ありません。**

# この記事で紹介すること
- 作ることになった経緯
- サービスで提供している機能
- サービスを支える技術
    - 主にFirebase

# 作ることになった経緯
LTイベントを開催した際、**タイムキーパーが思ったより大変**でした。
ストップウォッチと時計を見ながら、測り忘れやアナウンス漏れが無いよう常に集中する必要があります。
また、1回のLTイベントで**3レーン同時のように並列進行する際、タイムキーパー全員の時計を合わせる**必要もあります。

そこで、

- あらかじめタイムテーブルを登録しておき、そこを見ながら進行できる
- 残り時間カウントのためのストップウォッチ操作が不要
- クライアントサイドに依存した時間ではなく、サーバサイドで同時進行できる
- 発表者も自主的に気付きやすいよう、プッシュ通知を送る

サービスを作ることになりました。

# サービスで提供している機能

ソーシャルログインができる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/8d0fa15f-9a23-179b-65c0-f77f1942da49.png" width="500">

ログインすると、1アカウント1イベントのタイムテーブル情報登録ができる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/ff12fa14-bb69-94f3-dace-b67242bf7bbe.png" width="500">

開始1分前、開始時、終了1分前、終了時の4タイミングでプッシュ通知が来る
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/22da3450-c392-a2ee-3b65-1a78991cb775.png" width="500">

ページ内で、クライアントの時刻に関係なく日本標準時とほぼズレずにカウントダウンされる
かつ、URLさえ知っていればこのページを誰にでも共有できる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/63fe1cd1-eed1-3d3b-4ae1-010eb52f8aab.png" width="500">

プッシュ通知受け取り中の一覧を表示する
また、アカウントの削除ができる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/4a9c4748-528a-3985-775d-90a4f09a13ae.png" width="500">

# サービスを支える技術

すごく雑な言い方をすると、全てFirebaseとjsで構成されています。

- フロントエンド
    - Nuxt.js(Vue.js)
        - Vuetify
- バックエンド、インフラ
    - Firebase
        - Authentication（認証）
        - Cloud Firestore（NoSQL）
        - Realtime Database（クライアントとサーバの時刻ズレ修正としてだけ）
        - Cloud Messaging
        - Cloud Functions for Firebase（プッシュ通知受け取り/停止のAPI、プッシュ通知配信の定期実行）
            - Node.js
        - Hosting（本サイトのホスティング）

## Firebaseのススメ
Firebaseって名前はたまに聞くけど、何ができるの…？
という方のために、今回使ったFirebaseの技術に関して軽く説明します。

### Firebase Authentication

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/c105362d-f89b-2085-5579-a09b42f7b096.png" width="300">

簡単にユーザーの登録、ログイン、ログアウト、退会等ができる機能を提供します。

管理画面のスクショですが、こんな感じにいわゆるソーシャルログインを簡単に有効/無効設定できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/52ddaa9d-856e-e18b-934a-2abf4b0a4a65.png" width="500">

メール/パスワードとGoogle以外のサービスに関しては各5分ぐらいアプリケーション設定の手間がかかりますが、非常に簡単にソーシャルログインの導入ができます。

ログインすると、以下の通りユーザー一覧が確認でき、作ったアプリケーションに対するアカウントの停止/削除等の操作ができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/d981046d-37d0-4427-7a19-337d141fe500.png" width="500">

フロントエンド側もfirebaseのmoduleをimportした後

```js
firebase.auth().onAuthStateChanged((user) => {
  console.log(user) // ログイン中ユーザー情報が取得できる
})
```

のように書くだけで、ログイン中ユーザーの名前やメールアドレスが取得できます。超楽。

そして、電話番号認証を使わない限りは無料で利用できます。

### Cloud Firestore

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/826792fb-002f-aee6-159f-ee333b79a620.png" width="300">


NoSQLサービスです。
FirebaseはRDB（MariaDB, MySQL, PostgreSQL等）を提供しておらず、Firebase内で完結させるためには、NoSQLであるFirestoreを使っていくことになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/ef82e87c-67d6-ce78-debd-77ee4ed37352.png" width="300">

こんな感じでブラウザのFirebase管理画面上で値を確認や変更ができます。

また、firebase moduleをフロントエンドでimportしていれば、**サーバサイド言語を使わず、フロントエンドからデータの取得・登録・更新・削除**といった操作が可能です。
ただし便利な半面、フロントエンドから直接データ操作ができるということは、セキュリティルールを正しく設定しないとデータの漏洩や改竄等も容易にできるため注意が必要です。

サーバサイドでももちろん使うことができるので、APIサーバを立てて処理することもできます。
記事執筆時点では、以下言語に対応しています。

- ウェブ(js)
- iOS(Swift)
- Android(Java)
- Android(Kotlin)
- Java
- Python
- Node.js
- Go
- PHP
- C#
- Ruby

### Realtime Database

Firestoreができる前、古い頃のデータベースサービスです。
基本的に今はFirestoreの使用が推奨されます。

今回LTタイマーにおいては、クライアント時刻とのズレを取得し調整する目的でのみ利用しています。

### Cloud Messaging
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/baacd396-562f-5f61-86f0-ff0b1be845f7.png" width="300">

プッシュ通知を簡単に送れるサービスです。

Webのプッシュ通知の他、AndroidやiOSへも送ることができます。

フロントエンドでプッシュ通知の許可をした場合、トークンがFirebaseへ送られます。
そのトークンに対し、あるいはtopicという単位をsubscribeすることで、メッセージ送信ができます。

許可したトークン一覧をFirebase管理画面で閲覧できるわけではないので、Cloud Messagingに関してはバックエンドの構築が必要になります。

今回のLTタイマーにおいては許可して「このイベントのタイマー通知を受け取る」を選んだ時点で後述するCloud FunctionsにトークンとイベントIDを送り、topicをsubscribeさせています。

### Cloud Functions for Firebase

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199678/c8847bdf-dadb-9fda-081a-687e0872c341.png" width="300">

Cloud Functionsはサーバレスで、サーバサイドの処理を実行することができます。
注意したいのは、**GCPのGoogle Cloud Functionsと、Cloud Functions for Firebaseは別物**ということです。

実は今回のLTタイマーアプリケーション、試作品の段階ではCloud Messagingのサーバサイド処理はGoで実装していました。
が、作った後に**GCPのGoogle Cloud FunctionsはGo対応しているが、Cloud Functions for FirebaseはNode.jsでしか書けない**ことを知りました。

また、今回は1分ごとにFirestoreを見に行き、開始1分前/開始/終了1分前/終了の4タイミングに一致するイベントがあればCloud Messagingでメッセージ配信を実行しています。
なお、定期実行は無料プランではなく従量課金の有料プランに切り替える必要があります。
（が、今回のアプリケーションにおいてはまだアクセス数が少ないため、今のところ0円です）

### Hosting
Hostingはその名の通り、ホスティングサービスです。
今回のLTタイマーのWebアプリケーションをせっかく作っても、Web上に公開しないと誰にも見て・使ってもらえません。

HostingはCLIでコマンドを1個叩くだけで静的サイトを簡単にdeployすることができます。
その結果、
https://lightning-talks-timer.web.app/
というURLでサイトを閲覧することができます。

# 最後に

こんな感じにFirebaseを駆使することで、一通り機能の揃ったWebサービスを公開することができます。
無料でできる範囲は非常に広いので、とりあえず認証機能のあるWebサイトを作ってみてはいかがでしょうか。