Files
main_plugin_farm/docs/03-business-rules.md
T

102 lines
5.4 KiB
Markdown
Raw Normal View History

2026-10-15 14:14:58 +08:00
# 业务逻辑与一致性设计
状态:以下是建议约束。涉及用户资产归属、玩法与跨实例互通的选择,
需按 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 时间戳,业务日期按配置时区计算;日志记录时区语义。
时钟可注入,覆盖午夜、闰日、月切换和重启后的结算。
核心状态改变必须由事务内显式步骤完成。
提交后的消息、图片、统计等副作用失败不撤销已提交业务;
需要可靠重试时使用操作结果或持久化任务。事件槽捕获异常不能把
必需的资产更新失败隐藏成成功。首期不必新增通用事件总线。
展示读取业务结果,不在绘图过程中更新余额或土地;
图片失败回退文本,不重复执行业务。