年末休暇の自由研究としてSalesforceユーザー一括作成アプリを開発した話

## 先に作ったアプリの動作の様子とリポジトリ
![Salesforceユーザー一括作成動画.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/d1e98260-c343-9568-2c7d-92b2023d0a23.gif)

- リポジトリ：https://github.com/Kyohei-takiyama/my-salesforce-user-app

## 概要
- 作ったアプリ
    - Salesforceのユーザーを一括作成（あるいは更新）できるツール。
- 狙い
    - いろんな技術に触れて「楽しい×学び多い」を実現する
    - 使ったことがない技術を取り入れてスキルアップ
    - もしかしたら業務に活かせるかも？というモチベーションで継続しやすくする

## ポイント

- いろんな技術に触れて楽しむこと
    - 全部が初めてだとハードルが高く、挫折しやすい。半分ぐらいは経験済み技術を取り入れて「ちょうどいい塩梅」にする。
- 挫折しないが学びのある技術選び
    - 「全く触れたことのない技術Only」は魅力的だけどハードルが高い。半々くらいがちょうど良い。
- 作るだけ ではなく 業務効率化への貢献 を見据える
    - 個人開発で終わらず、実際の業務で使えそうな部分がないか考える。
実務での課題感を意識することで、自分のモチベーション維持にもつながる。

## 作成者のスキル感
- Amplify 未経験(存在は知っていた程度)
- Salesforce歴4年
- Terraform歴1年半
- AWS を用いた開発歴1年半
- Nextjs 未経験(ずっとReactで開発していた)
## 主要技術と構成

- AWS Amplify (ホスティング & CI/CD 用途)
- AWS Lambda (API 実行基盤)
- AWS API Gateway (API エンドポイント)
- Terraform (AWS リソースの IaC 化)
- Next.js (フロントエンドフレームワーク)
- Docker + GitHub Actions (Lambda イメージビルド & デプロイ)
- jsforce (Salesforce 連携用)
クラウドもフロントエンドもインフラも、個人的にはまだまだ学びが足りない領域ばかりなので、今回まとめて挑戦してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/5ac62f83-d9dd-7531-0194-f83edbe120c6.png)


