# 建立 Amplify Next 專案 + 設定 Gen2 Backend 功能
###### 參考資料:
* https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/
* https://docs.amplify.aws/react/build-a-backend/data/set-up-data/
* https://docs.amplify.aws/react/build-a-backend/auth/use-existing-cognito-resources/
---
AWS 提供的 Amplify 有資料庫功能結合前端框架,很適合個人網站或客製化的中小型網站使用,實現全端架構的網站!
---
### 建立專案
###### Note:建立新的 Amplify App 需要 AWS管理員 開放 [IAM 角色權限](https://docs.aws.amazon.com/zh_tw/amplify/latest/userguide/security-iam-awsmanpol.html)
1. 先[從模板建立專案](https://github.com/new?template_name=amplify-next-template&template_owner=aws-samples&name=amplify-next-template&description=My%20Amplify%20Gen%202%20starter%20application)後,在 [Amplify控制台](https://console.aws.amazon.com/amplify/create/repo-branch) 建立應用
(這裡使用 Amplify 提供的 [Next.js template](https://github.com/aws-samples/amplify-next-template) ,內含 Amplify CI/CD 流程)

2. 連結 Github 帳號與分支

3. 基本設定

4. Review 確認後 deploy 就建立好專案了

---
### Data 設定
1. 在本地打開專案中的 **amplify/data/resource.ts**
更改資料結構

```javascript
Settings: a // Settings 是資料庫名
.model({
key: a.string(), // 欄位 1
value: a.string(), // 欄位 2
})
.authorization((allow) => [allow.publicApiKey()]),
```
2. commit 這筆修改,push 後 Amplify 就會自動開始部署
等部署完就可在 [AWS 管理後台](https://console.aws.amazon.com/amplify/apps) > 專案名 > 點進分支 > 資料 > 資料管理員
看到剛剛新增的資料表 settings
可以直接在這新增資料:

3. 在本地讀取剛剛push完產生的設定檔:
[AWS 管理後台](https://console.aws.amazon.com/amplify/apps) > 專案名 > 點進分支 > 點進最新的部署 > Deployed backend resources > 下載 amplify_outputs.json 檔
存在本地專案根目錄,即可在本地讀取該分支的資料表
(如果一直下載 amplify_outputs.json 沒更新,請用無痕模式下載)
*或用指令部署到沙盒就可在本地操作沙盒資料表
`npx ampx sandbox`
4. 其他資料表操控與呼叫方法可參考 [Amplify Docs Gen2 - Data](https://docs.amplify.aws/nextjs/build-a-backend/data/)
---
### Authentication 設定
這個可以用來跟AWS的 Cognito 溝通,來製作登入註冊的功能
1. 原本模板的設定:
可自定義登入註冊需要的功能,然後 push 到遠端後 Amplify 會自動產生 Cognito 的 User Pool 和 Identity Pool
```typescript
// amplify/auth/resource.ts
import { defineAuth } from "@aws-amplify/backend";
export const auth = defineAuth({
loginWith: {
email: true,
},
});
```
2. 改成連結現有 Cognito (with backend)
需在[Cognito](https://ap-northeast-1.console.aws.amazon.com/cognito/)先建好 User Pool 和 Identity pool
因原本已有 User Pool,這邊只說明建立 App client 與 Identity pool流程:
- App client : Cognito > User pools > App clients > Create app client
要使用SPA方式的,然後 Create

###### App client > Login pages > Edit > Allowed callback URLs, Allowed sign-out URLs 要填寫, 否則 amplify CLI跑不出 amplify_outputs.json
- Identity pool : Cognito > Identity pools > Create identity pool
Step 1 : 勾選Authenticated access, Guest access, Amazon Cognito user pool

Step 2 : 兩種都創新的 IAM role, 名稱結尾分別可用 authauthenticate 與 authauthenticatedU (這邊需要有AWS創立IAM的權限才能成功創建)

Step 3 : 連結到你的User pool跟App client (有下拉選單直接選擇)

Step 4 : 命名 Identity pool

Step 5 : 確認資訊然後就創建完成了
###### * Gen2 文件上有 without backend 的方式,但因已有用 backend 的方式連結 Data 了(如果用without會跟amplify_outputs.json打架),所以一樣用 with backend的方式連結現有 Cognito
3. 在各個 pool 中找到對應的資訊,把amplify/auth/resource.ts 改成以下:
- userPoolClientId 在 User pools > 你的 pool > App clients
- authRoleArn(Authenticated access) 和 unauthRoleArn(Guest access) 在 Identity pools > User access
```typescript
import { referenceAuth } from "@aws-amplify/backend";
import * as dotenv from "dotenv";
/*
在本地 npx ampx sandbox 時,
這裡會讀不到環境變數,要用 dotenv,
然後可在 amplify 後台設環境變數 env=amplify
*/
if (process.env.ENV !== "amplify") {
dotenv.config();
}
export const auth = referenceAuth({
userPoolId: process.env.COGNITO_USER_POOL_ID!,
userPoolClientId: process.env.COGNITO_USER_POOL_CLIENT_ID!,
identityPoolId: process.env.COGNITO_IDENTITY_POOL_ID!,
authRoleArn: process.env.COGNITO_AUTH_ROLE_ARN!,
unauthRoleArn: process.env.COGNITO_UNAUTH_ROLE_ARN!,
});
```
###### * env 變數資訊存在 AWS Amplify > 專案名 > Hosting: Environment variables, 在本地 npx ampx sandbox時讀不到 .env.local的變數
4. 然後跟 Data 設定一樣去 Amplify 控制台取得 amplify_outputs.json 設定檔,或部署到沙盒就可在本地操作沙盒資料
`npx ampx sandbox`
5. 登入註冊相關 API使用方式可參考 [Amplify Docs Gen2 - Authentication](https://docs.amplify.aws/gen2/build-a-backend/auth)
----
### 登入註冊API注意事項
- 建立 User pool 時就要選擇使用哪種方式為帳號識別(email,phone,username),如果要修改就要重建 User pool,例如已經選擇為 email 的話,使用註冊 API 時,email 就會是必填選項
- 註冊時的驗證方式選擇在 Cognito > Sign-up > Attribute verification and user account confirmation 設定
- resendSignUpCode, resetPassword, sendUserAttributeVerificationCode 在短時間內最多只能打 5 次
- Passkey 要對到所使用的 domain 才起作用
User pools > auth.ohread.com > Authentication methods > Passkey > Domain for relying party ID
- 有設定 MFA 的話,Passkey 登入會失敗,兩者不能同時存在
----
### Amplify build output 限制 220MB
要注意的是,Amplify 的 build output 不能超過 220 MB。
#### [檢查 amplify 部署 build ouput 大小:](https://docs.aws.amazon.com/amplify/latest/userguide/troubleshooting-SSR.html#build-output-too-large)
可於 terminal 執行檢查 build output 結構(job-id 為第幾個 Deploy,例如 Deploy20 的 job-id 為 20)
```
aws amplify get-job --app-id abcd1234 --branch-name main --job-id 2
```
執行後找到 `stepName: "BUILD"` 區塊中的 artifactUrl 輸入瀏覽器下載 build output 資料夾
- [Amplify 部署規範](https://docs.aws.amazon.com/zh_cn/amplify/latest/userguide/ssr-deployment-specification.html)
- [Github issue](https://github.com/aws-amplify/amplify-hosting/issues/3647)
- [Github issue](https://github.com/aws-amplify/amplify-hosting/issues/3863)
- [Github issue](https://github.com/alexnguyennz/astro-aws-amplify/issues/23)
----
### 使用 Amplify Auth 遇到的狀況
1. referenceAuth 不支援 Custom Domain
[相關討論](https://github.com/aws-amplify/amplify-backend/issues/2350)
referenceAuth 轉出的 `amplify_outputs.json` (auth.oauth.domain 裡只讀得到 cognito domain )讀不到 Custom Domain,所以要自己設定在 config 裡
```typescript
const outputs = JSON.parse(JSON.stringify(originalOutputs));
outputs.auth.oauth.domain = process.env.NEXT_PUBLIC_AUTH_DOMAIN;
Amplify.configure(outputs);
```
2. Passkey 、MFA不能同時存在
[官方說不會改這功能](https://repost.aws/questions/QU-DKBR1VdQQuRn-WZRFCMzg/cognito-passkey-login-without-email-username-and-with-mfa-enabled)
3. cognito設定 > App client > Login pages > Allowed callback URLs 一定要設兩個:localhost跟線上的callback網址,否則會出現redirect錯誤 (好像只有在使用Hosted UI的時候才會,用Managed login可以)
4. 遇到`User needs to set a password to
sign in`可能的解法:
* 匯入 user CVS 檔時 mfa_enabled 設定要留空
* 在 User Pool 按 Action>Reset password,讓使用者到登入頁走 signIn API 的 RESET_PASSWORD 流程
* 在 AWS CLI 重設 User 密碼
```js
aws cognito-idp admin-set-user-password \
--user-pool-id YOUR_USER_POOL_ID \
--username yourmail@gmail.com \
--password NEW_PASSWORD \
--permanent
```
5. 只有 Managed login 能有 HttpOnly Cookie
[相關連結](https://docs.amplify.aws/nextjs/build-a-backend/server-side-rendering/#authentication-with-nextjs-server-side-runtime)
自己做 layout+Amplify API 不能