坡晓馒 poxiaoman.com 全栈架构拆解:一个 Worker + 一个数据库,撑起顾客下单、收银 POS、老板后台
2026-06-14
一句话:整套系统没有传统服务器,就是一段跑在 Cloudflare 上的程序 + 一个小数据库,对外是三个网址(顾客下单、老板后台、收银 POS),对内共用同一套数据。所以老板看到的营收 = 线上单 + 线下单,自动合并;同一份订单,顾客看是「套餐」,后厨看是「要做几个包子」。
说明:本文讲的是真实上线的系统(poxiaoman.com),重点在「为什么这样设计」,技术名词第一次出现都会用大白话解释。
整套系统的骨架其实很简单:
poxiaoman.com —— 顾客下单;boss.poxiaoman.com —— 老板后台;pos.poxiaoman.com —— 收银台 POS(店员到店收银)。三个网址背后是同一段程序、同一个数据库。这一点是整个系统的灵魂:数据只有一份,谁写的单都进同一张订单表,所以营收、对账、备货全都自动合并,老板不用对两本账。
「serverless(无服务器,不是真没服务器,而是你不用管服务器——平台帮你按请求自动跑、自动扩容、不用时不收钱)」。对一个包子店来说,这意味着没有运维、平时几乎零成本。
顾客、老板、店员看到的界面完全不同,但底下读写的是同一批数据:
| 入口 | 谁用 | 它其实在做什么 |
|---|---|---|
| 顾客站 | 顾客 | 往订单表写一条待付款单;查自己的会员数据 |
| 收银 POS | 店员 | 往订单表写一条已付的「线下单」,标记是哪个收银员 |
| 老板后台 | 老板 | 读订单表,算营收、画备货图、对账 |
这就是「一份数据、多种视图」:不复制数据、不同步、不对账,而是让不同的人用不同的「眼镜」去看同一张表。
一个最能说明问题的例子是「生产计划」——
顾客下的是「科学平衡盒」「高蛋白组合」这些套餐;但后厨需要知道的是「鲜肉包做几个、青菜包做几个」。系统里存了一张「BOM(物料清单,bill of materials,就是「一个套餐由哪些单品、各几个」组成的配方表)」,把当天所有订单按 BOM 展开求和,就得到一张「今天每种包子要做多少」的柱状图。同一份订单,换个视图,就从「卖了什么」变成「要做什么」。
涉及钱的地方,系统用一台状态机来管——每张订单的付款状态只能按固定规则走,绝不乱跳:
未付款 ──付款成功──▶ 已付款(自动加积分、通知老板)
未付款 ──失败/超时──▶ 失败 / 过期
已付款 ──退款──▶ 已退款(自动扣回积分)
光有流程还不够,钱要算得对,靠三道「防线」:
这三道防线是用伪造的付款事件逐条压测过的:正常付款、重复通知、金额不符、退款、坏签名——结果全部符合预期。钱的事,不靠「应该没问题」,靠「测过」。
最早会员只是「按手机号记积分」。但一旦加了「储值余额」(顾客可以充钱进账户,比如充 500 送 80),「只凭手机号」就成了漏洞——别人知道你手机号就能花你的钱。于是会员升级成了真账户:
这里有个通用的教训:加了新功能,常常会让旧的「方便」变成新的「风险」。系统里一放「钱」,原来「凭手机号查会员」的便利设计立刻得收紧。
系统会在没人盯着的时候自己干活,靠两样东西:
这些通知都做成了「接好但默认关着」——代码就绪,等接上 WhatsApp 的官方凭证就自动开启,不用改一行逻辑。
这套系统在很多地方选了「更省、更简单」的做法,值得说一下为什么:
| 选择 | 为什么 |
|---|---|
| 无状态令牌(不建会话表) | 服务器不用存任何登录态,验证时重算签名即可——零数据库读、天然能扩容 |
| 商品/订单/会员都进一个 D1 | 数据一份,营收/对账/备货自动合并,不用同步两套 |
| 支付二维码、状态机都「手写」不引库 | 边缘函数冷启动快、部署小、依赖少、不容易出意外 |
| 中英文用一个小词典切换 | 不引翻译库,商品名直接取数据库里已有的中英双名 |
| 配色/品牌写成一组变量 | 改主题只改一处 |
核心思路是:一个小店的系统,不需要大公司那套重型架构。一段边缘程序 + 一个小数据库,把「一份数据、多种视图 + 钱的事严谨」这两件事做扎实,就够撑起顾客下单、收银、对账、会员、备货一整套。
复杂的不是技术堆叠,而是想清楚同一份数据要被谁、以什么方式看。把这件事想透,剩下的就是一段不长的程序——但每一处碰到钱的地方,都得当真。