## 開発の軌跡
### Amplify のセットアップ
- Terraform で作成
- 最初に作成した状況
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/3135bdf6-2088-47f6-3900-0544e928bf0a.png)
- 作成された直後は自動ではデプロイされないため、アプリ画面を開き、デプロイ画面へ遷移してデプロイを実行する（[参考](https://dev.classmethod.jp/articles/amplify-hosting-github-with-basic-auth/)）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/a98c478d-0f01-65c4-1ece-5770ed0efe29.png)

#### Amplify のセットアップでハマった部分
- buildが失敗する
  - モノレポ構成の場合buildspec.yamlがトップディレクトリに配置される形で実行されるので、buildspec.yaml内に特定のディレクトリに変更するように`cdコマンド`を適宜記述する必要がある
    ```yaml
    version: 1
    frontend:
      phases:
        preBuild:
          commands:
            # ここでディレクトリを変更すれば、"phases"ではディレクトリの移動を書く必要がない
            # https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/edit-build-settings.html#navigating-to-a-subfolder
            - cd frontend
            - npm install
        build:
          commands:
            - npm run build
      artifacts:
        # 出力先もトップディレクトリからのパスを記述しておく
        baseDirectory: "frontend/.next"
        files:
          - '**/*'
      cache:
        paths:
          - node_modules/**/*
    ```
- デプロイ成功してURLを開いても接続できない
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/2b93031c-5a08-fdd4-e0bc-2971013de042.png)
  - プラットフォームとフレームワークの設定をする必要がある

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/4223ee64-3134-f8b5-ec26-bdbc50548a98.png)
    - terraform だと`aws_amplify_app`のリソースセクションに記載
    ```hcl
    resource "aws_amplify_app" "nextjs_app" {
      ...
      
      platform     = "WEB_COMPUTE" # ←ここの話
      auto_branch_creation_config {
        # Enable auto build for the created branch.
        enable_auto_build = true
        framework         = "Next.js - SSR" # ←ここの話
      }
    
      # Basic Auth (カンタンなパスワード保護) やカスタムドメイン設定したい場合は追記可能
    }
    ```
  - 参考にさせていただいた記事二件
    - https://zenn.dev/dsakai07/articles/0aa6678a98a03c
    - https://zenn.dev/makoto00000/articles/4cbfe554ff8837
 - 下記エラーが出てBuildに失敗する
   - `CustomerError: Failed to find the deploy-manifest.json file in the build output. Please verify that it exists within the "baseDirectory" specified in your buildSpec. If it's not there, we will also check the .amplify-hosting directory as a fallback. When using a framework adapter for hosting on Amplify, double-check that the adapter settings are correct.`
   - どうやらモノレポ構成でルートディレクトリを環境変数で設定しないとエラーが出てしまうらしい。  
     - 環境変数を設定すると解決した
        ```hcl
        resource "aws_amplify_app" "nextjs_app" {
          ...
          environment_variables = {
            AMPLIFY_DIFF_DEPLOY       = "false"
            AMPLIFY_MONOREPO_APP_ROOT = "frontend" # ←ここをフロントエンドディレクトリを設定する
          }
        ```
        - 参考にした[Issueコメント](https://github.com/aws-amplify/amplify-hosting/issues/3853#issuecomment-1862011163)


### Backend のセットアップ
- LambdaのデプロイはGithub Actionsを使用
- Dokerfileを用意してビルドしたイメージをAWS ECRへプッシュしLambdaをデプロイする
- Lambdaへイメージを元にデプロイする際のDockerfileは少し特殊なので公式の手順を参考にする
    - https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-image.html#nodejs-image-instructions
- Lambdaのイメージでのデプロイ時に`--platform`を指定して適切なモデルでビルドしないと`Error Type: Runtime.InvalidEntrypoint`という悲しいエラーが出て解決に苦労する可能性があります。（私はこれで結構ハマりました）
- Salesforceへの連携はお馴染みの`jsforce`を使っていきます
- 認証情報などの秘匿情報はローカル実行時には`.envファイル`からでLambdaからの実行時には`AWS Seacret Manager`から取得するようにしました

### Frontend のセットアップ
- ブラウザアプリ（Next.js）から Lambda + API Gateway にリクエストを送る仕組み。
#### ハマった点
- ブラウザからリクエストを送る際にCORSエラーが出た(preflight requestについては[こちらの記事](https://qiita.com/nnishimura/items/1f156f05b26a5bce3672)がわかりやすいです)
  - 結論
    - ブラウザが`preflight request`を送る際にAPI Gateway 側で `OPTIONS リクエスト`に対応するPathを用意していなかったためpreflight requestを捌けずCORSが出ていた
  - 対応
    - AWS API Gateway で OPTIONS メソッドを定義し、Lambda 側でCORS 許可ヘッダーを返す設定が必要。

----------------------------------------

## 作る中で思ったこと
- Amplify の UI がすごく綺麗で見やすい
    - コンソール画面で CI/CD の状態がひと目で分かるのが便利。
- Amplify のモノレポ構成デプロイは大変
    - Terraform でやろうとすると設定項目が多く、ドキュメントが少ない印象。とはいえ、一度ハマりどころを押さえてしまえば今後の再利用がしやすそう。
- API Gateway の設定が意外と手間
    - CORS や OPTIONS メソッドを忘れずに設定する重要性を再認識した。
- 「業務効率化」と結びつけるモチベーション
    - 「これ会社で使えたら便利そう」という気持ちが、学習コストの高さを乗り越える推進力になる。

## まとめ
今回のアプリ開発では、使ったことのある技術半分・初めての技術半分 というバランスで挑戦したことで、適度にチャレンジングでありながらも挫折しにくい環境を作ることができました。
さらに、「ただ作る」だけでなく「業務に活かせるかもしれない」という期待感を持つと、学ぶ過程がより楽しく、モチベーションの維持にもつながります。

今後も新しい技術を取り入れながら、実務につながるような小さなアプリをどんどん作っていきたいです。この記事がどなたかの参考になれば嬉しいです。最後までご覧いただきありがとうございました！