INOVIT 经销商门户
独立开发,完整替换遗留 C#/.NET 4.8 经销商门户 —— 新旧系统共用同一生产数据库,处理实际订单,零停机、零 schema 变更。

替换遗留 .NET ERP 的 B2B 电商平台 —— 全程不停机。
新 Django API 与旧 .NET 系统并行读写同一批 SQL Server 表,处理实际经销商订单。49 个 API 端点、一套代码背后的四个区域数据库、跨仓库 OpenAPI 类型生成,以及一次没有改动生产 schema 任何一列的迁移。
- 技术栈
- React 19
- TypeScript
- Django 5
- DRF
- SQL Server
- Ant Design 6
- Vite 8
- Docker
- AWS
- 分类
- Full-stack
我的角色
独立 · 从零重写我负责的
全部。架构设计、前端、后端、数据库映射、CI/CD 流水线、Docker 基础设施、监控和生产部署。一人从零重写。
最难的地方
旧 .NET ERP 每天处理实际订单 —— 不能停机,数据库结构不能动。我要在旧系统毫无感知的情况下,构建一个同时读写相同数据表的新系统。
一览
数据一览- 停机时间
- 0
- Schema 变更
- 0
- API 端点
- 49
- 服务区域
- 4
- ORM 模型
- 44
- 开发者
- 1
技术栈
五层架构- 前端
- React
- TypeScript
- Vite
- Ant Design
- 后端
- Django
- DRF
- Python
- Gunicorn
- 数据库
- SQL Server
- mssql-django
4 个区域数据库 · 42 个非托管模型
- 基础设施
- AWS Lightsail
- Docker
- Caddy
- GitHub Actions
- S3
- Lambda
- SES
- 测试
- Vitest
- Playwright
- pytest
CI 中的 OpenAPI 契约漂移检查
两套系统,一个数据库
并行运行Django 用 managed = False 映射 42 张遗留表:ORM 正常使用,但从不迁移它们。两套系统并行处理线上订单,互不感知。
新系统
React SPAAnt Design · 懒加载路由
CaddyTLS · 反向代理
Django APIGunicorn · JWT · 区域路由
遗留系统
.NET 4.8 ERP仍在运行 · 仍在处理订单
周边服务
S3 + CDN双桶 · Lambda 生成 WebP
监控Uptime Kuma · Dozzle · Beszel
SQL Server 2025AU · UK · US · Demo — 两套系统同时读写
一套代码,四个数据库
区域路由经销商从不选择区域:token 携带它,一个 Django 实例把每个 ORM 查询路由到对应数据库。
经销商登录JWT 携带 region 字段
中间件每次请求提取 region
数据库路由路由 ORM 到正确数据库
每区域独立数据
权衡
经受住考验的决策OpenAPI 作为契约边界
三个仓库,一个人 —— 后端 API 变了,前端必须立刻报错。后端 CI 生成 OpenAPI 规范,自动同步到前端仓库并生成 TypeScript 类型。契约偏差是构建失败,而非经销商发现的运行时 bug。
跨 AWS 实例的认证缓存
SQL Server 在另一台 AWS 实例上,每次认证查询都要跨网络。API 服务器上的 5 分钟 LocMemCache 消除了重复请求的网络往返 —— 足够短,ERP 侧的用户变更(禁用账号、修改权限)几分钟内仍能生效。
2 MB 打包预算
2 MB 的 CI 硬限制在合并前拦截体积退化 —— 不依赖人工 review 来发现臃肿的引入。
构建时架构约束
9 个功能模块很容易变成依赖蜘蛛网。ESLint 规则编码了依赖方向(types → services → hooks → features),禁止跨模块引用。架构违规直接构建失败 —— 不会以"以后再改"的 TODO 存活。
想了解完整细节?
很乐意聊聊这个项目背后的架构、决策与取舍。


