元救助隊員が４か月で災害活動時に使える、位置情報を管理するアプリを開発【React / Typescript】

# はじめに
　2024年1月1日(元旦)に発生した石川県能登半島地震、誰もが知っていると思います。地震に限らずあのような大規模な災害で活動するのは自衛隊や消防、警察だけでなく病院、ボランティア団体などあらゆる機関が被災地へ赴き活動します。
　災害時に救出活動や支援活動を行う **「ONE TOHOKU」** というNPO法人の団体があります。
 ※ 詳しくはこちらをご覧ください →　https://onetohoku0311.jp/
 
こちらは現役の消防士から、元消防士など救出活動を使命としているプロフェッショナル集団で構成された組織です。なぜこのような組織があるのかというと、消防は公的な機関であることから災害時、予め決められた消防機関しか現場に赴くことができません。また、活動する際に隊それぞれが保有している資機材や持っている技術もバラバラなため、できる活動というのも制限されます。それでは助かる命も助けられない！救出したい！そういう熱い気持ちの集まりが形となってできた組織で、結成されてまだ間もないです。
　そんな組織の代表を務めている知人から依頼されていたことと、JISOUでの自由課題がマッチして作り始めたのが今回の<font color=red> **「災害時部隊管理システム」** </font>です。
　実際に大規模な災害で活動する場合、必須となるのが**位置情報・現場情報の取得・共有**です。
 災害時にはリーダーになる者がONE TOHOKU総勢100名以上いるメンバーの指揮を執らなければならず、そのためにはそれぞれの部隊の動きを把握し、現場情報を管理することが不可欠です。
 災害活動とは初めて踏み入れる地域がほとんどで、地理も地名も分かりません。ましてや大規模災害となると建物もなく目標物がないため、**自分が今どこにいるのか分からなくなります。** そういう時に頼りになるのが**位置情報**です。また活動時はどこで、どんな災害が起きて、どんな状況になっているのか全く分からないことがほとんどで、現地に行って初めて状況を知ることになります。
 　そんな中それぞれの部隊がバラバラに活動していては、最優先で助けなければならない人を置き去りにしてしまいかねません。また道路損壊や土砂崩れ、川の氾濫など様々な被害により通行できない箇所もあるでしょう。いかに現場の状況を早く把握して、それを共有することで初めて効果的な指揮が執れるようになります。
 　現在NPO法人のような団体が使える <font color=blue>**災害時に特化したアプリはありません。**</font> 公的機関は保有していますが、それはその公的な組織の中だけでしか使うことができませんし、**位置情報をマーカーで表示し追従するような機能はありません。**
  位置情報を把握するためだけなら市場のアプリはありますが、それでは総合的な情報の管理が必要な災害活動では使い勝手が悪く、痒いところに手が届かない状態で活動することになってしまいます。
  説明が長くなりましたが、そんな理由・経緯で作り始めたアプリを紹介させていただきます。
 
　私は救助隊を務めたこともある元消防士です。昨年１１月からReactの学習を始めました。
最初はReactもJavascriptもTypescriptも何も分からない、分からないことだらけでしたが、今回個人でアプリを開発できるようになりました。
　付けたい機能は沢山思い付きましたが、どのように実装すればいいのか全く分からずゼロから調べるところからのスタート。ほとんどが未知の世界でした。

# アプリの概要
　アプリの説明をさせていただきます。
　開発したのは冒頭でもお話しした「災害時部隊管理システム」です。
災害時に指揮を執るリーダーが登録したメンバーの位置情報・災害情報を把握・管理し指揮を執ること、メンバー間で災害情報共有をすることが目的です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/bfd559e6-06a3-4771-a2f8-4bd82355093a.gif">


****
### 機能１：SupabaseAuth認証機能 サインアップ・Welcomeページ認証・ログイン・ログアウト・パスワードリセット、パスワード再設定


