第七节:让 AI 写代码前,先证明权限和数据不会出错
开发任务书冻结以后,AI 终于开始写正式代码。我们没有先接模型,也没有先做最吸引人的聊天界面。

第一阶段不是选 ORM,而是让两个候选做同一道题
D01 需要在 Prisma 和 Drizzle 之间做选择。
如果只让 AI 解释概念,它可以给出一张很完整的优缺点表,但这张表回答不了当前项目真正关心的问题:工单更新、人工确认和审计必须在同一个事务里成功;只要中间一步失败,就不能留下半条记录。
所以两个候选接受了同一组实验:
•
从空数据库执行迁移;重复初始化不能产生脏数据;
•
正常事务同时更新工单、人工结果和审计;工单版本过期时返回冲突;
•
中途制造故障,检查所有写入是否回滚;读取工单及最近一次处理摘要。
⭕
最终 Prisma 和 Drizzle 都能完成核心事务。第一版选择 Prisma,不是因为它在所有项目中都更好,而是它在当前 Next.js + TypeScript 项目里减少了 AI 生成迁移、类型和数据访问代码时的语言切换,并且实验已经证明事务和回滚满足要求。
这里真正值得复用的方法是:技术选择不要问“谁更流行”,要让候选解决同一个业务问题,再比较证据。
登录成功,不代表权限系统已经完成
D02 一共准备了五个合成账号:一线客服、另一团队客服、客服主管、管理员和只读访客。

我们验证的不只是“账号密码能不能登录”,而是下面这些情况:
•
未登录访问受保护接口,返回 401;
•
已登录但没有动作权限,返回 403;
•
资源不属于当前身份范围,返回 404,避免泄露资源是否存在;
•
浏览器伪造 role=admin、x-role 或 x-user-id,服务端仍然按照原身份拒绝;
•
只读访客不能写入;
•
账号停用后,已有会话立即撤销;
•
原始会话值不进入数据库,只保存哈希。

这张截图的重要之处不是页面出现了“无权限”三个字,而是这个结果来自真实服务端接口。
前端隐藏入口只能改善体验,不能构成安全。用户完全可以绕过页面直接请求 API。真正的权限必须在服务端重新验证会话、角色、资源归属和动作。
工单页面首先决定“最少展示什么”
D03 开始实现工单列表、详情、领取、更新和备注。
一线客服可以看到自己负责的完整工单;同组未领取工单只展示主题、分类和优先级等最小摘要;另一团队的工单不会出现在结果中;只读访客只能访问指定演示集。
这个设计提醒了我:页面字段不是“数据库里有什么就展示什么”。每个字段都应该回答:当前角色完成任务真的需要它吗?
企业产品的权限经常不是“整页能看或不能看”,而是同一个对象在不同角色下拥有不同的信息密度和动作范围。
两个人同时修改,不能让后保存的人偷偷覆盖前一个人
工单领取和编辑采用了乐观锁。每次写入都必须携带当前 version。
如果客服打开页面后,另一位同事已经修改了这张工单,旧页面再提交时,服务端返回 409。页面保留尚未提交的选择,让人决定重新加载还是重新应用,而不是静默覆盖别人的结果。
这类失败状态在演示产品里很容易被省略,但它直接决定企业系统能不能承担多人协作。
第一版没有做复杂自动派单和消息队列。我们的并发目标很克制:先证明不会静默丢失数据,再讨论更高吞吐量。
页面报错也必须给人下一步
API 中断时,工单列表不能只剩空白,也不能把“请求失败”显示成“当前没有工单”。页面需要说明系统暂时不可用,保留当前筛选条件,并提供重试入口。
空数据、筛选无结果、无权限、服务异常和真实没有工单,是五种不同状态。它们看起来都可能是“列表里没有内容”,但对用户的解释和下一步完全不同。
每一阶段都要留下失败证据
D01 保存迁移、事务、冲突和回滚结果;D02 保存允许与拒绝矩阵;D03 保存正常页面、无结果、403、409 和 API 中断截图。
AI 完成自测后,只能把阶段改成“待人工验收”。我检查范围、证据和已知限制,再回复“验收通过并冻结”。前一阶段没有冻结,下一阶段不能开始。
这样做以后,我不需要逐行判断代码写得漂不漂亮。我只需要判断:业务事实是否成立,失败时会不会伤害用户,证据是否足以支持“完成”这个结论。
可以直接交给 AI 的执行要求:
代码块
Plain Text
先不要接入模型。
请按数据一致性、服务端权限、工单核心业务三个阶段执行。每阶段分别列出正常路径、失败路径、权限边界、自动测试、页面截图、已知限制和停止条件。
所有权限由服务端决定;浏览器角色参数不构成授权。
到这里,项目终于有了可以信任的业务地基。下一步才进入 D04:不是把几份 PDF 塞进向量库,而是用一套合成企业文档,真正验证中文检索、版本、停用和无答案处理。