连锁餐饮系统采购需要验证门店独立操作和总部汇总,也要检查员工撤权后已经申请的报表还能否下载。下面针对“申请时有权、生成或领取时已撤权”的工程故障,给出授权版本与任务状态设计,把结果用于交付验收。
微订当前第一方子帐号说明介绍岗位独立账号和权限,店内点单说明列出代客下单、桌号和云收银入口。此背景支持安排权限演示,不表示产品默认采用下列导出机制;文件存储、下载签名与具体部署均需项目确认。
模型与转换
grant_row表示某组织、用户、门店的授权,rev每次授权变更递增,active表示是否有效。export_job在申请时固定该授权rev和单店范围,状态为queued;生成前重新核验授权,才可改ready。撤权将active设0并递增rev,旧queued/ready任务改cancelled。下载请求必须同时满足ready、当前有效授权和版本相等。
完整核心SQL
示例依赖SQLite 3.35及以上。为便于逐步检查,以下按同一组织、单店导出演示正常申请和生成,再撤权并重新尝试领取。BEGIN IMMEDIATE使本模型写路径串行;如果有其他写入方绕过该事务约定,保证不成立。设计未执行,输出均为预期。
PRAGMA foreign_keys=ON;
CREATE TABLE grant_row(
tenant TEXT NOT NULL, user_id TEXT NOT NULL, store TEXT NOT NULL,
rev INTEGER NOT NULL CHECK(rev>0),
active INTEGER NOT NULL CHECK(active IN (0,1)),
PRIMARY KEY(tenant,user_id,store)
);
CREATE TABLE export_job(
tenant TEXT NOT NULL, job_id TEXT NOT NULL,
user_id TEXT NOT NULL, store TEXT NOT NULL,
grant_rev INTEGER NOT NULL CHECK(grant_rev>0),
state TEXT NOT NULL CHECK(state IN ('queued','ready','cancelled')),
PRIMARY KEY(tenant,job_id),
FOREIGN KEY(tenant,user_id,store)
REFERENCES grant_row(tenant,user_id,store)
);
INSERT INTO grant_row VALUES('org1','u1','A',1,1);
BEGIN IMMEDIATE;
INSERT INTO export_job
SELECT tenant,'J1',user_id,store,rev,'queued'
FROM grant_row WHERE tenant='org1' AND user_id='u1'
AND store='A' AND active=1;
COMMIT;
BEGIN IMMEDIATE;
UPDATE export_job AS j SET state='ready'
WHERE j.tenant='org1' AND j.job_id='J1' AND j.state='queued'
AND EXISTS(SELECT 1 FROM grant_row g
WHERE g.tenant=j.tenant AND g.user_id=j.user_id
AND g.store=j.store AND g.active=1 AND g.rev=j.grant_rev)
RETURNING job_id,state;
COMMIT;
-- download authorization: one row before revocation
SELECT j.job_id FROM export_job j JOIN grant_row g
ON g.tenant=j.tenant AND g.user_id=j.user_id AND g.store=j.store
WHERE j.tenant='org1' AND j.job_id='J1' AND j.user_id='u1'
AND j.state='ready' AND g.active=1 AND g.rev=j.grant_rev;
BEGIN IMMEDIATE;
UPDATE grant_row SET active=0,rev=rev+1
WHERE tenant='org1' AND user_id='u1' AND store='A';
UPDATE export_job SET state='cancelled'
WHERE tenant='org1' AND user_id='u1' AND store='A'
AND state IN ('queued','ready');
COMMIT;
-- Repeat the same download SELECT: expected zero rows.
SELECT j.job_id FROM export_job j JOIN grant_row g
ON g.tenant=j.tenant AND g.user_id=j.user_id AND g.store=j.store
WHERE j.tenant='org1' AND j.job_id='J1' AND j.user_id='u1'
AND j.state='ready' AND g.active=1 AND g.rev=j.grant_rev;
SELECT rev,active FROM grant_row WHERE tenant='org1'
AND user_id='u1' AND store='A';
SELECT state FROM export_job WHERE tenant='org1' AND job_id='J1';
逐步结果及反例
申请后J1为queued,生成返回J1/ready,首次领取查询返回J1;撤权后授权应为rev=2、active=0,任务为cancelled,同一领取查询返回零行。若先撤权再生成,生成条件也不成立。另一组织或另一用户即使知道J1,完整查询条件仍不应返回该任务。
重新授权必须继续递增rev,旧任务不能仅因active恢复为1就被复活;需要新任务和新申请范围。生成失败可留queued及独立失败记录,由负责人决定重试或取消,不能把空文件标记ready。多店报表应另有不可变门店集合并逐店核授权,不能把本例单店模型直接冒充总部全范围实现。
文件系统边界与采购意义
SQL只是授权决策。若对象存储已经发出长期可访问的直链,后续数据库拒绝不能自动撤销该直链;文件访问应经过可复核授权的服务,或有明确短时授权及失效方案。领取与撤权同时发生时,还需约定请求生效边界和在途传输处理,不能承诺追回已下载副本。
现场验收要记录申请、生成、撤权、下载四个时间与实际文件范围,分别测试旧页面和原文件入口。日志只能支持本次版本与场景结论,不能推出全部连锁权限通过。本SQL未执行,不存在本地示例、云部署或微订客户实测结果。
菜单发布采用发送意图与门店条件应用
连锁点餐上云的菜单故障可具体化为总部改价后门店售罄,回退又覆盖售罄。以下是通用设计,非微订现网实现:menu_change以(tenant,change_id)唯一保存字段补丁、base_version、目标门店集合快照及payload_hash;delivery以(tenant,change_id,store_id)唯一保存queued/sending/unknown/applied/conflict/failed和门店确认版本;outbox以(tenant,change_id,store_id,event_type)唯一保存发送意图。
总部受理事务先核认证范围与申请身份,相同编号不同补丁报冲突;检查字段策略和依据版本后同时写change、各店delivery及outbox,任何写入失败全部回滚。发送者条件取得queued到sending,向同一门店使用原change_id;超时转unknown,只查原应用结果。重送前必须确认原操作未应用,重复接收按相同身份查原结果。
门店应用事务先查操作身份,再按固定顺序锁目标字段,匹配原依据版本才应用批准补丁并存applied。门店售罄与总部价格分属不同字段,回退仅恢复原改价字段;后续同字段已变则conflict,由授权者审阅当前值。applied回执重复不再写字段,历史确认不能回退已生效新版本。
自设输入总部价2000分变2200分,A店随后售罄=true;按约定撤销改价,预期价回2000分且售罄保留。若A店价格也已变2100分并由规则允许覆盖,回退显示冲突,原已付订单仍按成交快照解释。发送丢响应时按原change_id查,不能新建批次掩盖unknown。上述表、状态转换及正常/异常输出为未运行的扩展设计,旧SQL结果不算本轮实测。
作者:微订(上海逊柯计算机科技有限公司)。