diff --git a/.planning/phases/07-login-auth/07-RESEARCH.md b/.planning/phases/07-login-auth/07-RESEARCH.md
new file mode 100644
index 0000000..9c1b9a7
--- /dev/null
+++ b/.planning/phases/07-login-auth/07-RESEARCH.md
@@ -0,0 +1,474 @@
+# Phase 7: 登录认证体系 - Research
+
+**Researched:** 2026-03-17
+**Domain:** Playwright 浏览器自动化、知乎登录认证、Cookie 管理
+**Confidence:** HIGH
+
+## Summary
+
+本阶段实现知乎登录认证体系,支持二维码扫码和手动 Cookie 两种认证方式。核心技术基于 Playwright 浏览器自动化,参考 MediaCrawler 项目的成熟实现模式。
+
+关键实现点:
+1. **二维码登录流程**:访问登录页 → Canvas 截图获取二维码 → 保存图片 → 轮询检测 `z_c0` Cookie → 超时退出
+2. **Cookie 验证**:通过 `GET /api/v4/me` 接口检测登录状态
+3. **Cookie 持久化**:存储到 `~/.kb_env` 文件,格式为 `ZHIHU_COOKIE="name1=value1; name2=value2"`
+
+**Primary recommendation:** 扩展现有 `PlaywrightBrowser` 类添加二维码登录能力,复用 `KBSettings` 的 `zhihu_cookie` 字段,新增 `login` CLI 子命令。
+
+
+## User Constraints (from CONTEXT.md)
+
+### Locked Decisions
+
+#### 二维码显示方式
+- **显示方式**: 保存为图片文件,作为标准 step 输出(让 AI 代理能够获取并展示)
+- **存储位置**: 中间目录(与现有中间文件存放位置一致)
+- **等待超时**: 60 秒
+- **超时行为**: 轮询检测,超时退出(不自动重试)
+
+#### Cookie 存储策略
+- **存储位置**: `~/.kb_env` 文件(与现有配置文件一致)
+- **输入格式**: 支持 JSON 导入(Chrome Cookie 导出插件格式),内部存储为字符串
+- **存储格式**: 原始 Cookie 字符串,例如 `ZHIHU_COOKIE="name1=value1; name2=value2"`
+- **加密**: 不加密,用户需自行保护 `~/.kb_env` 文件权限
+
+#### 过期检测机制
+- **检测时机**: 每次使用前检测 Cookie 有效性
+- **检测方法**: 请求知乎用户信息接口,检查返回状态
+- **过期处理**: 自动触发扫码重新登录
+
+#### 命令行交互流程
+- **登录命令**: `python3 kb-workflow/kb_workflow.py login`
+- **默认模式**: 扫码模式(弹出二维码让用户扫码)
+- **手动设置**: `--import-cookie cookies.json` 从文件导入 JSON 格式 Cookie
+- **状态查看**: `login --status` 检查当前 Cookie 是否有效
+
+### Claude's Discretion
+- 二维码图片的具体文件名格式
+- 用户信息接口的具体 URL 和返回格式
+- JSON Cookie 解析的具体实现
+- 错误提示信息的具体文案
+
+### Deferred Ideas (OUT OF SCOPE)
+None - discussion stayed within phase scope
+
+
+
+## Phase Requirements
+
+| ID | Description | Research Support |
+|----|-------------|-----------------|
+| AUTH-01 | 用户可通过二维码扫码登录知乎 | Playwright Canvas 截图 + `z_c0` Cookie 轮询检测 |
+| AUTH-02 | 用户可手动设置 Cookie 进行认证 | JSON 解析 + `_add_cookies()` 方法复用 |
+| AUTH-03 | Cookie 自动持久化到本地文件,下次自动复用 | `KBSettings.zhihu_cookie` + `~/.kb_env` 写入 |
+| AUTH-04 | Cookie 过期时自动检测并提示重新登录 | `/api/v4/me` 接口验证 + 状态码检测 |
+
+
+## Standard Stack
+
+### Core
+| Library | Version | Purpose | Why Standard |
+|---------|---------|---------|--------------|
+| playwright | 已安装 | 浏览器自动化 | 现有项目已使用,支持 Cookie、Canvas 操作 |
+| pydantic | v2 | Schema 验证 | 现有项目使用,类型安全 |
+| pydantic-settings | 已安装 | 配置管理 | 现有 KBSettings 使用 |
+| tenacity | 需安装 | 重试/轮询逻辑 | 登录状态轮询的标准库 |
+
+### Supporting
+| Library | Version | Purpose | When to Use |
+|---------|---------|---------|-------------|
+| rich | 可选 | 终端输出美化 | CLI 交互提示 |
+| httpx | 可选 | HTTP 请求 | Cookie 验证接口调用(或复用 Playwright) |
+
+### Alternatives Considered
+| Instead of | Could Use | Tradeoff |
+|------------|-----------|----------|
+| playwright | selenium | Playwright 更现代,项目已使用 |
+| playwright | requests + 手动逆向 | 免维护,无需逆向签名算法 |
+| tenacity | 自实现轮询 | tenacity 提供声明式重试,更可靠 |
+
+**Installation:**
+```bash
+pip install tenacity
+```
+
+## Architecture Patterns
+
+### Recommended Project Structure
+```
+kb_workflow/
+├── auth/ # 新增:认证模块
+│ ├── __init__.py
+│ ├── zhihu_login.py # 知乎登录核心逻辑
+│ └── cookie_manager.py # Cookie 持久化管理
+├── metadata/
+│ └── zhihu_extractor.py # 现有:PlaywrightBrowser 类(可扩展)
+├── pipeline/
+│ └── config.py # 现有:KBSettings(已有 zhihu_cookie)
+└── kb_workflow.py # 现有:CLI 入口(添加 login 子命令)
+```
+
+### Pattern 1: 二维码登录流程
+
+**What:** 使用 Playwright 访问知乎登录页,从 Canvas 元素截图获取二维码,轮询检测登录状态
+
+**When to use:** 默认登录模式
+
+**Example:**
+```python
+# Source: MediaCrawler media_platform/zhihu/login.py
+import asyncio
+from tenacity import retry, stop_after_attempt, wait_fixed
+
+class ZhihuLogin:
+ LOGIN_URL = "https://www.zhihu.com/signin"
+ CANVAS_SELECTOR = "canvas.SignIn-qrcode"
+
+ @retry(stop=stop_after_attempt(60), wait=wait_fixed(1))
+ async def check_login_state(self) -> bool:
+ """轮询检测登录状态 - 检查 z_c0 Cookie"""
+ cookies = await self.context.cookies()
+ for cookie in cookies:
+ if cookie["name"] == "z_c0":
+ return True
+ return False
+
+ async def login_by_qrcode(self):
+ """二维码登录主流程"""
+ # 1. 访问登录页
+ await self.page.goto(self.LOGIN_URL)
+
+ # 2. 从 Canvas 截图获取二维码
+ canvas = await self.page.wait_for_selector(self.CANVAS_SELECTOR)
+ screenshot = await canvas.screenshot()
+ qr_base64 = base64.b64encode(screenshot).decode()
+
+ # 3. 保存二维码图片
+ qrcode_path = Path(f"~/work/intermediate/zhihu_qrcode_{timestamp}.png")
+ qrcode_path.write_bytes(screenshot)
+
+ # 4. 轮询等待扫码(60秒超时)
+ try:
+ logged_in = await self.check_login_state()
+ if logged_in:
+ # 5. 提取并保存 Cookie
+ cookies = await self.context.cookies()
+ cookie_str = self._format_cookies(cookies)
+ return cookie_str
+ except RetryError:
+ raise TimeoutError("扫码超时,请重试")
+```
+
+### Pattern 2: Cookie 验证
+
+**What:** 通过知乎 API 检测 Cookie 是否有效
+
+**When to use:** 每次使用 Cookie 前、`login --status` 命令
+
+**Example:**
+```python
+# Source: 知乎 API 实测
+VALIDATION_URL = "https://www.zhihu.com/api/v4/me"
+
+async def validate_cookie(self, cookie_str: str) -> dict:
+ """验证 Cookie 有效性"""
+ # 方式1:使用 Playwright context(推荐,与登录流程一致)
+ self.browser.start(cookie=cookie_str)
+ response = await self.page.request.get(self.VALIDATION_URL)
+
+ if response.status == 200:
+ user_info = await response.json()
+ return {
+ "valid": True,
+ "username": user_info.get("name", ""),
+ "user_id": user_info.get("id", "")
+ }
+ elif response.status == 401:
+ return {"valid": False, "reason": "Cookie 已过期"}
+ else:
+ return {"valid": False, "reason": f"验证失败: {response.status}"}
+```
+
+### Pattern 3: JSON Cookie 导入
+
+**What:** 解析 Chrome Cookie Editor 导出的 JSON 格式
+
+**When to use:** `--import-cookie` 参数
+
+**Example:**
+```python
+# Chrome Cookie Editor JSON 格式:
+# [{"name": "z_c0", "value": "xxx", "domain": ".zhihu.com"}, ...]
+
+def parse_json_cookies(json_path: str) -> str:
+ """从 JSON 文件解析 Cookie 为字符串格式"""
+ import json
+
+ with open(json_path, 'r') as f:
+ cookies = json.load(f)
+
+ # 过滤知乎域名,转换为 name=value 格式
+ zhihu_cookies = [
+ f"{c['name']}={c['value']}"
+ for c in cookies
+ if 'zhihu.com' in c.get('domain', '')
+ ]
+
+ return '; '.join(zhihu_cookies)
+```
+
+### Pattern 4: Cookie 持久化
+
+**What:** 将 Cookie 写入 `~/.kb_env` 文件
+
+**When to use:** 登录成功后、导入 Cookie 后
+
+**Example:**
+```python
+# 复用现有 KBSettings 的 zhihu_cookie 字段
+# 存储格式: ZHIHU_COOKIE="name1=value1; name2=value2"
+
+def save_cookie_to_env(cookie_str: str):
+ """保存 Cookie 到 ~/.kb_env"""
+ env_path = Path.home() / ".kb_env"
+
+ # 读取现有内容
+ lines = []
+ if env_path.exists():
+ lines = env_path.read_text().splitlines()
+
+ # 更新或添加 ZHIHU_COOKIE 行
+ cookie_line = f'ZHIHU_COOKIE="{cookie_str}"'
+ found = False
+ for i, line in enumerate(lines):
+ if line.startswith("ZHIHU_COOKIE="):
+ lines[i] = cookie_line
+ found = True
+ break
+ if not found:
+ lines.append(cookie_line)
+
+ # 写回文件
+ env_path.write_text('\n'.join(lines) + '\n')
+
+ # 清除配置缓存
+ get_settings.cache_clear()
+```
+
+### Anti-Patterns to Avoid
+
+- **手动逆向 x-zse-96 签名**: 维护成本高,算法经常变化。使用二维码登录完全避免此问题。
+- **在终端直接显示二维码 ASCII**: 兼容性差,AI 代理无法读取。保存为图片文件是更可靠的方案。
+- **硬编码超时逻辑**: 使用 tenacity 的 `@retry` 装饰器更清晰、可测试。
+- **忽略 Cookie 域名过滤**: 导入时必须过滤 `.zhihu.com` 域名,否则会导入无关 Cookie。
+
+## Don't Hand-Roll
+
+| Problem | Don't Build | Use Instead | Why |
+|---------|-------------|-------------|-----|
+| 轮询重试逻辑 | while loop + sleep | tenacity @retry | 声明式、可配置、有异常处理 |
+| Cookie 字符串解析 | 手动 split(';') | 现有 `_add_cookies()` 方法 | 已处理边界情况 |
+| 配置文件读写 | 手动文件操作 | pydantic-settings | 自动类型转换、环境变量支持 |
+| Canvas 截图 | 手动像素提取 | Playwright element.screenshot() | 内置优化,支持多种格式 |
+
+**Key insight:** 现有代码库已有 Playwright 封装和配置管理,优先复用而非新建。
+
+## Common Pitfalls
+
+### Pitfall 1: Canvas 选择器变化
+**What goes wrong:** 知乎更新前端后,Canvas 选择器 `canvas.SignIn-qrcode` 失效
+**Why it happens:** 前端类名可能随版本变化
+**How to avoid:**
+1. 使用多个备选选择器
+2. 添加选择器存在性检测
+3. 失败时给出明确错误提示
+
+**Warning signs:** `wait_for_selector` 超时
+
+```python
+CANVAS_SELECTORS = [
+ "canvas.SignIn-qrcode",
+ "canvas[class*='qrcode']",
+ "canvas" # 最宽松的备选
+]
+
+async def find_qrcode_canvas(self):
+ for selector in self.CANVAS_SELECTORS:
+ try:
+ return await self.page.wait_for_selector(selector, timeout=5000)
+ except TimeoutError:
+ continue
+ raise RuntimeError("无法找到二维码 Canvas 元素")
+```
+
+### Pitfall 2: z_c0 Cookie 延迟出现
+**What goes wrong:** 用户扫码后,`z_c0` Cookie 不是立即出现
+**Why it happens:** 服务端验证需要时间
+**How to avoid:** 使用 tenacity 的 1 秒间隔轮询,60 次重试(60 秒总超时)
+
+**Warning signs:** 扫码成功但检测失败
+
+### Pitfall 3: Cookie 格式不一致
+**What goes wrong:** 不同来源的 Cookie 格式不同(字符串 vs JSON vs 字典)
+**Why it happens:** Chrome 插件、手动复制、Playwright 导出格式各异
+**How to avoid:**
+1. 统一内部格式为字符串 `name1=value1; name2=value2`
+2. 在边界层做格式转换
+3. 提供格式自动检测
+
+**Warning signs:** Cookie 设置后仍显示未登录
+
+### Pitfall 4: ~/.kb_env 文件权限
+**What goes wrong:** Cookie 明文存储可能被其他用户读取
+**Why it happens:** 文件创建时使用默认 umask
+**How to avoid:**
+1. 创建文件时设置 600 权限
+2. 提示用户检查权限
+
+```python
+env_path = Path.home() / ".kb_env"
+env_path.touch(mode=0o600, exist_ok=True)
+```
+
+## Code Examples
+
+### CLI 子命令扩展
+
+```python
+# Source: 现有 kb_workflow.py 模式
+# 在 main() 函数中添加 login 子命令
+
+def add_login_subparser(subparsers):
+ """添加 login 子命令"""
+ login_parser = subparsers.add_parser('login', help='知乎登录认证')
+ login_parser.add_argument('--import-cookie', '-i', type=str,
+ help='从 JSON 文件导入 Cookie')
+ login_parser.add_argument('--status', action='store_true',
+ help='检查当前 Cookie 状态')
+ return login_parser
+
+# 在 main() 中:
+if args.command == 'login':
+ if args.status:
+ result = check_cookie_status()
+ elif args.import_cookie:
+ result = import_cookie_from_file(args.import_cookie)
+ else:
+ result = login_by_qrcode()
+ print(json.dumps(result, ensure_ascii=False, indent=2))
+```
+
+### 扩展 PlaywrightBrowser
+
+```python
+# Source: 现有 zhihu_extractor.py PlaywrightBrowser 类
+# 添加二维码登录相关方法
+
+class PlaywrightBrowser:
+ # 现有方法保持不变...
+
+ async def get_qrcode_screenshot(self) -> bytes:
+ """获取登录二维码截图"""
+ canvas = await self.page.wait_for_selector("canvas.SignIn-qrcode")
+ return await canvas.screenshot()
+
+ async def check_login_cookie(self) -> bool:
+ """检测是否已登录(检查 z_c0 Cookie)"""
+ cookies = await self.context.cookies()
+ return any(c["name"] == "z_c0" for c in cookies)
+
+ async def get_all_cookies_str(self) -> str:
+ """获取所有 Cookie 为字符串格式"""
+ cookies = await self.context.cookies()
+ return '; '.join(f"{c['name']}={c['value']}" for c in cookies)
+```
+
+## State of the Art
+
+| Old Approach | Current Approach | When Changed | Impact |
+|--------------|------------------|--------------|--------|
+| 逆向 x-zse-96 签名 | 二维码扫码登录 | 2024+ | 免维护,无需逆向 |
+| 终端 ASCII 二维码 | 图片文件保存 | 本项目决定 | AI 代理可读取 |
+| 手动 Cookie 管理 | 自动持久化 | 本项目决定 | 用户体验提升 |
+
+**Deprecated/outdated:**
+- 纯 API 请求(无浏览器):需要维护签名算法,知乎经常更新
+- 第三方打码服务:付费且不稳定,二维码登录免费可靠
+
+## Open Questions
+
+1. **二维码图片文件名格式**
+ - What we know: 存储在中间目录,包含时间戳
+ - What's unclear: 是否需要包含随机数避免冲突
+ - Recommendation: 使用 `zhihu_qrcode_{timestamp}.png` 格式,同一秒内多次登录概率低
+
+2. **验证接口的精确返回格式**
+ - What we know: `/api/v4/me` 返回用户信息
+ - What's unclear: 具体字段名称(name vs username)
+ - Recommendation: 实现时先打印完整响应,根据实际返回调整字段名
+
+## Validation Architecture
+
+### Test Framework
+| Property | Value |
+|----------|-------|
+| Framework | pytest |
+| Config file | pytest.ini |
+| Quick run command | `pytest tests/test_auth/ -x -v` |
+| Full suite command | `pytest tests/ -v` |
+
+### Phase Requirements → Test Map
+| Req ID | Behavior | Test Type | Automated Command | File Exists? |
+|--------|----------|-----------|-------------------|-------------|
+| AUTH-01 | 二维码扫码登录 | unit + integration | `pytest tests/test_auth/test_qrcode_login.py -x` | Wave 0 |
+| AUTH-02 | 手动设置 Cookie | unit | `pytest tests/test_auth/test_cookie_import.py -x` | Wave 0 |
+| AUTH-03 | Cookie 持久化 | unit | `pytest tests/test_auth/test_cookie_persistence.py -x` | Wave 0 |
+| AUTH-04 | Cookie 过期检测 | unit | `pytest tests/test_auth/test_cookie_validation.py -x` | Wave 0 |
+
+### Sampling Rate
+- **Per task commit:** `pytest tests/test_auth/ -x`
+- **Per wave merge:** `pytest tests/ -v`
+- **Phase gate:** Full suite green before `/gsd:verify-work`
+
+### Wave 0 Gaps
+- [ ] `tests/test_auth/__init__.py` — 测试模块初始化
+- [ ] `tests/test_auth/test_qrcode_login.py` — AUTH-01 二维码登录测试
+- [ ] `tests/test_auth/test_cookie_import.py` — AUTH-02 Cookie 导入测试
+- [ ] `tests/test_auth/test_cookie_persistence.py` — AUTH-03 Cookie 持久化测试
+- [ ] `tests/test_auth/test_cookie_validation.py` — AUTH-04 Cookie 验证测试
+- [ ] `tests/test_auth/conftest.py` — 共享 fixtures (mock browser, mock env file)
+
+**测试策略:**
+- 使用 `unittest.mock` 模拟 Playwright browser 和 context
+- 使用 `tmp_path` fixture 创建临时 `~/.kb_env` 文件
+- Cookie 验证测试使用 mock HTTP 响应
+
+## Sources
+
+### Primary (HIGH confidence)
+- **MediaCrawler 源码** - `media_platform/zhihu/login.py`, `tools/crawler_util.py`
+ - 二维码登录完整实现
+ - Cookie 格式转换函数
+- **现有项目代码** - `kb_workflow/metadata/zhihu_extractor.py`
+ - PlaywrightBrowser 类实现
+ - Cookie 设置方法 `_add_cookies()`
+- **现有项目代码** - `kb_workflow/pipeline/config.py`
+ - KBSettings 配置类
+ - zhihu_cookie 字段定义
+
+### Secondary (MEDIUM confidence)
+- 知乎 API 实测 - `/api/v4/me` 端点行为
+- Chrome Cookie Editor JSON 格式规范
+
+### Tertiary (LOW confidence)
+- 网络博客关于知乎登录流程的描述(需实现时验证)
+
+## Metadata
+
+**Confidence breakdown:**
+- Standard stack: HIGH - 现有项目已使用 Playwright 和 pydantic-settings
+- Architecture: HIGH - MediaCrawler 提供了成熟的参考实现
+- Pitfalls: MEDIUM - 部分边界情况需要在实现时验证
+
+**Research date:** 2026-03-17
+**Valid until:** 2026-04-17 (知乎 API 可能变化,选择器可能更新)