# QY LTY Backend(洛天依统一后端服务) ## 项目简介 QY LTY Backend 是「洛天依(Luotianyi)智能陪伴产品」生态的统一 Django 后端,同时服务于 **3 个客户端**:Unity 设备端(`LTY_Project`)、Unity 移动 App(`LTY_App_Project_URP`)、Web 管理后台(`qy-lty-admin`)。提供用户认证、AI 对话(含语音)、设备实时通信(WebSocket + RTC)、卡片/二维码、成就、订阅等综合能力。 ## 核心价值 **设备端与手机端通过同一个用户身份实时互通**——`device_{user_id}` 分组模型必须始终成立。一旦绑定/控制权解析、WebSocket 路由、RTC 房间号三者偏离同一 user_id,整个产品的"陪伴"价值就坍塌了。其他能力(卡片、成就、订阅)可以暂时降级,这条不行。 ## 本期 Milestone:v1.0 通用凭据槽位(APP ID + Access Token) **启动日期**:2026-05-07 **目标**:在后端提供一组全局单例的通用凭据存储槽位(APP ID + Access Token),管理后台可写入,手机端 + 设备端可读取。不绑定特定服务商,运营自由填值;前端联动 milestone 在 `qy-lty-admin` 仓库另行启动。 **目标能力**: - 后端单例配置模型(保存 APP ID + Access Token,强制全局唯一记录) - 管理端读写接口(admin token 鉴权,`/api/v1/admin/` 命名空间,GET 时 Access Token 脱敏) - 客户端读取接口(user token 鉴权,复用 `RedisTokenAuthentication`,明文返回供 LTY_App_Project_URP / LTY_Project 实际调用第三方服务) - 敏感字段脱敏(响应壳层 + 阿里云日志),避免 Access Token 落入生产日志 **关键约束**: - 客户端实际使用 Access Token 调用第三方服务,所以**客户端 GET 接口必须返回明文**;只有管理端 GET 与日志做脱敏 - 单例语义:DB 中保证最多一条记录(建议 `pk=1` 固定主键 + `get_or_create` 模式,或单字段唯一约束) - 与现有 `StandardResponseMiddleware` 响应壳层兼容(`{ success, code, message, data }`) - 不引入新的鉴权体系:管理端走 `admin_token:{token}`,客户端走 `token:{token}`,与现有所有接口对齐 ## 需求清单 ### 已交付 **用户与认证(userapp)** - ✓ **AUTH-01** 自定义用户模型 `ParadiseUser`(含 gender、MBTI、interests 等画像字段)— existing - ✓ **AUTH-02** Redis 后端 token 认证(`RedisTokenAuthentication`,30 天 TTL,key `token:{token}` / `admin_token:{token}`)— existing - ✓ **AUTH-03** 手机号 + 阿里云 SMS 验证码登录 — existing - ✓ **AUTH-04** WeChat 社交登录(django-allauth + Weixin provider)— existing - ✓ **AUTH-05** 设备端通过 MAC 换 user-token(`POST /api/user/mac-login/`,按 `-bound_at` 取最新绑定者)— existing **AI 对话与语音(aiapp)** - ✓ **AI-01** 单轮 / 多轮文本对话(接 Kimi,OpenAI 兼容协议)— existing - ✓ **AI-02** 多服务商语音抽象 `AudioService`(火山引擎 / 阿里云 NLS / 腾讯,via `AUDIO_SERVICE_PROVIDER`)— existing - ✓ **AI-03** 语音合成(TTS)+ 语音识别(ASR)通用接口 — existing - ✓ **AI-04** 字幕落库(`ConversationSubtitle`)+ Bot 配置管理 — existing **设备交互(device_interaction)** - ✓ **DEV-01** WebSocket 双通道:`/ws/device/`(Header 鉴权)和 `/ws/device/token/{token}/`(URL 鉴权)— existing - ✓ **DEV-02** Channel Layer 分组模型 `device_{user_id}`,端到端唯一身份 — existing - ✓ **DEV-03** 设备绑定 / 解绑 / 设主 / 状态查询 REST 接口 — existing - ✓ **DEV-04** 设备心跳:消息触发刷新 Redis key `device:last_seen:{mac}`(5 min TTL)— existing - ✓ **DEV-05** 设备状态写库(`Device.status` connected/disconnected)— existing - ✓ **DEV-06** "后绑挤先绑"控制权语义(`UserDevice.Meta.ordering = ['-bound_at']`)— existing - ✓ **DEV-07** 火山引擎 RTC token 签发(`/api/device/rtc-token/get_by_mac/`,`room_id = room_{user_id}`)— existing - ✓ **DEV-08** WebSocket 消息类型完整:chat/weather/sing/dance/touch/flow_light/device_info/device_state/conversation_status/conversation_subtitle/factory_reset — existing **卡片系统(card)** - ✓ **CARD-01** 卡片分类管理 + 属性配置 — existing - ✓ **CARD-02** 卡片批量生成 + 二维码 — existing - ✓ **CARD-03** 卡片使用追踪 + 数据分析 — existing **成就(achievement_app)** - ✓ **ACH-01** 成就定义 + 稀有度等级 + 用户进度追踪 — existing - ⚠️ **ACH-02** 成就解锁条件校验 — **TODO 占位**(`achievement_app/views.py:139` 标记未实现,当前 endpoint 任意客户端可主张任意成就,详见 CONCERNS.md) **订阅(subscription_app)** - ✓ **SUB-01** 用户订阅模型 + 订阅状态管理 — existing - ✓ **SUB-02** APScheduler 定时任务调度(生产环境)— existing **好感度系统(userapp / device_interaction,2026-04 完成 P1)** - ✓ **AFF-01** 设备级好感度计数(`UserDevice.favorability`,从 `ParadiseUser.favorability` 迁移)— existing - ✓ **AFF-02** AffinityRule / AffinityLevel / AffinityLog / AffinityCounter / AffinitySetting / AffinityRewardClaim 6 张表 — existing - ✓ **AFF-03** 配置驱动的规则 / 等级 / 奖励 / 上限 / 冷却 / 区间随机 — existing - ⏳ **AFF-04** Service 层(P2)+ 接口层(P3)+ 客户端集成(P4)— **未交付**,待后续 milestone **视觉智能(ali_vi_app)** - ✓ **VI-01** 阿里云人脸检测 / 识别 SDK 集成 — existing **通用基础设施(common)** - ✓ **INF-01** `StandardResponseMiddleware` 统一响应包装(`success` / `code` / `message` / `data`)— existing - ✓ **INF-02** `CustomPageNumberPagination` 自定义分页(`page_size` 可调)— existing - ✓ **INF-03** Aliyun OSS 文件上传抽象(`common/oss.py`)— existing - ✓ **INF-04** Aliyun Log Service 生产日志集成 — existing - ✓ **INF-05** Swagger / ReDoc API 文档自动生成(drf-yasg)— existing **管理后台(admin)** - ✓ **ADM-01** Django Admin 深度定制(SimpleUI 主题 + 中英双语)— existing - ✓ **ADM-02** `/api/v1/admin/` 命名空间为 Web 管理后台提供 REST 接口 — existing **部署(deployment)** - ✓ **DEP-01** Docker + docker-compose 容器化(端口 12012)— existing - ✓ **DEP-02** Daphne ASGI(同时承载 HTTP + WebSocket)— existing - ✓ **DEP-03** PostgreSQL(主库)+ Redis(缓存 + Channel Layer)— existing - ✓ **DEP-04** i18n 双语(zh_HAns / en)via django-rosetta — existing ### 进行中 **Milestone v1.0 通用凭据槽位**(启动 2026-05-07): - [ ] **CRED-01** 单例 `CredentialSlot` 模型 + 迁移(强制 DB 中最多一条) - [ ] **CRED-02** Django Admin 注册(`Access Token` 字段写入态可见,列表/查看态脱敏) - [ ] **CRED-03** 管理端 GET `/api/v1/admin/credential-slot/`(admin token 鉴权,Access Token 字段脱敏掩码返回) - [ ] **CRED-04** 管理端 PUT `/api/v1/admin/credential-slot/`(admin token 鉴权,全字段覆写更新) - [ ] **CRED-05** 客户端 GET `/api/credential-slot/`(user token 鉴权 via `RedisTokenAuthentication`,明文返回 APP ID + Access Token) - [ ] **CRED-06** Access Token 在阿里云日志中过滤(日志格式化器 / 中间件层避免 secret 落生产日志) ### 范围外 - **Web 管理后台前端实现** — 在独立项目 `../qy-lty-admin/` 中维护(Next.js 15 + React 19)。本仓库**只**提供 `/api/v1/admin/` REST 接口,不写任何前端代码。 - **Unity 客户端业务逻辑** — 在 `C:\Unity2022project\LTY_App_Project_URP`(手机 App)和 `C:\Unity2022project\LTY_Project`(设备端)独立维护。本仓库提供 HTTP / WebSocket / RTC 协议接口,不耦合客户端实现。 - **跨项目的混合修改记录** — 服务端 / 管理后台改动**各自记录**到本仓库 `docs/修改记录.md` 与 `qy-lty-admin/docs/修改记录.md`,跨项目联动**两端各写一条互相引用**,不混在同一条目里(CLAUDE.md 显式规定)。 - **会话完整管控(如 Sentry / APM 全链路追踪)** — 当前用阿里云日志服务,没有上 APM。如需要再开 milestone 评估。 - **多 Redis 实例 / Sentinel 集群** — 当前是单 Redis,CONCERNS.md 标记为 HA 风险,但不在本次范畴内;待性能/可用性 milestone 决议。 - **真正意义的测试套件** — 当前 ≈10 个 test 文件中只有 1 个真正在测,无 mock 基础设施。这是 CONCERNS.md 标的 HIGH-severity 工程债,但需要独立 milestone 系统性修。 ## 背景上下文 **生态位**:本服务是「设备—App—管理端」三角的中心节点,对所有客户端来说**它是唯一的真理来源**。 **对接客户端清单**(以 CLAUDE.md 为准): | 客户端 | 路径 | 通讯方式 | |--------|------|---------| | LTY_App_Project_URP(手机端 Unity URP) | `C:\Unity2022project\LTY_App_Project_URP` | HTTP REST + WebSocket `/ws/device/` | | LTY_Project(设备端 Unity) | `C:\Unity2022project\LTY_Project` | HTTP REST + WebSocket + RTC(火山引擎) | | qy-lty-admin(Web 管理后台) | `../qy-lty-admin/` | HTTP REST `/api/v1/admin/` | **最近活跃工作**(git log + 修改记录): - 2026-04-24 ~ 至今:好感度系统从「用户级单值」演进到「设备级独立计数」,P1 数据层已上线,P2/P3/P4 待后续 milestone - 设备交互视图持续更新(最近 commit `a13a081`) - CI 触发性 commit 多次(`6c1cfde` / `ba16766` / `df85773`)—— 暗示 CI/CD 配置仍在调试 **已知工程现状**(详见 `.planning/codebase/`): - 整体规模约 168 个 Python 文件 - 测试覆盖**极低**(实质 ≈ 0),是最大的工程债 - `device_interaction/views.py` 单文件 1867 行,承载 30+ action method —— 需要拆分但风险高(无测试保护) - `requirements.txt` 不锁版本(无 lockfile)—— 部署一致性靠 Docker 镜像保证 - Python 3.8 已 EOL(2024-10),需要规划升级 ## 约束 - **技术栈**:Django 4.2.13 + DRF + Channels + Daphne — 已锁定,迁移成本极高 - **技术栈**:Python 3.8(EOL)— 当前限制,但近期需升级 - **技术栈**:PostgreSQL(主)+ Redis(缓存 + Channel Layer)— 不可替换 - **技术栈**:ASGI 必须,因为 WebSocket 是核心 — WSGI 路径 (`wsgi.py`) 仅作历史保留 - **兼容性**:WebSocket 消息协议(11 种 message type)被 2 个 Unity 客户端依赖 — 任何新增字段必须向前兼容,删除字段需协调 3 方排期 - **兼容性**:REST API 响应包装格式(`StandardResponseMiddleware` 输出的 `{success, code, message, data}`)被 `qy-lty-admin` 依赖 — 整体结构不可改 - **兼容性**:`device_{user_id}` 分组命名 + `room_{user_id}` 房间命名是端到端的隐式契约 — 改名要同步 Unity / Volcengine RTC 配置 - **文档规范**:每次代码改动**必须**追加到 `docs/修改记录.md` 顶部(CLAUDE.md 强制规则,结构性文档变更同样适用) - **沟通语言**:与用户沟通使用中文(CLAUDE.md「沟通语言」章节强制) - **项目独立**:`qy_lty` 与 `qy-lty-admin` 独立维护,**修改记录、planning 工件不混合** - **安全**:`.env` 不入库,所有 SDK secret 必须通过环境变量加载(CONCERNS.md 已标 SECRET_KEY / DEBUG / CORS 多处需收紧) ## 关键决策 | 决策 | 理由 | 结果 | |------|------|------| | WebSocket 分组用 `device_{user_id}`(不是 `device_{mac}`) | 让"同一用户"的多个端点(手机 + 设备)天然共享同一通信空间;同时一个设备同一时刻只能被最新绑定的用户控制,符合"陪伴"产品语义 | ✓ Good — 已支撑生产 | | `UserDevice.Meta.ordering = ['-bound_at']` 隐式驱动控制权解析 | 实现"后绑挤先绑"语义无需显式状态机,依赖 ORM 默认排序 | ⚠️ Revisit — 语义正确但隐式,新人容易误删旧记录或绕过 ordering 直接 query;建议改写为显式 `current_owner` 字段 | | 30 天 token TTL(Redis 后端) | 设备 + 手机端长期在线,短 TTL 体验差 | ✓ Good — 与产品形态匹配 | | 多服务商音频抽象(`AudioService` 工厂) | Aliyun/腾讯/火山随时切换、降本调优 | ✓ Good — 实测有效,火山为当前默认 | | `StandardResponseMiddleware` 统一包装响应 | 客户端只需处理一种响应壳层 | ✓ Good — 已被 3 个客户端依赖 | | 设备级好感度(vs 用户级)— 2026-04 P1 | 同一用户多设备时不互相污染好感度 | — Pending — 需 P2 service 层落地后才能完整验证 | | 测试 MAC `AA:BB:CC:DD:EE:FF` 硬编码绕过绑定校验 | 早期开发便利 | ⚠️ Revisit — CONCERNS.md 标 HIGH,上规模前必须替换为环境变量开关 | | `.planning/` 锚定在 `qy_lty\`(不是 `Lila-Server\`) | `qy_lty` 与 `qy-lty-admin` 是独立项目,CLAUDE.md 规定各自维护 | ✓ Good — 2026-05-07 通过预创建空目录强制锚定生效 | ## 演进规则 本文档在 phase 切换与 milestone 边界处更新。 **每次 phase 切换后**(通过 `/gsd-transition`): 1. 需求被推翻?→ 移到「范围外」并说明理由 2. 需求已交付?→ 移到「已交付」并标注 phase 引用 3. 出现新需求?→ 加到「进行中」 4. 有决策需要记录?→ 加到「关键决策」 5. 「项目简介」是否仍然准确?→ 如有偏移则更新 **每个 milestone 完成后**(通过 `/gsd-complete-milestone`): 1. 全面回顾所有章节 2. 复核「核心价值」—— 是否仍是当前最高优先级? 3. 审视「范围外」—— 排除理由是否仍然成立? 4. 用当前状态更新「背景上下文」 --- *最后更新:2026-05-07,启动 Milestone v1.0「通用凭据槽位(APP ID + Access Token)」*