# 网文创作工作流（Writer Work Flow）

> AI 辅助的**中文网文写作工作流**，以 Web 应用形态交付。核心理念：**把写长篇当软件工程做**——先立架构（世界观 / 角色 / 大纲），对着规格逐章生成，每章写完即测（多维审查），全程维护单一真相源（数据库）。

作者不再让 AI「一口气瞎写十万字」，而是像写代码一样：需求（立项）→ 架构（设定库）→ 建模（角色卡）→ 接口（大纲）→ 实现（逐章生成）→ 测试（写完即审）→ 集成（验收更新全局状态）→ 回归（全书一致性）。AI 是「灵感增幅器 + 质检员」，作者始终掌控创意。

---

## 功能总览

- **引导式立项** — 一句灵感走向连载：选题材 / 基调 / 结局走向 / 叙事视角，AI 起草世界观、主角、金手指、总纲方案，一键建库。
- **设定库（Codex）** — 结构化的单一真相源：
  - 角色卡（外貌 / 动机 / 目标 / 口癖 / 性格弧光 / 人物关系图）
  - 世界观（力量体系 / 势力 / 地理 / 词条）
- **大纲 / 细纲** — AI 排分卷分章骨架，逐层细化到场景清单，并提示伏笔回收窗口。
- **写章（SSE 流式）** — 注入设定 + 文风指纹，按 genre-aware 的网文写作教条（黄金三章、章末钩子、爽点密度）流式产出本章草稿。
- **五审（写完即审）** — 一致性 / 伏笔 / 文风 / 节奏 四审 + 人物塑造（advisory 建议性）。审查器**只读**，不静默改稿。
- **验收事务（HITL）** — 人在环中：作者裁决冲突后，唯一写入路径提交；未解决冲突阻断验收。章节摘要从**最终已验收文本**抽取，绝不污染真相源。
- **创作工具箱（15 个生成器）** — 声明式 skill 框架，「加生成器 = 加一份声明」：脑洞 / 书名 / 简介 / 取名 / 金手指 / 词条 / 黄金开篇 / 细纲 / 续写 / 扩写 / 降 AI / 拆书，外加世界观 / 角色 / 大纲。
- **模板库** — 复用与沉淀常用创作模板。
- **多 Provider LLM 网关** — 路由 / 回退 / 熔断的自建薄网关；Agent 只声明能力 tier，网关按配置映射到 provider+model；支持 Kimi Code 订阅 OAuth（device flow）。

---

## 技术栈（已锁定）

| 层 | 选型 |
|---|---|
| 前端 | **Next.js + TypeScript**（仅 UI；经 OpenAPI 生成的 TS 客户端调后端，无手写共享类型） |
| 后端 | **Python + FastAPI**（async，SSE） |
| 编排 | **LangGraph**（写→审→验收 图，Postgres checkpointer 可恢复） |
| LLM 访问 | 自建**薄网关**，覆盖 `anthropic` + `openai`（baseURL 兼容 DeepSeek/Kimi/Qwen/GLM）+ `google-genai` |
| 结构化输出 | **Pydantic + instructor** |
| ORM / 迁移 | **SQLAlchemy 2.0（async）+ Alembic** |
| 存储 | **Postgres**（原型不启用 pgvector） |
| 长任务 | FastAPI BackgroundTasks + `jobs` 表（原型不引入独立队列） |

工具链：**uv**（Python workspace，8 个成员）+ **pnpm**（前端）。Python 3.12+，Node 22。

---

## 快速开始

