Files
main_plugin_farm/docs/03-business-rules.md
T
2026-10-15 14:14:58 +08:00

102 lines
5.4 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.
# 业务逻辑与一致性设计
状态:以下是建议约束。涉及用户资产归属、玩法与跨实例互通的选择,
需按 07-decisions.md 确认后进入正式规格。
## 身份与农场归属
框架(真寻/NoneBot/AstrBot)不等于消息平台(QQ/Telegram 等)。
玩家至少需要 deployment_id、realm_id、platform、platform_user_id;
platform_user_id 保存字符串,禁止跨平台按相同数字自动认定同一人。
建议独立部署默认独立数据,realm 可配置群内或部署内共享。
各协议暴露的同平台 ID 也未必同义,官方 QQ 的开放标识与 OneBot
账号不能自动合并。迁移需要明确来源命名空间、人工确认映射与审计。
双人操作如偷菜必须确定双方处于同一允许交互的 realm,
检查自己偷自己、跨群目标、无农场目标和权限。@对象解析留在接入层。
## 货币与库存
- 内部货币、数量使用整数;设置合理上限并检查乘法后的范围。
- 增量和设置新值采用不同接口名称;应用层不能直接写余额缓存。
- 扣款使用数据库条件更新,例如余额足够才扣减,检查实际影响行数。
- 不足返回明确失败;不能静默把负余额截成零后继续发货。
- 每次资产变动记录 operation_id、actor、realm、币种、增量、原因、
关联物品和提交时间;日志不代替可查询的账本。
- 已锁定作物在单项出售、批量出售、交易与其他消耗入口采用一致规则。
- 所有数量入口测试 0、负数、缺省、超大值、全部数量与库存不足;
命令层的默认参数不得被误当成任意合法业务值。
## 购买与出售
购买:读取有效目录→校验数量/等级→同一事务中校验和扣款→增加种子
→写操作流水→提交→生成展示数据。任一步失败整体回滚。
出售:按明确数量计算可出售库存→同一事务中检查锁定和库存版本
→扣库存→只增加本次收益→流水→提交。返回实际成交数量与新余额。
网络发送失败不回滚已成交交易;重试同一 operation_id 返回原结果。
## 播种与收获
播种:空地校验、种子消耗、星级选择、作物实例创建在同一事务中。
土地收益与生长速度采用已确认公式,记录规则或目录版本,
不能让资源更新悄悄改变已播种作物的结算契约。
收获:每块地独立计算产量和经验,再求和;不对累计经验反复加成。
每轮作物有可辨识的 cycle_id/harvest_index,防止重试和并发重复领奖。
作物入仓、经验增加、收获次数、下一成熟时间或枯萎状态、偷取记录
的结算必须在同一业务事务内完成。精确的事务批次由全收获与部分成功
策略决定,先定义用户可见结果,不能任意留半完成状态。
未种植、生长中、成熟、枯萎是明确状态;不要用多组互相冲突的布尔值
表示同一阶段。除草、虫害、施肥等独立属性另行建模。
## 签到、升级与确认
签到采用明确业务时区,(realm、player、business_date) 唯一;
签到记录、奖励发放、累计奖励领取标记在同一事务内。
“已签到”与“新签到成功”分开返回,防止重复展示发奖。
补签与连续签到规则分别定义,不从字段名猜测。
开垦和土地升级在用户确认后重新读取余额与地块状态,重新校验条件。
确认凭据绑定发起人、会话、动作、参数、过期时间和一次性标识;
不能把任何消息里的“是”当作任意待办操作的确认。
升级使作物成熟这一旧行为需明确保留或调整。
## 幂等与并发
operation_id 由框架事件标识与部署作用域产生;没有稳定事件标识时,
用已持久化的交互操作标识,而不是每次重试生成新的随机 ID。
同一操作不同参数应拒绝,不能错误复用第一次结果。
唯一约束、条件更新或状态版本是最终防线。
进程内锁只作辅助,跨进程不能共享这把锁。
单实例 SQLite 的连接/事务应由一个明确管理者协调;
BEGIN 的锁等待、busy timeout、取消回滚、事务嵌套和连接关闭都要测试。
WAL 是部署选项,不能解决错误的业务事务边界。
## 外部金币兑换
真寻金币和本地农场币位于不同存储,不能承诺一个本地 SQLite 事务
同时回滚两边。先核对外部钱包是否支持 operation_id、条件扣款、
查询和退款;使用持久化兑换单与可重试状态机协调。
无法确认结果时进入待对账状态,禁止直接重复扣款或盲目发币。
普通 NoneBot、AstrBot 默认只支持内部农场货币;
外部经济系统通过能力配置接入,不导入真寻代码。
兑换比例、手续费、舍入、最小单位和失败恢复写入明确规格。
## 时间、事件与展示
保存 UTC 时间戳,业务日期按配置时区计算;日志记录时区语义。
时钟可注入,覆盖午夜、闰日、月切换和重启后的结算。
核心状态改变必须由事务内显式步骤完成。
提交后的消息、图片、统计等副作用失败不撤销已提交业务;
需要可靠重试时使用操作结果或持久化任务。事件槽捕获异常不能把
必需的资产更新失败隐藏成成功。首期不必新增通用事件总线。
展示读取业务结果,不在绘图过程中更新余额或土地;
图片失败回退文本,不重复执行业务。