# 2026-01-13 工作日志

## 今日目标

1. SSE 模块重构 → Notifications 通知系统（独立分支）
2. Stateflow 信号机制 + Shipment 模块开发（主分支）

---

## 已完成工作（SSE 重构分支）

### A1. SSE 问题修复

- **根因**：SSE 长连接占用数据库连接不释放，导致连接池耗尽
- **修复**：在 `sse/views.py` 中认证后立即 `connection.close()`
- **新增**：连接超时（30分钟）、心跳超时（2分钟）、连接数上限（每商户30个）

### A2. Notifications 通知系统（新模块）

- **目的**：将事件发布与 SSE 渠道解耦，支持未来扩展（企业微信等）
- **文件结构**：
  ```
  notifications/
  ├── __init__.py
  ├── apps.py              # 渠道注册
  ├── base.py              # NotificationPayload + NotificationChannel 抽象基类
  ├── dispatcher.py        # NotificationDispatcher 分发器
  ├── events.py            # resource_changed(), object_event()
  └── channels/
      └── sse.py           # SSE 渠道实现
  ```

- **核心设计**：
  - 业务代码调用 `notifications.events`，不关心具体渠道
  - 分发器同步调用各渠道的 `send()`
  - 各渠道自行决定同步/异步（SSE 同步放入队列，企业微信应内部 Celery）
  - 新增渠道只需实现 `NotificationChannel` 并注册

- **配置**：
  - `SSE_ENABLED` 同时控制 SSE 端点和通知渠道

### A3. 文档整理

- **创建**：
  - `docs/notifications.md` — 后端通知接口文档
  - `docs/notifications_frontend.md` — 前端 SSE 接入文档
  - `docs/sse_refactor_execute_django_ver.md` — 技术方案文档

- **删除**（减少心智成本）：
  - `docs/sse.md`
  - `docs/sse_event_interface.md`
  - `docs/sse_refactor.md`

### A4. 兼容处理

- `sse/events.py` 改为兼容层，调用会触发 `DeprecationWarning`
- 现有业务代码无需立即修改

---

## 已完成工作（主分支）

### 1. Stateflow 信号机制

- **文件**：`stateflow/signals.py`（新增）
- **功能**：
  - 定义 `process_completed` 信号 — 流程全部完成时触发
  - 定义 `state_advanced` 信号 — 每次状态推进时触发
  - `sender` 使用 `content_object.__class__`，支持按类型过滤
  - 参数包含：`process_id`、`business_object`、`content_object`、`last_completed_state_id`、`last_completed_by` 等

- **文件**：`stateflow/services.py`（修改）
  - 在 `advance_to_next_state` 中发送信号
  - 添加日志记录信号发送过程

---

### 2. Shipment 模块（新建）

- **文件结构**：
  ```
  shipment/
  ├── __init__.py
  ├── apps.py
  ├── models.py
  ├── admin.py
  └── migrations/
      ├── 0001_initial.py
      ├── 0002_salesitem_shipment_nullable.py
      └── 0003_salesitem_position_remark.py
  ```

- **模型**：
  - `Shipment`（出货单）— 关联客户，包含多个销售品
  - `SalesItem`（销售品）— 名称、数量、单位（米/件/码/个）、货位、备注、关联生产任务ID

- **设计特点**：
  - `SalesItem.shipment` 可空，支持"待分配"状态
  - `printing_job_id` 使用整数而非外键，避免模块间强依赖
  - 提供 `get_printing_job()` 方法获取关联对象，带完整 type hint

---

### 3. PrintingJob 流程完成自动创建销售品

- **文件**：`printing/handlers.py`（新增）
  - 监听 `process_completed` 信号（sender=PrintingJob）
  - 从指定流程节点获取"米数"参数
  - 自动创建 `SalesItem`，关联 `printing_job_id`

- **文件**：`printing/apps.py`（修改）
  - 在 `ready()` 中注册信号处理器
  - 添加启动日志确认注册成功

- **配置项**（settings.py + .env）：
  ```python
  PRINTING_SALES_ITEM_SOURCE_STATE_ID = env.int('PRINTING_SALES_ITEM_SOURCE_STATE_ID')  # 必须配置
  PRINTING_SALES_ITEM_QUANTITY_KEY = '米数'
  ```

---

### 4. 其他修改

- **stateflow/services.py**：
  - 添加 `logging` 模块导入
  - `clone_business_object` 函数暂停使用（2026-01-13），抛出 `NotImplementedError`

- **flower/settings.py**：
  - 添加 `'shipment'` 到 `INSTALLED_APPS`
  - 添加销售品自动创建配置项

---

## 架构说明

### 信号流程

```
PrintingJob 流程推进完成
    ↓
stateflow.services.advance_to_next_state()
    ↓
发送 process_completed 信号 (sender=PrintingJob)
    ↓
printing.handlers.on_printing_job_process_completed() 接收
    ↓
从指定节点获取"米数"参数
    ↓
创建 SalesItem（待分配出货单）
```

### 解耦设计

- **stateflow** 不依赖任何业务模块，只发送信号
- **printing** 监听信号并处理自己的业务逻辑
- **shipment** 被 printing 调用，但不知道调用者是谁

---

## 待办事项

### SSE 重构分支

- [ ] 合并到主分支后，在测试环境启用 SSE（`SSE_ENABLED=True`）
- [ ] 前端实现重连逻辑
- [ ] 监控数据库连接数，确认不再泄漏
- [ ] 逐步迁移业务代码到 `notifications.events`

### 主分支

- [ ] 在 `.env` 中配置 `PRINTING_SALES_ITEM_SOURCE_STATE_ID`
- [ ] 应用数据库迁移：`uv run python manage.py migrate shipment`
- [ ] 测试完整流程：推进 PrintingJob 直到完成，验证 SalesItem 创建
- [ ] 移除调试日志（生产环境前）

---

## 备注

### SSE 重构分支

- SSE 模块此前因数据库连接泄漏导致线上灾难，已被禁用
- Notifications 模块设计考虑了未来 Golang 迁移和企业微信扩展
- 企业微信渠道仅有示例代码，尚未实现

### 主分支

- Shipment 模块是全新创建的，需要执行迁移
- 信号处理器只在流程**全部完成**时触发，不是每次推进
- 如果指定节点的"米数"参数不存在，会跳过创建并记录警告日志
