diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ed5f12..4b93b5f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ your contributions are licensed under the same terms. ### 运行测试 项目提供跨平台测试套件(Windows / macOS / Linux),详见 -[`docs/LOCAL_TESTING.md`](docs/LOCAL_TESTING.md): +[`docs/zh-CN/LOCAL_TESTING.md`](docs/zh-CN/LOCAL_TESTING.md): ```bash # 后端 —— pytest + moto(内存模拟 DynamoDB,无需 Docker / AWS) @@ -151,7 +151,7 @@ CI 在每次 Pull Request 时运行二者,见 [`.github/workflows/`](.github/w - **Angular/TypeScript**:遵循现有 standalone 组件 + Material M3 模式,不要重新 引入已废弃的包(如 `@angular/flex-layout`)。 - **不提交敏感信息**:切勿提交 Cognito 池/客户端 ID、API URL、邮箱、密码或 AWS - 账号 ID。使用占位符并在 [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) 中说明。 + 账号 ID。使用占位符并在 [`docs/zh-CN/CONFIGURATION.md`](docs/zh-CN/CONFIGURATION.md) 中说明。 ### 贡献的许可 diff --git a/README.zh-CN.md b/README.zh-CN.md index 89834eb..f2be36f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -10,7 +10,7 @@ 本项目派生自 AWS 官方的 [AWS Serverless SaaS Workshop](https://github.com/aws-samples/aws-serverless-saas-workshop)(基于其 `Lab6`),并在其基础上做了**后端架构重构、数据模型简化、运行时与依赖升级、部署脚本增强**等大量修改,已作为独立衍生项目按 MIT-0 演进。 -- 完整的差异清单与原因:[`docs/CHANGES_FROM_WORKSHOP.md`](docs/CHANGES_FROM_WORKSHOP.md) +- 完整的差异清单与原因:[`docs/zh-CN/CHANGES_FROM_WORKSHOP.md`](docs/zh-CN/CHANGES_FROM_WORKSHOP.md) - 版权溯源与署名:[`NOTICE`](NOTICE) | 许可证:[`LICENSE`](LICENSE)(MIT-0) ## 核心特性 @@ -165,7 +165,7 @@ aws-serverless-saas-quickstart/ - [`docs/zh-CN/TENANT_MANAGEMENT.md`](docs/zh-CN/TENANT_MANAGEMENT.md) —— 平台租户管理实现(生命周期、用户/租户关联、权限控制、分级) - [`docs/zh-CN/API_CONFIGURATION.md`](docs/zh-CN/API_CONFIGURATION.md) —— 管理端与租户端接口配置关系剖析 - [`docs/zh-CN/THROTTLING_AND_MONITORING.md`](docs/zh-CN/THROTTLING_AND_MONITORING.md) —— 监控运维、使用计划限流,以及 CloudWatch 限流指标机制 -- [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) | [`docs/LOCAL_TESTING.md`](docs/LOCAL_TESTING.md) | [`docs/CHANGES_FROM_WORKSHOP.md`](docs/CHANGES_FROM_WORKSHOP.md) | [`docs/DEPENDENCY_AUDIT.md`](docs/DEPENDENCY_AUDIT.md) +- [`docs/zh-CN/CONFIGURATION.md`](docs/zh-CN/CONFIGURATION.md) | [`docs/zh-CN/LOCAL_TESTING.md`](docs/zh-CN/LOCAL_TESTING.md) | [`docs/zh-CN/CHANGES_FROM_WORKSHOP.md`](docs/zh-CN/CHANGES_FROM_WORKSHOP.md) | [`docs/zh-CN/DEPENDENCY_AUDIT.md`](docs/zh-CN/DEPENDENCY_AUDIT.md) 深度剖析的英文版位于 [`docs/`](docs/) 根目录。 @@ -303,7 +303,7 @@ ng serve ### 测试 -跨平台测试套件(Windows / macOS / Linux),详见 [`docs/LOCAL_TESTING.md`](docs/LOCAL_TESTING.md): +跨平台测试套件(Windows / macOS / Linux),详见 [`docs/zh-CN/LOCAL_TESTING.md`](docs/zh-CN/LOCAL_TESTING.md): ```bash # 后端:pytest + moto(内存模拟 DynamoDB,无需 Docker / AWS) @@ -349,7 +349,7 @@ CI 见 `.github/workflows/`:`backend-tests.yml`(三平台 pytest)、`front ## 许可证 本项目基于 [MIT-0](LICENSE) 许可证开源。上游溯源与署名见 [`NOTICE`](NOTICE), -与上游 Workshop 的差异见 [`docs/CHANGES_FROM_WORKSHOP.md`](docs/CHANGES_FROM_WORKSHOP.md)。 +与上游 Workshop 的差异见 [`docs/zh-CN/CHANGES_FROM_WORKSHOP.md`](docs/zh-CN/CHANGES_FROM_WORKSHOP.md)。 ## 相关资源 diff --git a/SECURITY.md b/SECURITY.md index 2758ca0..94528c0 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -138,7 +138,7 @@ This project is distributed under the terms in [LICENSE](LICENSE). - **切勿将硬编码的凭据**(密码、API 密钥、令牌)提交到仓库。请使用环境变量、参数存储或 密钥管理服务。 - 已知的依赖安全公告及其修复方案记录在 - [docs/DEPENDENCY_AUDIT.md](docs/DEPENDENCY_AUDIT.md) 中。例如,为避免 CVE-2024-33663 + [docs/zh-CN/DEPENDENCY_AUDIT.md](docs/zh-CN/DEPENDENCY_AUDIT.md) 中。例如,为避免 CVE-2024-33663 与 CVE-2024-33664,从无人维护的 `python-jose` 迁移到 `PyJWT[crypto]` 的过程便记录于此。 本项目依据 [LICENSE](LICENSE) 中的条款进行分发。 diff --git a/docs/CHANGES_FROM_WORKSHOP.md b/docs/CHANGES_FROM_WORKSHOP.md index a1f85ff..cd2ed32 100644 --- a/docs/CHANGES_FROM_WORKSHOP.md +++ b/docs/CHANGES_FROM_WORKSHOP.md @@ -1,114 +1,154 @@ -# 与上游 AWS Serverless SaaS Workshop 的差异说明 +# Changes from the Upstream AWS Serverless SaaS Workshop -本文件记录 **aws-serverless-saas-quickstart** 相对上游 **AWS Serverless SaaS -Workshop**(`aws-samples/aws-serverless-saas-workshop`,对应其 `Lab6`)所做的 -修改及原因。 +[**English**](CHANGES_FROM_WORKSHOP.md) | [中文](zh-CN/CHANGES_FROM_WORKSHOP.md) -## 1. 血缘与定位 +[← Back to README](../README.md) -- 本项目派生自上游 Workshop 的 **Lab6**(最终实验版本)。版权与许可证溯源见 - 仓库根目录的 [`NOTICE`](../NOTICE) 与 [`LICENSE`](../LICENSE)(MIT-0)。 -- 上游 Workshop 是一套**教学实验序列**(Lab1~Lab7,逐步引导搭建),定位是培训 - 材料;本项目则把 Lab6 重构为一个**可直接落地、结构精简的参考实现/快速启动模板**。 -- **本项目已作为独立衍生项目演进,不再向上游回馈改动**,原因见第 4 节。 +This document records the changes that **aws-serverless-saas-quickstart** makes +relative to the upstream **AWS Serverless SaaS Workshop** +(`aws-samples/aws-serverless-saas-workshop`, corresponding to its `Lab6`), and +the reasons behind them. -## 2. 差异概览 +## 1. Lineage and Positioning -以 quickstart 对比 workshop/Lab6(已排除 `node_modules`、构建产物等): +- This project is derived from **Lab6** of the upstream Workshop (its final lab + version). For copyright and license provenance, see the [`NOTICE`](../NOTICE) + and [`LICENSE`](../LICENSE) (MIT-0) files in the repository root. +- The upstream Workshop is a **teaching lab sequence** (Lab1–Lab7, building up + step by step), positioned as training material; this project instead + refactors Lab6 into a **directly deployable, streamlined reference + implementation / quick-start template**. +- **This project has evolved as an independent derivative and no longer + contributes changes back upstream**; the reasons are given in Section 4. -| 类别 | 文件数 | 说明 | +## 2. Overview of Differences + +Comparing quickstart against workshop/Lab6 (excluding `node_modules`, build +artifacts, etc.): + +| Category | File count | Notes | |---|---:|---| -| 完全相同 | 184 | 多为前端 Angular 脚手架、Landing 页、未改动的模板 | -| 同路径但已修改 | 24 | 依赖升级、配置、部分前端 service/model | -| 仅 quickstart(新增) | 69 | 重构后的新结构、新增运维脚本、许可证文件等 | -| 仅 Lab6(被替换/删除) | 38 | 旧的扁平 server 结构 | - -按文件数约 66% 相同,但相同部分集中在前端样板;**后端(项目核心)几乎被重写**。 - -## 3. 主要变更与原因 - -### 3.1 后端架构:单体模板 → 按服务拆分 -- **变更**:上游 server 下的扁平服务目录(`ProductService/`、`OrderService/`、 - `TenantManagementService/`)与两个大模板(`shared-template.yaml`、 - `tenant-template.yaml`)被重组为: - - `server/services/{product-service, order-service, tenant-api}/`——每个服务 - 拥有**独立**的 `template.yaml` + `samconfig.toml`(拆成可独立部署的微栈); - - Python 代码引入 DAL 分层:`*_service.py` + `*_service_dal.py` + `*_models.py`。 -- **原因**:降低服务间耦合、支持服务独立部署、提升模板可维护性。 -- **相关提交**:`bcb1d1a` (restructure serverless SaaS architecture with service - separation)、`0805565`、`753aa67`、`666dd8b`。 - -### 3.2 共享资源归集到 `server/shared/` -- **变更**:`layers/`、`nested_templates/`、`custom_resources/`、`Auth/`、 - `tenant-management/` 等由散落在 server 根目录,统一收纳到 - `server/shared/{auth, layers, nested_templates, custom_resources, tenant-management}/`。 -- **原因**:明确区分「共享基础设施」与「业务服务」,目录职责更清晰。 -- **相关提交**:`0805565` (move tenant-management from infrastructure to shared)、 - `753aa67` (restructure shared infrastructure directory layout)、 - `b632860` (reorganize auth components)。 - -### 3.3 数据模型:移除 `shardId` 分片,改用 `tenant_id` 分区键 -- **变更**:Order / Product 服务的 DynamoDB 设计由「`shardId` 分片 + 并行查询」 - 改为以 `tenant_id` 作为分区键的简化设计;同步更新数据模型、CRUD 与前端模板。 -- **原因**:消除复杂的分片/并行查询逻辑,数据分布更可预测,降低存储与查询成本 - (详见 README「数据库设计规则」一节)。 -- **相关提交**:`37a2587` (use tenant_id instead of shardId)、`40ea9ff`。 - -### 3.4 Python 运行时升级到 3.13 -- **变更**:Lambda 运行时与 CDK 流水线由旧版本统一升级到 **Python 3.13**, - CodeBuild 构建镜像改为 `STANDARD_7_0`。 -- **原因**:上游使用的旧运行时已接近/到达 EOL,升级以获得长期支持与安全更新。 -- **相关提交**:`7ea8533`。 - -### 3.5 依赖修复与升级(含 AWS Lambda Powertools) -- **变更**:修复并升级过时依赖,重点修正 Powertools 相关依赖。 -- **原因**:上游依赖版本过时,存在兼容性/安全问题。 -- **相关提交**:`b632860` (fix powertools dependencies)。 - -### 3.6 前端:Angular 与 Amplify 调整 -- **变更**:初期尝试 Angular 16.2.12 + AWS Amplify v6(`51c412b`),后因兼容性 - **回滚到 Angular 14.x**,并将认证逻辑改为更新后的 Amplify 调用方式(`184f5f9`)。 -- **原因**:版本兼容性与稳定性。 -- **相关提交**:`51c412b`、`184f5f9`、`40ea9ff`。 - -### 3.7 部署与运维脚本增强 -- **变更**: - - 各前端 `package.json` 增加 `deploy` / `reset` 脚本(S3 sync + CloudFront 失效); - - 新增一批 Node.js 运维工具脚本:`create-admin-user.js`、`manage-users.js`、 - `set-admin-password.js`、`get-login-info.js`、`generate-env-config.js`; - - 新增 `scripts/DEPLOYMENT_GUIDE.md` 部署指南。 -- **原因**:简化部署流程与租户/管理员用户的日常管理。 -- **相关提交**:`5366935` 及上述新增文件。 - -### 3.8 其他配置调整 -- 租户栈命名 `pooled-tenant-stack` → `stack-pooled`(`8634f86`)。 -- `LambdaReserveConcurrency` 默认值 `20` → `0`(`2a262ad`),避免在账号预留并发 - 配额受限的环境下部署失败。 - -## 4. 为什么不再向上游回馈 - -1. **结构性重构难以回馈**:目录改名、模板拆分、数据模型变更使绝大多数改动无法 - 干净地 cherry-pick 回上游——路径与结构都对不上,PR 会变成大规模的「删一片、 - 加一片」,评审与合并成本极高。 -2. **定位不同**:上游是分步教学的实验序列(Lab1~Lab7),刻意保留逐层演进的结构; - 本项目是面向落地的精简产品,二者目标不一致。 -3. **维护独立**:因此本项目作为**独立衍生项目**维护,按 MIT-0 开源;上游署名与 - 来源在 `NOTICE` 中保留。 - -> 注:仅有少量「同路径的窄改动」(如部署脚本修复、个别依赖升级)在技术上仍可回馈, -> 但综合收益有限,当前不作为目标。 - -## 5. 结构对照(旧 → 新) - -| 上游 Lab6 路径 | quickstart 路径 | +| Identical | 184 | Mostly the Angular frontend scaffolding, landing page, and unmodified templates | +| Same path but modified | 24 | Dependency upgrades, configuration, some frontend services/models | +| quickstart only (added) | 69 | The refactored new structure, new operational scripts, license files, etc. | +| Lab6 only (replaced/removed) | 38 | The old flat server structure | + +By file count roughly 66% is identical, but the identical portion is +concentrated in frontend boilerplate; **the backend (the core of the project) +is almost entirely rewritten**. + +## 3. Major Changes and Reasons + +### 3.1 Backend Architecture: Monolithic Templates → Per-Service Split +- **Change**: The flat service directories under the upstream `server` + (`ProductService/`, `OrderService/`, `TenantManagementService/`) and the two + large templates (`shared-template.yaml`, `tenant-template.yaml`) were + reorganized into: + - `server/services/{product-service, order-service, tenant-api}/` — each + service has its **own** `template.yaml` + `samconfig.toml` (split into + independently deployable micro-stacks); + - The Python code introduces a DAL layering: `*_service.py` + + `*_service_dal.py` + `*_models.py`. +- **Reason**: Reduce coupling between services, support independent service + deployment, and improve template maintainability. +- **Related commits**: `bcb1d1a` (restructure serverless SaaS architecture with + service separation), `0805565`, `753aa67`, `666dd8b`. + +### 3.2 Shared Resources Consolidated into `server/shared/` +- **Change**: `layers/`, `nested_templates/`, `custom_resources/`, `Auth/`, + `tenant-management/`, etc., which were scattered across the server root, were + consolidated into + `server/shared/{auth, layers, nested_templates, custom_resources, tenant-management}/`. +- **Reason**: Clearly distinguish "shared infrastructure" from "business + services", giving directories clearer responsibilities. +- **Related commits**: `0805565` (move tenant-management from infrastructure to + shared), `753aa67` (restructure shared infrastructure directory layout), + `b632860` (reorganize auth components). + +### 3.3 Data Model: Remove `shardId` Sharding, Switch to `tenant_id` Partition Key +- **Change**: The DynamoDB design for the Order / Product services was changed + from "`shardId` sharding + parallel queries" to a simplified design that uses + `tenant_id` as the partition key; the data models, CRUD, and frontend + templates were updated accordingly. +- **Reason**: Eliminate the complex sharding/parallel-query logic, make the data + distribution more predictable, and reduce storage and query costs (see the + "Database Design Rules" section of the README for details). +- **Related commits**: `37a2587` (use tenant_id instead of shardId), `40ea9ff`. + +### 3.4 Python Runtime Upgraded to 3.13 +- **Change**: The Lambda runtime and the CDK pipeline were unified and upgraded + from older versions to **Python 3.13**, and the CodeBuild build image was + changed to `STANDARD_7_0`. +- **Reason**: The older runtime used upstream was near/at EOL; the upgrade + obtains long-term support and security updates. +- **Related commits**: `7ea8533`. + +### 3.5 Dependency Fixes and Upgrades (incl. AWS Lambda Powertools) +- **Change**: Fixed and upgraded outdated dependencies, with a focus on + correcting Powertools-related dependencies. +- **Reason**: The upstream dependency versions were outdated and had + compatibility/security issues. +- **Related commits**: `b632860` (fix powertools dependencies). + +### 3.6 Frontend: Angular and Amplify Adjustments +- **Change**: An initial attempt at Angular 16.2.12 + AWS Amplify v6 + (`51c412b`) was later **rolled back to Angular 14.x** due to compatibility + issues, with the authentication logic changed to the updated Amplify call + style (`184f5f9`). +- **Reason**: Version compatibility and stability. +- **Related commits**: `51c412b`, `184f5f9`, `40ea9ff`. + +### 3.7 Deployment and Operations Script Enhancements +- **Change**: + - Each frontend `package.json` gained `deploy` / `reset` scripts (S3 sync + + CloudFront invalidation); + - A batch of new Node.js operational tooling scripts was added: + `create-admin-user.js`, `manage-users.js`, `set-admin-password.js`, + `get-login-info.js`, `generate-env-config.js`; + - Added the `scripts/DEPLOYMENT_GUIDE.md` deployment guide. +- **Reason**: Simplify the deployment process and the day-to-day management of + tenant/admin users. +- **Related commits**: `5366935` and the new files listed above. + +### 3.8 Other Configuration Adjustments +- Tenant stack naming `pooled-tenant-stack` → `stack-pooled` (`8634f86`). +- `LambdaReserveConcurrency` default value `20` → `0` (`2a262ad`), to avoid + deployment failures in environments where the account's reserved-concurrency + quota is constrained. + +## 4. Why We No Longer Contribute Back Upstream + +1. **Structural refactoring is hard to contribute back**: directory renames, + template splits, and data-model changes make the vast majority of changes + impossible to cleanly cherry-pick back upstream — the paths and structure no + longer line up, and a PR would turn into a large-scale "delete one chunk, add + another chunk", making review and merge costs extremely high. +2. **Different positioning**: the upstream is a step-by-step teaching lab + sequence (Lab1–Lab7) that deliberately preserves a layer-by-layer evolving + structure; this project is a streamlined product aimed at deployment, and the + two have inconsistent goals. +3. **Independent maintenance**: this project is therefore maintained as an + **independent derivative**, open-sourced under MIT-0; the upstream attribution + and provenance are preserved in `NOTICE`. + +> Note: only a small number of "narrow same-path changes" (such as deployment +> script fixes and a few dependency upgrades) are technically still +> contributable, but the overall benefit is limited, so this is not a current +> goal. + +## 5. Structure Mapping (Old → New) + +| Upstream Lab6 path | quickstart path | |---|---| | `server/ProductService/` | `server/services/product-service/src/` | | `server/OrderService/` | `server/services/order-service/src/` | -| `server/TenantManagementService/` | `server/shared/tenant-management/`、`server/services/tenant-api/` | +| `server/TenantManagementService/` | `server/shared/tenant-management/`, `server/services/tenant-api/` | | `server/Auth/` | `server/shared/auth/` | | `server/layers/` | `server/shared/layers/` | | `server/nested_templates/` | `server/shared/nested_templates/` | | `server/custom_resources/` | `server/shared/custom_resources/` | -| `server/shared-template.yaml` + `server/tenant-template.yaml` | 拆分为各服务 `services/*/template.yaml` + `server/shared/**` + `server/services/template.yaml` | +| `server/shared-template.yaml` + `server/tenant-template.yaml` | split into per-service `services/*/template.yaml` + `server/shared/**` + `server/services/template.yaml` | -> 上表为目录级对应关系,文件在迁移过程中可能伴随重命名与代码重构,仅供溯源参考。 +> The table above shows directory-level correspondences; files may have been +> renamed and code refactored during migration, so it is for provenance +> reference only. diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index c79aacb..1209c36 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -1,48 +1,56 @@ -# 配置指南(前端环境与 Cognito) +# Configuration Guide (Frontend Environment & Cognito) -本仓库**不包含任何真实部署的标识符**。以下文件中的值均为**占位符**, -需替换为你自己部署的值后再构建/运行。 +[**English**](CONFIGURATION.md) | [中文](zh-CN/CONFIGURATION.md) -> 说明:Cognito User Pool ID、App Client ID、API Gateway URL、CloudFront -> Distribution ID 都会被打包进浏览器或脚本,**并非机密**;占位化的目的是 -> 不让本公开仓库绑定到任何特定的 AWS 部署。 +[← Back to README](../README.md) -## 需要填写的占位符 +This repository **does not contain any real deployment identifiers**. The values in +the files below are all **placeholders** and must be replaced with your own +deployment's values before building/running. -| 占位符 | 含义 | 出现位置 | +> Note: The Cognito User Pool ID, App Client ID, API Gateway URL, and CloudFront +> Distribution ID all get bundled into the browser or into scripts, so they are +> **not secrets**; the purpose of using placeholders is simply to avoid binding +> this public repository to any specific AWS deployment. + +## Placeholders to fill in + +| Placeholder | Meaning | Where it appears | |---|---|---| -| `us-east-1_XXXXXXXXX` | Cognito User Pool ID | `client/Admin/src/aws-exports.ts`、`client/Admin/script/auth-config.js` | -| `XXXXXXXXXXXXXXXXXXXXXXXXXX` | Cognito App Client ID | 同上 | -| `YOUR_API_ID` | 共享 API Gateway 的 REST API ID | 各 app `src/environments/environment*.ts` | -| `YOUR_CLOUDFRONT_DISTRIBUTION_ID` | 各站点的 CloudFront 分发 ID | 各 app `package.json` 的 `reset` 脚本 | +| `us-east-1_XXXXXXXXX` | Cognito User Pool ID | `client/Admin/src/aws-exports.ts`, `client/Admin/script/auth-config.js` | +| `XXXXXXXXXXXXXXXXXXXXXXXXXX` | Cognito App Client ID | Same as above | +| `YOUR_API_ID` | REST API ID of the shared API Gateway | `src/environments/environment*.ts` in each app | +| `YOUR_CLOUDFRONT_DISTRIBUTION_ID` | CloudFront distribution ID for each site | The `reset` script in each app's `package.json` | -## 方式一:脚本生成(推荐,针对 environment.ts) +## Option 1: Generate with a script (recommended, for environment.ts) -仓库已提供 `scripts/generate-env-config.js`,会用 AWS CLI 查询共享 API 并 -生成对应 app 的 `environment.ts`: +The repository already provides `scripts/generate-env-config.js`, which uses the +AWS CLI to query the shared API and generate the `environment.ts` for the +corresponding app: ```bash -# 需先配置好 AWS CLI 凭证与区域 +# AWS CLI credentials and region must be configured first node scripts/generate-env-config.js Admin prod node scripts/generate-env-config.js Application prod node scripts/generate-env-config.js Landing prod ``` -## 方式二:手动填写 +## Option 2: Fill in manually -1. **Cognito**(`client/Admin/src/aws-exports.ts`):把 `us-east-1_XXXXXXXXX`、 - `XXXXXXXXXXXXXXXXXXXXXXXXXX` 替换为你的 User Pool ID 与 App Client ID。 -2. **API URL**(`client/*/src/environments/environment*.ts`):把 `YOUR_API_ID` - 替换为共享 API Gateway 的 REST API ID。 -3. **CloudFront**(`client/*/package.json` 的 `reset` 脚本):把 - `YOUR_CLOUDFRONT_DISTRIBUTION_ID` 替换为各站点分发 ID。 +1. **Cognito** (`client/Admin/src/aws-exports.ts`): replace `us-east-1_XXXXXXXXX` + and `XXXXXXXXXXXXXXXXXXXXXXXXXX` with your User Pool ID and App Client ID. +2. **API URL** (`client/*/src/environments/environment*.ts`): replace `YOUR_API_ID` + with the REST API ID of the shared API Gateway. +3. **CloudFront** (the `reset` script in `client/*/package.json`): replace + `YOUR_CLOUDFRONT_DISTRIBUTION_ID` with each site's distribution ID. -## ⚠️ 避免再次提交真实值 +## ⚠️ Avoid committing real values again -填入真实值后,**不要把它们提交回仓库**。建议本地用下列方式之一隔离: +After filling in real values, **do not commit them back to the repository**. We +recommend isolating them locally using one of the following approaches: ```bash -# 让 git 忽略对这些文件的本地改动(不影响他人) +# Have git ignore your local changes to these files (without affecting others) git update-index --skip-worktree \ client/Admin/src/aws-exports.ts \ client/Admin/src/environments/environment.ts \ @@ -53,4 +61,4 @@ git update-index --skip-worktree \ client/Landing/src/environments/environment.prod.ts ``` -(撤销:`git update-index --no-skip-worktree `) +(To undo: `git update-index --no-skip-worktree `) diff --git a/docs/DEPENDENCY_AUDIT.md b/docs/DEPENDENCY_AUDIT.md index 4b8bffc..74ac51f 100644 --- a/docs/DEPENDENCY_AUDIT.md +++ b/docs/DEPENDENCY_AUDIT.md @@ -1,86 +1,90 @@ -# 依赖与运行时支持状态审计 +# Dependency & Runtime Support Status Audit -> 审计日期:2026-06-14 | 对照"当前社区维护 / AWS 官方支持"状态 +[**English**](DEPENDENCY_AUDIT.md) | [中文](zh-CN/DEPENDENCY_AUDIT.md) -## 总体结论 +[← Back to README](../README.md) -- **后端 / 基础设施**:运行时选型健康,当前受支持。 -- **前端**:Angular / Amplify 技术栈整体已 **EOL(生命周期结束)**,停留在 2022 年版本。 -- **最高优先安全项**:`python-jose` 已弃维且存在活跃 CVE,需替换。 +> Audit date: 2026-06-14 | Assessed against "current community maintenance / official AWS support" status + +## Overall Conclusion + +- **Backend / infrastructure**: Runtime choices are healthy and currently supported. +- **Frontend**: The Angular / Amplify stack is **EOL (end of life)** overall, frozen at 2022 versions. +- **Highest-priority security item**: `python-jose` is unmaintained and has active CVEs; it must be replaced. --- -## 1. 后端 / 基础设施(✅ 大体良好) +## 1. Backend / Infrastructure (✅ Largely Healthy) -| 组件 | 代码中版本 | 状态 | 说明 | +| Component | Version in code | Status | Notes | |---|---|---|---| -| Lambda runtime | `python3.13` | ✅ 当前受支持 | AWS 支持至约 2029-10;最新已是 3.14(2025-11),3.13 为稳妥 LTS | -| CodeBuild 镜像 | `STANDARD_7_0` + `python:3.13` | ✅ 可用 | Python 3.13 自 2025-03 起内置于 standard:7.0 | -| `aws-cdk-lib` | `^2.0.0` | ✅ 受支持 | CDK v2 在维护(v1 已 2023-06 EOL)。floor 偏低,建议核对 lockfile 解析到最新 2.x | -| `constructs` | `^10.0.0` | ✅ | 与 CDK v2 匹配 | -| `aws-lambda-powertools` `jsonpickle` `simplejson` `requests` `pytest-mock` | 未锁版本 | ✅ 维护中 | — | +| Lambda runtime | `python3.13` | ✅ Currently supported | AWS support through ~2029-10; the latest is already 3.14 (2025-11), 3.13 is a safe LTS choice | +| CodeBuild image | `STANDARD_7_0` + `python:3.13` | ✅ Available | Python 3.13 has been bundled in standard:7.0 since 2025-03 | +| `aws-cdk-lib` | `^2.0.0` | ✅ Supported | CDK v2 is maintained (v1 reached EOL 2023-06). Floor is low; recommend verifying the lockfile resolves to the latest 2.x | +| `constructs` | `^10.0.0` | ✅ | Matches CDK v2 | +| `aws-lambda-powertools` `jsonpickle` `simplejson` `requests` `pytest-mock` | Unpinned | ✅ Maintained | — | -## 2. 后端需要注意(⚠️ / ❌) +## 2. Backend Items to Watch (⚠️ / ❌) -| 项 | 状态 | 影响位置 | 处置 | +| Item | Status | Affected locations | Disposition | |---|---|---|---| -| **`python-jose[cryptography]`** | ❌ 弃维 + CVE | `services/tenant-api`、`shared/auth`、`shared/layers` | **迁移到 `PyJWT`**。涉及 JWT 校验(安全敏感路径)。相关 CVE:CVE-2024-33663(算法混淆)、CVE-2024-33664(JWE DoS) | -| **Python 依赖未锁版本** | ⚠️ 可复现性/供应链风险 | 全部 `requirements.txt` | 固定大版本或引入 lock(pip-tools) | -| `crhelper` / `aws_requests_auth` | ⚠️ 低活跃 | `shared/custom_resources`、多处 | 仍可用,留意 | -| `@types/node` | ⚠️ `10.17.27`(Node 10 已 2021 EOL) | `TenantPipeline` | 升级到与构建 Node 对应的 `@types/node`(仅类型,运行时无影响) | +| **`python-jose[cryptography]`** | ❌ Unmaintained + CVE | `services/tenant-api`, `shared/auth`, `shared/layers` | **Migrate to `PyJWT`**. Involves JWT verification (security-sensitive path). Related CVEs: CVE-2024-33663 (algorithm confusion), CVE-2024-33664 (JWE DoS) | +| **Unpinned Python dependencies** | ⚠️ Reproducibility / supply-chain risk | All `requirements.txt` | Pin major versions or introduce a lock (pip-tools) | +| `crhelper` / `aws_requests_auth` | ⚠️ Low activity | `shared/custom_resources`, multiple places | Still usable, keep an eye on it | +| `@types/node` | ⚠️ `10.17.27` (Node 10 reached EOL 2021) | `TenantPipeline` | Upgrade to a `@types/node` matching the build Node (types only, no runtime impact) | -## 3. 前端(❌ 整体 EOL) +## 3. Frontend (❌ EOL Overall) -| 组件 | 代码中版本 | 状态 | 当前/目标 | +| Component | Version in code | Status | Current / target | |---|---|---|---| -| `@angular/core` / `@angular/cli` | `~14.0.0` / `~14.0.5` | ❌ EOL(约 2023 年底) | 在维护:20(至 2026-11)/ 21(至 2027-05)/ 22 | -| `aws-amplify` | `~4.3.27` | ❌ EOL | 仅 v5/v6 受支持 | -| `@aws-amplify/ui-angular` | `~2.4.14` | ❌ 远古 | 最新 5.3.5,要求 Angular ≥ 19 | -| `typescript` | `~4.7.2` | ⚠️ 旧(被 Angular 14 锁定) | 5.x | -| `rxjs` / `zone.js` | `7.5` / `0.11.4` | ⚠️ 旧(随 Angular 14 绑定) | — | +| `@angular/core` / `@angular/cli` | `~14.0.0` / `~14.0.5` | ❌ EOL (~end of 2023) | Maintained: 20 (through 2026-11) / 21 (through 2027-05) / 22 | +| `aws-amplify` | `~4.3.27` | ❌ EOL | Only v5/v6 are supported | +| `@aws-amplify/ui-angular` | `~2.4.14` | ❌ Ancient | Latest 5.3.5, requires Angular ≥ 19 | +| `typescript` | `~4.7.2` | ⚠️ Old (pinned by Angular 14) | 5.x | +| `rxjs` / `zone.js` | `7.5` / `0.11.4` | ⚠️ Old (bound to Angular 14) | — | -> 前端为互锁技术栈:Angular 14 ↔ Amplify v4 ↔ ui-angular 2.x ↔ TS 4.7。 -> 现代化需整体跃迁:Angular `14→20/21`、aws-amplify `v4→v6`、ui-angular `2.x→5.x` -> (ui-angular 5.x 需 Angular 19+)。其中 **Amplify v4→v6 的 Auth API 为破坏性重写**,工作量最大,应作为独立迁移项目并配合构建/E2E 验证。 +> The frontend is an interlocked stack: Angular 14 ↔ Amplify v4 ↔ ui-angular 2.x ↔ TS 4.7. +> Modernization requires a coordinated jump across the board: Angular `14→20/21`, aws-amplify `v4→v6`, ui-angular `2.x→5.x` +> (ui-angular 5.x requires Angular 19+). Among these, the **Amplify v4→v6 Auth API is a breaking rewrite** with the largest workload, and should be treated as a standalone migration project with build/E2E verification. --- -## 4. 处置优先级 +## 4. Disposition Priority -| 级别 | 事项 | 风险/工作量 | +| Level | Item | Risk / effort | |---|---|---| -| 🔴 P0(安全) | `python-jose` → `PyJWT` | 中,需改 JWT 校验代码并测试 | -| 🟠 P1(可复现) | Python 依赖锁定版本 | 低 | -| 🟢 P2(杂项) | `@types/node` 升级、CDK lockfile 核对 | 低 | -| 🟡 P3(大工程) | 前端 Angular 20/21 + Amplify v6 + ui-angular 5.x 整体升级 | 高,破坏性,需单独立项 | +| 🔴 P0 (security) | `python-jose` → `PyJWT` | Medium; requires changing JWT verification code and testing | +| 🟠 P1 (reproducibility) | Pin Python dependency versions | Low | +| 🟢 P2 (misc) | `@types/node` upgrade, CDK lockfile verification | Low | +| 🟡 P3 (large effort) | Frontend overall upgrade to Angular 20/21 + Amplify v6 + ui-angular 5.x | High, breaking, requires a dedicated project | -## 4.1 处置进度(2026-06-14,分支 `chore/dependency-modernization`) +## 4.1 Disposition Progress (2026-06-14, branch `chore/dependency-modernization`) -| 级别 | 状态 | 说明 | +| Level | Status | Notes | |---|---|---| -| 🔴 P0 | ✅ 完成 | `python-jose` → `PyJWT[crypto]`,重写两个 authorizer 验签;6 用例单元验证通过 | -| 🟠 P1 | ✅ 完成 | 全部 `requirements.txt` 锁版本(兼容区间锁大版本) | -| 🟢 P2 | ✅ 完成 | `@types/node`→`^20`、`aws-cdk-lib`→`^2.258` 并刷新 lockfile;修 `\*` 转义 | -| 🟡 P3 | ✅ 完成(构建层) | **三个前端应用全部 Angular 14 → 20**;Admin/Application 同时 **Amplify v4 → v6**、ui-angular 2→5;移除已废弃的 `@angular/flex-layout`;生产构建均通过 | - -### 前端迁移要点 -- 统一各 `@angular/*` 至 `^20`、TypeScript `5.8`、zone.js `0.15`、rxjs `7.8`。 -- Material:移除已删的 `legacy-*` 导入;主题改用 M3 `mat.theme()`(indigo→violet、pink→rose,视觉相近)。 -- Angular 19 起组件默认 standalone:给 NgModule 声明的组件补 `standalone: false`。 -- Amplify v6:`Auth.currentSession()`→`fetchAuthSession()`、`getJwtToken()`→`token.toString()`、`isValid()`→`!!tokens?.idToken`、`Auth.signOut()`→`signOut()`;`Amplify.configure(aws_exports)` 旧格式 v6 仍兼容。 -- SCSS 去除 webpack `~` 前缀;ui-angular 5 的 `theme.css` 经 angular.json `styles` 引入(其 exports 字段不暴露该子路径)。 - -### ⚠️ 尚未验证(需运行时确认) -- 生产构建通过 ≠ 运行时通过。**Amplify v6 的登录/会话/登出流程需在浏览器实测**(`npm start` + 真实 Cognito 登录)。 -- 后端 PyJWT 为独立单元验证,**未在已部署的 Lambda 中集成测试**。 -- Material 主题色由 indigo 变为 violet(如需精确品牌色需自定义 M3 调色板)。 - -## 5. 信息来源 - -- AWS Lambda runtimes: -- Lambda 增加 Python 3.13: -- CodeBuild 增加 Python 3.13(standard:7.0): -- python-jose CVE-2024-33663: -- PyJWT 迁移指引: -- Angular 版本与 EOL: -- @aws-amplify/ui-angular(npm registry): +| 🔴 P0 | ✅ Done | `python-jose` → `PyJWT[crypto]`, rewrote signature verification in two authorizers; 6 unit test cases passing | +| 🟠 P1 | ✅ Done | Pinned all `requirements.txt` versions (compatible-range pinning at the major version) | +| 🟢 P2 | ✅ Done | `@types/node`→`^20`, `aws-cdk-lib`→`^2.258` and refreshed lockfile; fixed `\*` escaping | +| 🟡 P3 | ✅ Done (build layer) | **All three frontend apps Angular 14 → 20**; Admin/Application also **Amplify v4 → v6**, ui-angular 2→5; removed the deprecated `@angular/flex-layout`; production builds all pass | + +### Frontend Migration Notes +- Unified all `@angular/*` to `^20`, TypeScript `5.8`, zone.js `0.15`, rxjs `7.8`. +- Material: removed deleted `legacy-*` imports; switched theming to M3 `mat.theme()` (indigo→violet, pink→rose, visually similar). +- Since Angular 19, components are standalone by default: added `standalone: false` to components declared in NgModules. +- Amplify v6: `Auth.currentSession()`→`fetchAuthSession()`, `getJwtToken()`→`token.toString()`, `isValid()`→`!!tokens?.idToken`, `Auth.signOut()`→`signOut()`; the legacy `Amplify.configure(aws_exports)` format is still compatible in v6. +- SCSS: removed the webpack `~` prefix; ui-angular 5's `theme.css` is imported via the `styles` array in angular.json (its exports field does not expose that subpath). + +### ⚠️ Not Yet Verified (requires runtime confirmation) +- A passing production build ≠ passing at runtime. **The Amplify v6 sign-in/session/sign-out flow needs real-browser testing** (`npm start` + a real Cognito login). +- The backend PyJWT change was verified by standalone unit tests, **not integration-tested in a deployed Lambda**. +- The Material theme color changed from indigo to violet (a custom M3 palette is needed for exact brand colors). + +## 5. Sources + +- AWS Lambda runtimes: +- Lambda adds Python 3.13: +- CodeBuild adds Python 3.13 (standard:7.0): +- python-jose CVE-2024-33663: +- PyJWT migration guidance: +- Angular versions and EOL: +- @aws-amplify/ui-angular (npm registry): diff --git a/docs/LOCAL_TESTING.md b/docs/LOCAL_TESTING.md index 1f0f58e..3ee9cb9 100644 --- a/docs/LOCAL_TESTING.md +++ b/docs/LOCAL_TESTING.md @@ -1,91 +1,114 @@ -# 免费本地后端测试(无需 AWS 账号) +# Free Local Backend Testing (No AWS Account Required) -在本地真实跑后端服务,验证 Lambda handler + DAL + DynamoDB 读写——零成本、 -不碰真实 AWS。提供两种方式。 +[**English**](LOCAL_TESTING.md) | [中文](zh-CN/LOCAL_TESTING.md) -> 注意:两种方式都**不含 Cognito**。真实登录依赖 Cognito(无免费本地方案,见 -> `docs/MIGRATION_VERIFICATION.md`)。均通过 `requestContext.authorizer` -> 注入假的鉴权上下文(`tenantId`/`userRole`)来绕过 authorizer。 +[← Back to README](../README.md) -## 方式一(推荐,跨平台):pytest + moto +Run the backend services for real, locally, to verify the Lambda handler + DAL + +DynamoDB reads/writes — at zero cost, without touching real AWS. Two approaches +are provided. -纯 Python,**Windows/macOS/Linux 通用,无需 Docker、无需 AWS**。`moto` 在内存里 -模拟 DynamoDB。两条命令: +> Note: neither approach includes **Cognito**. Real login depends on Cognito +> (there is no free local alternative — see `docs/MIGRATION_VERIFICATION.md`). +> Both bypass the authorizer by injecting a fake auth context +> (`tenantId`/`userRole`) through `requestContext.authorizer`. + +## Approach 1 (Recommended, Cross-Platform): pytest + moto + +Pure Python, **works on Windows/macOS/Linux, no Docker and no AWS required**. +`moto` simulates DynamoDB in memory. Two commands: ```bash pip install -r requirements-test.txt pytest ``` -- 测试位于 `server/services/*/tests/test_*.py`:直接 import handler、用 moto mock - DynamoDB、断言 CRUD(含 update 回归测试,锁住已修复的 3 个 bug)。 -- 共享设置见 `server/conftest.py`(把共享层与各服务 `src/` 加进 `sys.path`,并在 - import 前设好环境变量)。 -- CI:`.github/workflows/backend-tests.yml` 在 ubuntu/windows/macOS 三平台跑 `pytest`。 +- Tests live in `server/services/*/tests/test_*.py`: they import the handler + directly, mock DynamoDB with moto, and assert CRUD (including update + regression tests that lock in the 3 fixed bugs). +- Shared setup is in `server/conftest.py` (adds the shared layer and each + service's `src/` to `sys.path`, and sets environment variables before import). +- CI: `.github/workflows/backend-tests.yml` runs `pytest` on all three + platforms — ubuntu/windows/macOS. -写测试套件、跑 CI 首选此方式。下面的 DynamoDB Local 更保真但更重、依赖 Docker 与 -Git Bash(非跨平台),适合偶尔高保真验证。 +This is the preferred approach for writing test suites and running CI. The +DynamoDB Local approach below is higher fidelity but heavier, depends on Docker +and Git Bash (not cross-platform), and suits occasional high-fidelity +verification. -## 方式二(高保真):DynamoDB Local + sam local invoke +## Approach 2 (High Fidelity): DynamoDB Local + sam local invoke -### 前置 -- Docker 运行中 -- SAM CLI(`pip install aws-sam-cli`) -- 本地 Python + boto3(`pip install boto3`) +### Prerequisites +- Docker running +- SAM CLI (`pip install aws-sam-cli`) +- Local Python + boto3 (`pip install boto3`) -## 一键运行(product-service 全 CRUD) +## One-Command Run (product-service full CRUD) ```bash bash scripts/local-test-product.sh ``` -脚本会:起 DynamoDB Local(`-sharedDb`)→ 建 `Product-pooled` 表 → 构建 → -依次 invoke create/get/update/list/delete,最后自动还原临时改动。 -停止本地库:`docker rm -f ddb-local`。 +The script will: start DynamoDB Local (`-sharedDb`) → create the `Product-pooled` +table → build → invoke create/get/update/list/delete in sequence, and finally +automatically revert the temporary changes. +Stop the local database: `docker rm -f ddb-local`. -## 关键坑(手动操作时务必注意) +## Key Pitfalls (Be Careful When Doing This Manually) -1. **DynamoDB Local 要加 `-sharedDb`**:否则按"凭证+区域"隔离数据库文件, - 建表方和函数看到的不是同一个库。 +1. **DynamoDB Local needs `-sharedDb`**: otherwise it isolates the database file + by "credentials + region", so the table creator and the function don't see + the same database. ```bash docker run -d --network saas-local --name ddb-local -p 8000:8000 \ amazon/dynamodb-local -jar DynamoDBLocal.jar -inMemory -sharedDb -port 8000 ``` -2. **`sam local invoke --env-vars` 只能覆盖模板里已声明的环境变量**。 - `AWS_ENDPOINT_URL_DYNAMODB`(让函数 boto3 指向本地库)若不在模板里, - 不会被注入。所以需临时把它加进 `template.yaml` 的 `Globals.Function.Environment`: +2. **`sam local invoke --env-vars` can only override environment variables + already declared in the template**. `AWS_ENDPOINT_URL_DYNAMODB` (which points + the function's boto3 at the local database) won't be injected if it's not in + the template. So you need to temporarily add it to + `Globals.Function.Environment` in `template.yaml`: ```yaml AWS_ENDPOINT_URL_DYNAMODB: "http://ddb-local:8000" ``` - (脚本会自动加、用完 `git checkout` 还原。) + (The script adds it automatically and reverts with `git checkout` when done.) -3. **函数容器要接入同一 Docker 网络**:`sam local invoke ... --docker-network saas-local`, - 这样函数里用主机名 `ddb-local` 能解析到 DynamoDB Local 容器。 +3. **The function container must join the same Docker network**: + `sam local invoke ... --docker-network saas-local`, so that the hostname + `ddb-local` used inside the function resolves to the DynamoDB Local container. -4. **关掉 X-Ray**:env 里设 `POWERTOOLS_TRACE_DISABLED=true`,避免本地无 X-Ray daemon 报噪。 +4. **Turn off X-Ray**: set `POWERTOOLS_TRACE_DISABLED=true` in the env, to avoid + noisy errors from the missing local X-Ray daemon. -## 已验证结果(2026-06-14) +## Verified Results (2026-06-14) -product-service 五个操作全部 `statusCode 200`:create / get / get_products / -update / delete。本地测试还**发现并修复了 update 的两个预先存在 bug** -(`datetime` 误用、`ReturnValues=UPDATED_NEW`)——见 commit `b61c780`。 +All five product-service operations returned `statusCode 200`: create / get / +get_products / update / delete. Local testing also **found and fixed two +pre-existing bugs in update** (misuse of `datetime`, +`ReturnValues=UPDATED_NEW`) — see commit `b61c780`. -order-service 为相同代码模式,已应用相同修复(可仿照本脚本建 `Order-pooled` 表后同样验证)。 +order-service follows the same code pattern and has had the same fixes applied +(you can verify it the same way by creating an `Order-pooled` table following +this script). --- -## 前端:Playwright 运行时冒烟(跨平台) +## Frontend: Playwright Runtime Smoke Test (Cross-Platform) -`e2e/` 是独立的 Playwright 项目,**Windows/macOS/Linux 通用**。它 serve 三个 app -的构建产物,用无头 Chromium 加载,断言:Angular 20 正常 bootstrap、应用外壳与关键 -元素渲染(Admin 验证 `` 出现)、无致命 JS 错误。 +`e2e/` is a standalone Playwright project that **works on +Windows/macOS/Linux**. It serves the build artifacts of all three apps, loads +them with headless Chromium, and asserts: Angular 20 bootstraps correctly, the +app shell and key elements render (Admin verifies that +`` appears), and there are no fatal JS errors. ```bash -# 先构建三个 app(各自目录):npx ng build --configuration production +# First build the three apps (each in its own directory): npx ng build --configuration production cd e2e npm install -npx playwright install chromium # 大陆可加速:PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries/playwright +npx playwright install chromium # Speed up in mainland China: PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries/playwright npx playwright test ``` -- 不测真实登录(无免费本地 Cognito);针对占位配置的预期网络/鉴权错误已忽略。 -- CI:`.github/workflows/frontend-e2e.yml` 构建三个 app 后跑 Playwright。 +- Does not test real login (no free local Cognito); expected network/auth + errors against the placeholder config are ignored. +- CI: `.github/workflows/frontend-e2e.yml` builds the three apps and then runs + Playwright. diff --git a/docs/MIGRATION_VERIFICATION.md b/docs/MIGRATION_VERIFICATION.md index 9d04988..9a9d39a 100644 --- a/docs/MIGRATION_VERIFICATION.md +++ b/docs/MIGRATION_VERIFICATION.md @@ -1,68 +1,74 @@ -# 前端迁移运行时验证清单(Angular 20 + Amplify v6) +# Frontend Migration Runtime Verification Checklist (Angular 20 + Amplify v6) -> 适用分支:`chore/dependency-modernization` -> 目的:生产构建已通过,但**构建通过 ≠ 运行时通过**。本清单用于在浏览器中 -> 实测三个应用的认证流程(Amplify v6 的登录/会话/登出)。 +[**English**](MIGRATION_VERIFICATION.md) | [中文](zh-CN/MIGRATION_VERIFICATION.md) -## 0. 前置条件 +[← Back to README](../README.md) -- Node ≥ 20(本仓库迁移在 Node 22 上完成)。 -- 各应用 `node_modules` 已安装(迁移过程中已 `npm install`)。 -- **有效的后端配置**:登录需要真实的 Cognito 用户池与已部署的 API。 - - `Admin`:读取 `client/Admin/src/aws-exports.ts`(静态 Cognito 配置)。 - - `Application`:通过 `…/tenant/init/` 动态获取每租户配置,URL 需带租户名。 - - `Landing`:仅注册表单,调用 `environment.regApiGatewayUrl`。 +> Applies to branch: `chore/dependency-modernization` +> Purpose: the production build already passes, but **a passing build ≠ a passing +> runtime**. This checklist is for actually testing the authentication flows of +> the three apps in the browser (Amplify v6 sign-in / session / sign-out). -## 1. 启动(任选其一) +## 0. Prerequisites + +- Node ≥ 20 (the migration in this repo was done on Node 22). +- Each app's `node_modules` is installed (`npm install` was run during the migration). +- **Valid backend configuration**: sign-in requires a real Cognito user pool and a deployed API. + - `Admin`: reads `client/Admin/src/aws-exports.ts` (static Cognito config). + - `Application`: dynamically fetches per-tenant config via `…/tenant/init/`; the URL must include the tenant name. + - `Landing`: registration form only, calls `environment.regApiGatewayUrl`. + +## 1. Start up (pick either option) ```bash -# 便捷脚本:三个应用分别在 4200/4201/4202 启动 +# Convenience script: starts the three apps on 4200/4201/4202 respectively bash scripts/serve-clients.sh -# 或手动单独启动 +# Or start each one manually cd client/Landing && npx ng serve --port 4200 cd client/Application && npx ng serve --port 4201 cd client/Admin && npx ng serve --port 4202 ``` -## 2. 逐应用验证清单 - -### 2.1 Landing(无认证,最先验证) -- [ ] 打开 `http://localhost:4200`,页面正常渲染(无白屏)。 -- [ ] 浏览器 Console **无报错**(尤其无 Angular/zone.js 启动错误)。 -- [ ] 填写注册表单并提交 → 网络面板可见对 `regApiGatewayUrl` 的请求。 -- [ ] Material 控件(输入框/按钮/snackbar)样式正常(主题色现为 violet)。 - -### 2.2 Admin(静态 Cognito 登录) -- [ ] 打开 `http://localhost:4202`,**Amplify Authenticator 登录界面正常渲染** - —— 这验证了 Amplify v6 `Amplify.configure(aws_exports)` 运行时成功。 -- [ ] Console 无 `Amplify has not been configured` 或模块解析类报错。 -- [ ] 用管理员账号登录 → 成功进入后台(不再回到登录页)。 -- [ ] 进入“租户/用户”页 → 网络请求头含 `Authorization: Bearer ` - —— 验证 `auth.interceptor.ts` 的 `fetchAuthSession()` 取 token 正常。 -- [ ] 顶部显示用户名(验证 `nav.component` 读取 `idToken.payload`)。 -- [ ] 点击登出 → 回到登录页(验证 `signOut({ global: true })`)。 - -### 2.3 Application(动态每租户登录) -- [ ] 以带租户的入口打开,例如 `http://localhost:4201/` 或应用约定的 - 注册后跳转路径(触发 `auth-configuration.service` 的 `configureAmplifyAuth()`)。 -- [ ] Authenticator 登录界面正常渲染(验证动态 `Amplify.configure(awsmobile)`)。 -- [ ] 租户用户登录成功 → 进入 dashboard。 -- [ ] `CognitoGuard` 行为:未登录访问受保护路由 → 跳 `/unauthorized`。 -- [ ] orders / products 列表能加载(请求头含 Bearer token)。 -- [ ] 登出正常。 - -## 3. Amplify v6 重点观察项(出问题时优先看这些) - -| 现象 | 可能原因 | 位置 | +## 2. Per-app verification checklist + +### 2.1 Landing (no auth, verify first) +- [ ] Open `http://localhost:4200`; the page renders correctly (no blank screen). +- [ ] Browser Console has **no errors** (especially no Angular/zone.js startup errors). +- [ ] Fill out and submit the registration form → the Network panel shows a request to `regApiGatewayUrl`. +- [ ] Material controls (inputs/buttons/snackbar) are styled correctly (the theme color is now violet). + +### 2.2 Admin (static Cognito sign-in) +- [ ] Open `http://localhost:4202`; the **Amplify Authenticator sign-in screen renders correctly** + —— this verifies that Amplify v6 `Amplify.configure(aws_exports)` succeeds at runtime. +- [ ] Console has no `Amplify has not been configured` or module-resolution errors. +- [ ] Sign in with an admin account → successfully enter the backoffice (no longer bounced back to the sign-in page). +- [ ] Go to the "Tenants/Users" page → network request headers include `Authorization: Bearer ` + —— verifies that `auth.interceptor.ts`'s `fetchAuthSession()` retrieves the token correctly. +- [ ] The username is shown at the top (verifies `nav.component` reads `idToken.payload`). +- [ ] Click sign out → return to the sign-in page (verifies `signOut({ global: true })`). + +### 2.3 Application (dynamic per-tenant sign-in) +- [ ] Open via a tenant-aware entry point, e.g. `http://localhost:4201/` or the + post-registration redirect path defined by the app (triggers `auth-configuration.service`'s `configureAmplifyAuth()`). +- [ ] The Authenticator sign-in screen renders correctly (verifies dynamic `Amplify.configure(awsmobile)`). +- [ ] A tenant user signs in successfully → enters the dashboard. +- [ ] `CognitoGuard` behavior: accessing a protected route while signed out → redirect to `/unauthorized`. +- [ ] The orders / products lists load (request headers include the Bearer token). +- [ ] Sign out works correctly. + +## 3. Amplify v6 key things to watch (check these first when something breaks) + +| Symptom | Possible cause | Location | |---|---|---| -| 登录页空白 / `Amplify has not been configured` | `Amplify.configure` 未在 bootstrap 前执行或配置格式不被接受 | `main.ts` / `auth-configuration.service.ts` | -| 请求缺少 `Authorization` 头 | `fetchAuthSession()` 返回的 `tokens?.idToken` 为空 | `auth.interceptor.ts` | -| 登录后仍判定未认证 | `!!tokens?.idToken` 判定逻辑 | `nav.component.ts` / `cognito.guard.ts` | -| 用户名/公司名空白 | `idToken.payload['custom:...']` 字段名 | `nav.component.ts` | -| 登出无效 | `signOut({ global: true })` | `*/auth.component.ts`、`nav.component.ts` | +| Blank sign-in page / `Amplify has not been configured` | `Amplify.configure` not run before bootstrap, or the config format is not accepted | `main.ts` / `auth-configuration.service.ts` | +| Request missing the `Authorization` header | `tokens?.idToken` returned by `fetchAuthSession()` is empty | `auth.interceptor.ts` | +| Still considered unauthenticated after sign-in | `!!tokens?.idToken` check logic | `nav.component.ts` / `cognito.guard.ts` | +| Username/company name blank | `idToken.payload['custom:...']` field name | `nav.component.ts` | +| Sign-out has no effect | `signOut({ global: true })` | `*/auth.component.ts`, `nav.component.ts` | -## 4. 通过标准 +## 4. Pass criteria -三个应用均:可启动、登录页渲染、能登录、受保护请求带 token、可登出,且 -Console 无致命报错 → 视为运行时验证通过,可合并分支。 +All three apps: can start up, render the sign-in page, can sign in, send the token +on protected requests, and can sign out, with no fatal Console errors → considered +to have passed runtime verification, and the branch may be merged. diff --git a/docs/zh-CN/CHANGES_FROM_WORKSHOP.md b/docs/zh-CN/CHANGES_FROM_WORKSHOP.md new file mode 100644 index 0000000..0d8fbcd --- /dev/null +++ b/docs/zh-CN/CHANGES_FROM_WORKSHOP.md @@ -0,0 +1,118 @@ +# 与上游 AWS Serverless SaaS Workshop 的差异说明 + +[English](../CHANGES_FROM_WORKSHOP.md) | [**中文**](CHANGES_FROM_WORKSHOP.md) + +[← 返回 README](../../README.zh-CN.md) + +本文件记录 **aws-serverless-saas-quickstart** 相对上游 **AWS Serverless SaaS +Workshop**(`aws-samples/aws-serverless-saas-workshop`,对应其 `Lab6`)所做的 +修改及原因。 + +## 1. 血缘与定位 + +- 本项目派生自上游 Workshop 的 **Lab6**(最终实验版本)。版权与许可证溯源见 + 仓库根目录的 [`NOTICE`](../NOTICE) 与 [`LICENSE`](../LICENSE)(MIT-0)。 +- 上游 Workshop 是一套**教学实验序列**(Lab1~Lab7,逐步引导搭建),定位是培训 + 材料;本项目则把 Lab6 重构为一个**可直接落地、结构精简的参考实现/快速启动模板**。 +- **本项目已作为独立衍生项目演进,不再向上游回馈改动**,原因见第 4 节。 + +## 2. 差异概览 + +以 quickstart 对比 workshop/Lab6(已排除 `node_modules`、构建产物等): + +| 类别 | 文件数 | 说明 | +|---|---:|---| +| 完全相同 | 184 | 多为前端 Angular 脚手架、Landing 页、未改动的模板 | +| 同路径但已修改 | 24 | 依赖升级、配置、部分前端 service/model | +| 仅 quickstart(新增) | 69 | 重构后的新结构、新增运维脚本、许可证文件等 | +| 仅 Lab6(被替换/删除) | 38 | 旧的扁平 server 结构 | + +按文件数约 66% 相同,但相同部分集中在前端样板;**后端(项目核心)几乎被重写**。 + +## 3. 主要变更与原因 + +### 3.1 后端架构:单体模板 → 按服务拆分 +- **变更**:上游 server 下的扁平服务目录(`ProductService/`、`OrderService/`、 + `TenantManagementService/`)与两个大模板(`shared-template.yaml`、 + `tenant-template.yaml`)被重组为: + - `server/services/{product-service, order-service, tenant-api}/`——每个服务 + 拥有**独立**的 `template.yaml` + `samconfig.toml`(拆成可独立部署的微栈); + - Python 代码引入 DAL 分层:`*_service.py` + `*_service_dal.py` + `*_models.py`。 +- **原因**:降低服务间耦合、支持服务独立部署、提升模板可维护性。 +- **相关提交**:`bcb1d1a` (restructure serverless SaaS architecture with service + separation)、`0805565`、`753aa67`、`666dd8b`。 + +### 3.2 共享资源归集到 `server/shared/` +- **变更**:`layers/`、`nested_templates/`、`custom_resources/`、`Auth/`、 + `tenant-management/` 等由散落在 server 根目录,统一收纳到 + `server/shared/{auth, layers, nested_templates, custom_resources, tenant-management}/`。 +- **原因**:明确区分「共享基础设施」与「业务服务」,目录职责更清晰。 +- **相关提交**:`0805565` (move tenant-management from infrastructure to shared)、 + `753aa67` (restructure shared infrastructure directory layout)、 + `b632860` (reorganize auth components)。 + +### 3.3 数据模型:移除 `shardId` 分片,改用 `tenant_id` 分区键 +- **变更**:Order / Product 服务的 DynamoDB 设计由「`shardId` 分片 + 并行查询」 + 改为以 `tenant_id` 作为分区键的简化设计;同步更新数据模型、CRUD 与前端模板。 +- **原因**:消除复杂的分片/并行查询逻辑,数据分布更可预测,降低存储与查询成本 + (详见 README「数据库设计规则」一节)。 +- **相关提交**:`37a2587` (use tenant_id instead of shardId)、`40ea9ff`。 + +### 3.4 Python 运行时升级到 3.13 +- **变更**:Lambda 运行时与 CDK 流水线由旧版本统一升级到 **Python 3.13**, + CodeBuild 构建镜像改为 `STANDARD_7_0`。 +- **原因**:上游使用的旧运行时已接近/到达 EOL,升级以获得长期支持与安全更新。 +- **相关提交**:`7ea8533`。 + +### 3.5 依赖修复与升级(含 AWS Lambda Powertools) +- **变更**:修复并升级过时依赖,重点修正 Powertools 相关依赖。 +- **原因**:上游依赖版本过时,存在兼容性/安全问题。 +- **相关提交**:`b632860` (fix powertools dependencies)。 + +### 3.6 前端:Angular 与 Amplify 调整 +- **变更**:初期尝试 Angular 16.2.12 + AWS Amplify v6(`51c412b`),后因兼容性 + **回滚到 Angular 14.x**,并将认证逻辑改为更新后的 Amplify 调用方式(`184f5f9`)。 +- **原因**:版本兼容性与稳定性。 +- **相关提交**:`51c412b`、`184f5f9`、`40ea9ff`。 + +### 3.7 部署与运维脚本增强 +- **变更**: + - 各前端 `package.json` 增加 `deploy` / `reset` 脚本(S3 sync + CloudFront 失效); + - 新增一批 Node.js 运维工具脚本:`create-admin-user.js`、`manage-users.js`、 + `set-admin-password.js`、`get-login-info.js`、`generate-env-config.js`; + - 新增 `scripts/DEPLOYMENT_GUIDE.md` 部署指南。 +- **原因**:简化部署流程与租户/管理员用户的日常管理。 +- **相关提交**:`5366935` 及上述新增文件。 + +### 3.8 其他配置调整 +- 租户栈命名 `pooled-tenant-stack` → `stack-pooled`(`8634f86`)。 +- `LambdaReserveConcurrency` 默认值 `20` → `0`(`2a262ad`),避免在账号预留并发 + 配额受限的环境下部署失败。 + +## 4. 为什么不再向上游回馈 + +1. **结构性重构难以回馈**:目录改名、模板拆分、数据模型变更使绝大多数改动无法 + 干净地 cherry-pick 回上游——路径与结构都对不上,PR 会变成大规模的「删一片、 + 加一片」,评审与合并成本极高。 +2. **定位不同**:上游是分步教学的实验序列(Lab1~Lab7),刻意保留逐层演进的结构; + 本项目是面向落地的精简产品,二者目标不一致。 +3. **维护独立**:因此本项目作为**独立衍生项目**维护,按 MIT-0 开源;上游署名与 + 来源在 `NOTICE` 中保留。 + +> 注:仅有少量「同路径的窄改动」(如部署脚本修复、个别依赖升级)在技术上仍可回馈, +> 但综合收益有限,当前不作为目标。 + +## 5. 结构对照(旧 → 新) + +| 上游 Lab6 路径 | quickstart 路径 | +|---|---| +| `server/ProductService/` | `server/services/product-service/src/` | +| `server/OrderService/` | `server/services/order-service/src/` | +| `server/TenantManagementService/` | `server/shared/tenant-management/`、`server/services/tenant-api/` | +| `server/Auth/` | `server/shared/auth/` | +| `server/layers/` | `server/shared/layers/` | +| `server/nested_templates/` | `server/shared/nested_templates/` | +| `server/custom_resources/` | `server/shared/custom_resources/` | +| `server/shared-template.yaml` + `server/tenant-template.yaml` | 拆分为各服务 `services/*/template.yaml` + `server/shared/**` + `server/services/template.yaml` | + +> 上表为目录级对应关系,文件在迁移过程中可能伴随重命名与代码重构,仅供溯源参考。 diff --git a/docs/zh-CN/CONFIGURATION.md b/docs/zh-CN/CONFIGURATION.md new file mode 100644 index 0000000..6b1317b --- /dev/null +++ b/docs/zh-CN/CONFIGURATION.md @@ -0,0 +1,60 @@ +# 配置指南(前端环境与 Cognito) + +[English](../CONFIGURATION.md) | [**中文**](CONFIGURATION.md) + +[← 返回 README](../../README.zh-CN.md) + +本仓库**不包含任何真实部署的标识符**。以下文件中的值均为**占位符**, +需替换为你自己部署的值后再构建/运行。 + +> 说明:Cognito User Pool ID、App Client ID、API Gateway URL、CloudFront +> Distribution ID 都会被打包进浏览器或脚本,**并非机密**;占位化的目的是 +> 不让本公开仓库绑定到任何特定的 AWS 部署。 + +## 需要填写的占位符 + +| 占位符 | 含义 | 出现位置 | +|---|---|---| +| `us-east-1_XXXXXXXXX` | Cognito User Pool ID | `client/Admin/src/aws-exports.ts`、`client/Admin/script/auth-config.js` | +| `XXXXXXXXXXXXXXXXXXXXXXXXXX` | Cognito App Client ID | 同上 | +| `YOUR_API_ID` | 共享 API Gateway 的 REST API ID | 各 app `src/environments/environment*.ts` | +| `YOUR_CLOUDFRONT_DISTRIBUTION_ID` | 各站点的 CloudFront 分发 ID | 各 app `package.json` 的 `reset` 脚本 | + +## 方式一:脚本生成(推荐,针对 environment.ts) + +仓库已提供 `scripts/generate-env-config.js`,会用 AWS CLI 查询共享 API 并 +生成对应 app 的 `environment.ts`: + +```bash +# 需先配置好 AWS CLI 凭证与区域 +node scripts/generate-env-config.js Admin prod +node scripts/generate-env-config.js Application prod +node scripts/generate-env-config.js Landing prod +``` + +## 方式二:手动填写 + +1. **Cognito**(`client/Admin/src/aws-exports.ts`):把 `us-east-1_XXXXXXXXX`、 + `XXXXXXXXXXXXXXXXXXXXXXXXXX` 替换为你的 User Pool ID 与 App Client ID。 +2. **API URL**(`client/*/src/environments/environment*.ts`):把 `YOUR_API_ID` + 替换为共享 API Gateway 的 REST API ID。 +3. **CloudFront**(`client/*/package.json` 的 `reset` 脚本):把 + `YOUR_CLOUDFRONT_DISTRIBUTION_ID` 替换为各站点分发 ID。 + +## ⚠️ 避免再次提交真实值 + +填入真实值后,**不要把它们提交回仓库**。建议本地用下列方式之一隔离: + +```bash +# 让 git 忽略对这些文件的本地改动(不影响他人) +git update-index --skip-worktree \ + client/Admin/src/aws-exports.ts \ + client/Admin/src/environments/environment.ts \ + client/Admin/src/environments/environment.prod.ts \ + client/Application/src/environments/environment.ts \ + client/Application/src/environments/environment.prod.ts \ + client/Landing/src/environments/environment.ts \ + client/Landing/src/environments/environment.prod.ts +``` + +(撤销:`git update-index --no-skip-worktree `) diff --git a/docs/zh-CN/DEPENDENCY_AUDIT.md b/docs/zh-CN/DEPENDENCY_AUDIT.md new file mode 100644 index 0000000..fa45a01 --- /dev/null +++ b/docs/zh-CN/DEPENDENCY_AUDIT.md @@ -0,0 +1,90 @@ +# 依赖与运行时支持状态审计 + +[English](../DEPENDENCY_AUDIT.md) | [**中文**](DEPENDENCY_AUDIT.md) + +[← 返回 README](../../README.zh-CN.md) + +> 审计日期:2026-06-14 | 对照"当前社区维护 / AWS 官方支持"状态 + +## 总体结论 + +- **后端 / 基础设施**:运行时选型健康,当前受支持。 +- **前端**:Angular / Amplify 技术栈整体已 **EOL(生命周期结束)**,停留在 2022 年版本。 +- **最高优先安全项**:`python-jose` 已弃维且存在活跃 CVE,需替换。 + +--- + +## 1. 后端 / 基础设施(✅ 大体良好) + +| 组件 | 代码中版本 | 状态 | 说明 | +|---|---|---|---| +| Lambda runtime | `python3.13` | ✅ 当前受支持 | AWS 支持至约 2029-10;最新已是 3.14(2025-11),3.13 为稳妥 LTS | +| CodeBuild 镜像 | `STANDARD_7_0` + `python:3.13` | ✅ 可用 | Python 3.13 自 2025-03 起内置于 standard:7.0 | +| `aws-cdk-lib` | `^2.0.0` | ✅ 受支持 | CDK v2 在维护(v1 已 2023-06 EOL)。floor 偏低,建议核对 lockfile 解析到最新 2.x | +| `constructs` | `^10.0.0` | ✅ | 与 CDK v2 匹配 | +| `aws-lambda-powertools` `jsonpickle` `simplejson` `requests` `pytest-mock` | 未锁版本 | ✅ 维护中 | — | + +## 2. 后端需要注意(⚠️ / ❌) + +| 项 | 状态 | 影响位置 | 处置 | +|---|---|---|---| +| **`python-jose[cryptography]`** | ❌ 弃维 + CVE | `services/tenant-api`、`shared/auth`、`shared/layers` | **迁移到 `PyJWT`**。涉及 JWT 校验(安全敏感路径)。相关 CVE:CVE-2024-33663(算法混淆)、CVE-2024-33664(JWE DoS) | +| **Python 依赖未锁版本** | ⚠️ 可复现性/供应链风险 | 全部 `requirements.txt` | 固定大版本或引入 lock(pip-tools) | +| `crhelper` / `aws_requests_auth` | ⚠️ 低活跃 | `shared/custom_resources`、多处 | 仍可用,留意 | +| `@types/node` | ⚠️ `10.17.27`(Node 10 已 2021 EOL) | `TenantPipeline` | 升级到与构建 Node 对应的 `@types/node`(仅类型,运行时无影响) | + +## 3. 前端(❌ 整体 EOL) + +| 组件 | 代码中版本 | 状态 | 当前/目标 | +|---|---|---|---| +| `@angular/core` / `@angular/cli` | `~14.0.0` / `~14.0.5` | ❌ EOL(约 2023 年底) | 在维护:20(至 2026-11)/ 21(至 2027-05)/ 22 | +| `aws-amplify` | `~4.3.27` | ❌ EOL | 仅 v5/v6 受支持 | +| `@aws-amplify/ui-angular` | `~2.4.14` | ❌ 远古 | 最新 5.3.5,要求 Angular ≥ 19 | +| `typescript` | `~4.7.2` | ⚠️ 旧(被 Angular 14 锁定) | 5.x | +| `rxjs` / `zone.js` | `7.5` / `0.11.4` | ⚠️ 旧(随 Angular 14 绑定) | — | + +> 前端为互锁技术栈:Angular 14 ↔ Amplify v4 ↔ ui-angular 2.x ↔ TS 4.7。 +> 现代化需整体跃迁:Angular `14→20/21`、aws-amplify `v4→v6`、ui-angular `2.x→5.x` +> (ui-angular 5.x 需 Angular 19+)。其中 **Amplify v4→v6 的 Auth API 为破坏性重写**,工作量最大,应作为独立迁移项目并配合构建/E2E 验证。 + +--- + +## 4. 处置优先级 + +| 级别 | 事项 | 风险/工作量 | +|---|---|---| +| 🔴 P0(安全) | `python-jose` → `PyJWT` | 中,需改 JWT 校验代码并测试 | +| 🟠 P1(可复现) | Python 依赖锁定版本 | 低 | +| 🟢 P2(杂项) | `@types/node` 升级、CDK lockfile 核对 | 低 | +| 🟡 P3(大工程) | 前端 Angular 20/21 + Amplify v6 + ui-angular 5.x 整体升级 | 高,破坏性,需单独立项 | + +## 4.1 处置进度(2026-06-14,分支 `chore/dependency-modernization`) + +| 级别 | 状态 | 说明 | +|---|---|---| +| 🔴 P0 | ✅ 完成 | `python-jose` → `PyJWT[crypto]`,重写两个 authorizer 验签;6 用例单元验证通过 | +| 🟠 P1 | ✅ 完成 | 全部 `requirements.txt` 锁版本(兼容区间锁大版本) | +| 🟢 P2 | ✅ 完成 | `@types/node`→`^20`、`aws-cdk-lib`→`^2.258` 并刷新 lockfile;修 `\*` 转义 | +| 🟡 P3 | ✅ 完成(构建层) | **三个前端应用全部 Angular 14 → 20**;Admin/Application 同时 **Amplify v4 → v6**、ui-angular 2→5;移除已废弃的 `@angular/flex-layout`;生产构建均通过 | + +### 前端迁移要点 +- 统一各 `@angular/*` 至 `^20`、TypeScript `5.8`、zone.js `0.15`、rxjs `7.8`。 +- Material:移除已删的 `legacy-*` 导入;主题改用 M3 `mat.theme()`(indigo→violet、pink→rose,视觉相近)。 +- Angular 19 起组件默认 standalone:给 NgModule 声明的组件补 `standalone: false`。 +- Amplify v6:`Auth.currentSession()`→`fetchAuthSession()`、`getJwtToken()`→`token.toString()`、`isValid()`→`!!tokens?.idToken`、`Auth.signOut()`→`signOut()`;`Amplify.configure(aws_exports)` 旧格式 v6 仍兼容。 +- SCSS 去除 webpack `~` 前缀;ui-angular 5 的 `theme.css` 经 angular.json `styles` 引入(其 exports 字段不暴露该子路径)。 + +### ⚠️ 尚未验证(需运行时确认) +- 生产构建通过 ≠ 运行时通过。**Amplify v6 的登录/会话/登出流程需在浏览器实测**(`npm start` + 真实 Cognito 登录)。 +- 后端 PyJWT 为独立单元验证,**未在已部署的 Lambda 中集成测试**。 +- Material 主题色由 indigo 变为 violet(如需精确品牌色需自定义 M3 调色板)。 + +## 5. 信息来源 + +- AWS Lambda runtimes: +- Lambda 增加 Python 3.13: +- CodeBuild 增加 Python 3.13(standard:7.0): +- python-jose CVE-2024-33663: +- PyJWT 迁移指引: +- Angular 版本与 EOL: +- @aws-amplify/ui-angular(npm registry): diff --git a/docs/zh-CN/LOCAL_TESTING.md b/docs/zh-CN/LOCAL_TESTING.md new file mode 100644 index 0000000..429076a --- /dev/null +++ b/docs/zh-CN/LOCAL_TESTING.md @@ -0,0 +1,95 @@ +# 免费本地后端测试(无需 AWS 账号) + +[English](../LOCAL_TESTING.md) | [**中文**](LOCAL_TESTING.md) + +[← 返回 README](../../README.zh-CN.md) + +在本地真实跑后端服务,验证 Lambda handler + DAL + DynamoDB 读写——零成本、 +不碰真实 AWS。提供两种方式。 + +> 注意:两种方式都**不含 Cognito**。真实登录依赖 Cognito(无免费本地方案,见 +> `docs/zh-CN/MIGRATION_VERIFICATION.md`)。均通过 `requestContext.authorizer` +> 注入假的鉴权上下文(`tenantId`/`userRole`)来绕过 authorizer。 + +## 方式一(推荐,跨平台):pytest + moto + +纯 Python,**Windows/macOS/Linux 通用,无需 Docker、无需 AWS**。`moto` 在内存里 +模拟 DynamoDB。两条命令: + +```bash +pip install -r requirements-test.txt +pytest +``` + +- 测试位于 `server/services/*/tests/test_*.py`:直接 import handler、用 moto mock + DynamoDB、断言 CRUD(含 update 回归测试,锁住已修复的 3 个 bug)。 +- 共享设置见 `server/conftest.py`(把共享层与各服务 `src/` 加进 `sys.path`,并在 + import 前设好环境变量)。 +- CI:`.github/workflows/backend-tests.yml` 在 ubuntu/windows/macOS 三平台跑 `pytest`。 + +写测试套件、跑 CI 首选此方式。下面的 DynamoDB Local 更保真但更重、依赖 Docker 与 +Git Bash(非跨平台),适合偶尔高保真验证。 + +## 方式二(高保真):DynamoDB Local + sam local invoke + +### 前置 +- Docker 运行中 +- SAM CLI(`pip install aws-sam-cli`) +- 本地 Python + boto3(`pip install boto3`) + +## 一键运行(product-service 全 CRUD) +```bash +bash scripts/local-test-product.sh +``` +脚本会:起 DynamoDB Local(`-sharedDb`)→ 建 `Product-pooled` 表 → 构建 → +依次 invoke create/get/update/list/delete,最后自动还原临时改动。 +停止本地库:`docker rm -f ddb-local`。 + +## 关键坑(手动操作时务必注意) + +1. **DynamoDB Local 要加 `-sharedDb`**:否则按"凭证+区域"隔离数据库文件, + 建表方和函数看到的不是同一个库。 + ```bash + docker run -d --network saas-local --name ddb-local -p 8000:8000 \ + amazon/dynamodb-local -jar DynamoDBLocal.jar -inMemory -sharedDb -port 8000 + ``` + +2. **`sam local invoke --env-vars` 只能覆盖模板里已声明的环境变量**。 + `AWS_ENDPOINT_URL_DYNAMODB`(让函数 boto3 指向本地库)若不在模板里, + 不会被注入。所以需临时把它加进 `template.yaml` 的 `Globals.Function.Environment`: + ```yaml + AWS_ENDPOINT_URL_DYNAMODB: "http://ddb-local:8000" + ``` + (脚本会自动加、用完 `git checkout` 还原。) + +3. **函数容器要接入同一 Docker 网络**:`sam local invoke ... --docker-network saas-local`, + 这样函数里用主机名 `ddb-local` 能解析到 DynamoDB Local 容器。 + +4. **关掉 X-Ray**:env 里设 `POWERTOOLS_TRACE_DISABLED=true`,避免本地无 X-Ray daemon 报噪。 + +## 已验证结果(2026-06-14) + +product-service 五个操作全部 `statusCode 200`:create / get / get_products / +update / delete。本地测试还**发现并修复了 update 的两个预先存在 bug** +(`datetime` 误用、`ReturnValues=UPDATED_NEW`)——见 commit `b61c780`。 + +order-service 为相同代码模式,已应用相同修复(可仿照本脚本建 `Order-pooled` 表后同样验证)。 + +--- + +## 前端:Playwright 运行时冒烟(跨平台) + +`e2e/` 是独立的 Playwright 项目,**Windows/macOS/Linux 通用**。它 serve 三个 app +的构建产物,用无头 Chromium 加载,断言:Angular 20 正常 bootstrap、应用外壳与关键 +元素渲染(Admin 验证 `` 出现)、无致命 JS 错误。 + +```bash +# 先构建三个 app(各自目录):npx ng build --configuration production +cd e2e +npm install +npx playwright install chromium # 大陆可加速:PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries/playwright +npx playwright test +``` + +- 不测真实登录(无免费本地 Cognito);针对占位配置的预期网络/鉴权错误已忽略。 +- CI:`.github/workflows/frontend-e2e.yml` 构建三个 app 后跑 Playwright。 diff --git a/docs/zh-CN/MIGRATION_VERIFICATION.md b/docs/zh-CN/MIGRATION_VERIFICATION.md new file mode 100644 index 0000000..1005a08 --- /dev/null +++ b/docs/zh-CN/MIGRATION_VERIFICATION.md @@ -0,0 +1,72 @@ +# 前端迁移运行时验证清单(Angular 20 + Amplify v6) + +[English](../MIGRATION_VERIFICATION.md) | [**中文**](MIGRATION_VERIFICATION.md) + +[← 返回 README](../../README.zh-CN.md) + +> 适用分支:`chore/dependency-modernization` +> 目的:生产构建已通过,但**构建通过 ≠ 运行时通过**。本清单用于在浏览器中 +> 实测三个应用的认证流程(Amplify v6 的登录/会话/登出)。 + +## 0. 前置条件 + +- Node ≥ 20(本仓库迁移在 Node 22 上完成)。 +- 各应用 `node_modules` 已安装(迁移过程中已 `npm install`)。 +- **有效的后端配置**:登录需要真实的 Cognito 用户池与已部署的 API。 + - `Admin`:读取 `client/Admin/src/aws-exports.ts`(静态 Cognito 配置)。 + - `Application`:通过 `…/tenant/init/` 动态获取每租户配置,URL 需带租户名。 + - `Landing`:仅注册表单,调用 `environment.regApiGatewayUrl`。 + +## 1. 启动(任选其一) + +```bash +# 便捷脚本:三个应用分别在 4200/4201/4202 启动 +bash scripts/serve-clients.sh + +# 或手动单独启动 +cd client/Landing && npx ng serve --port 4200 +cd client/Application && npx ng serve --port 4201 +cd client/Admin && npx ng serve --port 4202 +``` + +## 2. 逐应用验证清单 + +### 2.1 Landing(无认证,最先验证) +- [ ] 打开 `http://localhost:4200`,页面正常渲染(无白屏)。 +- [ ] 浏览器 Console **无报错**(尤其无 Angular/zone.js 启动错误)。 +- [ ] 填写注册表单并提交 → 网络面板可见对 `regApiGatewayUrl` 的请求。 +- [ ] Material 控件(输入框/按钮/snackbar)样式正常(主题色现为 violet)。 + +### 2.2 Admin(静态 Cognito 登录) +- [ ] 打开 `http://localhost:4202`,**Amplify Authenticator 登录界面正常渲染** + —— 这验证了 Amplify v6 `Amplify.configure(aws_exports)` 运行时成功。 +- [ ] Console 无 `Amplify has not been configured` 或模块解析类报错。 +- [ ] 用管理员账号登录 → 成功进入后台(不再回到登录页)。 +- [ ] 进入“租户/用户”页 → 网络请求头含 `Authorization: Bearer ` + —— 验证 `auth.interceptor.ts` 的 `fetchAuthSession()` 取 token 正常。 +- [ ] 顶部显示用户名(验证 `nav.component` 读取 `idToken.payload`)。 +- [ ] 点击登出 → 回到登录页(验证 `signOut({ global: true })`)。 + +### 2.3 Application(动态每租户登录) +- [ ] 以带租户的入口打开,例如 `http://localhost:4201/` 或应用约定的 + 注册后跳转路径(触发 `auth-configuration.service` 的 `configureAmplifyAuth()`)。 +- [ ] Authenticator 登录界面正常渲染(验证动态 `Amplify.configure(awsmobile)`)。 +- [ ] 租户用户登录成功 → 进入 dashboard。 +- [ ] `CognitoGuard` 行为:未登录访问受保护路由 → 跳 `/unauthorized`。 +- [ ] orders / products 列表能加载(请求头含 Bearer token)。 +- [ ] 登出正常。 + +## 3. Amplify v6 重点观察项(出问题时优先看这些) + +| 现象 | 可能原因 | 位置 | +|---|---|---| +| 登录页空白 / `Amplify has not been configured` | `Amplify.configure` 未在 bootstrap 前执行或配置格式不被接受 | `main.ts` / `auth-configuration.service.ts` | +| 请求缺少 `Authorization` 头 | `fetchAuthSession()` 返回的 `tokens?.idToken` 为空 | `auth.interceptor.ts` | +| 登录后仍判定未认证 | `!!tokens?.idToken` 判定逻辑 | `nav.component.ts` / `cognito.guard.ts` | +| 用户名/公司名空白 | `idToken.payload['custom:...']` 字段名 | `nav.component.ts` | +| 登出无效 | `signOut({ global: true })` | `*/auth.component.ts`、`nav.component.ts` | + +## 4. 通过标准 + +三个应用均:可启动、登录页渲染、能登录、受保护请求带 token、可登出,且 +Console 无致命报错 → 视为运行时验证通过,可合并分支。