フォームに必要項目を入力しボタンを押すことで送信完了。
Supabaseから自動送信されるメールに添付されているリンクを開くとWelcomeページへ遷移し認証完了となります。Welcomeページの「ログイン画面へ」のリンクからそのままログイン画面へ移動することができます。

サインアップ、Welcomeページからログイン画面に遷移する状況です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/c30930d5-368c-4757-9427-c133afbf2a69.gif" width=45%> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/08e4e04d-c1ce-4042-b56d-4ff372823e6b.gif" width=45%>
<br>

ログイン、ログアウトの状況です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/77b22edd-7209-4032-a3ec-1b1bb914bb03.gif" width=45%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/b6df7b32-9122-461f-b76b-55c95cb0d2c7.gif" width=45%>

パスワードリセットはメールアドレスを入力後ボタンを押して申請することができます。
Supbaseから自動送信されるメールに添付されたリンクを開くと再設定ページへ遷移します。
そこで新しいパスワードを入力すると再設定完了になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/74cbe22d-9e14-41ed-af0b-13c5c764353b.gif" width=45%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/2488c9fb-2b73-4bb2-8fc0-73ca7b661c61.gif" width=45%>


ホーム画面です。表示されている通り、ログインすると「Map」「投稿」「投稿一覧」機能を使うことができます。
良く使いそうな機能を上位に表示しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/03426f0a-eeab-48a1-b299-00b28b9746ac.png" width=45%>

***
### 機能２：投稿、投稿一覧
タイトル、内容を入力し画像を選択し投稿することができます。画像はプレビュー表示するようにしています。
また投稿した内容を一覧で表示させ、ページネーション機能もあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/ef375b4d-7c94-423c-9976-c19dc82acc1d.gif" width=45%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/93f536ed-e7e0-4a03-8ca2-6e0f0b2be776.gif" width=45%>

***
### 機能３：位置情報マーカー表示（追従機能付き）
画像はスマホで操作したものです。
個人情報の観点から全ての位置情報をお見せすることはできませんが、**マーカーで現在地の座標を表示しマーカーを追従**するようにしています。地図の操作をした場合は追従機能停止、現在地に移動ボタンを押すことでマーカーが画面中央に表示され、再度追従機能が開始されるようにしています。
災害時は冒頭でもお話したとおり位置情報が必須です。またヘリコプターとの連携活動となった場合、住所での情報共有はほとんどなく、座標で位置を共有するため**常に座標が目につくことは災害活動時に有効な機能**であるため実装しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/c3444c36-db12-4738-9b02-3e537e8361df.gif" width=60%>

***
### 機能４：投稿マーカー表示
地図上に投稿した位置をマーカー表示しています。マーカーをクリックすると投稿したタイトル・画像が表示され、画像をクリックすると拡大されてダウンロードも可能です。
この機能により**どこでどのような災害や被害が発生しているのかメンバー全員で共有できる**ようになります。
マーカーは青が自分、黄色が他のメンバー、緑が投稿です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/1515c83d-0559-499d-a349-577459c91f2c.gif">

### 機能５：メンバー全員の位置情報マーカー表示（追従機能付き）

**自分以外のメンバーの位置もマーカーで表示**するようにしています。
常に追従させるとレンダリングが多く発生しメモリを消費してしまうことから、現在の場所から５００ｍ移動するとマーカー位置が更新されるようにしています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/8dd80759-7f32-4669-960b-c0e29981441b.gif">

# 機能まとめ
**【Supabase Auth】**
・サインアップ
・ログイン
・ログアウト
・Emailでの認証確認
・パスワードリセット
・パスワード再設定

**【投稿】**
・投稿（タイトル、内容、画像）
・投稿一覧

**【地図表示】**
・現在地マーカー表示（座標表示・追従機能付き）
・他のメンバーの現在地マーカー表示（500m移動ごとに更新）
・投稿内容マーカー表示（タイトル・画像）


# 構成・使用言語等

