医院物业SaaS管理后台 — 项目技术要求
版本:v1.1
定位:内部团队开发标准,所有开发人员必须严格按照此标准执行
日期:2026-04-16
一、技术栈选型与版本要求
1.1 后端技术栈
| 技术 |
版本要求 |
用途 |
| Java |
17+ |
开发语言 |
| Spring Boot |
3.x |
应用框架 |
| MariaDB |
10.6+ |
主数据库(主从复制读写分离) |
| Redis |
7.x |
缓存(权限/字典/菜单)、分布式锁 |
| MyBatis-Plus |
3.5+ |
ORM框架 |
| Spring Security |
6.x |
认证与授权 |
| JWT (jjwt) |
0.12+ |
Token生成与校验 |
| 腾讯云COS SDK |
最新稳定版 |
文件存储 |
| ShedLock |
5.x+ |
分布式定时任务锁 |
1.2 前端Web技术栈
| 技术 |
版本要求 |
用途 |
| Vue |
3.x |
前端框架 |
| TypeScript |
5.x |
类型安全 |
| Vite |
5.x |
构建工具 |
| Pinia |
2.x |
状态管理 |
| Vue Router |
4.x |
路由管理 |
| Element Plus |
最新稳定版 |
UI组件库 |
| Axios |
1.x |
HTTP客户端 |
| ECharts |
5.x |
图表可视化 |
1.3 微信小程序技术栈
| 技术 |
版本要求 |
用途 |
| uni-app |
3.x |
跨端框架(Vue 3模式) |
| uni-ui |
最新稳定版 |
UI组件库 |
| uni-ble |
兼容最新版 |
蓝牙低功耗(BLE)插件 |
1.4 基础设施
| 技术 |
用途 |
| Docker + Docker Compose |
私有云容器化部署 |
| Nginx |
反向代理 + 静态资源 |
| Jenkins / GitLab CI |
CI/CD流水线 |
| Git |
版本管理 |
二、架构设计要求
2.1 整体架构
┌─────────────────────────────────────────────────┐
│ 客户端层 │
│ Vue3 Web管理后台 │ uni-app微信小程序 │
└───────────┬───────────┴───────────┬──────────────┘
│ HTTPS │
┌───────────▼───────────────────────▼──────────────┐
│ 网关层 │
│ Nginx 反向代理 │
└───────────┬──────────────────────────────────────┘
│
┌───────────▼──────────────────────────────────────┐
│ 应用层 │
│ Spring Boot 单体应用(模块化 IModulePlugin) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │报修 │ │巡检 │ │保洁 │ │考勤 │ │合同 │... │
│ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │
│ └────────┴────────┴────────┴────────┘ │
│ Spring Event 模块间通信 │
└───────────┬──────────────────────────────────────┘
│
┌───────────▼──────────────────────────────────────┐
│ 数据层 │
│ MariaDB主库 ──复制──▶ MariaDB从库(读写分离) │
│ Redis 缓存(权限/字典/菜单) │
│ 腾讯云COS(照片/附件/合同文件) │
└──────────────────────────────────────────────────┘
2.2 多租户方案
- 隔离方式:共享数据库 + 行级隔离(
tenant_id字段)
- 实现方式:MyBatis-Plus
TenantLineInnerInterceptor 自动注入 tenant_id 条件
- 租户识别:从JWT Token中提取
tenant_id,无需前端传递
- 超管例外:超级管理员操作不受租户隔离限制
2.3 模块化架构
- 核心接口:
IModulePlugin(详见 05-接口规范.md)
- 模块注册:系统启动时自动扫描并注册所有
IModulePlugin 实现类
- 模块通信:Spring
ApplicationEvent + ApplicationEventPublisher
- 模块隔离:各模块独立目录结构,禁止跨模块直接调用Service,必须通过Event解耦
- 租户级控制:支持按租户启用/禁用特定模块(
sys_tenant_module 表)
2.4 前后端分离
- Web端与后端通过RESTful API通信
- 小程序端与后端通过同一套API通信
- 前端路由由后端权限接口动态驱动
- 统一JWT认证,Web端存localStorage,小程序端存本地Storage
2.5 读写分离方案
- 实现方式:MariaDB主从复制 + MyBatis-Plus动态数据源切换
- 路由规则:
- 写操作(INSERT/UPDATE/DELETE)→ 主库
- 读操作(SELECT)→ 从库
- 注解标记:自定义
@ReadOnly 注解标记读操作,AOP切面切换数据源
- 容错机制:从库不可用时自动降级到主库读取,超时阈值3秒
- 配置要求:在
application.yml 中分别配置 spring.datasource.master 和 spring.datasource.slave 两套数据源连接地址
三、去中间件方案
不引入RocketMQ/Kafka等消息中间件,采用以下Spring Boot内置机制替代:
3.1 权限变更实时通知
- 替代方案:Redis Pub/Sub + Spring Event
- 实现细节:
- 权限变更时,通过 Redis Pub/Sub 发布变更消息
PUBLISH permission:changed <version>
- 各服务实例订阅
permission:changed 频道,收到消息后触发 Spring Event
- 监听器刷新本地权限缓存
- 优势:毫秒级延迟,零数据库压力,复用已有 Redis 实例
- 降级策略:Redis 连接断开时,权限缓存 TTL(2小时)到期后自动刷新
- 实现要点:
- 权限变更时通过
StringRedisTemplate.convertAndSend() 发布消息到 permission:changed 频道
- 各实例
MessageListener 订阅该频道,收到消息后发布 Spring Event
@EventListener 监听事件并刷新本地权限缓存
3.2 异步任务处理
- 替代方案:Spring
@Async + 自定义线程池
- 线程池配置要求:
- 核心线程数:CPU核心数(默认4)
- 最大线程数:CPU核心数×2(默认8)
- 队列容量:1000
- 线程空闲时间:60秒
- 拒绝策略:CallerRunsPolicy(调用者线程执行)
- 适用场景:报表导出、消息推送、日志异步写入、图片处理
- 持久化保障:关键任务必须先落库再异步执行,避免线程池丢失任务
3.3 模块间事件通信
- 替代方案:Spring
ApplicationEvent + ApplicationEventPublisher
- 进程内通信:直接使用Spring Event,事件定义在共享API模块中
- 跨实例通信:Redis Pub/Sub 广播事件(与权限通知同一机制)
- 预定义事件:
| 事件类型 |
来源模块 |
消费方 |
| ORDER_COMPLETED |
repair |
evaluation(触发评价) |
| INSPECTION_ABNORMAL |
inspection |
repair(生成报修) |
| CLEANING_TIMEOUT |
cleaning |
notification(推送预警) |
| BEACON_OFFLINE |
device |
notification(推送预警) |
| PERMISSION_CHANGED |
permission |
各模块(刷新缓存) |
3.4 定时任务
- 替代方案:Spring
@Scheduled + 数据库分布式锁
- 分布式锁实现:ShedLock 或数据库行锁(
SELECT ... FOR UPDATE)
- 适用场景:巡检任务自动生成、保洁超时预警、合同到期提醒、Beacon心跳检测
- 实现要点:定时方法加
@Scheduled 注解声明cron表达式,配合 @ShedLock 注解声明锁名称、最少/最多持有时间,确保多实例部署时同一时刻仅一个实例执行
四、安全要求
4.1 认证方案
| 场景 |
认证方式 |
Token管理 |
| Web端登录 |
用户名+密码 → JWT |
localStorage存储,2小时过期 |
| 小程序登录 |
微信openid静默登录 → JWT |
本地Storage存储,2小时过期 |
| 小程序首次使用 |
微信授权openid + 手机号绑定 |
自动创建账号 |
JWT载荷标准字段:
| 字段 |
说明 |
| sub |
用户ID |
| tid |
租户ID |
| utype |
用户类型 |
| hid |
医院ID |
| pid |
物业公司ID |
| sid |
员工ID |
| iat |
签发时间 |
| exp |
过期时间 |
4.2 四级权限体系
权限按 功能菜单 → 页面 → 功能点 → 动作 四级树形结构划分:
- 7种动作类型:查看(view)、新增(create)、编辑(update)、删除(delete)、审批(approve)、导出(export)、分配(assign)
- 权限编码规范:
{module}:{page}:{action},如 repair:list:create
- 自动同步:新模块通过
IModulePlugin.getPermissionDefinitions() 自动注册到权限配置表
- 实时生效:权限变更后毫秒级生效(Redis Pub/Sub),无需重新登录
4.3 数据权限(行级隔离)
| 角色 |
数据范围 |
实现方式 |
| 超级管理员 |
全局所有数据 |
不注入tenant_id条件 |
| 医院账号 |
本医院+关联物业公司数据 |
注入hospital_id条件,只读 |
| 物业公司管理员 |
绑定医院数据 |
注入tenant_id + hospital_id条件 |
| 主管 |
本班组数据 |
注入team_id条件 |
| 员工 |
仅本人数据 |
注入staff_id条件 |
实现方式:MyBatis-Plus拦截器自动注入SQL条件,禁止手动拼接数据权限条件。
4.4 蓝牙策略配置
蓝牙打卡/巡检/拍照是否强制要求连接,由物业公司配置、医院账号审核:
- 配置方:物业公司管理员
- 审核方:医院账号
- 配置项:各场景是否强制蓝牙连接
| 场景 |
配置项 |
强制蓝牙时的行为 |
非强制蓝牙时的行为 |
| 巡检打卡 |
inspection_check_in |
必须连接Beacon打卡,失败进补录 |
可手动打卡(check_type=MANUAL) |
| 巡检拍照 |
inspection_photo |
必须在蓝牙连接下拍照 |
可自由拍照 |
| 保洁打卡 |
cleaning_check_in |
必须连接Beacon打卡,失败进补录 |
可手动打卡(check_type=MANUAL) |
| 保洁拍照 |
cleaning_photo |
必须在蓝牙连接下拍照 |
可自由拍照 |
| 考勤打卡 |
attendance_check |
必须连接Beacon打卡,失败提交异常申诉 |
可手动打卡(check_type=MANUAL) |
- 数据标记:所有打卡记录区分
check_type(BLUETOOTH/MANUAL),后台列表和统计报表明确显示
- 降级逻辑:
- 非强制蓝牙场景:蓝牙失败可直接手动打卡
- 强制蓝牙场景:蓝牙失败进入补录模式,需主管审核
- 审核流程:物业公司提交配置 → 医院账号审核通过后生效 → 审核拒绝则维持原配置
4.5 审计日志
- 记录范围:所有写操作(CREATE/UPDATE/DELETE/APPROVE/ASSIGN/EXPORT)自动记录
- 实现方式:AOP切面统一处理,业务代码无感知
- 记录内容:操作人、时间、IP、模块、操作类型、变更前后数据快照
- 权限变更日志:单独记录,展示变更前后权限对比
- 数据补录日志:单独记录,标记补录原因和审核状态
- 日志保留:至少保留1年,支持导出
4.6 通用安全要求
| 安全项 |
要求 |
| SQL注入防护 |
必须使用MyBatis-Plus参数化查询,禁止拼接SQL |
| XSS防护 |
所有用户输入必须HTML转义后存储,前端渲染使用v-text而非v-html |
| 密码存储 |
BCrypt加密,禁止明文存储 |
| 敏感数据 |
手机号脱敏显示(138****1234),身份证号如需存储需AES加密 |
| 接口鉴权 |
所有API必须声明权限要求(除公开接口外) |
| 跨域控制 |
Nginx配置白名单域名,禁止 Access-Control-Allow-Origin: * |
| 请求限流 |
Redis令牌桶限流,API默认100次/分钟/用户 |
五、性能要求
5.1 响应时间基线
| 指标 |
要求 |
测量方式 |
| API平均响应时间 |
< 300ms |
服务端P50 |
| API P99响应时间 |
< 500ms |
服务端P99 |
| 列表查询(含分页) |
< 500ms |
端到端 |
| 报表生成(单月数据) |
< 5s |
端到端 |
| 蓝牙扫描超时 |
3秒 |
客户端 |
| 蓝牙连接建立 |
< 3秒 |
客户端 |
5.2 并发与容量
- 单实例支持100 QPS
- 支持水平扩展(无状态设计,Session存Redis)
- 数据库连接池:HikariCP,最大连接数 = CPU核心数 * 2 + 1
- Redis连接池:Lettuce,最大连接数 = CPU核心数 * 2
5.3 缓存策略
| 缓存对象 |
过期策略 |
刷新机制 |
| 用户权限集 |
2小时TTL |
权限变更时实时刷新(毫秒级,Redis Pub/Sub) |
| 字典数据 |
24小时TTL |
字典变更时手动/自动刷新 |
| 菜单配置 |
24小时TTL |
菜单变更时手动/自动刷新 |
| 业务数据 |
按需懒加载 |
不缓存,实时查询 |
5.4 蓝牙交互可靠性
| 指标 |
要求 |
| 连接判定 |
不判断距离,只要成功连接蓝牙设备即可打卡 |
| 信号阈值 |
RSSI > -70dBm(可配置,仅用于判定是否能建立连接) |
| 扫描超时 |
3秒 |
| 重试次数 |
3次 |
| 补录降级 |
蓝牙失败后必须提供补录/手动打卡入口 |
| 心跳检测 |
Beacon每5分钟上报心跳,超15分钟标记OFFLINE |
六、数据库备份与恢复
6.1 备份策略
| 备份类型 |
频率 |
工具 |
保留时间 |
| 全量备份 |
每日凌晨2:00 |
mysqldump --single-transaction |
30天 |
| 增量备份 |
每4小时 |
MariaDB binlog |
7天 |
| 异地备份 |
每日 |
rsync/scp到备份服务器 |
30天 |
6.2 备份存储
- 主存储:私有云本地磁盘(独立磁盘,与数据盘分离)
- 异地存储:异地备份服务器(不同机房或不同物理机)
- 备份文件命名:
hospital_mgmt_full_YYYYMMDD_HHmmss.sql.gz、hospital_mgmt_incr_YYYYMMDD_HHmmss.binlog.gz
6.3 恢复方案
| 指标 |
要求 |
| RTO(恢复时间目标) |
< 2小时 |
| RPO(恢复点目标) |
< 4小时(增量备份间隔) |
| 恢复方式 |
全量恢复 + binlog重放 |
| 恢复流程 |
1. 停止应用 → 2. 恢复最近全量备份 → 3. 重放binlog到故障时间点 → 4. 验证数据完整性 → 5. 启动应用 |
6.4 恢复演练
- 频率:每季度一次
- 内容:在测试环境执行完整恢复流程,验证RTO和RPO
- 记录:演练结果记录文档,问题纳入改进计划
- 责任人:DBA + 运维
6.5 备份脚本要求
- 全量备份使用
mysqldump --single-transaction 导出并gzip压缩
- 备份文件命名格式:
hospital_mgmt_full_YYYYMMDD_HHmmss.sql.gz(增量:hospital_mgmt_incr_YYYYMMDD_HHmmss.binlog.gz)
- 自动清理30天前的全量备份文件
- 备份完成后通过 rsync 同步到异地备份服务器
七、开发与测试规范
开发规范、测试规范已独立为 04-开发与测试规范.md,本章仅保留引用。
- 后端开发规范(代码分层、命名、数据库、模块开发、审计日志)→ 详见
04-开发与测试规范.md 第一章
- 前端开发规范(Vue3组件、TypeScript、状态管理、API调用)→ 详见
04-开发与测试规范.md 第二章
- 小程序开发规范(目录、蓝牙、图片上传)→ 详见
04-开发与测试规范.md 第三章
- Git分支与提交规范 → 详见
04-开发与测试规范.md 第四章
- 前后端协作规范 → 详见
04-开发与测试规范.md 第五章
- 代码审查要求 → 详见
04-开发与测试规范.md 第六章
- 测试规范(单元测试、集成测试、蓝牙测试、性能测试、安全测试)→ 详见
04-开发与测试规范.md 第七章
八、部署与运维要求
8.1 部署架构(私有云)
┌──────────────────────────────────────────┐
│ 私有云服务器 │
│ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ Nginx │ │ Docker Compose │ │
│ │ 反向代理 │──│ ┌────────────┐ │ │
│ │ 静态资源 │ │ │ Spring Boot│ │ │
│ └─────────────┘ │ │ 应用容器 │ │ │
│ │ └────────────┘ │ │
│ │ ┌────────────┐ │ │
│ │ │ Redis │ │ │
│ │ │ 缓存容器 │ │ │
│ │ └────────────┘ │ │
│ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ MariaDB主库 │ │ MariaDB从库 │ │
│ │ 写操作 │──│ 读操作 │ │
│ └─────────────┘ └─────────────────┘ │
└──────────────────────────────────────────┘
8.2 Docker Compose部署要求
部署包含以下服务容器:
| 服务 |
镜像 |
说明 |
| app |
hospital-mgmt:latest |
Spring Boot应用,端口8080,依赖Redis和MariaDB主库 |
| redis |
redis:7-alpine |
缓存服务,持久化存储 |
| mariadb-master |
mariadb:10.6 |
主库(写),持久化存储 |
| mariadb-slave |
mariadb:10.6 |
从库(读),依赖主库,持久化存储 |
| nginx |
nginx:alpine |
反向代理+静态资源,端口80/443,挂载自定义nginx.conf和前端dist目录 |
- 环境变量注入:通过
SPRING_PROFILES_ACTIVE、SPRING_DATASOURCE_URL、SPRING_DATASOURCE_SLAVE_URL、SPRING_REDIS_HOST 等环境变量配置连接信息,禁止硬编码
8.3 小程序版本更新策略
小程序启动
│
调用 GET /system/versions/latest 获取最新版本号
│
与本地版本号比较
│
├── 版本一致 ──▶ 正常使用
│
├── 小版本更新(兼容) ──▶ 提示"发现新版本,是否更新?"
│
└── 大版本更新(不兼容) ──▶ 强制更新,引导前往微信更新
8.4 缓存管理策略
| 触发方式 |
清理范围 |
说明 |
| 系统启动 |
全部缓存 |
启动时自动清理 |
| 权限变更 |
权限缓存 |
变更后毫秒级自动刷新(Redis Pub/Sub) |
| 手动清理 |
指定模块缓存 |
超管在"缓存管理"页面操作 |
| 系统更新 |
全部缓存 |
部署新版本后自动清理 |
8.5 监控与告警
| 监控项 |
告警条件 |
通知方式 |
| 应用健康 |
健康检查失败 |
邮件+企业微信 |
| 数据库连接 |
连接池使用率>80% |
企业微信 |
| Redis连接 |
连接池使用率>80% |
企业微信 |
| Beacon离线 |
离线超过15分钟 |
系统内通知 |
| Beacon低电量 |
电量<20% |
系统内通知 |
| 磁盘空间 |
使用率>85% |
邮件+企业微信 |
| 备份失败 |
备份任务失败 |
邮件 |
九、接口规范
接口规范已独立为 05-接口规范.md,本章仅保留引用。
- 全局约定(请求头、统一响应格式、错误码、查询参数)→ 详见
05-接口规范.md 第一章
- 认证规范(认证方式、JWT载荷、权限编码)→ 详见
05-接口规范.md 第二章
- 文件上传规范 → 详见
05-接口规范.md 第三章
- 模块化架构规范(IModulePlugin、模块注册、事件通信、版本升级、安全规范)→ 详见
05-接口规范.md 第四~八章
- 接口权限汇总 → 详见
05-接口规范.md 第九章
十、环境配置管理
10.1 环境划分
| 环境 |
用途 |
数据库 |
配置文件 |
| dev |
本地开发 |
本地MariaDB |
application-dev.yml |
| test |
集成测试 |
测试MariaDB |
application-test.yml |
| staging |
预发布 |
预发布MariaDB |
application-staging.yml |
| prod |
生产 |
生产MariaDB主从 |
application-prod.yml |
10.2 敏感配置管理
- 数据库密码、Redis密码、JWT密钥、腾讯云SecretKey等 禁止硬编码
- 使用环境变量注入:
SPRING_DATASOURCE_PASSWORD, JWT_SECRET, COS_SECRET_KEY
- 生产环境密码定期轮换(每季度)
10.3 配置项清单
| 配置项 |
说明 |
默认值 |
jwt.expiration |
Token过期时间(秒) |
7200 |
jwt.refresh-expiration |
Refresh Token过期时间(秒) |
604800 |
bluetooth.rssi-threshold |
蓝牙信号阈值(dBm) |
-70 |
bluetooth.distance-threshold |
已废弃 蓝牙不判断距离,连接即打卡 |
— |
bluetooth.scan-timeout |
蓝牙扫描超时(秒) |
3 |
permission.redis-channel |
权限变更Redis频道名 |
permission:changed |
async.pool.core-size |
异步线程池核心线程数 |
CPU核心数 |
async.pool.max-size |
异步线程池最大线程数 |
CPU核心数*2 |
upload.max-size |
文件上传大小限制(MB) |
20 |
cos.bucket-name |
腾讯云COS存储桶名称 |
— |
backup.full-cron |
全量备份cron |
0 2 * * ? |
backup.incr-interval-hours |
增量备份间隔(小时) |
4 |
本文档为内部开发标准,所有开发人员必须严格按照此标准执行。如有疑问或需要调整,需经技术负责人审批。