前置：Python 3.12+ · Node 22 · [uv](https://docs.astral.sh/uv/) · pnpm · Docker

> **本地端口（宿主已 +1000，防与其他项目冲突）**：前端 **http://localhost:4000** · 后端 **http://localhost:9000**（API 文档 `/docs`）· Postgres **localhost:6432**。容器内部端口不变（3000 / 8000 / 5432），只改宿主发布端口；要改回默认各减 1000 即可。接线：前端 `apps/web/.env.local` 的 `NEXT_PUBLIC_API_BASE=http://localhost:9000` 指向后端；后端 `.env` 的 `CORS_ORIGINS` 放行 `http://localhost:4000`、`DATABASE_URL` 指向 `localhost:6432`。

```bash
# 1. 克隆后，安装后端依赖（仓库根，uv workspace）
uv sync

# 2. 安装前端依赖
cd apps/web && pnpm install && cd ../..

# 3. 配置环境变量（CREDENTIAL_ENC_KEY 为必填的凭据加密 Fernet key，启动即校验）
cp .env.example .env
#    生产请重新生成：
#    uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

# 4. 起 Postgres 并跑迁移
docker compose up -d pg
uv run alembic upgrade head

# 5. 起后端 API（http://localhost:9000，文档 /docs）— 宿主端口 +1000
uv run uvicorn ww_api.main:app --port 9000 --reload

# 6. 起前端（另开终端，http://localhost:4000）— pnpm dev 已内置 -p 4000
cd apps/web && pnpm dev
```

或一键起全套（pg + api + web，宿主端口均已 +1000）：

```bash
docker compose up   # web → :4000 · api → :9000 · pg → :6432
```

> **LLM API Key 不放 `.env`**：在应用设置页 **`/settings/providers`** 录入，密文存于数据库凭据库（用 `CREDENTIAL_ENC_KEY` 加密）。`.env` 里只有那把加密主密钥本身。

---

## 工具链 & 门禁

改动声明「完成」前须全绿（TDD 先红后绿，覆盖率 ≥ 80%）。

**后端**（仓库根）：

```bash
uv run ruff check .            # lint
uv run ruff format .           # format
uv run mypy packages apps      # 类型
uv run pytest -q               # 单元 + 集成（需 pg：docker compose up -d pg）
uv run alembic check           # 改过模型后校验无迁移漂移
uv run pytest -q --cov --cov-report=term-missing --cov-fail-under=80   # 覆盖率门禁
```

**前端**（`apps/web`）：

```bash
pnpm lint
pnpm typecheck
pnpm test            # vitest（范围 lib/**：纯逻辑 + hooks）
pnpm build
pnpm test:coverage   # 覆盖率门禁（阈值 80%）
```

**改过后端 schema** 后重生成 TS 客户端：

```bash
cd apps/web && pnpm gen:api
```

CI 见 `.github/workflows/ci.yml`（backend job 带 pg service 跑 ruff/mypy/alembic/pytest；frontend job 跑 gen:api/lint/typecheck/test）。

---

## 项目结构

```
apps/
  api/        FastAPI 应用：路由 / service / 请求响应 schema / SSE 端点
  web/        Next.js 前端：Server Components 读视图 + Client 编辑器/流式交互
packages/
  shared/     跨栈 Pydantic 契约 schema（前端经 OpenAPI 消费）
  config/     应用配置（Settings，环境变量边界）
  db/         SQLAlchemy 2.0 模型 / Alembic 迁移 / Repository
  llm_gateway/ 多 provider 网关：路由 / 回退 / 熔断 / adapter / 计费台账
  agents/     声明式 AgentSpec + 外置 prompt（Agent 只声明能力 tier）
  core/       domain 领域逻辑 · memory 记忆真相源（确定性选择注入）· orchestrator LangGraph 图
  skills/     工具箱注册表 + skill 注册（声明驱动的生成器）
```

---

## 文档地图

四份 spec 分层，每层细化上一层；实现暴露的规格缺口须回写对应 spec。

| 文档 | 回答什么 | 何时读 |
|---|---|---|
| [`PRODUCT_SPEC.md`](./PRODUCT_SPEC.md) | 是什么 & 为什么 —— 问题、功能（含 P0/P1/P2 优先级）、数据模型、端点、Agent | 理解范围或某功能 |
| [`UX_SPEC.md`](./UX_SPEC.md) | 长什么样 —— 信息架构、用户流、页面线框、组件、视觉 token（纸感 / warm-cream 主题） | 做任何 UI |
| [`ARCHITECTURE.md`](./ARCHITECTURE.md) | 怎么实现 —— 完整 DDL、网关内部、编排引擎、API 契约、横切关注点 | 实现后端 / 数据 / 网关 |
| [`DEV_PLAN.md`](./DEV_PLAN.md) | 按什么顺序 —— Phase 0–5，每个任务标注学科 skill | 挑下一个任务 |
| [`PROGRESS.md`](./PROGRESS.md) | 交付到哪了 —— 权威状态台账 + 变更日志 | 开工前必读 |

冲突裁决：更具体 / 更靠后的文档为准（`ARCHITECTURE` > `UX_SPEC`/`DEV_PLAN` > `PRODUCT_SPEC`）。协作与开发规范见 [`CLAUDE.md`](./CLAUDE.md)。

---

## 测试与原型边界

- **测试**：TDD 强制（先写失败测试）；三层——单元（一个节点/函数/Repository，mock IO）→ 集成（FastAPI 端点 + DB + mock 网关）→ E2E（写→审→验收，mock 网关）。**所有测试一律 mock LLM，绝不命中真实 LLM API**。覆盖率门禁 ≥ 80%。

原型作用域，以下**明确不做**（勿误用于生产）：

- **单用户，无 auth / 多租户** —— `users` / `owner_id` 为占位桩。
- **无向量检索 / pgvector** —— 记忆注入是确定性按需选择（显式点名 + 主要角色 + 最近 N 章），非向量搜索（向量检索列 P2）。
- **无独立任务队列** —— 长任务走 FastAPI BackgroundTasks + `jobs` 表。
- 不做模型微调、内容分发 / 发布平台对接、移动原生 App。
