# 积分规则与开发契约 ## 2026-10-19 正式更新 积分一期已随20261019-photo-points-token-r1于17:40:33上线至111.230.144.231:每日10分,上海每日一次,两个字段及两个索引迁移完成,无历史补发。客户端最新完整策略校验和规则文案仍需用户重新编译发行,正式签到到账/真机未验收。记录见后端database/photo-points-token-release-20261019.md;下方未发布/正式关闭为历史阶段。 ## 2026-10-19 一期本地收尾 用户在一期规则建议后要求“继续下一步”,本轮按每日签到10分、上海业务日每日一次、不补签、无连续奖励、积分不过期、不联动会员等级推进;兑换、提现、AI额度抵扣、资料和邀请奖励均关闭。不导入本机体验积分,不补发历史奖励。该决定覆盖下文2026-10-02的“首阶段建议待确认”,不代表正式活动已启用。 - 已补齐积分规则弹窗的业务日、加成、有效期、等级和用途说明;奖励额继续读取服务端,前端没有写死10分。暂停状态明确为“签到已暂停”,保留已配置规则、余额和明细。 - 前端读取规则时校验状态、版本、奖励、时区和完整一期策略。不支持或不一致的策略返回错误,不用一期文案套用未知权益,也不展示部分余额和签到入口。 - 后端新增 `database/points-phase1.env.example` 配置片段,版本 `points-checkin-20261019-v1`,默认关闭;它不由应用自动读取,未修改实际 `.env` 或 `application/extra/points.php`。`false`/`none`使用引号,测试采用框架相同的默认INI解析,避免被解析为空值。未来启用必须先核实积分表、完成配套迁移,再设置明确运行配置。 - 本轮251项后端纯内存检查、190项HTTP输入检查、110项迁移纯检查、98项写保护检查、21个前端规则/页面行为场景,以及原协议30/照片26场景通过。旧写保护测试补齐Token统计新增的只读查询替身,业务守卫保持。未启动数据库、Redis或worker,未重新执行数据库/HTTP持久化检查。 - 实际H5页面在390×844与1280×900检查通过,包含规则弹窗、草稿/暂停/异常规则、签到响应丢失后刷新并用原键确认。49项记录包含各接口鉴权观察;全部接口为浏览器拦截合成响应,不是正式到账或数据库验收。无运行错误和意外外部请求,控制台只有刻意制造的未发布协议404及丢响应网络错误。截图已查看,未见遮挡或横向溢出。 - 使用既有HBuilderX5.26编译器完成微信29页编译,产物仅在仓库外证据目录,不是已上传包。桌面CLI因HBuilderX未打开不可用,改用同一已安装编译器直接构建;Browser插件未提供,使用已有Python Playwright/Chrome,未安装依赖。 证据:`D:/AAdesk/202609/airz-backups/points-phase1-20261019-r1`。正式积分仍关闭、原表迁移未执行、未发布后端/前端或规则、未访问生产、未调用真实模型,真机和正式到账未验证。积分与累计Token额度互相独立;前一轮Token未发布改动完整保留。 下列章节保留前期设计和验收历史;业务规则是否确认以本节为准,历史“前端未发行”仅描述当时积分联调阶段,不否认后续小程序1.1.0已发行记录。积分正式启用须单独安排迁移、配套上线和到账验收;邀请体系及资料奖励不属于本期完成范围。 记录日期:2026-10-02。版本:points-page-20261002-v3。状态:**后端已随5fee3cf部署、积分页面读取与恢复隔离联调通过;业务规则未定稿,正式配置关闭,原表未迁移、前端未发行**。归属既有 POINT-001—004,不新增任务编号。POINT-002/004保持开发中;DEC-POINT/POINT-001仍待确认,POINT-003未实施。 本文件作为积分实施入口;数据库具体增量见[积分数据库方案](D:/AAdesk/202609/airz/database/points-design.md),最新页面状态与证据见[开发进度0.51](开发进度.md)。未获规则确认时不填真实奖励,配置默认false/null;合成联调不代表正式积分可用。 ## 0. 最新页面恢复与隔离联调 页面主流程98项/127次积分请求和补充81项/81次积分请求通过,共201次进入本机真实PHP/MySQL、7次受控故障/网络中断。覆盖真实丢响应后原键确认、跨接口一致性、读取失败时确认入口、确定拒绝弃键、坏回执保键、账户切换及迟到401;登录响应只为合成认证,真机、生产迁移与正式发布仍未完成。 未知请求由页面会话范围调整为原userId作用域的恢复命令上下文:只含requestId/expectedDate/expectedRuleVersion,不含Token、余额、流水或填写资料;401、会话过期、退出及账户切换仍清资料缓存和会话,但该键保留至确认或明确拒绝。恢复前核验当前账户,POST仍重新鉴权;不会把原请求迁移到别的会员,也不会在登录/刷新后自动发奖。此恢复例外不改变DEC-POINT业务参数。 共享清理专项35项通过(15真实积分HTTP、2合成密码登录):真实401清掉会话与该账户的其它资料缓存、保留原命令,同账户重新登录后实际重放且无重复到账。专项未实测本机过期/主动退出/完整账户切换交互;它们共用的清理函数已按上述规则实现。三批共214项/223积分请求,临时环境及私密配置已清理,正式发布/原表迁移状态保持。 ### 0.1 前序:协议与隔离开发检查 87个真实HTTP请求/1079项检查通过,经过实际ThinkPHP路由、Redis Token鉴权和积分控制器。覆盖匿名/无效/停用/删除/撤销、Cookie/旧Token头拒绝、允许Origin的匿名OPTIONS、JSON/原始query/错误方法、草案/发布/暂停/坏规则、跨日/版本变化、实际丢弃已提交成功响应后的原键确认、本人快照/隐私/旧NULL与0流水、余额边界、坏回执和Redis不可用。 新脚本tests/points_http.php仅取明确私密环境的本机3309连接,创建独立合成数据库、临时ROOT/RUNTIME、随机ENV_PREFIX和Redis DB15随机Token作用域;不读取正式.env,不启动worker或调用模型。成功后自建数据库、Token、临时服务/文件已清理,共享fa_user/fa_user_score_log结构/数据及原Redis队列摘要保持。所有权标记限制目录清理;清理失败返回非0并保留受限目录及安全定位,不能声称资源已移除。 主服务238项、HTTP输入190项纯检查通过。原表23项只读预检通过,仍4增量、14类质量计数各项0,applied=false。迁移新增非NULL历史时间质量计数,正UINT流水ID并入invalidLedgerIntegers;合法NULL历史时间保留,非NULL时间范围0—253402271999,确保上海ISO8601四位年份。首次快照坏主键固定409/POINT_LEDGER_INVALID。当前业务配置保持false/null,页面、原表迁移及部署未完成。 迁移纯110项、独立合成库apply/备份/Windows ACL/恢复89项通过。共享隔离库只复制结构,第一新库合成2会员4流水;apply4增量、重复为0,完整双表schema+NDJSON恢复第二新库并逐列摘要一致。目录3文件ACL及读写probe通过,修正Windows原生绝对路径及父级路径校验,纯路径边界覆盖;两新库、私密INI/备份/probe已清理,源表摘要保持。安全verification保留于C:/Users/JUN/AppData/Local/Temp/airz-points-migration-20261001/apply-20261001-115749-d50a5cd87fd5a84a/verification.json。仅为开发演练,未执行共享原表DDL或生产操作。 ### 0.2 历史:0.48后端基础检查 已新增 PointsRules、UserPoints、v1 Points 控制器、五条路由、默认未发布配置、显式迁移脚本及测试。通用后台score/level、通用模型更新与旧User::score均已拒绝写入;新服务直接在账户锁内限定更新score并保存完整流水,不重算level。新会员0分、数据库默认0级及Auth注册1级初始化保持。schema.sql和ScoreLog中文注释已同步目标结构,不能据此声称目标库已经增加字段。 纯检查237项服务、98项写保护、84项迁移通过。隔离MySQL3309随机前缀合成表45项检查通过,包含同键/异键双PHP并发、锁等待跨日和真实流水insert故障回滚;测试表及临时文件已精确清理。原fa_user/fa_user_score_log结构和数据摘要保持。另22项只读迁移入口检查通过,重复预检仍为4增量、13类质量计数均0,applied=false;本轮修复PHP7.4 PDO不追踪原始START事务导致预检commit失败,改PDO事务接口与RR只读快照。 没有迁移原表、运行apply/备份/Windows ACL、调用模型/worker/Redis/HTTP、编译页面或部署。提交结果未知和连接故障由纯替身覆盖,不是实际断网或生产到账证据;页面状态、真实HTTP、迁移应用与恢复仍须后续开发检查。 ## 1. 首阶段建议与待确认项 建议先实施 POINT-002 的账户余额、流水、每日签到,再接 POINT-004 对应页面部分。POINT-003 邀请关系和可信奖励独立实施;不因完成签到而标记整个积分模块完成。 | 项目 | 首阶段建议 | 状态与理由 | | --- | --- | --- | | 每日签到 | 已登录且状态正常的会员,每个业务日一次,每次 10 分 | **待确认数额**;沿用既有页面建议,不表示已批准真实奖励 | | 业务日 | 服务端 Asia/Shanghai,00:00 至次日 00:00,不提供补签 | 待确认;设备时间、时区及登录连续天数不作为依据 | | 连续签到加成 | 不启用,始终固定当期奖励 | 待确认;不需要新增连续签到表 | | 完善资料奖励 | 首阶段关闭,奖励数额为 null | 必须后续确定完整标准、可信事件和一次性范围;进入档案或编辑资料不发奖 | | 邀请奖励 | 首阶段关闭,奖励数额为 null | 有效邀请条件、双方奖励、次数和归因期限待定;复制、分享、绑定码不直接发奖 | | 积分用途 | 首阶段只提供余额与流水,不启用提现、现金兑换、AI 次数抵扣或贷款优惠 | **待确认权益范围**;不能把积分说成授信、信用分、放款条件 | | 有效期 | 首阶段建议不自动过期 | **待确认**;若需要到期扣减,须先设计到期批次/消费抵扣,不靠定时清零余额实现 | | 会员等级 | 新签到服务首阶段建议仅变更 score,不新增等级或权益联动 | **待确认**;旧 User::score 会按余额改 level,需要明确兼容处理后实施 | | 历史体验积分 | 不导入、不补发真实积分 | 本机记录可篡改,匿名也可签到;正式余额只取服务端既有 score | | 历史服务端数据 | 原 score、流水、日期、备注、业务键保留 | 不按流水合计重建余额、不自动清零、不擅自修复差异 | 首阶段的业务确认应至少覆盖“每天 10 分、上海每日一次、不补签”“资料/邀请奖励关闭”“权益、有效期及等级处理”。在明确确认前,设计状态保持 draft;未来配置的安全默认值必须为未发布、停止新入账,奖励数额不得用页面示例兜底。 ## 2. 已核实的源码现状 | 位置 | 当前能力或风险 | 实施处理 | | --- | --- | --- | | [积分页面](../packages/account/points/points.uvue) | 已读取服务端余额、规则、任务和本人流水;按服务端日期/规则恢复签到请求 | 关闭配置时继续显示未发布状态,不伪造奖励;原键确认后重新读取当前余额 | | [账户服务](../packages/account/services/account.uts) | 已有登录、账户变化防护;资料 DTO 无 score/share_code | 积分服务复用会话,不扩充无关资料字段;登录恢复只接受固定 `resumePoints` 白名单 | | [请求基础](../services/api.uts) | 已保留 Token 变化、401 清理、HTTP 状态和业务 `errorCode` | 页面按确定拒绝与结果未知分别清理或保留原签到键,网络/账本故障不误判未入账 | | [数据库结构](D:/AAdesk/202609/airz/database/schema.sql) | fa_user.score 为有符号 INT;流水已具业务键、事件唯一及用户时间索引 | 复用余额和流水;目标库实际结构仍须迁移前只读核实 | | [通用积分方法](D:/AAdesk/202609/airz/application/common/model/User.php) | 旧score()已明确拒绝,通用模型不能更新score/level | 使用UserPoints领域服务,不再吞异常或随积分重算等级 | | [后台会员模型](D:/AAdesk/202609/airz/application/admin/model/User.php) | 模型事件、后台增改/批量及编辑表单已保护score/level | 积分/等级只读;任意SQL仍不经过模型守卫,新增写方须遵守共同账户锁 | 最初设计依据源码和schema.sql;本轮仅对显式隔离库读取实际结构/数据并在随机合成表检查事务。正式库未连接,隔离原积分表仍缺两个新列和两个索引,不能把合成表或结构文件当作正式迁移证据。 ## 3. 规则发布与事件身份 已增加application/extra/points.php,独立于模型调用额度。默认 `enabled=false`,rule_version/check_in_reward/expiry_policy/level_policy/benefits_policy均null;API映射ruleVersion/checkInReward。发布必须提供完整版本、1—1000的规范整数奖励及none/unchanged/none三项策略;这一范围是配置校验上限,不是批准的奖励额。enabled=false且保留完整发布内容表示paused,不删历史回执。损坏/不完整配置固定POINT_RULE_UNAVAILABLE。 规则版本格式为 2—64 位小写 ASCII,`^[a-z][a-z0-9-]{1,63}$`;拟首版名 `points-checkin-20261001-v1`。同一版本永久对应同一奖励额、日期和参与语义;变更必须新版本,不改历史流水。暂停活动不删除成功回执;启用配置编辑后台不属于首阶段,先使用受控部署配置。 每日签到的账本事件固定: ```text business_type = checkin business_id = 服务端上海业务日 YYYY-MM-DD unique = user_id + business_type + business_id ``` 事件键不包含规则版本,因此同一天发布新版本也不能重复奖励。新请求只能为当前业务日入账;设备日期和客户端字段不能指定补签。旧已成功请求允许在下一日、规则暂停或新版本发布后返回原回执,但仍要求当前账户有效且拥有该流水。 ## 4. 接口源码契约 统一前缀 `/api/v1`,全部要求显式合法Bearer及当前正常会员,不接受Cookie/旧Token头回退。沿用v1 Base的code/msg/data与data.errorCode、Cache-Control: no-store,v1框架错误亦补该缓存头。由认证身份取得userId;未知参数、客户端余额/奖励/业务完成状态/其他用户ID均拒绝。五条精确白名单路径、原键恢复和页面隔离联调已通过开发检查;原表迁移和规则发布仍未完成,不视为线上积分已启用。 签到要求application/json,可带UTF-8 charset;正文由原生JSON解码及领域校验,必须三个唯一字符串字段,重复键和Unicode等价重复键拒绝。原始QUERY_STRING校验唯一解码键、白名单及PHP解析一致;NUL、坏编码、重复和空片段拒绝。原始/有效HTTP方法须与接口方法一致,覆盖头存在即拒绝;错误方法405,未知路由404。Common既有入口在鉴权前处理允许Origin的匿名OPTIONS,不重复实现CORS。 | 方法与路径 | 严格输入 | data 主要字段 | | --- | --- | --- | | GET /points | 无业务参数 | balance:int、serverDate、timezone、signedToday、checkInEnabled、ruleVersion:string/null、checkInReward:int/null、balanceState:normal/anomaly | | GET /points/rules | 无业务参数 | status:draft/published/paused、ruleVersion:string/null、checkInReward:int/null、timezone、publishedRules;未发布规则不显示为已生效 | | GET /points/ledger | limit 默认20/最大50;后续页 beforeId + snapshotId | items、snapshotId、nextBeforeId;本人流水,ID 字符串 | | POST /points/check-in | requestId、expectedRuleVersion、expectedDate,必须恰好三个字段 | ledgerId、delta:int、balanceAfter:int、signedDate、ruleVersion、replayed:bool | | GET /points/tasks | 无业务参数 | 首阶段只返回已发布签到任务;未实施资料/邀请奖励明确 unavailable,reward=null | 流水源码采用与现有消息/内容一致的有界游标,替代旧page/pageSize目标草案;积分 API 已接入页面,但正式原表迁移和规则发布仍未完成。tasks实际返回serverDate/timezone/items,签到任务按已发布规则和今日状态显示,资料/邀请始终unavailable且reward=null。邀请/invitations和/invitations/bind保留后续阶段目标,不返回固定码或假的奖励进度。 ### 4.1 签到请求及回执 `requestId` 为 `pts_` 加 32 位小写十六进制,由客户端生成并在同一用户命名空间内作为幂等键;服务端以唯一约束和原请求确认保证不重复入账。正式发布前仍应将生成源替换为跨端可用的安全随机实现。`expectedRuleVersion` 为页面实际读取的已发布版本;`expectedDate` 为同一次读取返回的 serverDate,是操作预期条件,**不是指定奖励日期**。日期须为真实有效的 YYYY-MM-DD,拒绝非法日历日期、空值、数组和宽松类型转换。 示例仅描述获批发布后的协议形状,当前无这样的运行规则: ```json { "requestId": "pts_0123456789abcdef0123456789abcdef", "expectedRuleVersion": "points-checkin-20261001-v1", "expectedDate": "2026-10-01" } ``` 入账回执与原流水绑定;重放中 `replayed=true`,其余业务字段保持原值。`balanceAfter` 是这笔入账后的历史余额,不是当前余额;页面必须随后重新 GET /points,不能用旧回执覆盖新余额。不同请求键同日重复签到返回明确的 `POINT_ALREADY_SIGNED`,不写第二条零分流水,也不把新的请求键附到原流水。 ### 4.2 余额与流水读取 余额、今日签到状态与规则须来自一次一致的读取:先按当前会员事务读取,固定一个服务端业务日,再完成对应状态查询,避免日界/入账途中混合视图。日期和规则必须一起提供,客户端不能用本机时钟补齐。服务不可读时固定失败,不把错误或未知余额转成 0。 流水DTO为ledgerId/delta/balanceBefore/balanceAfter/businessType/businessDate/ruleVersion/createdAt。时间为ISO8601带时区,历史未知时间保留null;日期为上海YYYY-MM-DD。ID为字符串,支持现有无符号INT至4294967295,服务/迁移要求64位PHP。历史未识别事件统一legacy,业务日/版本可null;不返回原memo、原业务标识或请求键。历史真实0分记录如实展示,不因新服务禁止零分占位而删除。 首次列表取得本会员最大 ID 作为 snapshotId,空为字符串 "0";后续固定上界并按 `id B[锁账户并查成功请求] B -->|同意图命中| C[返回原流水回执] B -->|未命中| D[锁后日期校验] D --> E[检查当日事件 再校验规则与积分边界] E --> F[余额和一条流水同事务提交] D -->|日期或版本变化| G[固定冲突并刷新] E -->|已签到| G ``` ## 6. 首阶段数据库与写路径 schema.sql及显式迁移脚本已定义可空request_id/rule_version、唯一(user_id,request_id)和ID游标索引(user_id,id);原表未应用,旧流水保持。已有业务唯一和用户时间索引不重复添加;用户时间索引不能直接保证按ID排序。成功流水保存日唯一和请求回执,不建独立签到/请求/连续签到表。具体字段、中文注释与预检见[数据库增量方案](D:/AAdesk/202609/airz/database/points-design.md)。 本轮已盘点并封闭通用后台绝对值编辑、批量、User::score和模型score/level更新;仅新增服务加锁不能防其他旧写方覆盖余额。受控管理员积分调整独立排期,当前只读;任意SQL不经过模型守卫,后续插件/导入必须重新审查。会员删除的既有历史策略本轮保持,可能有孤儿流水;已删除/停用账户不能通过新服务读取或重放。 新服务拒绝外层事务,确保成功意味着本次真正提交;不回滚调用方已有事务。数据库break_reconnect必须严格false,防断线自动重连使单条SQL意外自动提交。事务竞争只在确认本人事务回滚后映射409,未知提交返回503保留原键,不进行自动SQL重试。 后续邀请关系需独立表,受邀人唯一绑定、禁止自邀、邀请码唯一且历史冲突先人工处理。资料奖励以永久任务事件去重,不能按每次资料修订发奖。只有服务端可信业务事件可触发奖励;不能用客户端声称“资料已完成/好友已注册”发奖。 ## 7. 页面实施边界 - 登录后恢复积分页需为现有登录白名单增加固定 `resumePoints` 目标,不接受任意回跳 URL。 - 初次/刷新分别处理加载、失败、空流水、未发布规则、已签到;失败清掉不可信旧状态,不显示假的 0 分或成功。 - 发送中锁定签到按钮;请求结果未知时保留原 requestId/date/version 和账户身份,只允许原请求确认。不能因刷新、关闭提示或跨日自动生成另一签到请求。 - 原回执仅确认原业务日;回执后重新读取当前余额和 serverDate。要签到新一天,必须由用户在刷新后明确点击。 - 离页/换账号拒绝迟到响应;未知请求在原userId作用域保留,离页、401、过期、退出和切换账户不会弃键,不能跨账户迁移。只保留三字段恢复命令,其它账户缓存照常清除;重新登录该会员后才能显式确认,仍须服务端鉴权。 - 从 API 的 ruleVersion/reward 显示规则与奖励,不再写死 10、AI2680 或本机积分。未接邀请前不显示“真实个人邀请码”或未发生的邀请奖励。 - 清理体验签到缓存不产生服务器写入;原匿名/本机记录不影响服务器 signedToday。 ## 8. 后续开发检查清单与顺序 以下为完整开发检查范围;已覆盖部分见第0节和开发进度0.51。积分读取/签到恢复隔离页面检查已通过,邀请与资料奖励、原表迁移、正式发布及真机仍未完成: | 检查 | 关键反例 | | --- | --- | | 并发入账 | 同日同键/异键双进程;只有一笔奖励和流水,余额正确 | | 历史重放 | 第一天成功、第二天原键仍原回执;新日期复用成功键拒绝 | | 日期边界 | 锁等待跨午夜;昨日未执行请求不能在新一天到账;客户端时区/时钟篡改无效 | | 规则边界 | 规则变化/暂停/未发布;成功旧回执仍可读,未成功新请求拒绝 | | 原子回滚 | 流水 insert、余额 update、commit 故障;无“加分成功但无流水” | | 数据边界 | 负数、INT 上限、坏元数据、NULL 历史事件、非规范业务键不被误认 | | 所有权与隐私 | 匿名/禁用/跨账户、流水游标和自由备注;只本人读写 | | 老写方 | 后台伪造 score/level、legacy 方法/插件调用;不能覆盖新账本 | | 页面状态 | 实际响应丢失、原键确认、换账号、登录恢复、加载/空/错、迟到回包 | | 迁移和恢复 | 原表只读预检;新合成库apply4增量/重复0、完整备份/ACL/第二库恢复、旧数据摘要一致及精确清理已通过 | 当前后端可在规则未定稿时保持默认关闭。页面真实读取、登录恢复及原键确认已完成隔离联调;下一步是确认首阶段业务规则,随后执行正式库只读预检、完整备份、4项增量迁移和线上关闭状态烟测。邀请资格/奖励规则与关系方案留POINT-003,完整POINT-004后续推进。发布参数在确认前保持空值。 正式迁移、上线、真机/多设备、权益运营和真实业务验收后续按实际范围安排,不复用历史生产授权。本轮为源码、纯测试及显式隔离开发检查,不是生产签到到账或积分页面完成证据。