# AIwelink 技术实现规则 本文补充 [AIwelink 技术方案](./technology-stack.md)。 文档说明请求怎样进入系统、代码怎样分层、数据怎样保存。 文档也列出第一阶段的部署和测试要求。 ## 1. Web 和 API 使用一个域名 ### 1.1 请求路径 第一阶段对外使用一个公网域名: ```text https://aiwelink.com/ -> Next.js Web https://aiwelink.com/api/v1/... -> REST API ``` 入口代理(例如 Nginx)按路径转发: ```text 客户端 | v Nginx |-- /api/v1/* -> api:3000 |-- /* -> web:3000 ``` NestJS 设置全局前缀 `/api/v1`。代理和应用要统一路径处理方式,避免请求出现两次 `/api/v1`。 ### 1.2 这样安排的好处 - 浏览器通过同域名直接访问 API,开发和生产使用相同请求路径; - HttpOnly Cookie 的会话处理更简单; - 分享页、公开机会页和登录后的工作台使用同一域名; - 本地、测试和生产环境可以使用相同的请求路径; - 将来改用 `api.aiwelink.com` 时,资源路径仍可以保持稳定。 ### 1.3 入口代理要配置的规则 - Web 和 API 使用各自的超时、缓存和安全策略; - Next.js 负责页面,业务规则统一放在 API; - Next.js 服务端调用 API 时优先走 Docker 内网; - 未来接入 App、第三方赛事系统或开放平台时,再单独设计 CORS、Token 和 API 子域名; - 未来使用 SSE 时,代理关闭响应缓冲,并设置足够长的连接超时。 ## 2. NestJS 和 Fastify NestJS 提供模块、依赖注入、Guard、拦截器、异常过滤器和 OpenAPI 集成。 Fastify Adapter 负责底层 HTTP 服务。 这个组合适合授权、项目、邀请、积分和订单等规则较多的业务。 代码按以下规则编写: - 使用兼容 Fastify 的 NestJS 插件; - Controller 只接收请求、调用应用服务并组织响应; - 复杂业务规则放在应用服务; - Guard 和资源归属检查共同完成权限校验; - 所有输入使用 DTO 校验; - API 响应使用专门的响应类型,数据库实体只在数据访问层使用; - 错误格式统一,并带 `requestId`; - API 路径使用 `/api/v1`,JSON 字段使用 `camelCase`,URL 使用小写短横线。 推荐的目录如下: ```text src/ modules/ identity/ users/ profiles/ consents/ projects/ opportunities/ invitations/ points/ commerce/ recommendations/ operations/ common/ guards/ filters/ interceptors/ decorators/ infrastructure/ database/ storage/ cache/ ``` ## 3. REST API 规则 ### 3.1 用资源设计路径 资源名使用名词和复数形式: ```text GET /api/v1/projects GET /api/v1/projects/{projectId} POST /api/v1/projects PATCH /api/v1/projects/{projectId} DELETE /api/v1/projects/{projectId} ``` 明确的从属关系使用嵌套资源: ```text GET /api/v1/projects/{projectId}/members POST /api/v1/projects/{projectId}/applications ``` 生成报告等耗时动作建模为报告资源或任务资源。 客户端先创建任务,再查询任务进度和结果。 ### 3.2 HTTP 状态码 | 状态码 | 使用场景 | | --- | --- | | `200` | 读取或更新成功 | | `201` | 创建资源成功 | | `202` | 异步任务已接受 | | `204` | 成功且没有响应内容 | | `400` | 请求格式错误 | | `401` | 未登录或会话失效 | | `403` | 当前用户没有权限 | | `404` | 资源不存在 | | `409` | 当前资源状态不允许这次操作 | | `422` | 字段校验失败 | | `429` | 请求频率超过限制 | | `500` | 服务端出现未处理异常 | ### 3.3 响应和错误格式 成功响应统一使用 `data` 字段。列表响应在 `meta` 中返回游标和分页信息。 错误响应采用 `application/problem+json`。 响应至少包含 `type`、`title`、`status`、`code`、`detail` 和 `requestId`。 ### 3.4 可重复提交的写操作 订单创建、积分发放、邀请接受、付费权益创建和报告任务等操作支持 `Idempotency-Key`。 服务端保存请求结果,客户端重试时返回同一结果。 权限由 API 服务端统一检查,前端按钮只负责展示状态。 ## 4. Identity 身份模块 ### 4.1 职责 `Identity` 负责用户身份和会话。 个人资料、能力画像、项目经历和测评结果由其他模块管理。 建议的核心表: ```text users user_identities sessions email_verifications login_events ``` ### 4.2 登录方式 - 微信扫码或授权登录作为主入口; - 邮箱用于绑定、验证、通知和账号恢复; - 登录方式和用户主体分开保存,同一用户可以绑定多种登录方式; - 会话使用 HttpOnly、Secure Cookie; - 服务端保存会话状态和撤销记录; - 长期 Token 放在服务端会话中管理。 未来可以增加手机号、学校身份验证或其他第三方身份,统一挂在 `users` 用户主体下。 ## 5. Drizzle 和原生 SQL ### 5.1 选择规则 | 场景 | 访问方式 | | --- | --- | | 普通增删改查 | Drizzle | | 普通事务 | Drizzle transaction | | JSONB 复杂筛选 | Drizzle + SQL | | `pgvector` 相似度查询 | SQL Repository | | 推荐排序 | SQL Repository | | 全文搜索 | SQL Repository | | 报表和聚合 | SQL Repository | 原生 SQL 使用参数绑定。查询条件和排序字段经过代码校验后再拼接。 ### 5.2 数据访问顺序 ```text Controller ↓ Application Service ↓ Repository Interface ↓ Drizzle Repository 或 SQL Repository ↓ PostgreSQL ``` Controller 通过 Repository 读取数据,这样业务规则和具体数据库工具可以分别测试和替换。 ### 5.3 数据库迁移 - 数据库结构用版本化迁移保存; - 普通表由 Drizzle Schema 和迁移工具维护; - `pgvector`、特殊索引、函数和分区可以使用手写迁移 SQL; - 生产环境的每次表结构变化都要留下迁移记录。 ## 6. PostgreSQL、JSONB 和 pgvector ### 6.1 PostgreSQL 保存什么 PostgreSQL 保存需要事务一致性的业务数据。 这些数据包括用户、身份、授权、项目、成员、申请、积分、订单、报告信息和推荐记录。 Redis 负责速度和临时状态。最终业务状态仍以 PostgreSQL 为准。 ### 6.2 JSONB 适合保存什么 JSONB 适合保存: - 灵活的用户偏好; - AI 输出的结构化报告内容; - 带版本号的推荐特征快照; - 运营可以调整的配置字段。 用户身份、权限、订单金额和状态,使用结构化字段。 积分流水和项目成员关系,也使用结构化字段。 数据库约束负责保证这些关系的一致性。 ### 6.3 pgvector 怎样使用 `pgvector` 用于项目、课程、学科和公开内容的语义检索。每条向量记录至少保存: - 来源资源 ID; - Embedding 模型名称; - 模型版本; - 向量维度; - 生成时间; - 来源内容版本。 测评原始回答等敏感数据的向量化需要单独评估,并保留可解释的推荐理由。 ## 7. 数据表和生命周期 ### 7.1 业务分层 建议按下面的业务层组织表: ```text 身份层:users、user_identities、sessions 资料层:profile_basics、profile_preferences、public_profiles 认知层:assessment_sessions、assessment_answers、insight_snapshots 证据层:insight_evidence、project_reviews、behavior_events 授权层:consent_grants、consent_audits 项目层:opportunities、projects、project_members、applications 增长层:referral_events、point_ledger 审计层:audit_logs ``` ### 7.2 大表处理 现在按业务功能拆表,方便权限、索引和数据保存周期管理。 大型追加型表按以下顺序处理: 1. 建立合理索引; 2. 优化时间范围查询; 3. 归档冷数据; 4. 为特殊查询建立单独的 SQL Repository; 5. 数据量持续增长后,再评估 PostgreSQL 分区。 ## 8. Redis 的用途 Redis 用于: - 热点数据缓存; - 请求限流; - 短期验证码和临时状态; - 异步任务队列; - 幂等键状态; - 短期排行榜。 最终积分余额、订单状态、授权记录和用户画像原始数据,统一从 PostgreSQL 读取。 项目成员关系也由 PostgreSQL 保存。 ## 9. 阿里云 OSS 文件流程 ```text API 创建临时凭证 ↓ 浏览器直接上传 OSS ↓ 上传完成后通知 API ↓ PostgreSQL 写入文件信息 ↓ 按需解析、审核或建立索引 ``` 数据库保存的文件信息包括: ```text fileId ownerId objectKey mimeType size hash visibility createdAt ``` 私有文件通过短期签名 URL 访问。上传流程检查文件类型、大小、哈希和归属关系。 ## 10. ECS 和 Docker Compose ### 10.1 第一阶段服务 ```text nginx web api worker(AI 助手方案待决定) postgres redis ``` 应用容器配置健康检查和自动重启。镜像推送到镜像仓库,生产环境使用固定版本标签。 ### 10.2 为未来 Kubernetes 做准备 现在就按以下方式运行: - Web、API 和 Worker 分开成容器; - 应用服务保持无状态; - 配置通过环境变量或 Secret 注入; - 文件放在 OSS; - 数据库迁移独立执行; - 服务之间通过内部 DNS 或配置发现通信。 ### 10.3 数据服务的运维要求 如果 PostgreSQL 和 Redis 运行在 ECS 上,至少准备独立数据盘,并安排: - 自动备份; - 备份保留周期; - 恢复演练; - 磁盘空间监控; - 数据库升级和回滚方案。 ## 11. Uptime Kuma 和测试 ### 11.1 可用性检查 建议提供两个健康检查接口: ```text GET /api/v1/health/live GET /api/v1/health/ready ``` `live` 只检查进程是否存活。`ready` 检查 PostgreSQL、Redis 和必要配置是否可用。 Uptime Kuma 监控首页、两个健康接口、TCP 端口和 HTTPS 证书到期时间。 ### 11.2 测试范围 第一阶段至少安排: - TypeScript 类型检查; - Lint; - API 单元测试和集成测试; - 关键流程端到端测试; - 发布前数据库迁移检查。 核心流程按下面的顺序覆盖: ```text 微信登录 → 绑定邮箱 → 创建个人资料 → 创建项目 → 发送邀请 → 授权共享 → 提交项目申请 → 记录积分流水 ``` ## 12. 仍需决定的技术事项 以下内容等产品流程和数据量更清楚后再决定: - AI 助手使用的模型供应商和模型路由; - AI 助手的对话编排框架; - 长报告和复杂任务使用哪种队列; - 推荐系统是否拆成独立服务; - 是否引入专用搜索引擎; - Kubernetes 的发行版和部署方式; - 完整的日志、指标和链路追踪方案。