Files
DanDingNoneBot/.trellis/tasks/08-16-standalone-sign-in-plugin/prd.md
Mr.Xia 9ee5545cac feat(sign_in): 新增独立每日签到插件,与抽卡签到共用同一份签到数据
- 群聊命令「签到」(别名: 每日签到/打卡),白名单群聊或管理员可用
- 复用 xapi /bot/gacha/sign-in + /bot/points/add,与抽卡/WPF 共用 bot_gacha_daily_sign_in 表
- 积分随机 1-100,流水沿用 gacha_sign/抽卡签到;先到先得,重复签到提示已签到
- 新增 10 个单元测试,ruff 通过;更新 PLUGINS.md / README.md
2026-08-16 09:02:11 +08:00

85 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 独立每日签到插件(与抽卡签到共用数据)
## Goal
在 danding-bot 中新增独立「签到」插件用户发送「签到」命令即可完成每日签到并领取积分抽卡插件onmyoji_gacha的「抽卡后自动签到」保持原功能不变两个入口与 WPF 客户端共用同一份签到数据xapi `bot_gacha_daily_sign_in` 表,每用户每天一条,先到先得)。
## What I already know
- 签到数据唯一权威源xapi DanDing 库 `bot_gacha_daily_sign_in` 表,`UNIQUE(bot_user_id, sign_date)`WPF 与 QQ Bot 已共用xapi `docs/bot-api.md` L126、`Application/Bot/gacha_router.py` L203-284、`Application/DanDing/wpf_gacha.py` L183-226
- QQ 抽卡签到现状:`onmyoji_gacha` 插件在抽卡/三连抽成功后调用 `POST /bot/gacha/sign-in`Body: user/token/user_id/points_awarded → data: {success, signed_already, signed_today, sign_date, points_awarded})记录签到,再调用 `/bot/points/add` 发积分source=`gacha_sign`reason=`抽卡签到`,随机 1-100 分)。
- WPF 签到:`POST /DD/gacha/sign-in` 在同一事务内写签到记录 + 发 Bot 积分(`BOT_GACHA_WPF_SIGN_IN_POINTS` 默认 20source=`gacha_sign`reason=`抽卡签到`)。重复签到返回 `signed_already=true` 且不重复发积分。
- xapi 无 `GET /bot/gacha/sign-in` 状态查询路由(只有内部 helper但写接口返回 `signed_already`,重复签到可直接提示"今天已签到"。
- 客户端 HTTP 封装已有现成模式:`onmyoji_gacha/data_manager.py`DataManager._request 模式)与 `danding_points/api.py`PointsAPI.add_points → POST /bot/points/add
- 权限模式:`onmyoji_gacha` 用白名单ALLOWED_GROUP_ID=621016172 / ALLOWED_USER_ID=1424473282的 check_permission Rule。
- 本任务不需要改 xapi复用现有 `/bot/gacha/sign-in` + `/bot/points/add` 即可实现共用数据),不涉及跨端契约新增。
## Requirements
- [x] 新增独立签到插件(目录 `danding_bot/plugins/sign_in/`
- [x] 群聊命令「签到」别名每日签到、打卡白名单权限ALLOWED_GROUP_ID / ALLOWED_USER_ID与抽卡一致
- [x] 命令触发签到:调用 xapi `POST /bot/gacha/sign-in` 记录签到,成功后调用 `/bot/points/add` 发放积分
- [x] 积分规则:随机 1-100与抽卡签到一致
- [x] 积分流水 source=`gacha_sign`、reason=`抽卡签到`(沿用现有标记,与 WPF/抽卡共用事件语义)
- [x] 重复签到signed_already=true提示"今天已签到",不发积分
- [x] onmyoji_gacha 抽卡签到保持现状,不做任何改动
- [x] 不新增「签到状态」查询命令(保持最小范围;重复签到提示利用响应自带的 sign_date/points_awarded
- [x] 更新 PLUGINS.md / README.md 文档
## Acceptance Criteria
- [x] 发送「签到」:首次签到成功,返回签到成功 + 积分 + 当前余额
- [x] 同一天再次「签到」:提示已签到,不重复发积分
- [x] 抽卡签到与新命令签到互斥(共用 daily_sign_in 去重),先到先得:先抽卡后命令 → 命令提示已签到;先命令后抽卡 → 抽卡不重复发积分(抽卡插件原有逻辑已处理)
- [x] 权限:白名单外的群/用户收到无权限提示Rule 拒绝后命令不触发)
- [x] 测试覆盖10 个 unit testsmock xapi aiohttp 调用,全部通过)
- [x] ruff lint 通过(新文件 0 违规)
## 实现状态2026-08-16
- 已实现:`danding_bot/plugins/danding_sign_in/`__init__/config/api/service/rules 5 文件)
- 已实现:`tests/test_danding_sign_in_plugin.py`10 用例全绿)
- 已更新文档PLUGINS.md新增 #14 + 抽卡章节交叉引用、README.md新增 #8
- 测试环境:无 conda bot 环境,用 xapi envpytest 9.0.2 + aiohttp + pydantic 2.13)跑通;无 nonebot 环境rules.py 采用延迟导入 nonebot 保证可测
- 代码复用决策:编排逻辑(先记录后发积分)未从 onmyoji_gacha 复制,而是自包含实现同模式 —— 避免 import onmyoji_gacha 包触发其 __init__ matcher/路由注册耦合;若将来出现第 3 个签到入口,再提取共享模块(规则三)
- 既有测试套件72 通过 + 1 失败test_danding_qqpush_article_render 中文编码问题,与本任务无关,环境性失败)
## Definition of Done (team quality bar)
- Tests added/updated (unit/integration where appropriate)
- Lint / typecheck / CI green
- Docs/notes updated if behavior changes
- Rollout/rollback considered if risky
## Technical Approach
- 新插件 `danding_bot/plugins/sign_in/`,模块结构仿照现有插件惯例:
- `__init__.py`NoneBot matcher 注册on_command("签到", aliases={每日签到, 打卡}, priority=5, rule=check_permission())+ handler
- `config.py`Pydantic 配置API host/token/白名单/积分区间,复用 onmyoji_gacha 配置命名惯例)
- `api.py`xapi 客户端(封装 `POST /bot/gacha/sign-in`,仿 DataManager._request 模式)
- `service.py` 或直接编排:记录签到 → 发积分 → 格式化消息(先记录后发积分,避免重复发积分,复用 `onmyoji_gacha/sign_in.py` 的 award_daily_sign_in_points 模式)
- 数据共用:直接调用与抽卡插件相同的 xapi 端点(`/bot/gacha/sign-in` + `/bot/points/add`),天然共用 `bot_gacha_daily_sign_in` 表,无需改动 onmyoji_gacha 插件。
- 可复用现有代码:`points_api`danding_points/api.py 的 PointsAPI直接 import签到编排可直接复用 `onmyoji_gacha/sign_in.py``award_daily_sign_in_points`(或独立实现同模式)。
- 测试:`tests/test_sign_in_plugin.py`,仿 `tests/test_onmyoji_gacha_http_api.py` 的 FakeSession/FakeResponse 模式 mock aiohttp。
## Decision (ADR-lite)
**Context**: 用户需要独立签到命令,且与抽卡签到共用数据、不破坏抽卡签到。
**Decision**: 新插件复用 xapi 现有 `/bot/gacha/sign-in` + `/bot/points/add` 端点(与抽卡插件同源),数据自然共用;积分 source/reason 沿用 `gacha_sign`/`抽卡签到`;命令仅群聊 + 白名单;积分随机 1-100。
**Consequences**: 零 xapi 改动、零契约新增;抽卡插件零改动(回归风险最低);流水无法区分签到触发入口(可接受,因为每天只有一次签到);「签到状态/连续天数」查询能力暂缺,后续需要时另开任务(契约先行)。
## Out of Scope
- 不改 xapi无新增端点
- 不做签到排行榜/连续签到统计/签到状态查询命令
- 不迁移签到数据表位置
- 不改 onmyoji_gacha 抽卡签到逻辑
## Technical Notes
- xapi 契约:`C:\Users\14244\source\repos\Danding_Webs\xapi_new_web\docs\bot-api.md` L114-126
- 表结构:`bot_gacha_daily_sign_in`migrations/DanDing/013_create_bot_data_migration_tables.py L99-109
- 客户端参考:`danding_bot/plugins/onmyoji_gacha/data_manager.py`_request 模式)、`danding_bot/plugins/onmyoji_gacha/sign_in.py`(先记录后发积分编排)、`danding_bot/plugins/danding_points/api.py`PointsAPI.add_points
- 测试模式参考:`tests/test_onmyoji_gacha_http_api.py`FakeSession/FakeResponse mock aiohttp
- 任务创建于 2026-08-16Trellis 自动加日期前缀)