## プロジェクト概要
---
Instagramのフォロワーが200万人弱ほどいる、人気アパレルブランドのアプリケーション開発。(iOS/Android)
ReactNativeによるクロスプラットフォーム開発。
現在は**約40万**ダウンロードを突破。
バックエンドは[Shopify API](https://shopify.dev/docs/api/storefront)を利用し、アプリ専用の追加機能は新たに作成した。管理画面も作成し、フレームワークは`Remix`を使用した。
## 目的、背景
---
元々、Shopifyを利用してノーコードで運用していたお客さんが、**サイトスピードや利便性に欠けるなどの不満**を抱えており、独自のアプリを作りたいという要望から生まれたプロジェクト。もっとも重視されていた部分は**パフォーマンスの向上**。スプラッシュ画面やアプリ全体の高速化を施したり、決済画面はWebViewによる実装をする必要があったがパフォーマンスを向上させるために工夫を凝らした。
またインフラ側(AWS)ではElastiCacheやCloudFrontを使用したキャッシュの使用、**アクティブユーザー数の変動に合わせたスケーリング設定**を施し、お客さんが求めている非機能要件を達成した。
## 使用技術
---
| | |
| ------------- | ------------------------- |
| フロントエンド | React Native, Expo, Remix, Redux toolkit |
| バックエンド |Laravel, JavaScript(一部)|
| DB | Postgres, Aurora |
| インフラストラクチャ | AWS, AWS CDK, Docker, Bitrise |
| 外部サービス | Shopify API, [Customer.io](https://customer.io/) |
| モニタリング・分析 | Sentry、Firebase |
| 開発支援ツール | GitLab, Slack, Chatwork, Backlog |
<br>
### 使用したAWSサービス
| カテゴリ | サービス |
| ----------------------------- | ---------------------------------------------- |
| **コンピューティング** | AppRunner, BastionHost |
| **コンテナ** | ECR |
| **ストレージ** | S3 |
| **データベース** | RDS(AuroraServerless V2), ElastiCache |
| **ネットワーキング** | Route53, VPC |
| **セキュリティ、アイデンティティ、コンプライアンス** | SecretManager, IAM, CertificateManager |
| **運用管理** | SystemsManager, CloudWatch |
| **コンテンツ配信** | CloudFront |
<br>
## 規模感、チーム構成、担当した役割
---
2024年6月にアプリを公開し、約1ヶ月でダウンロード数が10万人に達した。(現在約40万人)お客さん曰く、これからイベントや広告でさらに拡大し、2,3年後には100万ダウンロードを目標にしている。
内部では、
- PM: 1人
- PL: 1人
- アプリフロントエンド: 3人
- 管理画面フロントエンド: 1人
- バックエンド (PL含む): 2人
- インフラ: 1人
- UXデザイナー: 1人
- UIデザイナー: 1人
10人の構成。要件定義から運用保守まで一貫してプロジェクトに関わり、開発フェーズではインフラ、アプリフロントエンド、管理画面フロントエンドを担当した。
具体的には、
- 技術調査
- Shopifyについて
- Shopify APIについて
- [サードパーティのアプリ](https://apps.shopify.com/partners/shopify?locale=ja)について
- 設計書の作成
- 機能一覧
- DB設計書、ER図(レビューのみ)
- システム構成図、AWS構成図作成
- 画面単位の詳細設計書作成
- AWSによるクラウドインフラの設計・構築
- コンテナ(App Runner)、RDS(AuroraPostgres Serverless V2)、ElastiCache、CloudFront、S3、Lambda、Route53、System Manager、Bastion Host(踏み台サーバー)等のサービスを使ったコンテナアプリケーション(開発・テスト・本番環境)
- IaC(AWS CDK)による構成管理
- スケーラブルかつ高可用性のウェブインフラを構築
- 2AZ構成。またコンテナはCPU使用率を`50〜60%`をキープできる程度にスケーリングを設定。ElastiCacheによるキャッシュ化等々。
- 管理画面フロントエンド、バックエンド、IaCのCI/CDの構築
- GitLab CIによる自動テスト・デプロイを構築
- ReactNativeによるクロスプラットフォームアプリケーションの開発
- 状態管理はRedux、Shopify APIを使用するためGraphQLのApolloClientを使用
を担当。
<br>
## 開発・実装内容A
---
### 【概要】
CloudFront + [Lambda@Edge](https://aws.amazon.com/jp/lambda/edge/)によるレスポンスボディの書き換えで、アプリで表示するWebView画面に対してUI変換した画面を表示する
【どのような機能の開発・実装か】
アプリケーションのカート・決済画面は`Shopify API`がサポート対象外であったために`WebView`でそのまま表示することとなった。しかし、アプリ用に新規で作成したUIに合わせるために、弊社の自社プロダクトであるUI変換ツールを導入してUI変換した画面を表示する必要があった。UI変換をするためにはHTMLの<head>内にscriptを挿入する必要があるため、通常は静的にお客さん側で入れてもらうのだが、オリジンサーバーがShopifyであり、お客さん側で静的に入れることができないので、`CloudFront`のトリガーに設定できる`Lambda@Edge`を使用してレスポンスボディにscriptを挿入してクライアントに返す実装をした。
詳細は以下。
https://qiita.com/akira__0924/items/ad633e5557d4c590d1d4
### 【課題・問題点】
`Lambda@Edge`の当時(現在も)の仕様から、`CloudFront`で受け取ったレスポンスボディに対して操作をすることができない。
また、ヘッダのCookieやオリジン、リファラなど、正確なレスポンスを受け取ることができるかが不透明だった。
### 【打ち手・使用した技術】
当時、社内でも相談したが実現方法に苦戦していた。初めは`CloudFront Functions`を使用する想定だったが、レスポンスボディの書き換えができないと公式リファレンスに記載があったため、`Lambda@Edge`を採用することに決まった。そこから自身で調査し、`CloudFront`のレスポンスボディに対してLambdaで操作することができなかったので、**オリジンリクエスト**にトリガーを設定して、**LambdaからHTTPリクエストを送り、受け取ったレスポンスを書き換えてクライアントに返却する実装をした**。
また、**オリジン(Shopify)で使用しているドメインのサブドメインを使用**することで、ヘッダ情報(Cookieなど)を引き継ぐように実装した。
<br>
## 開発・実装内容B
---
### 【概要】
`WebView`内での認証情報の引き継ぎと、パフォーマンスの向上を図る
### 【どのような機能の開発・実装か】
上述したように、カート画面は`WebView`による実装になったため、画面をただ表示するだけではアプリでログイン状態になっていてもセッションは維持されない。そのためWebView画面でセッションを保持するための実装と画面表示までの表示速度を上げる方法を検討した。
### 【課題・問題点】
- カートの表示速度が遅くお客さんが不満を抱いていた。
- アプリでログインしていたときにどのようにしてWebView画面でログイン状態にするか
### 【打ち手・使用した技術】
- カートの表示速度が遅くお客さんが不満を抱いていた。
→カート画面を非同期でアプリの裏側で読み込んでおく実装を提案した。フロントエンドチームで検討し、結果、ReactNativeのnavigationで裏側で表示しておき、カートアイコンをタップした際にはその画面をただ表示するだけの状態にすることで、`カートの表示速度をほとんどノータイム`で実現することができた。
- アプリでログインしていたときにどのようにしてWebView画面でログイン状態にするか
→[Shopify Multipass](https://shopify.dev/docs/api/multipass)という`SSO`の機能が提供されており、メールアドレスだけでSSOできたので、アプリのログインのstateをみてログインユーザはmultipassログインをしてトークンを受け取り、そのトークンを**ReactNativeのCookieマネージャーで管理して、WebViewに渡す**ことでセッションを保持することに成功した。
<br>
## 取り組みの成果
---
お客さんからは「カートの表示がスムーズ・起動時(スプラッシュ画面)の表示速度が早く、快適。」との評価を得ることができた。
また、全体として、iOSでは195件の評価で`4.8`、Androidでは`4.5`の高評価をいただいています。