![DB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3707255/12ab915f-1d50-4c42-9405-ef7a40db2cea.png)

<table>
  <thead>
    <tr>
      <th>　　　　名前</th> <th>　　　　説明　★ 今回初実装　☆ 一部初実装</th>
    </tr>
  </thead>
  <tr>
    <td>【使用言語】</td> <td>・Typescript</td>
  </tr>
  <tr>
    <td>【フロントエンド】</td> <td>・React(UI構築)<br>・React Router（ルーティング制御）<br>・React hook form（フォームバリデーション）<br>・React Paginate（ページネーション）★<br>・Jotai（状態管理）★<br>・Tailwindcss（スタイリング）★</td>
  </tr>
  <tr>
    <td>【マップ / 位置情報】</td> <td>・React-Leaflet（地図表示）★<br>・OpenStreetMap（地図データ提供）★</td>
  </tr>
  <tr>
    <td>【バックエンド / BaaS】</td> <td>・Supabase（PostgreSQLベースのDB・認証・ストレージ）☆<br>・Firebase Hosting（静的アプリホスティング）</td>
  </tr>
   <tr>
    <td>【テスト・CI/CD】</td> <td> ・Jest（ユニットテスト）<br>・Firebase Hosting（静的アプリホスティング）<br>・Github Actions（CI/CDパイプライン） </td>
  </tr>
   <tr>
    <td>【その他】</td> <td>・Git（バージョン管理）</td>
  </tr>
</table>

# 大変だったところ

**データベース設計**
　これが完成しないと作り始めることができず、それぞれのテーブルの関係やタイプの選定に時間を使いました。特に今回初めて画像を扱うことからどのようなタイプがいいのか調べました。事前調査ではBYTEAで扱っている記事があったため、そちらを選択しましたが挙動がうまくいかず画像処理実装段階でVARCHARに変更することになりました。そのほかにも実装中、何度もテーブル内容を変更することになりました。改めてデータベース設計は重要なポジションだと思いました。
 それでも何度も変更作業をすることでSupabaseの操作に慣れることができました。今までの課題ではデータベース設計も決められていたため、最初に触ってしまうと以降はほとんど触らない。という状況だったのでまた別の課題を行う際には結構忘れてしまっていた部分がありましたが、今回のように実装中何度も触ることで何となくSupabaseの機能も把握することができました。複数回実装の有効性を認識することができました。
 今回UIではなく全てSQLでテーブル作成も行いました。今までUIだけで操作していましたがSQLを触ったことがなく、抵抗をなくしたかったことと、今後深く学ぶ機会があった場合に、ゼロスタートにしないためです。コマンド1つ1つ調べながらのため時間が掛かりましたが、お陰で抵抗感はなくなりましたし、コマンドの方が自分の意図したことができるため、今後もSQLを深く学びたいと思うきっかけにもなりました。
<br>

**Supabase認証機能**
　データベース設計の次はこれです。状態管理での簡易的な登録、ログイン機能実装という選択もありましたがそれだと実災害では使えないことと、認証機能はエンジニアの基礎となる部分かなと思いSupabaseのAuthでの認証機能を使うことにしました。軽く調べても沢山の有力な記事があったため、迷わず実装することを選びました。が、ドキュメントの内容と出回っている記事を見比べ、意味を調べながらだったので時間は掛かりました。
 認証が成功した時点でAuth.user.idと同じものをusersテーブルのidに挿入する実装をしたかったのですがフロントでAuthの挙動を制御できないことを知ることができましたしSupabaseにはfunctionという便利な機能があることも分かりました。
<br>

 **画像処理**
 　画像はSupabaseのStorageに保存。ただ保存するだけなら問題ありませんが、画像選択した際にプレビュー表示したかったこと、Storageに保存した画像データを取得してマーカーポップアップで表示したかったことから先に述べたデータベース設計時点でのタイプが影響しました。BYTEAだと保存は問題ありませんが、取得時に変換することが必要でまた負荷も増えることからVARCHARに変更しました。また画像を表示させるには公開URLに変換する必要があったため、ここでも大分つまずきました。
