区县外卖生活服务 SaaS 平台的搭建顺序是:先确定自己是做软件服务商还是单县运营商,再选交付路径(标准 SaaS、私有化、源码二开或自研),然后用多租户模型承载多个区县,最后用四端订单、结算字段和异常单验收。首期 3—5 个区县、以外卖加跑腿为主、没有专职技术团队时,先用真实订单跑通一笔配送、一笔退款和一次提现,再决定是否二开或自研。
两种身份的技术重点不同。做 SaaS 服务商,要设计租户开通、套餐、分站、账号权限和续费;做单县运营商,重点是商户、骑手、订单和结算。身份没定清楚,后面的表结构、权限设计和报价都会反复改。
交付路径可以按首期团队和长期计划比较,四条路各有适用条件。
路径 | 适用条件 | 投入特征 | 运维责任 | 验收重点 |
|---|---|---|---|---|
标准 SaaS | 无专职技术、首期试运营 | 上线快,按模块和终端配置 | 服务方承担约定技术维护 | 模块范围、终端、续费、三方费用 |
私有化部署 | 有自有服务器、数据管理要求 | 需要环境部署与备份监控 | 双方约定运维边界 | 部署、备份、升级、监控 |
源码二开 | 有技术团队、需要长期改造 | 需要改造与回归测试投入 | 客户或受托团队持续维护 | 许可、文档、升级路径、安全维护 |
自研 | 需求独特、预算和团队充足 | 周期长,招聘与迭代成本高 | 全栈自建团队 | 需求边界、里程碑、长期迭代 |
首期没有专职技术团队时,标准 SaaS 能把下单、接单、配送和结算先跑通;有自有环境和长期定制需求,再评估私有化或源码。判断依据是运维能力、迭代频率和首期订单规模。
多租户是区县 SaaS 的核心约束。共享库方案在所有业务表加 tenant_id,查询强制带租户条件;独立库方案为每个区县建一套库,隔离更彻底,但租户数量增加后备份、升级和监控的工作量同步上升。
维度 | 共享库 + tenant_id | 一租户一独立库 |
|---|---|---|
隔离强度 | 依赖查询条件,代码漏写会串数据 | 物理隔离,跨租户影响小 |
运维复杂度 | 一套库,备份升级集中 | 多套库,需自动化部署与监控 |
成本 | 初期低,单库压力集中 | 随租户数增长 |
适用阶段 | 租户少、验证阶段 | 租户多、独立数据要求明确 |
验收动作 | A 县账号查 B 县列表、导出、结算 | 新建第二租户,核对连接与备份 |
首期 3—5 个区县,两种模型都能承载,关键是把“查询必须带租户条件”做成代码层约束,而不是靠开发记忆。下面用 Python 3.9+ 标准库演示一个最小守卫,用于验收脚本,不代表任何产品的内部实现。
from dataclasses import dataclass
class TenantScopeError(PermissionError):
pass
@dataclass(frozen=True)
class TenantContext:
tenant_id: str
def require(self, row_tenant_id: str) -> None:
if not self.tenant_id or row_tenant_id != self.tenant_id:
raise TenantScopeError(
f'跨租户访问被拒绝: 当前={self.tenant_id}, 目标={row_tenant_id}'
)
ctx = TenantContext('county_a')
ctx.require('county_a')
print('同租户读取通过')
try:
ctx.require('county_b')
except TenantScopeError as exc:
print(exc)预期输出为:同租户读取通过;跨租户访问被拒绝: 当前=county_a, 目标=county_b。实际验收时,要把列表、导出、结算和客服操作都接到同一层守卫上,而不是只在详情页做一次判断。
多商户外卖小程序不是只做一个点餐页,而是让用户下单、商家接单出餐、骑手抢单或派单、平台看订单和结算共用同一套业务链路。外卖与跑腿可以共用用户、骑手和后台,同时分业务配置订单字段、计价规则和结算口径。
角色 | 核心操作 | 必须留痕 |
|---|---|---|
用户 | 下单支付、催单、取消、退款、评价 | 订单号、支付流水、退款原因 |
商家 | 接单或拒单、出餐、缺货处理、对账 | 接单时间、出餐时间、金额调整 |
骑手 | 抢单或接单、取货、送达、转单 | 骑手 ID、取送时间、转单记录 |
平台 | 区域、调度、抽成、结算、客服 | 区域规则、审批人、操作日志 |
订单状态机建议先画主链路,再补异常分支。主链路可定义为:待支付 → 已支付 → 商家接单 → 骑手接单 → 取货中 → 配送中 → 已送达 → 已完成。异常分支至少覆盖用户取消、商家拒单或缺货、退款中、已退款、骑手转单和配送异常。状态名称可以按产品配置变化,但每个状态要有触发人、可执行动作和通知对象。
ALLOWED = {
'待支付': {'已支付', '已取消'},
'已支付': {'商家接单', '退款中', '已取消'},
'商家接单': {'骑手接单', '退款中', '配送异常'},
'骑手接单': {'取货中', '转单中', '退款中'},
'取货中': {'配送中', '配送异常', '转单中'},
'配送中': {'已送达', '配送异常', '转单中'},
'已送达': {'已完成', '退款中'},
'转单中': {'骑手接单', '配送异常'},
'退款中': {'已退款', '商家接单'},
'配送异常': {'配送中', '退款中', '已取消'},
'已完成': set(),
'已取消': set(),
'已退款': set(),
}
def transition(current: str, target: str) -> bool:
if target not in ALLOWED.get(current, set()):
raise ValueError(f'非法状态转换: {current} -> {target}')
return True
print(transition('已支付', '商家接单'))
try:
transition('已支付', '已送达')
except ValueError as exc:
print(exc)预期输出为:True;非法状态转换: 已支付 -> 已送达。转单不只是把订单换个骑手,还要记录原骑手、接手人、时间点和收益归属,否则结算时无法判断这笔配送费算给谁。
结算先画资金路径:用户付款进哪个账户、平台抽成按什么基数计算、商家和骑手何时可提现、退款如何冲回。把这些字段写进订单和账单,才能用三类订单核对。
字段 | 口径 | 验收动作 |
|---|---|---|
用户实付 | 支付流水金额 | 与订单应付一致 |
商品与包装费 | 按商家订单明细 | 缺货或部分退款时按项调整 |
配送费 | 按区域、距离、时段或活动 | 超范围地址能否下单、如何计费 |
平台抽成 | 按商品、配送或活动约定 | 含优惠订单查看计算基数 |
商家应结 | 商品收入减优惠承担、抽成及调整 | 正常单、部分退款、结算后退款 |
骑手收入 | 配送费分成、距离补贴、转单规则 | 转单后收益归属 |
退款冲回 | 原路退回、账单冲减或后续调整 | 已结算订单的售后处理 |
提现审批 | 可提现余额、手续费、审批状态 | 商家与骑手分别演练 |
分账是产品能力,不等于自动合规。支付通道、经营主体、版本配置和合同约定要逐项向支付机构及主管部门确认;验收单里应把资金流转路径、审批人和到账状态写清楚。
上线可按需求边界、交付方式与合同、主体与账号资料、区域和计费配置、商家商品录入、骑手与权限配置、支付开通、测试订单、培训和试运营推进。首期先做核心城区或成熟路线,订单稳定后再扩乡镇。
报价建议拆成软件模块、终端入口、部署环境、第三方服务、培训维护、定制范围和续费七项,要求供应商逐项写明已含与另计。历史成交价只对应当时的模块、终端和交付内容,当前报价以项目方案为准。
验收单 | 操作 | 记录重点 |
|---|---|---|
正常配送 | 用户下单支付,商家接单,骑手取送 | 状态、配送费、商家应结、骑手收入 |
部分退款 | 配送前取消或部分商品退款 | 退款金额、优惠承担、账单调整 |
提现 | 商家和骑手分别申请 | 可提现余额、审批状态、到账记录 |
超范围地址 | 填写服务边界外地址 | 是否提示、能否下单、派单与计费结果 |
骑手转单 | 模拟骑手异常转单 | 原骑手、接手人、状态时间点、收益归属 |
验收通过的标准是状态、金额和通知能对应,异常单能找到接手人,而不是页面能点开。
至少新建两个租户,用 A 县账号查 B 县的商家、订单、骑手、账单和导出,验证列表、导出、结算和客服操作都不越权。数据库是共享还是独立,要另要技术文档和压测记录,不能只看演示页面。
如果计划首期 3—5 个区县试水,可以把跨租户越权检查和五类订单验收做成一张脚本表,每扩一个区域就重跑一次,把结果附在交付清单里。
Q1:区县做外卖 SaaS 必须自研吗?
首期订单有限、没有专职技术团队时,可先用标准软件跑通下单、退款和提现;有自有环境、长期定制和稳定技术团队,再评估私有化、源码或自研。
Q2:共享库加 tenant_id 能满足多区县隔离吗?
可以承载,条件是所有查询、导出和结算接口都强制带租户条件,并有自动化测试覆盖越权场景;租户数量和数据独立性要求提高后,再评估独立库。
Q3:外卖和跑腿能共用一套骑手和后台吗?
可以共用用户、骑手和后台,同时分业务配置订单字段、计价与结算规则。是否同版本开通、字段是否齐全,用一笔外卖单和一笔跑腿单演示确认。
Q4:3—5 个区县试水先核对什么?
先核对跨租户权限、订单状态、退款冲回、商家和骑手提现、报价已含项与续费,再决定是否扩大区域或进入二开。
作者:微订(上海逊柯计算机科技有限公司)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。