跳到主要内容
返回项目档案
独立作品进行中

服务市场 · 双边撮合平台

用一套统一模型承载本地服务与技能服务:发布 → 下单 → 接单 → 履约 → 评价全闭环,多包单仓 + 契约单点

角色
架构设计与全栈实现(单人)
量级
3 端 · 12 张核心表 · 契约单点
时间
2026年10月 — 至今
TypeScriptNestJSPrismaPostgreSQLRedisBullMQVue 3Element PlusVantpnpmTurborepoZodDocker Compose

做了什么

  • 一套模型承载两类服务:本地服务与技能服务共用服务商品与订单,差异收敛到分类属性与履约字段,避免双模型长期维护成本
  • 角色而非账号:服务者只是用户身上的一个角色,同一自然人可同时是需求方与服务者,账号 / 鉴权 / 地址 / 文件全部复用
  • 多包单仓 + 契约单点:pnpm + Turborepo 组织 api / admin / web,packages/shared 收敛类型与接口定义,类型端到端
  • 文档先行:AGENTS.md 规定设计、接口、库结构必须先文档后代码,接口清单与 Apifox 不一致视为任务未完成
  • 明确不做:支付分账、小程序、实时 IM、智能派单都写进 Non-Goals 并给出触发条件,避免范围蔓延

起点:两类服务,不能写两套模型

平台要同时承载本地服务(保洁、维修、搬家)与技能服务(设计、开发、文案)。它们的履约形态完全不同: 前者强依赖地址、服务范围与预约时段,后者强依赖交付期限、交付物、验收与改稿次数。

最省事的做法是各建一套表,但代价是每加一个功能都要写两遍、每次改需求都要对齐两处。 所以先解决建模:同一套服务商品与订单模型,把差异收进分类属性与履约字段,让主流程只有一条。

角色模型:服务者是角色,不是账号

PROVIDER 不是独立账号体系,而是 User.roles 里的一个角色。好处很直接:

  • 同一自然人既可以是需求方也可以是服务者,不用注册两个账号;
  • 鉴权、地址、文件、评价天然复用,不会出现「两个账号体系各有一套权限」;
  • 运营侧只需要一套用户视图,认证只是给角色加一层审核状态。

工程形态:让 AI 能持续迭代

这个仓库从一开始就是按「AI 编码助手要能长期在这里干活」设计的:

设计 解决什么
pnpm + Turborepo 多包单仓 api / admin / web / shared 在一个仓库,改契约时三端同时可见
契约单点(packages/shared) 接口类型只写一次,前端到后端类型贯通,避免「字段改了前端不知道」
Prisma + 迁移 schema 是唯一事实源,库结构与代码同进同退
AGENTS.md 硬约定 设计 / 接口 / 库结构必须先文档后代码,改完回写文档
Non-Goals 清单 支付、小程序、IM、智能派单明确不做,并写清什么时候做

其中最有价值的是最后一条:把「不做什么」写清楚,比列一堆待办更能防止范围蔓延。

目前状态

已完成用户、服务者、分类、服务商品、订单、订单事件、争议、评价、文件等核心建模,接口与后台骨架跑通; 支付分账、小程序端与智能派单按 Non-Goals 排在 P3,等闭环数据再决定。