QX Garage门店数字化交付

Java 重构与运营后台 · 实施计划

版本 v1 · 2026-11-10 · 对象:门店系统(现 Python 版已可用)→ Java 版 + 多租户运营后台

结论:门店端前端不动,只换后端;运营后台新写。 六个阶段,每阶段都能独立跑起来看效果, 总计约 48 人日 / 10–11 周(单人)。期间现有 Python 版继续对外演示和试跑,不停摆。

进度:P0 ✅ · P1 ✅ · P2 ✅ · 门店端页面已接 ✅ · P4 后台可管 ✅(2026-11-10)。 P0 = 骨架(登录 / 租户隔离 / 订阅状态 / 到期策略 / 后台只读); P1 = 核心(客户 / 车辆 / 价目表 / 工单 / 状态机 / 结算 / 交车 / 提醒); P2 = 增值(配件库存与领料、成本毛利、员工提成、营业大屏、客户看板、预约、打印数据、客户导入); 门店端 16 个页面已指向 Java 后端并逐页走查(开单 → 开工 → 完工 → 收款 → 交车、领料退料、打印、提成、大屏、看板、预约、设置); P4 = 运营后台写操作(建店 / 续费换套餐 / 到期策略 / 停用恢复 / 冒充登录 / 收款 / 审计 / 套餐改价)。 接口验收 136 项全绿(P0 27 + P1 33 + P2 46 + P4 30),线上 qxdemo.agent2.0755xzb.club 跑通。 剩下:车主端公开页(预约 / 查进度 / 报价)与短信验证码。

1 这份文档要你确认什么

要确认的我的建议
语言与框架Java 21 + Spring Boot 3.3 + MyBatis-Plus + PostgreSQL 16
前端怎么办不重写。现有 Vue3 手机端只改 API 地址,页面一行不动
分几步做6 步(P0 骨架 → P5 上线),每步有可验收的产物
三档套餐按你给的报价:6800/12800/39800 建设 + 1800/2800/9800 年费,功能开关见第 6 节
到期怎么处理后台按租户配:正常 + 横幅提醒 / 只读 / 禁止登录;默认「只读 + 7 天宽限」

2 原则:是重构,不是翻译

最省事的做法是把 Python 的 2000 行逐段翻成 Java——那会得到一套更重、更慢、更难改的系统。这次换语言的价值在于三件事,只有这三件事值得做:

  1. 订阅体系进内核。Python 版没有任何「套餐/到期」概念,现在只能在外部用表格管。Java 版把租户生命周期做成一等公民,到期自动限权。
  2. 并发与数据安全。PostgreSQL + 连接池 + 事务,替代单机 SQLite 的串行写;租户隔离用拦截器强制注入,而不是每个 SQL 手写 tenant_id=?。
  3. 可交付性。jar + docker compose 一键部署,甲方 IT 看得懂;迁移脚本、审计日志、接口文档齐全。
明确不做:不换前端、不做微服务、不上 Redis/MQ、不做多活。单店规模用不上,加了只会让运维更难。

3 技术选型(已定)

层选择为什么
语言 / 运行时Java 21 LTS长期支持,虚拟线程可用,Spring Boot 3 要求 17+
框架Spring Boot 3.3.x生态最全,招人最容易
持久层MyBatis-Plus现有逻辑全是手写 SQL,迁过来几乎能照抄;JPA 反而要重写映射
数据库PostgreSQL 16免费、JSONB 存功能开关、并发好;比 MySQL 更适合多租户
迁移Flyway版本化 DDL,甲方环境升级可追溯
鉴权Spring Security + JWTaccess 2 小时 / refresh 30 天;门店端与运营端两套密钥
门店前端现有 Vue3(不动)只把 baseURL 指向 Java 服务
运营后台前端Vue3 + Element Plus表格/表单/筛选是后台的主场景,Element 最省时间
部署docker compose(app + pg + nginx)单机可跑,连锁也能横向加一节点
监控Actuator + 日志轮转 + pg_dump 定时够用,不引入 Prometheus

4 六个阶段的实施计划

每一阶段结束都有能点开看的东西,不是等到最后才联调。工期为单人净开发日。

