# CLAUDE.md — xiangqin 项目地图

Claude 新会话的项目地图。

## 这是什么

**相亲平台 CLI** —— 付费置顶曝光商业模式。付费 = 在别人 query 结果里置顶 + 🔥 标记。

**不做**：推荐算法 / 聊天 / 匹配评分 / UGC 社区。查询权 100% 在用户 agent。

## 当前在做什么

看 [`brain/plan/index.md`](./brain/plan/index.md) 的「🛣️ 下一步（最多 3 个）」——这是最权威的推进信号。

## 目录地图

### `brain/` —— 对内

| 子目录 | 用途 | 入口 |
|---|---|---|
| `brain/objectives/` | 团队目标 + 指标 | [index.md](./brain/objectives/index.md) |
| `brain/plan/` | 里程碑拆分 + 下一步 | [index.md](./brain/plan/index.md) |
| `brain/decisions/` | ADR（为什么这么设计） | [index.md](./brain/decisions/index.md) |
| `brain/scenarios/` | 用户场景叙事（day-in-life） | [index.md](./brain/scenarios/index.md) |
| `brain/sop/` | 运维剧本（deploy / publish / restore / onboarding） | [index.md](./brain/sop/index.md) |
| `brain/raw/` | 从外部捕获的不可变事实（scrape / API dump / 第三方规范） | [index.md](./brain/raw/index.md) |
| `brain/wiki/` | Claude 从 raw + src 派生的综合（entities + concepts） | [index.md](./brain/wiki/index.md) |
| `brain/prd/` | 产品需求文档（为什么做 + 做什么 + 做到什么程度算赢；一对多 FEAT） | [index.md](./brain/prd/index.md) |
| `brain/blueprints/` | 数据库 schema / 服务端架构细节（项目底图，直接读 md 源文件，不进 MkDocs） | [index.md](./brain/blueprints/index.md) |
| `brain/issues/` | 文件版 issue 追踪（open / closed / archive + 评论） | [index.md](./brain/issues/index.md) |

### 对外（给用户 / 开发者 / 用户的 agent）

| 目录 | 用途 |
|---|---|
| `docs/` | MkDocs 源 → [agentaily-xiangqin.pages.dev](https://agentaily-xiangqin.pages.dev/) |
| `README.md` / `SKILL.md` | 仓库门面 + Claude Code skill 触发描述 |

### 代码与配置

| 路径 | 用途 |
|---|---|
| `src/xiangqin/` | 服务端（FastAPI + sqlite）+ `xq` CLI |
| `test/` | pytest（102 测试，`--cov-fail-under=70`） |
| `scripts/` | 部署 / 备份 / 发布 脚本 |
| `systemd/xiangqin.service` | 生产 systemd unit |
| `pyproject.toml` | deps（主 + `[dependency-groups]` dev/docs） |
| `mkdocs.yml` | 文档配置 |
| `vault.json` | vault v3 声明式凭证 |
| `.vault/secrets.json` | `vault install` 产物，**gitignored**，代码唯一凭证入口 |

## 不变量（宪法级约束）

改代码前确认不会违反：

1. **手机号永不明文**：HMAC-SHA256 是唯一存储形式；stdout / stderr / vault / 日志 / 备份都不能有明文
2. **查询权在用户**：服务端不做推荐 / 不做排序算分
3. **排序规则固定公开**：`ORDER BY exposure_remaining>0 DESC, updated_at DESC`（改动必须过 ADR）
4. **付费只影响可见性**：不影响搜索可达性，不退款
5. **WHERE 不能为空**；LIMIT 默认 50 最大 100
6. **删号 7 天物理清理窗口**，期间可撤销
7. **vault 是唯一对外 CLI 依赖**；不走 mailbox 和其它项目协作（自治单体实验）
8. **测试覆盖不能低于 70%**（CI 门闩，pyproject 钉死）

## 常用命令速查

```bash
# 开发
uv sync --all-groups
uv run pytest -q                     # 跑测试（带 coverage + junit + fail-under）
uv run ruff check src test scripts
uv run ruff format src test scripts
uv run --group docs mkdocs serve     # 本地文档站
pre-commit install                   # 启用 pre-commit

# 服务端
uv run xiangqin-server               # 起 FastAPI on :8000

# 客户端
uv run xq --help

# 部署 / 发布（剧本）
bash scripts/deploy.sh               # 见 brain/sop/services/deploy.md
bash scripts/publish-pypi.sh --canary  # 见 brain/sop/services/publish.md
bash scripts/restore.sh              # 见 brain/sop/services/restore.md
```

## 注意事项

新会话干活前留意：

- **凭证读取路径**：`from xiangqin import credentials as creds; creds.get("aliyun_sms")`。别名映射在 `vault.json` 里。改凭证名 / 加新凭证 → 同步改 `vault.json` → `vault install` 重拉
- **公开元数据不入 vault**：sms 的 `sign_name` / `template_code`、alipay 的 `gateway_url` 是写死常量（见 `src/xiangqin/sms/aliyun.py` / `payment/alipay.py`）。这些是服务方公开标识，不是秘密
- **服务端以 `xiangqin` 用户跑**（非 root）：改 deploy 脚本或 systemd unit 时注意 `chown -R xiangqin:xiangqin /opt/xiangqin`
- **支付 webhook 必须验签**：`/exposure/webhook/alipay` 用 `alipay_public_key` 做 RSA2；mock provider 和真付走同一签名路径，别绕开
- **测试默认不触真 DB**：`test/conftest.py` 的 `tmp_db` fixture 是 autouse；新加测试模块不用重复写 fixture
- **CI 会 `mkdocs build --strict`**：docs/ 里加 anchor 链接必须能解析（strict 模式下 warning 即 fail）
- **资产变动同步入 vault**：新开云账号 / 新发 token / 新建项目 / 绑定域名 → 立刻更新 vault 的 credential / resource，不要留在 vault 外的"临时记忆"里

## 和生态的关系

- **唯一对外 CLI 依赖**：[vault](https://agentaily-vault.pages.dev/)（凭证声明式管理）
- **不依赖**：matchmaker / cashier / backup / membership / host / oss / hitch（自治单体实验）
- **不收跨项目邮件**：`.mailbox/` 不设；跨项目协作走直接 ping

## CI/CD

- GitHub Actions: `test` + `lint` + `docs`（docs needs: [test, lint]）
- Cloudflare Pages: `agentaily-xiangqin` 项目，push main 自动部署
- 徽章生成：genbadge（coverage / tests）+ shields.io（CI / docs）
- Secrets 所在：GitHub repo `yarnovo/xiangqin` → `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID`（token 源在 vault `cloudflare-pages-deploy`，account_id 在 `cloudflare-main`）
