# 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` 条目下标记“任务清单已执行完毕（已完成编码）”

