お客様向け玄関の受付システムを自社開発しています
菅原です。色んなアプリの開発をしています😎
メジャーリーガーの菊池雄星選手が全額出資して岩手県花巻市に建てられる野球施設、 King of the Hill のオープンを個人的に待ち遠しく思っています⚾️
オフィスリニューアル活動
弊社グループでは現在、オフィスのリニューアル活動を行っており、特にフロア内の内装や会議室・休憩スペースなどの改装に取り組んでいます。
プレスリリース
リニューアル活動についてはミッドホールディングスのYouTubeチャンネルで紹介していますので、ぜひこちらもご覧ください😆
正面玄関と受付のリニューアル
このオフィスリニューアルの一環として、お越しいただいたお客様のおもてなしをする正面玄関も改装対象となりました。
玄関の完成イメージはこのような感じです👇
当初、この中央に配置されている受付端末(来訪者チェックイン・担当呼び出し・内線通話などの機能を持った受付用のシステム)には市販の既製品を導入することを考えていました。
が、自分たちの柔軟な発想力と確実な実現力をアピールする ためにも、ここは あえて内製にトライしてみよう! という話になりました。
現在のERiアプリ開発チームのスキルとノウハウ、そして未知の技術をすぐに使いこなす習得力・適応力をフル活用して開発をスタートさせました!💪
システムの構想
従来の受付の状況と、リニューアル後の受付の仕様について観察・考察したところ、以下のような問題や要望があることがわかりました。
- 従来は、打ち合わせの担当者が直接出迎えるのではなく、受付スタッフが一旦応対する形になっている
- 来訪者に関係している担当社員がいまいちわからず、誰に繋げばいいか困ることがあった
- 従来は、内線電話のみが設置されていたため、複雑な要件の場合に、受付スタッフが来訪の意図を掴むのが少々難しいことがあった(来訪者の姿や表情を見たいことがあった)
- 受付スタッフが打ち合わせの担当社員に連絡し、そこからさらに他のチームメンバーを呼び出していくのに、時間と手間がかかっていた
- リニューアル後、運送業者様には、受付呼び出し操作をとても簡単なものにしてあげたい
そこで、
- 来訪者名と担当者名を入力することで、誰を呼び出せばいいかを明確にできる
- 場合によっては、ビデオ通話ができる
- Slackのような外部グループウェアと連携できる
- 運送業者様向けに、ワンタップで受付を呼び出せるようにする
といった機能を持ったシステムを作ることにしました。
開発の結果
システム構造はこのような形となりました。
弊社の玄関に到着したお客様・運送業者様には、玄関端末アプリの画面を操作して各機能を呼び出していただきます。
この玄関端末アプリの操作結果は、弊社の受付スタッフの近くで稼働する管理端末アプリで受信されます。
このアプリから表示されたAndroidの通知表示を確認して、イベント内容に応じて適切に応対を行います。
玄関端末Webアプリ
玄関端末アプリでは、受付とのビデオ通話の開始機能も搭載されています。
1:1のビデオ通話を最速で構築するための技術としてはWebRTCがあることは知ってはいましたが、使ったことはなかったので、この機会にチャレンジしてみることにしました🤔
このWebRTCのブラウザーJS向けAPIを使うため、玄関側に設置する端末はWebアプリとして作りました。
画面の開発にはTypeScriptとReactを使っています。
私はずっとVue.jsを使っていましたが、最近になって、TypeScriptとの相性が抜群に優れているReactの良さがわかってきたところです📝
しかし、Vue.jsはVue.jsで、既存HTML資産が活用できる場面では非常に使いやすいと思っているので、甲乙つけがたいところです・・・。
また、画面の操作安定性・美麗さのために、デバイスにはiPadを採用し、Safariブラウザでページを表示させ続けるようにしました。
開発した画面は以下の通りです。
受付システムサーバー
WebRTCを使うには、「シグナリングサーバー」という、2者のクライアントからのメッセージを土管のように伝送するためのサーバーが必要です。
このメッセージ交換はビデオ通話の開始前にのみ必要で、通話を始めるための設定データを交換するためだけに使われます。
通話が始まるとクライアント同士が直接通信を行うため、サーバーに負荷は発生しません😃
つまり、サーバーはメッセージの転送だけができればよく、具体的な技術に指定はありません。
今回は、多くのWebRTC参考資料で使われていたWebSocketにて、JSONメッセージを送り合うことで実現することにしました。
このWebSocketサーバーは、Ubuntu PCにインストールしたbunで動作させました。
bunは、Node.jsの代わりに利用できるJavaScriptの実行環境で、こちらも前々から気になっていたものです。
これを使えば、なんとTypeScriptを事前ビルド無しで直接動かすことができます⚡️
TypeScriptでしっかり設計したコードを、ゼロコンフィグでサクッと動かすことができるので、ストレスのない優れた開発者体験が味わえました🤩
また、WebRTC用メッセージ転送のほか、打ち合わせ担当者の呼び出し・運送業者到着の連絡といったビデオ通話以外のイベント伝送も、WebSocketでJSONメッセージを送ることで対応させました。
bunのWebSocketサーバーAPIでは、JSONメッセージの転送および監視も簡単でした。
これを使ってメッセージを管理端末へ転送しつつ、その内容次第でSlackのIncoming Webhook APIを呼び出すようにするだけで、簡単にSlack連携を実現することができました。
なお、サーバーとの通信状況のデバッグができるよう、 systemctl + journalctl でサーバープログラムが起動・管理されるようにもしました⚙️
管理端末Androidアプリ
こちらのアプリでは、玄関端末アプリの操作に対応してローカル通知を発生させ、通知音と表示テキスト内容によって受付スタッフへ知らせます。
しかし、管理端末は、状況によっては他の操作のために別アプリが起動していたり、画面が消灯させられていたりすることがありそうでした🧐
ブラウザ上で動作するWebアプリはバックグラウンドに回されると期待通りに動作しなくなることがあるので、WebSocketの接続維持に障害が発生する心配がありました。
そのため、端末がどんな状態にあっても管理端末としての動作ができるよう、こちらはWebアプリではなく、Androidネイティブアプリで実装しました。
最近のAndroid OSでは省電力機能が強化されているため、長時間実行し続けるようなアプリはなかなか開発難易度が高いものですが、Foreground Serviceを使ってWebSocket接続を管理するようにすれば安定することがわかりました。
Service側で受信したJSONメッセージの内容をUIに反映するくだりも、ServiceのバインドとKotlin Flow(StateFlowクラス)を使うだけで、とても自然に実装することができました。
ただし、AndroidネイティブアプリでのWebRTCの実装は少々苦しかったです😥
Googleが管理しているWebRTC公式のAndroidライブラリは更新が止まってしまっていました。
その代わりにGetStream/webrtc-androidを使えばある程度はうまく行ったのですが、どうも玄関端末アプリとは正常に通話が開始できなかったり、音声にノイズが混ざってしまったりといった問題が多発していました。
ブラウザーJSのWebRTC API同士、またはネイティブアプリのwebrtc-android同士であれば動作は安定しており、これらをクロスさせた際に何か相性が良くないことがあるようです。
今回はたまたま、メッセージ交換の順番を工夫すればうまくいくことがわかったので、これを暫定対応策として採用しました😓
できたシステムの課題
担当者の内線番号の特定
システムをテスト稼働させて社内で使ってもらったところ、「管理端末で表示する内容に、担当者の机に紐付いている最寄りの内線番号を表示したい」といった要望が出てきました。
実装方法を検討しましたが、よく考えてみると、お客様が入力する会社名・担当者名は漢字だったりカタカナだったりと、表記にバリエーションがあるものです。
そのため、入力テキストに対する単純なマッピングでは内線番号を特定するのは難しく、最終的には文字を読んだ受付スタッフの自らの判断に頼る必要があると考えました。
・・・もしかすると、ここにLLM(大規模言語モデル)技術を組み合わせると、さらに高度な受付体験が実現できるのかもしれません🪄
テキスト入力を廃止すべき?
そもそも、会社名や担当者名をテキスト入力してもらう使い方自体が、お客様へ相当の負荷をかけてしまうのではないか?という意見もありました。
この点については、確かに利用者の使用環境を十分に想定できてなかったと感じています。
たとえタブレットのソフトウェアキーボード操作に慣れている方であっても、ほとんどのお客様は手ぶらではなく、ノートPCケースなどの荷物を持って来訪します。
そのため、片手で簡単に操作できることを重視すべきでした。
そこで、ソフトウェアキーボードの代わりに、スタイラスペンで手書き入力してもらう案、
いっそのことテキスト入力画面自体を廃止し、ビデオ通話のみにする案などを検討しています。
しかし、テキストデータを使わないと、管理端末やSlackとの連携といったバックエンド側での他システムとの連携が難しいものになってしまいます。
こうした連携のことを考えると、メディアデータをテキストデータに変換して活用する仕組みも必要になってくるでしょう。
なお、実際に玄関に設置して稼働させるのは、このブログを投稿した後の話になります。
今後社内外から得られたフィードバックはどんどん取り入れていきたいです!