
线上 Demo: flow.houmq.cn/
前置阅读: M1:Harness 骨架与 SSE 流式对话(SSE、Nginx 流式配置、Docker 双容器部署)
前言
M1 把流式聊天壳子和公网部署跑通了,但对话存在浏览器 localStorage,没有账号、换设备就丢。
M1.5 在原有 SSE 通道上加了四块能力:
- 账号体系 --- 注册 / 登录 / JWT,注册时选角色(PM / 前端 / 后端 / QA)
- 多对话持久化 --- PostgreSQL 存对话和消息,侧边栏管理
- RBAC 框架 --- 权限 seed 可扩展,M1.5 四角色聊天体验一致
- 聊天分享 --- 生成只读链接,未登录也能看
这是原路线图 M8「角色协作」的基础部分,提前到 M2 Session 之前做,避免后面反复迁移存储。
一、架构变更概览
| 层面 | M1 | M1.5 |
|---|---|---|
| 持久化 | localStorage | PostgreSQL 16 |
| 鉴权 | 无 | JWT(7 天) |
| 对话 | 单对话 | 每用户多条 conversation |
| Docker | 双容器 | 三容器(+ postgres) |
| 前端路由 | 单页 | react-router-dom(登录/注册/分享) |
部署拓扑
bash
浏览器 → Nginx → frontend 容器
├─ /api/* → backend (FastAPI)
└─ /* → React SPA
backend → postgres 容器
→ LLM API
backend 启动时自动执行 Alembic 迁移并 seed RBAC 权限。

二、数据模型
核心三张业务表:
bash
users 1──* conversations 1──* messages
roles *──* permissions (via role_permissions)
- users:email、password_hash(bcrypt)、role 枚举
- conversations:user_id、title、share_token(nullable)、updated_at(列表排序)
- messages:conversation_id、role(user/assistant/system)、content
分享只读 API 不返回 owner email / user_id。
三、后端实现要点
3.1 模块化路由
M1 所有逻辑在 main.py;M1.5 拆成:
bash
routers/auth.py 注册 / 登录 / /auth/me
routers/conversations.py 多对话 CRUD + 分享开关
routers/chat.py SSE 流式(history 从 DB 加载)
routers/shared.py 公开分享只读
deps.py JWT 解析 + require_permission()
3.2 JWT + RBAC
注册/登录返回 { token, user, permissions }。受保护路由:
less
@router.post("/chat/stream")
def chat_stream(
body: ChatStreamRequest,
user: Annotated[User, Depends(require_permission("chat:write"))],
...
):
权限数据存在 permissions + role_permissions 表,启动时 seed。M4--M7 加新能力只挂 permission code。
3.3 SSE 请求体变更
M1:
json
{ "message": "...", "history": [...] }
M1.5:
json
{ "conversation_id": "uuid", "message": "..." }
后端从 DB 加载 history,流开始前写 user message,流结束后写 assistant message。前端不再维护 history 数组。
四、前端实现要点
4.1 AuthContext
- token 存
localStorage - 启动时调
/auth/me恢复登录态 - 401 →
clearToken()→ 跳转/login
4.2 路由
| 路径 | 页面 |
|---|---|
/login |
登录 |
/register |
注册 + 角色下拉 |
/ |
聊天(ProtectedRoute) |
/share/:token |
只读分享 |
4.3 ChatPage
- 侧边栏
ConversationSidebar:新建 / 切换 / 重命名 / 删除 - 无对话时自动
POST /conversations ShareButton:开启/关闭分享,复制APP_PUBLIC_URL/share/{token}
storage.ts 已移除,消息持久化完全由后端负责。


五、部署变更
5.1 docker-compose 新增 postgres
yaml
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: devflow
POSTGRES_USER: devflow
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devflow -d devflow"]
backend depends_on: postgres: condition: service_healthy。
5.2 新增环境变量
ini
POSTGRES_PASSWORD=
DATABASE_URL=postgresql://devflow:${POSTGRES_PASSWORD}@postgres:5432/devflow
JWT_SECRET=
JWT_EXPIRE_DAYS=7
APP_PUBLIC_URL=https://flow.houmq.cn
六、与路线图关系
| 原里程碑 | M1.5 覆盖 | 剩余 |
|---|---|---|
| M1 对话通道 | 保留 SSE | --- |
| M8 角色协作 | 用户/角色/RBAC 基础 | 多人同 Session、状态机 |
| M10 生产级 | PostgreSQL 持久化 | HTTPS、审计、refresh token |
| M2 Session | conversations 可演进 | 文件树、Agent Loop |
七、总结
M1.5 看起来是「给聊天页加了个登录」,实质是把 Harness 从 Demo 壳子推进到多用户产品雏形:服务端持久化、权限框架、分享------都是 M2 Session 和 M8 协作的前置。
SSE 流式通道和 Nginx 配置没动,增量开发的好处就在这里:内核通道不变,外围能力叠上去。
附录
- GitHub:github.com/MingQi39/de...
- 设计规格:仓库内
docs/superpowers/specs/2026-09-16-m1-user-auth-design.md - 架构文档:仓库内
docs/architecture.md