Angularとfirebaseを使って何か作ってみる入門

**Angular + Firebaseを仕事で触る機会があったため知識の整理を含めて、個人開発レベルの小規模開発時の構成をまとめてみました。**

- Angularの使い方は公式のチュートリアルが秀逸
- Firebase関連の各サービスの使い方や、GCPのサービスの情報などは結構情報が溢れています。

しかし、いざ「*なんか作ってみよう*」と思った時に、「*どう組み合わせて作っていけばいいのか？*」というところで自分が悩んでググりまくったり相談したりしたため、誰かの参考になればと思い整理してみました。


### 対象読者
- Angular＋Firebaseでなんか作ってみたい人

### 作るもの
簡易な河川情報の管理システム
ざっとこんな感じの要件とします。

- 下記のような単位で川の情報が登録できる。
    - 信濃川
    - 利根川
- 川に対して、各グループごとに情報が登録できる
- グループには、管理者とユーザがいて、ユーザはコメントしか出来ない。（管理者は色々できる）


#### ユーザの構成
- Groupには、管理者とユーザが存在する。
    - GroupAdmin
    - GroupUserは河川情報に対してしてコメントのみ可能

##### ユーザ関連概要図
C/R/U/D・・・「Create（生成）、Read（読み取り）、Update（更新）、Delete（削除）」　です。

よくある感じの簡単なユーザ構成？をイメージしてみました。

![gaiyou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232326/da051f7a-1f9c-97a3-3e3d-5f44feb9a6c1.png)



### システムアーキテクチャ
本題はこちらです。
Firebase(GCP)について、下記のサービスを使用して図のように構成しました。
- [Firebase Hosting](https://firebase.google.cn/docs/hosting/use-cases?hl=ja)
- [Firebase Authentication](https://firebase.google.cn/docs/auth?hl=ja)
- [Cloud Firestore](https://firebase.google.cn/docs/firestore?hl=ja)
- [Cloud Functions](https://cloud.google.com/functions?authuser=8)
- [Cloud Storage](https://cloud.google.com/storage?authuser=8)
- [Cloud Pub/Sub](https://cloud.google.com/pubsub?hl=ja)

![gaiyou2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232326/76b55716-699e-5318-2582-f12830272566.png)

- ユーザの認証は「Firebase Authentication」を利用
- AngularとFirebaseの連携については、[AngularFire](https://github.com/angular/angularfire)を利用しました。
    - [AngularのプロジェクトにFirebaseを導入する](https://qiita.com/Yamamoto0525/items/437a2884c0c51f5a3af8)の記事が非常にわかりやすかったです。
- 画像データはCloudStrageへ保存
- テキストデータはCloudFirestoreへ保存

##### 大まかな処理の流れ
基本的な更新のフローとしては下記のような手順で行うようにします。
なるべくPubSubを介して、処理の流れを切り離します。

PubSub経由にしておくことで、処理の部分だけを動かしたい場合にGCPのコンソールからJSONデータを渡してFunctionsを起動するなども行うことが出来ます。

>Pub/Sub は、イベントを処理するサービスとイベントを生成するサービスを切り離す非同期メッセージング サービスです。
[PubSubとは？](https://cloud.google.com/pubsub/docs/overview?hl=ja)より引用

- AngularアプリからCloudFirestoreのデータを更新する。
- CloudFirestoreのデータが更新されたことをトリガーとして、CloudFunctionsの処理を起動する。
- CloudFunctionsからCloudPubSubへ通知する。
- CloudPubSubの通知を受けて実処理用のCloudFunctionsを起動する。
- 関連データの更新などを行う。


### データ構成
[CQRS/Event Sourcing]で作っていくんだ！
という方はこの記事をみていないと思うので、今回の小規模開発だとどのようにしてみるかを考えてみました。

やはり運用を考えると、書き込み用（Write)と読み込み用（Read）のデータはある程度分けた方が良いように思います。
CloudFirestoreの設計にあたってはこちらが非常に参考になりました。
[Cloud Firestoreを実践投入するにあたって考えたこと](https://qiita.com/1amageek/items/d606dcee9fbcf21eeec6)


##### CloudFirestoreの設計
今のところ、RDBでいうところのER図のような定番のドキュメントが特に無いようで、どうするのが正解かわかりません。
（あったら誰か教えて欲しい！）

ということで、自分の好きなマインドマップというツールを利用してみました。
これが意外とハマってイメージしながら描きやすかったのでお勧めです。


![スクリーンショット 2020-12-15 13.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232326/8dba2487-50b0-ad0a-ea36-c683d41ef4e5.png)


データの構成としてはまず大きく３つに分けています。

- common
    - 読み書きできる
- write
    - 書き込みOnly
- read
    - 読み込みOnly

このように、読み書きの権限によってTOPの階層を作っています。
上で紹介した参考サイトにもあるように、上位階層をドメインで切り、バージョン管理をドメイン単位で行っています。
こうすることで、変更が発生した場合の対応が比較的しやすくなっていきます。
（とはいえ小規模想定なのでほぼほぼ中の変更で吸収されると思われますが、切っておけば安心です）

writeのデータに関しては、書き込まれたタイミングでトリガーによりCloudFunctionsを走らせてreadのデータを作成します。

この時、アプリ側で取得表示するデータがreadのデータとなるため、書き込み後即時反映が行われません。
ここで、特に多少の前後が問題ないものであればいいのですが、即時反映されたように見せたい場合にはアプリ側での対応が必要となってきます。

### 最後に
以上、「*Angularとfirebaseを使って何か作ってみる入門*」でした。
一つ一つの使い方を深掘りしていないのは、木と森を一緒に語ると焦点がぼやけてしまうかなと思った次第です。
やはりもう少しここは細かく書いた方がいいかなぁ。などあれば、編集更新していくかもしれません。

なんとなく簡単そうだなと思ってもらい、軽率に手を出してみてもらえたら嬉しいです！


### おまけ（開発環境）

さて、本題とはちょっとずれてきますが、「*なんか作ってみよう*」と思い立った時にもう一つ気になるのは**「開発環境」**ではありませんか？

というわけで、一応軽くどんな構成でやったら楽だったかを残しておこうと思います。

##### 全体
開発環境はDockerを使用し、VSCODEで開発しています。
githubと[CloudBuild](https://cloud.google.com/cloud-build/docs/?hl=ja)を連携させて、FirebaseHostingおよび、CloudFunctionsへのデプロイを行います。

![dev_env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232326/5ce69c6d-04be-3adf-9c99-e2576e807882.png)

##### Deploy
CloudBuildを利用したデプロイの流れです。

- 指定のブランチへpushすると、ビルドステップが実行されます。
    - これは、CloudBuild側にて設定が行えます。
- cloudbuildのステップはyamlファイルで指定するだけ、簡単。
- Secret Managerを使えば外部サービスのIDなどをどう管理しておこうなどの悩みから開放されます。

是非、利用してみてください！

![dev_env2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232326/43bd6efc-989c-fdb8-2818-2101a2cfadf3.png)

セキリュティの部分については、こちらも参考にしてみてください。
[Cloud Functions for Firebase + Secret Manager でシークレット情報を扱う](https://qiita.com/hirok115/items/3366b2a60ff14f81ac3c)