# FSD M13 · 火花计划

LLMS 索引： [llms.txt](/llms.txt)

---

> [← 总则](/qmtv/fsd-qmtv/00-%E6%80%BB%E5%88%99/) ｜ [附录 →](/qmtv/fsd-qmtv/99-%E9%99%84%E5%BD%95/) ｜ 上游：[PRD §4 M13](/qmtv/product/prd-qmtv-v1/)
> 实现落点：`backend/internal/domain/spark/`（model/service/repo_gorp 三件）+ `cmd/server/spark_handlers.go`（34 行）+ `cmd/server/routes.go:259-262`（挂载——物理嵌在 M11 段 :258 与 :263 之间）。事实基准=Go 代码；冻结版 `qmtv/server/index.js:739-766` 仅差异对拍参照。
> 域内要点：二十六期补登域（P0 统计残留第八例——冻结 index.js:739-766 两条端点从未入任何模块行）；三阶梯 tier 表单数据源（per 系）；**PRD §4 M13「逐字对齐无差异」**——三十期新立 DIF-30（见 m09 册/99-附录 B）。E2E-SPK-01 已实现（spark.spec.ts，清单 :15）。

### M13 火花计划

2 端点全量（join+me）。零 provider 零 SSE；通知一发（join 成功）；扣费面为零（唯一 **Add 奖励面**——反向 credits 流转）。

#### F13.01 火花计划（spark/join + spark/me）

> 对应 PRD：§4 M13 · POST /api/spark/join、GET /api/spark/me ｜ 状态：实现 ｜ 实现落点：spark_handlers.go:13-34、service.go:33-86、model.go:13-46、repo_gorp.go ｜ UI：SparkView（三阶梯卡片+加入按钮）｜ 场景挂钩：**E2E-SPK-01**（已实现——重跑容错：残留轮直断投影面）

##### 1 功能定义

编剧激励计划：一次性加入（+100 奖励）与个人阶梯投影（按 published 过审数定档）。

##### 2 触发条件与前置状态

join：未加入前置——重复 400「您已加入火花计划」（ErrAlreadyJoined model.go:10，errRespond 400 映射，冻结 :749 同形）；me：零前置（**joined=false 也给完整阶梯投影**，quirk）。

##### 3 输入与校验

两端点无 body/参数（全按 token user_id）。

##### 4 处理流程（join 四动作禁事务）

置位 users.spark_joined → `credits.Add(+100, type='spark', 「加入火花计划奖励（+100）」)`（service.go:44，冻结 :751 同形）→ INSERT notifications「火花计划报名成功」→ 响应 `{joined: true, bonus: 100}`——**四动作逐序无事务**（:33-53，中途失败留半态=冻结无事务同形）。
me：total=submissions 非 draft 计数（repo_gorp.go:50-56）/published/pending 双计数 → `tierOf(published)` 定档（0 部无命中**回退首档星火**，model.go:51-58）→ next_tier **环形取下一档**（`tierTable[(idx+1)%len]`，service.go:84——燎原下一档回星火，冻结 :766 同式）。

##### 5 输出与结果状态

me 键序逐字（model.go:34-46，冻结 :762-766）：`joined/total/published/pending/tier/tier_perk/tier_rate/reward_earned/next_tier/tiers`——**reward_earned=published×per 即时计算**（非累计流水）；tiers=三档全量数组（min/max/per/name/perk，max `*int` null=无上限）。

##### 6 状态流转

spark_joined 0→1 单向（无退出机制）；阶梯随 published 增长单向升级（E2E-SUB-01 投稿过审联动）。

##### 7 边界与异常

| 条件 | 系统行为 | 提示/码 |
|---|---|---|
| 重复 join | 400 | 「您已加入火花计划」 |
| 0 部过审查 me | tier=星火完整投影（非空/非 404，quirk） | — |
| ErrNotConfigured | requireDB 前置后为死路径（repo_gorp.go:13/:21-26 guard，边界节素材） | — |
| bonus 与 tier per=100 | 数值偶合但**不同源**（service.go:44 硬编码 vs model.go:23 阶梯表——调价不同步 quirk） | — |

##### 8 权限与数据规则

`authed + amw`；Add 奖励走 credits 唯一入账口（ErrNoUser 容错装配侧）；零扣费零退款（全站唯一纯奖励域）；wire 全蛇形零驼峰（model.go 亲证）。

---

## 册尾端点覆盖对账（2/2）

对账 `backend/cmd/server/routes.go:259-262` 亲数 2 条 ↔ 本册 F13.01：

| # | 端点（routes.go:line） | 节 |
|---|---|---|
| 1 | POST /spark/join（:261） | F13.01 |
| 2 | GET /spark/me（:262） | F13.01 |

差异纪律：PRD §4 M13「逐字对齐无差异」——本册零差异零新立 DIF（bonus/per 不同源与 0 部回退均系双方一致 quirk，节内登记）；集成锚 SparkChain 第十六链（me 初态→join 对账→重复 400→submissions 直插阶梯联动→401）在位。

---

反链：

- [QMTV 功能规格说明书（FSD）v1.0 · 总则](/qmtv/fsd-qmtv/00-%E6%80%BB%E5%88%99/)
- [FSD 附录 · PRD 对照 / 代码域索引 / 差异台账](/qmtv/fsd-qmtv/99-%E9%99%84%E5%BD%95/)