阶段交付物范围与验收工期
P0
骨架
工程骨架、数据库、鉴权、OpenAPI 多模块 Maven(core / store-api / admin-api);Flyway 建表;JWT 登录打通; 租户解析拦截器(tenant 只从 token 取,绝不从 URL 取);统一响应 {ok,data,error}; Swagger 可访问。验收:登录拿 token → 调 /me 返回租户列表 4 天
P1
核心业务
客户、车辆、项目、工单、结算 开单(车牌自动带客户)、状态机 created→in_progress→pending_pay→done、 结算事务(写工单+客户累计+保养提醒)、提醒列表、价目表 CRUD。 验收:用现有演示数据走完「开单→开工→完工→收款」,金额与 Python 版逐分对齐 12 天
P2
增值业务
配件、提成、大屏、客户看板、预约、交车、打印、导入 领料扣库存与成本进毛利;提成规则与结算计提;大屏 5 指标 + 7 天趋势; 客户看板脱敏;预约到店与转工单;交车与「待交车」阶段;A5/A4 打印数据;CSV 导入。 验收:与 Python 版同一套截图逐项对照,数字一致 10 天
P3
公开端
报价页、H5 预约、查进度、openid 无登录接口 /pub/**:门店信息、自助预约(限频)、车牌+尾号查进度(无金额)、 报价 token 页与确认回写、openid 绑定。 验收:手机微信里打开能约、能查,抓包里看不到任何金额 6 天
P4
运营后台
租户/套餐/订阅/收款/到期策略/审计 见第 8 节页面清单。核心是订阅校验拦截器:到期后门店端按策略返回 402/403 并在页面顶部挂横幅。 验收:后台把某店改成「到期 + 只读」,该店立刻不能开单但能查;改回正常立刻恢复 10 天
P5
迁移上线
数据迁移、双跑、压测、文档 SQLite → PG 迁移脚本(客户/车辆/工单/明细/配件/提成/预约);两套并行 1 周对账; 50 并发压测;备份与恢复演练;部署手册 + 运维手册。 验收:迁移后订单数、金额合计、客户数三项完全一致;恢复演练能在 10 分钟内还原 6 天
合计(不含缓冲) 48 天

按每周 5 天计 = 9.6 周;加上联调、评审、甲方反馈,现实排期 10–11 周。若并行招一个前端做后台页面,可压到 8 周。

5 多租户与订阅模型

沿用「共享库 + tenant_id」——门店数量在几十的量级,分库是负担。关键是隔离由框架保证,不靠人记得写。

表关键字段说明
tenantid, name, city, phone, address, bays, status, created_atstatus: trial / active / grace / readonly / suspended
plancode, name, build_fee_cents, year_fee_cents, max_bays, max_staff, features(jsonb)三档套餐,功能开关放 JSONB
subscriptiontenant_id, plan_id, started_at, expires_at, grace_days, expire_policy, auto_renewexpire_policy: warn / readonly / block
tenant_contacttenant_id, owner_name, phone, wechat, address, signer, note你要的「客户联系方式」
paymenttenant_id, amount_cents, period_from, period_to, method, paid_at, note先手工记账,不接支付
audit_logactor, action, target, before, after, ip, created_at谁改了谁的套餐,可追溯

租户隔离怎么保证:MyBatis-Plus 的 TenantLineInnerInterceptor 自动给每条 SQL 追加 tenant_id = ?, 值来自 JWT 解析出的上下文;URL 里出现的 tenantId 只用于校验是否属于该用户,不参与取数。 这样即使某个新接口忘了写条件,也不会串店。

6 三档套餐与功能开关

按你给的报价,建设费一次性、年费按年。功能按「店里真的会用到的」划,不要用虚的功能数量区分。

项目轻量版标准版连锁版(3 店)
建设费¥6,800¥12,800¥39,800
年费¥1,800 / 年¥2,800 / 年¥9,800 / 年
门店数113
工位上限61212 / 店
员工账号515不限
工单 / 结算 / 提醒✓✓✓
打印接车单 / 结算单✓✓✓
客户导入✓✓✓
配件库与领料—✓✓
员工提成—✓✓
客户看板(挂墙)—✓✓
客户 H5(预约 / 查进度)—✓✓
老板营业大屏—✓✓ + 总部看板
跨店客户 / 统一价目表——✓

功能开关存在 plan.features(JSONB),门店请求到未开通的接口返回 403 FEATURE_LOCKED, 页面按提示「该功能在标准版及以上可用」。这样升级套餐不用改代码,后台点一下即可。

7 到期策略(后台可配)

你要求「后台配置型」,所以策略是租户级字段,不是硬编码。三档行为:

策略门店端表现接口行为适用
warn
提示
功能全开,页面顶部常驻黄条「服务已到期,请续费,否则 X 天后停用」全部 200,但响应带 subscription: {expired:true, days_left:-N, policy:'warn'}刚到期、在谈续费
readonly
只读(默认)
能看能查,所有「保存/开工/收款/交车」按钮置灰并说明原因GET 200;写操作 402 PAYMENT_REQUIRED,body 说明到期日与续费入口到期默认策略
block
禁止登录
登录页提示「账号已停用,请联系门店管理员」,不给验证码入口登录 403 ACCOUNT_SUSPENDED;已登录的 token 立即失效欠费久拖、主动停服

另外两个配套开关:

一定要做对的一点:限权必须在服务端。前端把按钮藏起来只是体验,接口仍要拦。 Python 版现在没有这层,所以这次把「订阅检查」做成拦截器,放在业务逻辑之前——绕过它的唯一办法是改代码。

8 运营后台页面清单

页面内容
1. 登录运营人员账号(与店主账号两套体系),支持二次验证(预留)
2. 租户列表搜索(店名/城市/电话)、状态筛选、到期倒计时(剩 ≤7 天标红)、套餐、客户数、最近登录
3. 租户详情门店信息 + 联系人 + 套餐与到期 + 用量(客户/工单/员工/工位数)+ 订阅历史; 操作:续费、换套餐、延长试用、改到期策略、停用/恢复、冒充登录看数据、重置店主密码
4. 新建租户填店名/城市/电话 + 选套餐 + 设试用天数 → 一键生成店主账号并初始化价目表
5. 套餐管理三档的价格、工位/员工上限、功能开关(勾选式),改完即时对所有新订阅生效
6. 到期提醒按剩余天数分组,显示负责人与电话,一键复制催费话术
7. 收款记录手工登记:金额、期间、方式、经手人;租户详情里能看到累计实收
8. 审计日志谁在什么时候改了哪个租户的什么字段,前后值对比

9 数据迁移与上线

  1. 迁移脚本:SQLite 导出 → 字段映射 → 灌入 PG。规则:租户 id 保留(t1/t2/t3),工单号保留, 金额(分)原样,时间保留;自增 id 重新生成并建映射表,供迁移报告核对。
  2. 对账三项:工单数、收款合计、客户数。三项一致才算迁移成功,缺一不可。
  3. 双跑一周:新系统只读,旧系统继续写;每天跑一次增量同步 + 对账,观察差异。
  4. 切换窗口:选门店打烊后 1 小时,冻结旧系统写入 → 最后一次增量 → 切 DNS/反代到 Java 服务 → 冒烟测试 10 项。
  5. 回滚方案:反代配置保留旧服务 7 天,出问题 5 分钟内切回。

10 风险、工期与报价

风险影响应对
工期滑点3 个月没有新单每阶段可演示;P1 结束就能替换核心业务,不必等全部完成
Java 无人维护后续改动变慢只用主流组合,不写自研框架;接口与表结构文档随代码走
迁移丢数据客户信任崩塌三项对账 + 双跑一周 + 7 天回滚窗口
过度设计成本膨胀不做微服务、不上 Redis/MQ、不做多活
口径金额说明
开发总量48 人日(10–11 周)单人;含后台前端
对外报价(自建)¥90,000 – ¥130,000按 1,800–2,600 元/人日,含迁移与上线
只做客制化后台(不动后端)¥15,000 – ¥25,0002 周,作为对比项给你参考
私有化部署(甲方机房)+¥20,000 – ¥40,000含安装、数据迁移、培训、一年远程支持

11 待你拍板的 5 件事

  1. 前端不重写(现有 Vue3 只改 API 地址)——同意 / 不同意
  2. MyBatis-Plus 而非 JPA(迁移更快,逻辑可照抄)——同意 / 不同意
  3. 套餐功能划分(第 6 节表格):轻量不含配件/提成/看板/H5,标准全含,连锁加总部能力——照此执行 / 需要调整
  4. 到期默认策略:只读 + 7 天宽限,后台可改——照此执行 / 改成别的默认
  5. 连锁版的「总部看板」要不要放进 P4(会多 2–3 天)——要 / 不要

这 5 条定了,P0 当天就能开工:先把工程骨架、数据库、登录和租户拦截器做出来给你看。