<br>

**地図機能**
　地図自体を表示させるのは沢山情報があったため問題ありませんでしたが、マーカーが追従しません。リアルタイムの緯度経度を表示するようにはしていますが、実際にリアルタイムで位置情報を取得してマーカーが移動するのか確認するため、実装してはスマホ持参で外へ出てマーカーの動きを確認する。これを繰り返しました。実装中何度も外へ出て動きを確認しました。
 　また追従するようになったあとは地図操作中に、現在地に移動するボタンも追加。結果、位置情報取得、位置情報監視、マーカーセンター表示機能、現在地に戻るボタンなど複数の機能で1つの状態管理を競合して使うことになった影響で意図した挙動にならなくなったりと状態管理の競合のし過ぎも良くないことがわかりました。
  また座標を変換しての登録、取得が複雑になりそうだっためSupabaseのfunctionを活用しました。
  冒頭のアプリ内容でもお話ししましたが他のメンバーの座標は常に監視しているとレンダリングが多くなってしまうことから、500メートル移動するごとに更新するようにしました。
<br>

**Jestのテスト**
　今まで作ったアプリもそうでしたが、Jestのテストでもつまずきました。特に関数のモック化。モック化するにはモック化しやすい関数にしていることが必要で実装した内容を変更し別ファイルに切り出しました。実装段階からテストのしやすい関数にしていることの必要性を学びました。
<br>

# <font color="blue">開発を通して</font>
### 今までの振り返り
Reactを主体とした学習をゼロからスタートし約4か月が経過しました。
Javascriptの構文もReactの構文も最初は全然分からず、udemyのハンズオンも3回やって何となく分かる程度。でもハンズオンの範囲外の実装は全然できませんでした。オブジェクト？クラス？インスタンス？どんどん知らない用語が出てきて頭の整理が大変でしたが、それでも疑問に思ったことは毎回調べました。確か前にも同じこと調べたなと思うことも沢山ありました。それでも継続することを意識して、**毎日調べ毎日コードに携わる**ことを心掛けました。
成長を感じ始めたのは**3か月**が経過した辺りでしょうか。Reactのこのhooksなら解決できそうと考えれるようになったこと、ドキュメントを見なくても実装できる箇所が増えてきたこと、そして今回初めての実装でもドキュメントと出回っている記事を頼りに実装できることを体感することで更に成長を感じれるようになりました。
　また最初は省略記法を書かないようにしました。省略することでコードがシンプルになりますが、まだ基本の構文も理解していない状態で省略することが返って後から、**自分のコードで理解に苦しむ**場面が多くありました。なぜ（）なのか｛｝なのか、オブジェクトなのかメソッドなのかプロパティなのかなど細かい部分を意識できるようになったのも成長を感じる部分です。今までは**何となく感覚で書いている**ことが多かったですが、そういうところを意識できるようになってくると、分からなくても**なぜそのようなコードになっているのか予想ができるようになってきました。** これも**継続することで理解できる範囲が広がった**ことによるものだと思います。そして、細かい疑問を持つことは個人的に大切なのではないかと思っています。
　今回1日最低5時間、多い日は10時間以上開発に没頭しました。時間は関係ないといいますが、これを1年間やった人とやっていない人はすごい差が生まれるのではないでしょうか。消防業界もそうでした。仕事中しか訓練しない人と休みの日も訓練している人は、数か月で同時期に始めた人と差が生まれます。そして、1年継続すると追いつけない領域に到達します。何の世界も自己研鑽で差別化されていくのかなと思いました。


