LINE API を使って開発した『地域共通ポイント「ゆりポ」』の技術スタック

# はじめに

この記事は [「LINE DC Advent Calendar 2023」](https://qiita.com/advent-calendar/2023/lineapi) 14日目の記事です。

この度 『地域共通ポイント「ゆりポ」』]は、[ヒーローズ・リーグ 2023](https://heroes-league.net/) で LINE API 賞をいただきました！

これを機会にこの記事では、[作品ページ](https://protopedia.net/prototype/4753) では書ききれなかった LINE API を使ったサービスで使っている技術スタックについて紹介します。


# 『地域共通ポイント「ゆりポ」』 とは

『地域共通ポイント「ゆりポ」』は自治会離れ対策や地域活動参加者のモチベーション維持のため、会員の地域活動への興味を見える化して活動の輪を広げる仕組みづくりを目指したシステムです。

![01_ゆりポ_サムネイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/65a9a7c0-4374-3c56-e05c-36d8c2b8efbe.png)

どのような背景や目的で開発されたかなど「ゆりポ」の全体像については、作品紹介ページである [Protopedia のページ](https://protopedia.net/prototype/4753) を参照してください。

# システム構成

## システム構成図

![ゆりポ_システム構成図_20231105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/9edc67e3-c19e-ddfd-e247-700dda2175b8.png)

「ゆりポ」は 2023年12月現在、上図のようなシステム構成となっています。
今回は、下記のカテゴリに分けて紹介していきます。

1. バックエンド
1. フロントエンド
1. その他

# バックエンド

## 実行環境

「ゆりポ」は基本的に Google Cloud Platform (GCP) の各種サービスを利用して実行環境を構築しています。

### API Server

「ゆりポ」では、フロントエンドや自治会の業務システムと連携するために REST API を提供しており、その API Server は GCP のフルマネージドなコンテナー実行環境である [Cloud Run](https://cloud.google.com/run?hl=ja) 上で稼働しています。

Docker コンテナーとして構築できれば、開発言語やサーバーに導入するライブラリなどの自由度が高いですし、ローカルでの開発環境整備も容易なことが採用理由です。「ゆりポ」は常時アクセスがあるシステムではないので、料金が実行時間にのみ発生することも魅力的でした。

https://cloud.google.com/run?hl=ja

### データベース

データベースには、こちらもフルマネージド環境である [Cloud Firestore](https://cloud.google.com/firestore?hl=ja) を採用しました。

フルマネージドであり、利用料金が非常に安いことが採用理由です。ただし、普段よく利用する RDB とは根本的な思想が違う NoSQL データベースであり、テーブル設計（特に、SubCollection, CollectionGroup）には注意する必要があります。

https://cloud.google.com/firestore?hl=ja

### データ分析

「ゆりポ」では、ポイント獲得・利用履歴の記録と取得だけでなく、今後は自治会員の地域活動履歴を分析して小さな地域活動同士を組み合わせて大きな活動へと広げていくためにデータ分析を行っていきます。

データの蓄積には Firestore との連携も容易な [BigQuery](https://cloud.google.com/bigquery?hl=ja) を、分析と可視化は GUI で非エンジニアも利用できる [Looker Studio（旧 Google データポータル）](https://cloud.google.com/looker-studio?hl=ja) を採用しています。

https://cloud.google.com/bigquery?hl=ja

https://cloud.google.com/looker-studio?hl=ja


## 開発言語やフレームワークなど

### NestJS

コンテナーに Node.js (v18) の実行環境を設け、コードは TypeScript、Web アプリケーションフレームワークには個人的に開発効率が良く、拡張機能も豊富な [NestJS](https://nestjs.com/) を採用しています。

https://nestjs.com/

NestJS は、API のエンドポイントとなる `Controller` と、ビジネスロジックやデータアクセスを実装する `Service` に分けて記述しやすくなっています。
標準搭載の DI コンテナーでロジックに必要な `Service` を依存を少なく簡単に利用することができるため、コードの再利用やロジックのテストがしやすことも気に入っている点です。

ただ、公式ドキュメント（英語、有志による日本語翻訳あり）は分かりやすいのですが、情報が少ないのが難点です。

### NestJS で使っている主な標準機能・拡張機能

#### Guards

Guards は、認証認可を実装するための機能を提供しています。

「ゆりポ」では、会員が使うフロントエンド（LIFF アプリケーション）からのリクエスト検証といったよく使う下記機能を Guards の interface で実装した `LiffAuthGuard` として開発し、各 API の `Controller` で利用しています。

- リクエストヘッダーから LIFF アクセストークンを取得
- LIFF アクセストークンを LINE API を使って検証
- 検証結果から LINE USER ID を取得してアプリユーザー情報を DB から取得
- 取得したアプリユーザー情報を各 API のエンドポイントに渡す

https://docs.nestjs.com/guards

#### @nestjs/swagger

コードに記載した API 定義のデコレーションを基に OpenAPI 定義（Swagger 定義）ファイルを出力できる拡張機能です。
これを使えばコードが API ドキュメントのソースになるだけでなく、出力した OpenAPI 定義ファイルを使ってフロントエンドで使う API Client を自動生成できるため、インターフェイスの齟齬を無くして開発を省力化できます。

リクエストパラメーターの項目定義とバリデーションと併せて記載できるので、必須項目の漏れや型の違いといった初歩的なミスが殆どありませんでした。

![OpenAPI定義.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/d9725d86-be96-483d-365b-62dc8c085fae.png)

https://docs.nestjs.com/openapi/introduction

#### nestjs-fireorm

Firestore へのデータ操作を行う ORM である [fireorm](https://fireorm.js.org/) を NestJS で利用できるようにする拡張機能です。

https://glebbash.github.io/nestjs-fireorm/

### LINE Messaging API

[LINE Messaging API](https://developers.line.biz/ja/services/messaging-api/) は、アプリケーションから LINE ユーザーへメッセージを送ったり、LINE ユーザーであることを検証するための API 群です。

今回は、会員へのメッセージ送信や、後述する LIFF アプリケーションから送信されるアクセストークンを用いて LINE ユーザーからのリクエストであることを検証することなどに利用しています。

https://developers.line.biz/ja/services/messaging-api/

https://developers.line.biz/ja/docs/messaging-api/

# フロントエンド

## 実行環境

### Firebase Hosting

フロントエンド アプリケーションをホスティングできる GCP のサービスで、CDN に配信できます。
後述する NuxtJS で開発した SPA を配置しています。

https://firebase.google.com/products/hosting?hl=ja

### Google Analytics

言わずとしれたサイト測定サービスです。
BigQuery との連携が簡単にできるのも優れた点です。

https://marketingplatform.google.com/intl/ja/about/analytics/

https://developers.google.com/analytics?hl=ja


## 開発言語やフレームワークなど

### NuxtJS (Nuxt3)

[NuxtJS (Nuxt3)](https://nuxt.com/) Vue.js ベースのフレームワークです。Webアプリケーションを開発するために必要となるルーティングやエラーハンドリング、ディレクトリ構成ルールの統一などの機能・設定を予め組み込んだフレームワークです。

シェアの高い React/Next.js と比べても今回の開発では機能的な遜色もなく、個人的には直感的に使えて開発効率が高いため採用しています。
Nuxt3 になって TypeScript が標準サポートされて非常に開発しやすくなりました。

https://nuxt.com/

### Vuetify

[Vuetify](https://vuetifyjs.com/en/) は Vue.js アプリケーション用の CSS フレームワークで、Googleが提唱したマテリアルデザインにのっとっており、直感的で使いやすいコンポーネントが提供されています。

名前のとおり Vue.js / NuxtJS との親和性が高く、提供されるコンポーネントが使いやすい点が採用理由です。

https://vuetifyjs.com/en/

### LINE Front-end Framework (LIFF)

LINE Front-end Framework (通称 LIFF) は、国内で幅広い世代で利用されているメッセンジャーアプリである LINE のユーザーID情報を利用してメッセージ送信などを行うアプリケーション（LIFF アプリケーション）を使うためのフレームワークです。


> LINE Front-end Framework（LIFF）は、LINEヤフー株式会社が提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。
> 
> LIFFアプリを使うと、LINEのユーザーIDなどをLINEプラットフォームから取得できます。LIFFアプリではこれらを利用して、ユーザー情報を活用した機能を提供したり、ユーザーの代わりにメッセージを送信したりできます。

「ゆりポ」は自治会員という幅広い世代の人々が利用するアプリであり、アプリの新規インストールや会員登録などをせずとも手軽に利用できることが重要なポイントであるため LINE アプリがあれば利用可能な LIFF アプリとして実装することが最適な選択と考えています。

https://developers.line.biz/ja/services/liff/

https://developers.line.biz/ja/docs/liff/overview/


# その他

## CI/CD

### Cloud Build

バックエンド アプリケーションのテストやコンテナーイメージの作成、フロントエンド アプリケーションのビルドや CDN への配置といった、いわゆる CI/CD には [Cloud Build](https://cloud.google.com/build?hl=ja) を採用しています。

GitHub リポジトリと連携させておけば、リポジトリへの Push 時に Cloud Build でのビルドを自動実行させることや、Cloud Run へのデプロイ設定を簡単に作成可能などの省力化できる点が採用理由です。

https://cloud.google.com/build?hl=ja

## 開発環境

### Firebase Local Emulator Suite

その名のとおり、ローカル開発環境で Firestore などの機能を利用できるエミュレーター環境です。

今回は Firestore のエミュレーターを使っています。開発をローカル環境で完結して行えるので、とても開発効率がよくなりました。

https://firebase.google.com/docs/emulator-suite?hl=ja


# おわりに

以上が『地域共通ポイント「ゆりポ」』 で利用している技術スタックの紹介でした。

開発メンバーがボランティアの私一人なため開発効率や省力化できる点と、大きな予算を持たない自治会が運用するシステムであるためコストを抑えるという点が採用理由として重要でした。
今後、他の自治体にも展開することができれば、開発メンバーや予算が増えたり機能追加が必要となるなどして技術スタックが更新されるでしょうから、その際にまた紹介できればと思います。