# Policy Links(任务清单) > 说明:本清单按 `plan.md` 拆分为可执行任务。 > 状态含义:`[ ]` 未完成,`[x]` 已完成。 ## 0. 前置检查 - [x] 确认客户端存在至少两处协议入口:首次同意页、个人主页弹窗(ProfileModal) - [x] 确认后端路由前缀体系为 `/v1/*` ## 1. 后端(FastAPI)——协议链接下发 ### 1.1 配置项(环境变量) - [x] 在后端配置类中新增协议链接配置(EN 兜底 + 可选 TC) - [x] 在 `server/env.example` 补充 `LEGAL_*` 配置示例与注释 ### 1.2 API 路由与返回结构 - [x] 新增 `GET /v1/legal/links` 接口 - [x] 解析 `Accept-Language`(轻量:只关心 `en/tc`,其他回退 `en`) - [x] 支持语言缺失/未配置时回退 EN - [x] 返回 `resolvedLang` 便于排查 - [x] 在 `app/main.py` 注册 legal router ### 1.3 代码质量与最小校验 - [x] 确保后端代码可被 `python3 -m compileall` 编译通过 - [x] (可选)补充单测:覆盖缺省、tc、zh-hant/zh-hk/zh-tw 等输入解析与回退(unittest) ### 1.4 内置协议内容页(兜底,保证有内容) - [x] 新增 `GET /v1/legal/privacy`、`GET /v1/legal/terms` 两个 HTML 页面接口 - [x] 未配置 `LEGAL_*` 时,`GET /v1/legal/links` 自动回退到内置页面绝对 URL - [x] 更新后端配置默认值:`LEGAL_*` 未配置时使用内置页面(`__internal__` 哨兵) ## 2. 客户端(React Native + Expo)——统一获取并打开链接 ### 2.1 新增统一请求封装 - [x] 新增 `client/src/services/legalApi.ts` - [x] 统一设置 `Accept-Language`(将客户端当前语言映射到 `en/tc`) - [x] 统一超时与错误处理(抛错给调用方兜底) ### 2.2 首次同意页接入 - [x] 将 `client/app/(splash)/splash.tsx` 的写死 URL 改为调用 `fetchLegalLinks()` - [x] 拉取失败不崩溃、不阻塞「同意并继续」 - [x] 点击协议入口用 `expo-web-browser` 打开后端下发链接 ### 2.3 个人主页弹窗接入 - [x] 将 `client/components/home/ProfileModal.tsx` 的 `toastTodo` 替换为打开后端下发链接 - [x] 弹窗打开时拉取链接(失败不影响其他功能) - [x] 修复 TypeScript 定时器类型(RN 环境兼容) ### 2.4 客户端最小验证 - [x] 运行现有 `vitest` 测试通过(`npm test`) - [x] (可选)补充一个轻量测试:`buildAcceptLanguage()` 映射规则(en/tc) ## 3. 文档与追踪 - [x] `spec_kit/Policy Links/spec.md` 增补:个人主页弹窗也必须使用同一 API;接口路径统一为 `GET /v1/legal/links` - [x] 生成 `spec_kit/Policy Links/plan.md` - [x] 生成 `spec_kit/Policy Links/tasks.md` - [x] 在 `spec_kit/overview.md` 的 `Policy Links` 条目下标记“任务清单已执行完毕(已完成编码)”