### 新しい実装へのチャレンジ
今回の開発を経験して自分なりに良かったと思う点ですが、初めて行う実装を盛り込んだことです。その実装の重さや量の選択は重要だと思いますが、最初に成長を感じるポイントは分からないことを調べ納得して実装できた時でした。そして次に成長を感じるのは2回目の同じような実装をする際に、確かこのようにやれば実装できたはずと予想ができるようになっていること。そういう点も成長を感じることができるポイントでした。


### リアルなクライアント
開発したアプリを実際に使ってくれる対象がいたことも良かったポイントでした。
実際に使ってくれるからこそ、妥協したくない実装もありましたし開発中機能が追加していくことで自分でもワクワクしながら開発することができました。

### 仕組化
　今更ながらかもしれませんが、自分のマニュアル資料のようなものは実装の都度作成した方が後々の時短実装につながると痛感しました。一度躓いたポイントで再度躓き、一から調べることは時間のロスになります。ましてやエンジニアの世界は難しい言葉が沢山あります。名前は憶えていませんがどなたかが副業するための記事で書いていたのを開発中に思い出しました。仕組化が仕事をしていくうえで重要。最初は時間が掛かりますが、作ってしまえば後々の絶大な効果を発揮します。ということで乱雑に記録したつまずきメモも整理していこうと思います。
　
### Jotaiによる状態管理
　初めて使いましたがとても簡単で便利でした。storeでatomを一括管理でき、どこからでもアクセス可能でコードも複雑にならずレンダリングの影響も少ないためReactのhooksには戻れなくなりました。
<br>

### 地図選び
　今回OpenStreetMap APIを選択しました。多機能のGoogle Maps APIも魅力的でしたが初めての地図APIだったので、ある程度無料枠を気にせず使えること、React-leafletというライブラリも使うことができて実装に関する情報が沢山ありそうだったことからこちらにしました。国土地理院の地図は表示してみましたが災害活動向けではありませんでした。
<br>

# 今後の課題

* MVPを意識した開発
　今回初めてのReactでの個人開発と初めての機能実装が多く、先が読めない中での開発となりMVPを意識した開発ができませんでした。簡単な実装から手を付けながら開発したため最低限使える状態になったのは完成まじかの時でした。また探りながらの実装だったため、テストを書いてもすぐに変更になることが多く結局最後にテスト実装することになってしまったので、更に経験を積んで開発計画ができるようになりたいです。
 <br>

* Jestのmock化
　テストの内容は今までの課題のお陰で理解できるようになっていましたが、テストを行うには関数のmock化が必要で、どのようにmock化すればいいのか分からずAI頼りのmock化になってしまい、mock化の知識・技術不足を痛感しました。
<br>

* 追加機能実装
NPO代表との協議が必要ですが災害時に更に役立つ機能を追加していきたいと思っています。
災害時は個々の動きの把握だけではなく、資機材管理も重要です。どの部隊がどんな種類をどれくらい持っているのか、また個々のスキルは何ができるのか把握することで災害時のチーム編成もしやすくなるでしょう。
画像だけでなく動画も投稿できれば、よりリアルな現場情報を共有することもできます。
そして現状フロントエンドだけの実装になっているので、バックエンドの実装も追加して、よりセキュリティ的にも強いアプリケーションにしていきたいと思っています。

# おわりに
 今回の開発で、成長を実感できるのは決められた課題をこなすだけではなく、**自分で作りたいものが苦労して形となった時。** **初めての実装を経験できた時**、それに加え今まで学んだスキルで**解決方法が予想できるようになった時**だと認識することができました。
 このような機会を与えてくださったJISOUには感謝しかありません。またJISOUメンバーの日報や投稿もとても良い刺激になりました。そしてメンバーの質問に対する回答のレスポンスの早さはエンジニアスクール業界No.1なのでは？と個人的に思っています。**自己学習だけでは絶対に甘えが出てここまで継続することはできなかった**と思います。
 これからも新しい実装に少しずつチャレンジしてエンジニアとしてのスキルを高めていきたいと思います。
<br>

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp