目前只實作 fig.pen 已定義的 donation catalog 列表流程:
- 公益團體列表
- 捐款專案列表
- 義賣商品列表
- 搜尋
- 類別篩選 modal
- infinite scroll / 分頁
- 搜尋中 / 無結果狀態
目前不做:
- 卡片點擊後 detail page
- 捐款流程
- 商品購物車 / 結帳
- 後台
- 這一層是
shared secret access gate,用途是保護 web preview / internal access,不是正式會員登入系統 - 前端層由
deploy/nginx.conf對網站路徑/啟用 HTTP Basic Auth;瀏覽器通過驗證後,會自動對同 origin request 帶上Authorizationheader - 後端層由 Express 全域 middleware 再驗一次 Basic Auth,避免繞過 Nginx 直接打 API
- API 白名單只保留
GET /api/health與 GraphQLhealthquery;其他/api/*路徑都需要驗證 - Basic Auth username 由
WEB_GATE_BASIC_USERNAME決定,預設值是deploy-flow - Basic Auth password 使用
WEB_GATE_SHARED_SECRET - staging / production 的 shared secret 預設存放在 AWS Systems Manager Parameter Store
SecureString - EC2 instance 透過 IAM role / instance profile 讀取 shared secret,deploy 時同步產生 Nginx 用的
deploy/auth/basic.htpasswd WEB_GATE_SESSION_SECRET目前只保留為後續 cookie/session gate 擴充用,現階段尚未使用,也不會 set cookie;目前僅採 Basic Auth header auth- 若未來需要更細的權限模型、rotation 或登入紀錄,再升級成 session-based gate 或正式身份系統
APP_STAGE=local時,database 預設連到本機 Docker PostgreSQL,可用.env覆寫 host / port / db name / username / password / sslAPP_STAGE=local時,web gate secrets 也從 local.env讀取,不依賴 AWS SSMAPP_STAGE=staging或APP_STAGE=production時,database connection 與 web gate secrets 都從 AWS Systems Manager Parameter Store 讀取- 本機開發只有在你主動驗證 non-local stage 設定時,才需要 AWS CLI / AWS SSO 登入與對應 parameter path / KMS decrypt 權限
- 若目標 PostgreSQL 需要自訂 CA 憑證,使用一般 env
DB_SSL_ROOT_CERT_PATH指向 container 內的憑證檔案路徑;此值不放 SSM - 建議 Parameter Store 命名規則為:
/<service>/<stage>/api/database/host/<service>/<stage>/api/database/port/<service>/<stage>/api/database/name/<service>/<stage>/api/database/username/<service>/<stage>/api/database/password/<service>/<stage>/api/database/ssl/<service>/<stage>/api/web-gate/shared-secret/<service>/<stage>/api/web-gate/session-secret
- local / dev 的 migration 可由開發者手動執行,用來驗證本機 Docker PostgreSQL schema
- staging migration 由 deploy workflow 在 EC2 上先執行
db-migration-show -> db-migration-run -> db-migration-show,再更新 container - staging migration 不建議由開發者從本機手動連 staging database 執行
- production migration 也應走 deploy workflow,並在 release 過程中確保同一時間只會有一個 migration job 執行
- deploy workflow 內的 migration job 應使用與應用程式相同的 SSM 參數來源與 IAM 權限
- rollback 不應預設自動執行;若 migration 失敗,先停止 release,再依 migration 內容決定人工 rollback 策略
- GitHub Actions:
.github/workflows/staging.yml - AWS:IAM role、EC2 instance profile、SSM RunCommand、ECR、CloudWatch Logs、Parameter Store
SecureString - staging EC2 套件:Node.js >=20.19、corepack、pnpm、docker、docker compose
- 發佈指令:
docker/build-push-action@v6、aws-actions/amazon-ecr-login@v2、aws-actions/configure-aws-credentials@v4 - 相關 docker-compose:
deploy/docker-compose.ec2.yml、docker-compose.prod.yml - nginx basic auth:
deploy/nginx.conf+deploy/auth/basic.htpasswd
- 目標 DB:PostgreSQL(local Docker
5433/ staging RDS) - migration 控制:
db-migration-show、db-migration-run、db-migration-generate、db-migration-create - seed 指令:
pnpm nx run @deploy-flow/api:db-seed-run,staging 不自動執行 - local 時資料來源:
.env或.env.local - staging/prod 參數來源:SSM Parameter Store
/deploy-flow/staging/api/database/host/deploy-flow/staging/api/database/port/deploy-flow/staging/api/database/name/deploy-flow/staging/api/database/username/deploy-flow/staging/api/database/password/deploy-flow/staging/api/database/ssl/deploy-flow/staging/api/web-gate/shared-secret/deploy-flow/staging/api/web-gate/session-secret
- 啟動本機 PostgreSQL:
pnpm nx run @deploy-flow/api:dev-db-up - 執行 migration:
pnpm nx run @deploy-flow/api:db-migration-run - 查看 migration 狀態:
pnpm nx run @deploy-flow/api:db-migration-show - 產生 migration:
pnpm nx run @deploy-flow/api:db-migration-generate --name=<migration-name> - 建立空白 migration:
pnpm nx run @deploy-flow/api:db-migration-create --name=<migration-name> - 寫入 demo seed:
pnpm nx run @deploy-flow/api:db-seed-run - 啟動 API:
pnpm nx serve @deploy-flow/api - local Docker PostgreSQL host port:
5433 - local 預設不需要 AWS 登入;只要
.env內的 DB 與WEB_GATE_*設定齊全即可 - local GraphQL Sandbox:
http://localhost:3000/api/graphql - local Swagger UI:
http://localhost:3000/api/docs/ - local OpenAPI JSON:
http://localhost:3000/api/openapi.json - 詳細 migration 流程文件:
docs/typeorm-migrations.md - 若要關閉本機 PostgreSQL:
pnpm nx run @deploy-flow/api:dev-db-down
- staging GraphQL Sandbox 路徑固定為
https://stg.bin-hq.com/api/graphql - staging Swagger UI 路徑固定為
https://stg.bin-hq.com/api/docs/ - staging OpenAPI JSON 路徑固定為
https://stg.bin-hq.com/api/openapi.json - staging deploy 時,GitHub Actions 會把
APP_STAGE=staging與AWS_SSM_PARAMETER_PREFIX傳給 EC2 上的 compose stack - staging deploy 會先在 EC2 repo checkout 上執行
pnpm nx run @deploy-flow/api:db-migration-show、db-migration-run、db-migration-show - staging host 需要有
node >= 20.19、corepack/pnpm與 workspace dependencies,deploy workflow 會在git pull後以ec2-user執行pnpm install --frozen-lockfile - 若 staging RDS 需要 CA bundle,先把憑證放到 EC2 的
deploy/certs/rds/,再把 GitHub Actions environment variableSTAGING_DB_SSL_ROOT_CERT_PATH設成 container 內路徑,例如/run/certs/rds/ap-southeast-2-bundle.pem - deploy workflow 會用上述 container 路徑自動推導 host 端 migration runner 的憑證路徑,例如
${STAGING_APP_DIR}/deploy/certs/rds/ap-southeast-2-bundle.pem - staging deploy 也會用
WEB_GATE_SHARED_SECRET自動產生deploy/auth/basic.htpasswd給 Nginx 使用 ap-southeast-2的 RDS CA bundle 可從https://truststore.pki.rds.amazonaws.com/ap-southeast-2/ap-southeast-2-bundle.pem下載到deploy/certs/rds/ap-southeast-2-bundle.pem- staging 的
api/client/nginxcontainer logs 會透過 Dockerawslogsdriver 送到 CloudWatch Logs,預設 log group 分別為/deploy-flow/staging/api、/deploy-flow/staging/client、/deploy-flow/staging/nginx - 若要改名,可在 deploy shell 額外提供
CLOUDWATCH_LOG_GROUP_API、CLOUDWATCH_LOG_GROUP_CLIENT、CLOUDWATCH_LOG_GROUP_NGINX - EC2 instance role 需要至少具備
logs:CreateLogGroup、logs:CreateLogStream、logs:PutLogEvents、logs:DescribeLogStreams - staging demo seed 不建議在每次 deploy 自動執行;應保留為手動 job 或另開管理指令
- 未完成:
- [ ] 任務名稱 - 完成後再改成:
- [x] 任務名稱(YYYY-MM-DD) - 先不要預先打勾;確認完成後再逐項補日期
- 測從
deploy/nginx.conf+Authorization: Basicheader 所支援的驗證(已在apps/api/src/server/create-app.spec.ts) - 測全域 auth guard 會擋住未授權 request(已在
apps/api/src/server/create-app.spec.ts) [ ] 測 POST /api/auth/access-key 驗證成功(目前未實作,Not required for current Basic Auth flow)[ ] 測 POST /api/auth/access-key 驗證失敗(目前未實作,Not required for current Basic Auth flow)[ ] 測 GET /api/auth/session 未登入回 401(目前未實作,Not required for current Basic Auth flow)[ ] 測 GET /api/auth/session 已登入回成功(目前未實作,Not required for current Basic Auth flow)[ ] 測過期 session cookie 會被拒絕(目前未實作,Not required for current Basic Auth flow)
目前
apps/api/src/server/web-gate.ts採用 HTTP Basic Auth(Authorization: Basic ...),不會在後端 Swagger/API 中自動 set cookie。
[ ] 建立首次進站auth/session檢查流程[ ] 建立 shared secret 輸入 UI[ ] 建立驗證失敗時重試輸入流程[ ] 建立驗證成功後重試資料載入流程[ ] 建立未驗證前阻擋 catalog query 的規則[ ] 建立驗證失敗提示文案
- 建立 Apollo GraphQL client(2026-03-18)
- 設定 ApolloProvider 掛到前端 root route(2026-03-18)
- 設定 GraphQL client 預設帶
credentials: 'include'(2026-03-18) - 建立前端 catalog query documents(2026-03-18)
- 建立 donation catalog 頁面路由(2026-03-18)
- 建立頁面外層 layout(2026-03-18)
- 建立頁首標題區塊(2026-03-18)
- 建立三個 tab 切換區塊(2026-03-18)
- 建立 tab active state 樣式(2026-03-18)
- 建立 tab 切換事件與狀態管理(2026-03-18)
- 建立搜尋輸入框元件(2026-03-18)
- 建立搜尋 icon 按鈕(2026-03-18)
- 建立搜尋 placeholder 文案(2026-03-18)
- 建立搜尋輸入狀態(2026-03-18)
- 建立搜尋 debounce(2026-03-18)
- 建立搜尋清空行為(2026-03-18)
- 建立搜尋送出後重置分頁行為(2026-03-18)
- 建立類別篩選 trigger(2026-03-18)
- 建立所有類別 modal 容器(2026-03-18)
- 建立 modal header(2026-03-18)
- 建立 modal 關閉按鈕(2026-03-18)
- 建立類別 chip/button 元件(2026-03-18)
- 建立類別選取 active state(2026-03-18)
- 建立類別切換後重置分頁行為(2026-03-18)
- 建立 modal 關閉後保留目前篩選狀態(2026-03-18)
- 建立公益團體卡元件(2026-03-18)
- 顯示團體 logo(2026-03-18)
- 顯示團體名稱(2026-03-18)
- 顯示團體簡介(2026-03-18)
- 建立公益團體列表容器(2026-03-18)
- 串接公益團體 query(2026-03-18)
- 套用公益團體 keyword 搜尋(2026-03-18)
- 套用公益團體 category 篩選(2026-03-18)
- 套用公益團體 infinite scroll(2026-03-18)
- 建立捐款專案卡元件(2026-03-18)
- 顯示專案封面圖(2026-03-18)
- 顯示所屬團體名稱(2026-03-18)
- 顯示專案標題(2026-03-18)
- 顯示專案類別 tags(2026-03-18)
- 建立捐款專案列表容器(2026-03-18)
- 串接捐款專案 query(2026-03-18)
- 套用捐款專案 keyword 搜尋(2026-03-18)
- 套用捐款專案 category 篩選(2026-03-18)
- 套用捐款專案 infinite scroll(2026-03-18)
- 建立義賣商品卡元件(2026-03-18)
- 顯示商品封面圖(2026-03-18)
- 顯示所屬團體名稱(2026-03-18)
- 顯示商品名稱(2026-03-18)
- 顯示商品價格(2026-03-18)
- 建立義賣商品列表容器(2026-03-18)
- 串接義賣商品 query(2026-03-18)
- 套用義賣商品 keyword 搜尋(2026-03-18)
- 套用義賣商品 category 篩選(2026-03-18)
- 套用義賣商品 infinite scroll(2026-03-18)
- 建立搜尋中 loading UI(2026-03-18)
- 建立列表初次載入 loading UI(2026-03-18)
- 建立載入更多 loading UI(2026-03-18)
- 建立搜尋無結果 UI(2026-03-18)
- 建立 API error UI(2026-03-18)
- 建立 keyword 與 category 同步查詢規則(2026-03-18)
[ ] 測首次進站未通過驗證會先進入 key 驗證流程(2026-03-18)- 測驗證成功後可正常載入 catalog(2026-03-18)
[] 測驗證失敗時不會載入 catalog(2026-03-18)- 測 tab 切換顯示正確列表(2026-03-18)
- 測搜尋輸入會觸發正確 query 參數(2026-03-18)
- 測類別 modal 開關行為(2026-03-18)
- 測類別選取 active state(2026-03-18)
- 測切換類別後列表重置(2026-03-18)
- 測 infinite scroll 追加資料(2026-03-18)
- 測無結果畫面(2026-03-18)
- 測 API error 畫面(2026-03-18)
-
database schema 變更一律走 migration,不使用 TypeORM auto sync /
synchronize: true -
安裝
express(2026-03-17) -
安裝
@apollo/server(2026-03-17) -
安裝
@as-integrations/express5(2026-03-17) -
安裝 TypeORM database driver(2026-03-17)
-
建立 Express app bootstrap(2026-03-17)
-
建立 Apollo GraphQL middleware 設定(2026-03-17)
-
建立 TypeORM
DataSource設定(2026-03-17) -
確認所有環境關閉 TypeORM auto sync(2026-03-17)
-
建立環境變數設定檔(2026-03-17)
-
定義
local full env + non-local full SSM設定策略(2026-03-17)
- 設定 staging API 透過 SSM 讀取 database 與 web gate secrets(2026-03-17)
- 設定 staging RDS CA bundle 掛載到 API container(2026-03-17)
- 設定 staging
api/client/nginxlogs 送到 CloudWatch Logs(2026-03-17) - 設定 staging deploy 先執行 migration 再更新 container(2026-03-18)
- 驗證 staging
/api/health可用(2026-03-17) - 驗證 staging
/api/graphql可載入 Apollo Sandbox(2026-03-17)
[ ] 建立POST /api/auth/access-key[ ] 建立GET /api/auth/session- 建立 shared secret 驗證 service(2026-03-18)
[ ] 建立 session cookie 簽發邏輯- 建立 session 驗證邏輯
- 建立全域 auth middleware(2026-03-18)
- 設定 auth whitelist(2026-03-18)
[] 加入 cookie parser- 設定 CORS credentials 策略(2026-03-17)
- 定義 SSM shared secret 載入策略(2026-03-17)
- 定義 SSM session secret 載入策略(2026-03-17)
[ ] 定義 cookie expiration 設定[ ] 加入 auth rate limiting- 定義 EC2 啟動時讀取 secret 的策略(2026-03-17)
- 定義 Parameter Store / Secrets Manager secret 路徑命名(2026-03-17)
- 建立
AssetEntity(2026-03-17) - 建立
CategoryEntity(2026-03-17) - 建立
OrganizationEntity(2026-03-17) - 建立
DonationProjectEntity(2026-03-17) - 建立
SaleProductEntity(2026-03-17) - 建立
OrganizationCategoryEntity(2026-03-17) - 建立
ProjectCategoryEntity(2026-03-17) - 建立
ProductCategoryEntity(2026-03-17) - 設定 organization -> logo relation(2026-03-17)
- 設定 organization -> categories relation(2026-03-17)
- 設定 donation project -> organization relation(2026-03-17)
- 設定 donation project -> categories relation(2026-03-17)
- 設定 donation project -> cover relation(2026-03-17)
- 設定 sale product -> organization relation(2026-03-17)
- 設定 sale product -> categories relation(2026-03-17)
- 設定 sale product -> cover relation(2026-03-17)
- 建立初始 migration(2026-03-18)
- 建立 migration 執行指令(2026-03-17)
- 建立 migration rollback 指令(2026-03-17)
- 建立 categories seed(2026-03-18)
- 建立 organizations seed(2026-03-18)
- 建立 donation projects seed(2026-03-18)
- 建立 sale products seed(2026-03-18)
- 建立 asset seed(2026-03-18)
- 建立 organization_categories seed(2026-03-18)
- 建立 project_categories seed(2026-03-18)
- 建立 product_categories seed(2026-03-18)
- 建立 seed 執行指令(2026-03-17)
- 驗證 seed 後三個 tab 都有資料(2026-03-18)
- 建立 TypeORM
AssetRepositoryimplementation(2026-03-18) - 建立 TypeORM
CategoryRepositoryimplementation(2026-03-18) - 建立 TypeORM
OrganizationRepositoryimplementation(2026-03-18) - 建立 TypeORM
DonationProjectRepositoryimplementation(2026-03-18) - 建立 TypeORM
SaleProductRepositoryimplementation(2026-03-18) - 建立 request-scoped catalog DataLoader(2026-03-18)
-
所有列表 pagination 一律採用 cursor-based pagination strategy
-
實作公益團體 keyword 搜尋(2026-03-18)
-
實作公益團體 category 篩選(2026-03-18)
-
實作公益團體 cursor pagination(2026-03-18)
-
實作捐款專案 keyword 搜尋(2026-03-18)
-
實作捐款專案 category 篩選(2026-03-18)
-
實作捐款專案 cursor pagination(2026-03-18)
-
實作捐款專案 categories 載入(2026-03-18)
-
實作義賣商品 keyword 搜尋(2026-03-18)
-
實作義賣商品 category 篩選(2026-03-18)
-
實作義賣商品 cursor pagination(2026-03-18)
-
實作義賣商品 categories 載入(2026-03-18)
-
實作義賣商品 price 欄位返回(2026-03-18)
-
實作 categories 排序查詢(2026-03-18)
- 建立 code-first GraphQL schema 建構流程(2026-03-18)
- 自動產出
graphql/schema.graphql(2026-03-18) - 建立
AssetGraphQL type(2026-03-18) - 建立
CategoryGraphQL type(2026-03-18) - 建立
OrganizationGraphQL type(2026-03-18) - 建立
DonationProjectGraphQL type(2026-03-18) - 建立
SaleProductGraphQL type(2026-03-18) - 建立
PageInfoGraphQL type(2026-03-18) - 建立
OrganizationConnectiontype(2026-03-18) - 建立
DonationProjectConnectiontype(2026-03-18) - 建立
SaleProductConnectiontype(2026-03-18) - 建立
CatalogConnectionArgs(2026-03-18) - 建立 catalog query resolver(2026-03-18)
- 建立
OrganizationResolver(2026-03-18) - 建立
DonationProjectResolver(2026-03-18) - 建立
SaleProductResolver(2026-03-18)
[ ] 測POST /api/auth/access-key驗證成功[ ] 測POST /api/auth/access-key驗證失敗[ ] 測GET /api/auth/session未登入回 401[ ] 測GET /api/auth/session已登入回成功- 測全域 auth guard 會擋住未授權 request
[ ] 測過期 session cookie 會被拒絕- 測 cursor pagination helper(2026-03-18)
- 測 catalog DataLoader 映射(2026-03-18)
- 測 catalog query resolver input / output(2026-03-18)
- 測 code-first schema 產出內容(2026-03-18)
- 測 field resolvers 透過 DataLoader 取值(2026-03-18)
- 測 seed 後 query 可正常回資料
pnpm nx show projects
pnpm nx test @deploy-flow/api
pnpm nx test @deploy-flow/client
pnpm nx test @deploy-flow/api-e2e