23 KiB
电子名片系统技术文档
1. 文档目标
本文档用于定义本项目的技术架构、技术栈、中间件、数据隔离策略、部署方案与工程结构,目标是在满足 JDK 21 + Spring Boot + Vue 3 + TypeScript 约束下,实现一套轻量、稳定、易扩展的多租户电子名片系统。
2. 技术设计原则
- 正确性优先:先保证多租户隔离、权限控制、数据一致性和关键链路稳定。
- 轻量优先:优先采用单体模块化架构,避免过早拆分微服务。
- 稳定优先:使用成熟、社区活跃、可持续维护的主流组件。
- 扩展优先:模块边界清晰,为后续审核流、线索、预约、营销等功能预留能力。
3. 总体架构
系统由 3 个前后端子系统组成:
- 后端服务:统一提供租户、账号、名片、文件、统计等业务接口。
- 后台管理端:供超级管理员、租户管理员、普通用户登录管理数据。
- 微信小程序:面向公众展示事务所与个人电子名片。
说明:
- 后台系统为多租户统一平台。
- 微信小程序按“1 个租户 = 1 个小程序 AppID”设计,每个事务所拥有独立小程序。
- 多个租户的小程序可复用同一套后端服务与同一套代码模板,通过配置完成租户绑定。
flowchart LR
A["超级管理员 / 租户管理员 / 普通用户"] --> B["后台管理端 Vue3 + TS"]
C["微信访客"] --> D["微信小程序"]
B --> E["Spring Boot API"]
D --> E
E --> F["MySQL 8"]
E --> G["Redis"]
E --> H["MinIO"]
E --> I["日志/监控"]
4. 推荐工程结构
建议在当前仓库基础上扩展为如下结构:
easycard/
├─ docs/ # 产品/技术/接口/部署文档
├─ backend/ # Spring Boot 后端
│ ├─ easycard-boot/ # 启动模块
│ ├─ easycard-common/ # 通用基础能力
│ ├─ easycard-module-system/ # 系统管理、权限、日志
│ ├─ easycard-module-tenant/ # 多租户管理
│ ├─ easycard-module-org/ # 组织/事务所信息
│ ├─ easycard-module-user/ # 用户与账号
│ ├─ easycard-module-card/ # 名片管理
│ ├─ easycard-module-file/ # 文件上传与素材管理
│ └─ easycard-module-stat/ # 浏览与分享统计
├─ admin-web/ # Vue3 后台管理端
└─ frontend_miniprogram/ # 微信小程序
说明:
- 当前仓库已存在
frontend_miniprogram/,后续应保持为独立子项目。 - 后端采用“单体应用 + 模块化分层”方案,控制复杂度,同时便于后续拆分。
5. 技术栈选型
5.1 后端技术栈
| 分类 | 选型 | 说明 |
|---|---|---|
| JDK | JDK 21 | 满足长期支持版本要求 |
| 框架 | Spring Boot 3.3.x | 稳定、生态成熟 |
| Web | Spring MVC | 提供 REST API |
| 参数校验 | Spring Validation | 请求参数校验 |
| ORM | MyBatis-Plus | 开发效率高,适合后台管理型系统 |
| 数据库 | MySQL 8.0 | 成熟稳定,部署简单 |
| 缓存 | Redis 7 | 缓存、会话、验证码、热点数据 |
| 鉴权 | Spring Security 6 + JWT | 标准化、安全性强、扩展性好 |
| 对象存储 | MinIO | 轻量、私有化友好,可替换云 OSS |
| 数据迁移 | Flyway | 管理数据库版本与初始化脚本 |
| API 文档 | springdoc-openapi + Knife4j | 自动生成接口文档,方便联调 |
| 日志 | Logback | 默认稳定方案 |
| 对象映射 | MapStruct | 降低 DTO/VO 转换样板代码 |
| 构建 | Maven | Java 生态成熟、稳定 |
| 测试 | JUnit 5 + Spring Boot Test + Testcontainers | 保证接口与数据库集成质量 |
5.1.1 为什么不优先使用微服务
当前场景的核心复杂度在于:
- 多租户隔离
- 角色权限控制
- 小程序与后台双端联动
- 名片内容与文件管理
这些问题本质上更适合“模块化单体”优先解决。若过早拆分为微服务,会明显增加:
- 部署复杂度
- 联调成本
- 配置和监控成本
- 分布式事务与调用链复杂度
因此第一阶段推荐单体架构,待租户数量、访问量和团队规模增长后,再按模块拆分。
5.2 后台管理端技术栈
| 分类 | 选型 | 说明 |
|---|---|---|
| 框架 | Vue 3 | 主流稳定 |
| 语言 | TypeScript | 类型安全 |
| 构建工具 | Vite | 启动与构建速度快 |
| 路由 | Vue Router | 标准路由方案 |
| 状态管理 | Pinia | 轻量清晰 |
| UI 组件库 | Element Plus | 适合中后台、生态成熟 |
| 请求库 | Axios | 简洁稳定 |
| 样式 | SCSS + CSS Variables | 可维护、便于主题化 |
| 表格/表单增强 | Element Plus 原生能力优先 | 减少额外依赖 |
| 图表 | ECharts | 用于统计分析页 |
5.3 微信小程序技术栈
| 分类 | 选型 | 说明 |
|---|---|---|
| 框架 | 原生微信小程序 | 当前仓库已采用 |
| 语言 | TypeScript | 已有基础 |
| 样式 | Less | 当前仓库已采用 |
| 数据请求 | 封装 wx.request |
简洁稳定,避免引入额外运行时 |
| 本地缓存 | wx.setStorageSync / wx.getStorageSync |
用于轻量本地状态,如浏览历史 |
说明:
- 当前小程序已有静态页面和 Mock 数据,后续改造重点是抽离 API 层、租户配置、环境变量管理和错误处理。
- 本项目按“一个小程序对应一个租户”设计,小程序内不再依赖页面参数动态切换租户。
- 小程序租户识别以
AppID为主键,后台需维护AppID -> tenant_id的映射配置。
6. 核心架构设计
6.1 多租户模型
第一阶段推荐使用:
- 共享数据库
- 共享数据表结构
- 业务表统一增加
tenant_id
该方案优点:
- 成本低
- 开发快
- 部署简单
- 适合中小规模 SaaS
需要重点保证:
- 所有租户业务表都必须带
tenant_id - 查询默认按
tenant_id过滤 - 非平台角色不可跨租户访问
- 日志中要记录操作人、租户、操作对象
补充说明:
- 多租户主要体现在后台管理端和后端数据层。
- 小程序虽然是“一租户一 AppID”,但后端仍是统一多租户服务,公开接口和管理接口都需要具备租户隔离能力。
6.1.1 表分类建议
平台级表:
sys_tenantsys_platform_usersys_platform_rolesys_menusys_dicttenant_miniapp_config
租户级表:
tenant_usertenant_roletenant_user_roleorg_departmentorg_firm_profilecard_profilefile_assetcard_view_statoperation_log
6.1.2 未来扩展策略
当单租户数据量或安全要求显著上升时,可平滑扩展为:
- 大租户独立数据库
- 普通租户共享数据库
为此后端需抽象租户上下文与数据访问入口,不把 tenant_id 获取逻辑写死在业务代码中。
6.1.3 小程序与租户绑定模型
本项目推荐采用:
- 后台:多租户统一平台
- 小程序:一个租户对应一个微信小程序 AppID
- 后端:统一一套服务,按小程序配置映射到具体租户
该模式的优点:
- 每个事务所有独立品牌入口,体验更清晰
- 不需要在小程序页面参数中显式传递
tenantCode - 可直接以小程序
AppID作为租户识别主键 - 每个租户可独立发布、独立审核、独立配置微信能力
- 后端仍可复用统一业务代码和统一数据库结构
需要接受的代价:
- 每增加一个租户,就需要新增一个小程序 AppID
- 小程序发布、审核、备案、类目维护成本会随租户数量线性增加
- 构建与配置管理需要支持按租户生成不同发行包
6.2 权限模型
推荐采用 RBAC 模型:
- 用户
- 角色
- 菜单
- 按钮权限点
- 数据范围
角色建议:
PLATFORM_SUPER_ADMINTENANT_ADMINTENANT_USER
权限控制分 3 层:
- 接口层:校验是否登录、是否具备角色/权限。
- 服务层:校验数据归属与业务状态。
- 数据层:统一追加租户过滤条件。
6.3 登录认证设计
6.3.1 后台管理端
采用 JWT Access Token + Redis 组合:
- 登录成功后签发短期 Access Token
- Redis 记录登录会话、验证码和黑名单
- 退出登录时清理 Redis 中的会话信息
这样做的原因:
- 便于水平扩容
- 比传统服务端 Session 更适合前后端分离
- Redis 介入后可控制踢下线、单点登录、风控扩展
6.3.2 微信小程序
小程序端建议区分两类访问:
- 公开访问:无需登录,可浏览公开名片
- 成员访问:后续如需在小程序维护本人名片,可通过微信登录绑定用户
第一阶段的最简实现:
- 小程序仅做公开展示
- 每个小程序在构建时写入固定
AppID配置 - 小程序启动后直接读取当前租户配置并调用公开接口
若后续要支持小程序内登录:
- 前端调用
wx.login() - 后端调用微信
code2Session - 将
openid/unionId与系统用户绑定
6.3.3 小程序如何确定对应租户
由于本项目采用“一个小程序对应一个租户”的模式,因此租户识别以微信小程序 AppID 为主,不再依赖页面参数中的 tenantCode。
推荐落地方式如下:
1. 租户配置表维护小程序信息
建议新增配置表或配置字段:
tenant_idtenant_codeminiapp_app_idminiapp_app_secretminiapp_nameminiapp_original_idrequest_domainpublish_status
其中:
miniapp_app_id是当前方案中的租户识别主键miniapp_app_secret仅后端保存,必须加密存储request_domain用于约束该小程序实际访问的接口域名,可作为辅助校验项
后台管理端需要新增“小程序配置”功能,至少支持:
- 为租户录入和修改
AppID - 配置
AppSecret - 校验
AppID全平台唯一 - 启停用小程序配置
- 查询当前租户是否已完成小程序配置
2. 小程序构建时注入固定租户配置
每个租户的小程序发行包包含固定配置,例如:
export const tenantRuntimeConfig = {
appId: 'wx1234567890xxxxxx',
apiBaseUrl: 'https://api.example.com',
}
说明:
appId是前端运行时的固定配置- 同一个租户的小程序所有页面默认只访问本租户数据
- 不允许在小程序内切换到其他租户
3. 后端接口通过租户上下文处理公开请求
公开接口建议改为以下风格:
/api/open/profile/api/open/cards/api/open/card/{cardId}/api/open/card/{cardId}/view/api/open/card/{cardId}/share
即:
- 小程序端不需要在路径中传
tenantCode - 后端通过
AppID识别当前租户
4. 请求上下文的识别策略
推荐策略如下:
- 小程序请求时显式传递
X-Miniapp-Appid - Spring Boot 在过滤器中解析
X-Miniapp-Appid - 后端查询
tenant_miniapp_config获取对应tenant_id - 将
tenant_id写入TenantContext - 后续查询统一按
tenant_id过滤
请求示例:
GET /api/v1/open/profile
X-Miniapp-Appid: wx1234567890xxxxxx
对应的服务端逻辑:
X-Miniapp-Appid -> tenant_miniapp_config -> tenant_id -> TenantContext
说明:
- 虽然
X-Miniapp-Appid由前端传入,但其值来自构建时固定配置,不是页面动态参数 request_domain可作为辅助白名单校验,避免错误小程序配置访问非目标域名- 对登录态接口和管理接口,仍必须叠加 token 与权限校验,不能只依赖
AppID
这种方式的优点是:
- 实现简单,适合当前单租户小程序模式
- 后端租户识别统一
- 与微信登录场景天然兼容,便于后续通过
AppID + AppSecret调用code2Session
5. 管理端与小程序的数据边界
需要明确:
- 小程序公开接口只返回“已发布、允许公开”的租户信息和名片信息
- 即使攻击者伪造请求,也只能尝试访问公开数据,不应接触后台管理数据
- 后台管理接口仍然必须基于登录态、角色和
tenant_id做严格隔离
6. 构建与发布策略
一个租户一个小程序,建议采用“同一套源码,多套租户配置”的方式发布:
- 公共源码只维护一套
- 每个租户维护一份环境配置
- 打包时选择目标租户配置生成对应小程序包
建议配置文件结构:
frontend_miniprogram/
├─ config/
│ ├─ tenants/
│ │ ├─ dev.default.ts
│ │ ├─ prod.nj_xx_law.ts
│ │ └─ prod.sample.ts
这样可以保证:
- 代码复用
- 配置隔离
- 发版过程可控
7. 结论
在“一个小程序对应一个租户”的前提下,小程序识别租户的核心是:
- 小程序
AppID - 后台维护的
AppID -> tenant_id映射关系 - 小程序请求头中的
X-Miniapp-Appid
后端则通过统一的租户上下文机制,把请求路由到正确的租户数据范围。
6.4 文件存储设计
使用 MinIO 统一管理:
- 租户 Logo
- 用户头像
- 名片二维码
- 封面图
建议做法:
- 按业务分桶或目录管理
- 保存原始文件名、MIME、大小、哈希值
- 生成缩略图或压缩图
- 通过业务表引用文件 ID,而非直接在业务表中散落 URL
6.5 统计设计
统计范围:
- 名片浏览次数
- 名片分享次数
- 热门名片排行
- 按日趋势统计
第一阶段建议方案:
- 实时写入行为日志
- 定时汇总到统计表
这样可以兼顾:
- 原始数据可追溯
- 查询统计页更高效
7. 分层设计
后端建议遵循以下分层:
- Controller:参数接收、鉴权注解、响应封装
- Service:业务编排、事务控制、权限校验
- Domain/Manager:核心领域规则
- Mapper:数据库访问
- DTO/VO:输入输出模型
统一规范:
- 禁止 Controller 直接编写复杂业务逻辑
- 禁止 Service 直接暴露数据库实体给前端
- 输入输出对象分离,避免前端字段误改
8. API 设计建议
8.1 接口风格
- 统一 RESTful 风格
- 统一响应结构:
code、message、data - 列表接口统一支持分页
- 查询接口统一支持关键字、状态、时间区间筛选
8.2 接口分组建议
平台端:
/api/platform/auth/*/api/platform/tenants/*/api/platform/users/*/api/platform/config/*
租户后台:
/api/tenant/auth/*/api/tenant/firm/*/api/tenant/org/*/api/tenant/users/*/api/tenant/cards/*/api/tenant/files/*/api/tenant/stats/*
小程序公开端:
/api/open/profile/api/open/cards/api/open/card/{cardId}/api/open/card/{cardId}/view/api/open/card/{cardId}/share
8.3 版本管理
建议从一开始就保留版本前缀:
/api/v1/...
这样便于未来做不兼容升级。
9. 数据库设计建议
9.1 核心表
建议第一阶段至少包含以下核心表:
sys_tenant:租户信息tenant_miniapp_config:租户与小程序配置映射sys_user:登录用户sys_role:角色sys_user_role:用户角色关系org_department:部门/分所org_firm_profile:事务所主页信息card_profile:个人名片主表card_specialty:名片专业领域file_asset:文件素材card_view_log:名片浏览日志card_share_log:名片分享日志card_stat_daily:名片按日统计表sys_login_log:登录日志sys_operation_log:操作日志
9.2 通用字段规范
每个业务表建议统一包含:
idtenant_idcreated_bycreated_timeupdated_byupdated_timedeleted
说明:
- 平台级表可不包含
tenant_id - 删除建议优先逻辑删除,关键日志表使用物理追加
9.3 小程序配置表建议
建议新增 tenant_miniapp_config 表,用于描述租户与微信小程序的绑定关系。
建议字段:
idtenant_idminiapp_app_idminiapp_app_secretminiapp_nameminiapp_original_idrequest_domainversion_tagpublish_statuscreated_timeupdated_time
用途说明:
- 后台超级管理员或平台实施人员配置租户对应的小程序信息
- 后端在微信登录、发布管理、AppID 识别时使用该表
- 后续若增加多个环境,可在该表中扩展
env字段区分测试和生产配置
约束建议:
miniapp_app_id全局唯一tenant_id与miniapp_app_id建立唯一映射miniapp_app_secret必须加密存储,不向前端返回
10. 部署方案
10.1 部署目标
目标是“轻量、稳定、可私有化部署”,推荐采用 Docker Compose 作为首期部署方式。
10.2 推荐中间件
| 组件 | 版本建议 | 用途 |
|---|---|---|
| Nginx | 1.26+ | 反向代理、静态资源分发 |
| JDK | 21 | 运行 Spring Boot |
| MySQL | 8.0 | 主数据库 |
| Redis | 7 | 缓存与会话 |
| MinIO | 最新稳定版 | 文件存储 |
10.2.1 服务器配置建议
本项目第一阶段目标是“轻量、稳定、可扩展”,因此不建议一开始就采购过重的集群资源。推荐按环境和业务规模分层配置。
1. 开发环境
适用场景:
- 本地开发
- 单人或小团队联调
建议配置:
- CPU:4 核
- 内存:8 GB
- 系统盘:100 GB SSD
部署建议:
- MySQL、Redis、MinIO 可通过 Docker Desktop 或本机服务运行
- 后端、后台前端、小程序开发工具本地启动
2. 测试环境
适用场景:
- 功能测试
- 接口联调
- UAT 验收
建议配置:
- CPU:4 核
- 内存:8 GB 到 16 GB
- 系统盘:100 GB SSD
- 数据盘:100 GB SSD
部署建议:
- 单台 Linux 服务器部署
Nginx + Spring Boot + MySQL + Redis + MinIO - 使用 Docker Compose 管理服务,便于迁移和重建环境
3. 生产环境当前推荐
适用场景:
- 仅服务 1 家事务所
- 约 20 名后台用户
- 小程序访问量较低到中等
- 以名片展示、资料维护、图片上传为主
建议配置:
- CPU:4 核
- 内存:8 GB
- 系统盘:50 GB SSD
- 数据盘:100 GB SSD
- 带宽:3 Mbps 到 5 Mbps
部署方式:
- 单机部署
- 使用 Docker Compose 部署
Nginx + Spring Boot + MySQL + Redis + MinIO
说明:
- 这是当前项目规模下更匹配的正式生产配置
- 对于 1 家事务所、20 名用户,该配置已能覆盖日常访问和后台维护需求
- 若图片、二维码、封面素材不多,
50 GB 系统盘 + 100 GB 数据盘基本足够 - MinIO、MySQL 数据目录建议挂载到数据盘,避免挤占系统盘
4. 容量规划建议
磁盘容量建议重点考虑以下部分:
- MySQL 数据量
- MinIO 文件素材
- 日志文件
- 数据库备份
经验建议:
- 当前项目规模下,初期生产环境总可用磁盘 150 GB 左右即可起步
- 若头像、二维码、宣传海报较多,可将数据盘扩展到 200 GB
- 数据库与对象存储应避免共用过小系统盘
5. 本项目首期推荐结论
按照当前明确范围:
- 1 家事务所
- 约 20 名用户
- 单租户使用
推荐采用以下生产配置:
- 1 台 4 核 8 GB Linux 云服务器
- 1 块 50 GB 系统盘
- 1 块 100 GB 数据盘
- 3 Mbps 到 5 Mbps 带宽
- Docker Compose 部署
Nginx + Spring Boot + MySQL + Redis + MinIO
如果希望多留一些冗余,可升级为:
- 1 台 4 核 16 GB 或 8 核 8 GB Linux 云服务器
- 数据盘提升到 200 GB
当前规模下,不需要一开始就做多机、主从或集群部署。
10.3 部署拓扑
flowchart TB
U["浏览器 / 微信小程序"] --> N["Nginx"]
N --> A["admin-web 静态站点"]
N --> B["backend API"]
B --> C["MySQL"]
B --> D["Redis"]
B --> E["MinIO"]
10.4 环境划分
建议至少划分 3 套环境:
dev:本地开发环境test:测试联调环境prod:生产环境
每套环境均需独立配置:
- 数据库连接
- Redis 地址
- 对象存储地址
- JWT 密钥
- 微信小程序配置
补充说明:
- 由于采用“一租户一小程序”,生产环境需要为每个租户维护独立的小程序生产配置
- 测试环境可使用测试小程序 AppID 或体验版配置
10.5 配置管理
建议采用:
- Spring Profiles 区分环境
- 前端使用
.env.development、.env.test、.env.production - 敏感配置通过环境变量注入,不写死在仓库
10.6 发布方式
推荐发布步骤:
- 后端 Maven 打包为可执行 Jar。
- 后台管理端 Vite 构建后部署到 Nginx 静态目录。
- 选择目标租户的小程序配置,构建对应发行包。
- 小程序通过微信开发者工具上传发布到该租户对应的小程序账号。
- 数据库通过 Flyway 自动迁移到目标版本。
小程序发布补充要求:
- 每个租户需独立维护小程序 AppID、类目、服务器域名和上传主体信息
- 发布前需校验当前构建包是否使用了正确的租户配置
- 建议在后台配置中记录当前租户对应的小程序版本号和发布时间
- 后端在生产环境中以
AppID作为公开接口租户识别的主键
10.6.1 Flyway 迁移约定
后端建议使用以下目录承载迁移脚本:
首批迁移建议:
V1__create_core_schema.sql:创建核心表结构V2__seed_platform_base_data.sql:初始化平台角色、菜单和字典
约束:
- 不回改已上线版本脚本
- 所有字段变更、新表、新索引均追加新版本
- 租户级默认数据在业务代码的“创建租户”流程中初始化,不直接写入平台基线迁移
11. 可观测性与运维
第一阶段建议最少落地以下能力:
- 应用日志滚动归档
- 登录日志与操作日志
- API 错误日志
- 文件上传失败日志
- 慢 SQL 排查
若进入正式商用阶段,建议增加:
- Prometheus + Grafana
- Spring Boot Actuator
- 异常告警通知
12. 安全设计
必须满足以下安全要求:
- 密码使用强哈希算法存储
- JWT 密钥与数据库密码不得入库明文
- 所有后台接口进行登录与权限校验
- 文件上传限制扩展名、大小与 MIME
- 公开接口做基础限流
- 防止越权读取其他租户数据
- 敏感操作写入审计日志
13. 开发实施建议
建议按以下顺序推进开发:
- 先搭建后端基础框架、权限框架、租户框架、数据库脚手架。
- 再完成后台管理端登录、租户管理、事务所管理、用户管理、名片管理。
- 最后将微信小程序从 Mock 数据切换为真实接口,并补齐统计与异常处理。
14. 第一阶段交付清单
第一阶段建议交付内容如下:
- 后端基础框架与数据库脚本
- 超级管理员租户管理
- 租户管理员事务所管理、用户管理、名片管理
- 普通用户个人名片维护
- 小程序主页、列表、详情、历史动态化
- 文件上传
- 浏览统计
- 接口文档
- Docker Compose 部署文件
15. 技术结论
结合当前需求与仓库现状,推荐采用:
- 后端:
JDK 21 + Spring Boot 3.3 + Spring Security + MyBatis-Plus + MySQL + Redis + MinIO + Flyway - 后台:
Vue 3 + TypeScript + Vite + Pinia + Element Plus - 小程序:
原生微信小程序 + TypeScript + Less + 一租户一 AppID 的租户配置方案 - 部署:
Nginx + Docker Compose
该方案在复杂度、交付速度、稳定性、私有化友好程度和后续扩展能力之间较为均衡,适合作为本项目第一阶段正式落地方案。后台统一多租户,小程序按租户独立发布,二者职责边界清晰,便于实施和运营。