11 KiB
合同模板上传与地区隔离改造方案
1. 背景
当前合同模板模块已具备以下只读能力:
/api/v3/contract-templates/categories/api/v3/contract-templates/api/v3/contract-templates/search/api/v3/contract-templates/{id}
当前实现可以支撑模板分类、列表、搜索、详情展示,但还不具备正式的模板管理上传能力。现阶段新增需求包括:
- 在
/contract-template/list页面支持上传合同模板 - 新模板必须存入
leaudit_platform主库,不再依赖旧项目库 - 模板数据需要支持地区区分
- 模板数据需要支持完整审计字段
- 模板数据需要支持软删除
- 前端与后端需统一按当前 LeAudit/FastAPI 风格实现
本方案仅覆盖“合同模板管理与上传”,不扩展“合同起草”独立业务模块。
2. 现状问题
2.1 数据表不足
当前 contract_templates 仅包含:
template_codetitlecategory_iddescriptionfile_pathfile_formatpdf_file_pathis_featuredcreated_atupdated_at
存在以下问题:
- 没有
region,无法做地区隔离 - 没有
created_by / updated_by,无法追踪操作者 - 没有
deleted_at,无法软删除 - 没有
original_file_name / mime_type / file_size,无法完整表达上传文件元数据 - 当前唯一约束仅为
template_code全局唯一,不适合多地区模板管理
2.2 读接口缺少统一数据范围控制
当前合同模板读接口没有套用平台现有“按用户地区可见”的规则,无法满足:
- 省级管理员查看全部或指定地区
- 地市管理员仅查看本地区及公共模板
- 非管理用户限制可见范围
2.3 OSS 路径未带地区
当前 BuildContractTemplateKey() 只按:
- 分类
- 模板编码
- 文件角色
生成路径,未带 region,多地区下会出现路径命名冲突与后期归档困难。
2.4 权限不足
当前仅具备读权限:
contract_template:list:readcontract_template:search:readcontract_template:detail:read
尚未具备:
- 上传创建权限
- 编辑权限
- 删除权限
3. 设计目标
本次改造目标如下:
- 为合同模板模块补齐上传能力
- 按地区隔离模板数据
- 支持审计字段与软删除
- 保持与现有
govdoc/document模块相同的权限和地区控制风格 - 新上传模板统一走新 OSS 路径规范
- 不影响现有搜索、列表、详情页面的继续使用
4. 数据模型设计
4.1 contract_categories
分类暂不做地区化,保留为全局字典表,但补齐审计与软删除字段。
建议字段:
id BIGSERIAL/SERIAL PRIMARY KEYname VARCHAR(100) NOT NULLicon VARCHAR(100) NULLdescription TEXT NULLsort_order INTEGER NOT NULL DEFAULT 0created_by BIGINT NULLcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_by BIGINT NULLupdated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()deleted_at TIMESTAMPTZ NULL
索引建议:
UNIQUE INDEX uq_contract_categories_name_active ON contract_categories(name) WHERE deleted_at IS NULLINDEX idx_contract_categories_sort_active ON contract_categories(sort_order) WHERE deleted_at IS NULL
4.2 contract_templates
模板表补齐地区、上传元数据、审计字段、软删除字段。
建议字段:
id BIGSERIAL PRIMARY KEYtemplate_code VARCHAR(50) NOT NULLtitle VARCHAR(200) NOT NULLcategory_id INTEGER NOT NULL REFERENCES contract_categories(id)region VARCHAR(50) NOT NULL DEFAULT '省级'description TEXT NULLfile_path VARCHAR(500) NULLpdf_file_path VARCHAR(500) NULLfile_format VARCHAR(10) NOT NULLoriginal_file_name VARCHAR(500) NOT NULL DEFAULT ''mime_type VARCHAR(200) NULLfile_size BIGINT NOT NULL DEFAULT 0pdf_file_size BIGINT NULLis_featured BOOLEAN NOT NULL DEFAULT FALSEcreated_by BIGINT NULLcreated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()updated_by BIGINT NULLupdated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()deleted_at TIMESTAMPTZ NULL
索引建议:
UNIQUE INDEX uq_contract_templates_region_code_active ON contract_templates(region, template_code) WHERE deleted_at IS NULLINDEX idx_contract_templates_region_active ON contract_templates(region) WHERE deleted_at IS NULLINDEX idx_contract_templates_category_active ON contract_templates(category_id) WHERE deleted_at IS NULLINDEX idx_contract_templates_updated_active ON contract_templates(updated_at DESC) WHERE deleted_at IS NULL
4.3 软删除策略
所有列表、搜索、详情查询统一增加:
deleted_at IS NULL
删除接口只做:
deleted_at = NOW()updated_at = NOW()updated_by = 当前用户
本期不执行物理删除 OSS 对象,避免误删无法恢复。
5. 地区隔离策略
5.1 用户上下文来源
复用现有用户上下文判断逻辑,基于:
sso_users.area- 用户角色
super_admin / provincial_admin / admin / 普通用户
参考现有实现:
documentServiceImpl._getCurrentUserContextdocumentServiceImpl._buildDocumentScopeFiltersgovdocServiceImpl._resolve_upload_region
5.2 模板可见性规则
采用“省级公共模板 + 地区私有模板”的一层可见性模型:
region = '省级':全局公共模板region = 用户地区:当前地区私有模板
读取规则:
super_admin / provincial_admin- 默认可查看全部地区
- 支持显式传
region做筛选
admin- 默认可查看
('省级', 自己地区)模板 - 若传入其他地区参数,返回空或直接拒绝
- 默认可查看
- 普通用户
- 默认可查看
('省级', 自己地区)模板 - 不允许跨地区筛选
- 默认可查看
5.3 上传地区规则
上传接口中,region 使用以下规则解析:
super_admin / provincial_admin- 可选择上传到任意地区,含
省级
- 可选择上传到任意地区,含
admin- 只能上传到自己地区
- 普通用户
- 默认不开放上传权限
5.4 为什么本期不做“地区模板覆盖省级模板”
本期不做同 template_code 的覆盖优先级逻辑,原因:
- 列表/搜索会出现同编码多条模板
- 详情页需要增加“实际命中版本”优先级
- 后续还会影响起草、下载、预览引用
本期先做“地区隔离 + 独立模板记录”,后续若业务明确需要,再做二期“本地覆盖省级模板”。
6. OSS 存储设计
6.1 新路径规范
建议合同模板 OSS key 改为:
contract-templates/{region}/{category}/{template_code}/{role}__{filename}
例如:
contract-templates/省级/房屋租赁/HT-RL-001/source__房屋租赁合同.docxcontract-templates/梅州/房屋租赁/HT-RL-001/preview__房屋租赁合同.pdf
6.2 文件角色
- 主模板文件:
source - 预览 PDF 文件:
preview
6.3 老数据策略
老数据短期不强制迁移到新地区路径:
- 已有历史数据继续可读
- 新上传统一走新路径
后续若需要统一整洁,再单独执行历史迁移脚本,将存量模板迁到 contract-templates/省级/...
7. 接口设计
7.1 新增接口
7.1.1 上传模板
POST /api/v3/contract-templates- 权限:
contract_template:create - Content-Type:
multipart/form-data
表单字段:
title: strtemplate_code: strcategory_id: intregion: strdescription: str | Noneis_featured: boolfile: UploadFilepdf_file: UploadFile | None
返回:
- 模板基础信息
- 文件路径
- 地区信息
- 审计时间
7.1.2 更新模板
PUT /api/v3/contract-templates/{id}- 权限:
contract_template:update
本期先可只支持元数据更新,文件替换可选一起补。
7.1.3 删除模板
DELETE /api/v3/contract-templates/{id}- 权限:
contract_template:delete
行为:
- 软删除,不物理删 OSS
7.2 既有接口增强
7.2.1 分类接口
- 过滤
deleted_at IS NULL - 返回
template_count时只统计当前用户可见地区且未删除模板
7.2.2 列表接口
新增可选参数:
region
逻辑:
- 仅返回当前用户可见模板
- 默认按
updated_at DESC
7.2.3 搜索接口
新增可选参数:
region
逻辑:
- 仅搜索当前用户可见模板
7.2.4 详情接口
逻辑:
- 校验模板存在
- 校验模板未删除
- 校验当前用户对模板所在地区可见
8. 权限设计
新增权限:
contract_template:createcontract_template:updatecontract_template:delete
保留权限:
contract_template:list:readcontract_template:search:readcontract_template:detail:read
角色建议:
super_admin- 全部读写删
provincial_admin- 全部读写删
admin- 读
- 上传
- 编辑本地区模板
- 删除本地区模板
- 普通用户
- 仅按需开放读权限
9. 前端设计
9.1 列表页入口
在 /contract-template/list 页面右上角增加:
- “上传模板”按钮
仅有 contract_template:create 权限时展示。
9.2 上传弹窗字段
- 模板标题
- 模板编码
- 模板分类
- 所属地区
- 模板简介
- 是否推荐
- 模板主文件
- 预览 PDF 文件(可选)
9.3 前端交互规则
admin用户地区默认锁定为自己地区provincial_admin可选择地区- 上传成功后:
- 提示成功
- 关闭弹窗
- 刷新当前列表
- 上传失败时:
- 表单级错误走 toast
- 403 需给出明确无权限提示
9.4 API 封装
在 lib/api/contract-template/index.ts 增加:
createContractTemplateupdateContractTemplatedeleteContractTemplate
上传使用 FormData 直接请求后端,不走多余代理语义。
10. 数据迁移方案
10.1 老表扩展
通过增量 SQL:
- 新增缺失列
- 回填默认值
- 修正索引
- 增加
updated_at触发器
10.2 老数据回填
建议回填:
region = '省级'original_file_name = ''或按旧路径推导file_size = 0deleted_at = NULL
10.3 回滚策略
若上传接口上线后发现问题:
- 可先关闭前端上传入口
- 已有新字段与索引保持兼容,不影响只读能力
11. 开发步骤
阶段 1:基础设施
- 扩展合同模板 SQL
- 扩展 RBAC seed
- 更新 OSS 路径工具
阶段 2:后端接口
- 增加 DTO/VO
- 扩展 Service 接口
- 实现上传、更新、删除
- 为列表、搜索、详情补地区过滤
阶段 3:前端页面
- 扩展 API 客户端
- 在列表页增加上传按钮和弹窗
- 接地区选择与权限控制
阶段 4:验证
- 省级管理员上传省级模板
- 地市管理员上传本地区模板
- 非本地区参数校验
- 403 提示
- 列表、搜索、详情联调
12. 本期明确不做
- 合同起草模块重构
- 模板占位符自动解析
- docx 自动转 pdf
- 地区模板覆盖省级模板优先级
- 模板版本管理
- OSS 历史模板统一搬迁
13. 推荐本期交付范围
建议本期落地以下完整闭环:
- 合同模板表完成地区化、审计化、软删除改造
- 合同模板后端新增上传接口
- 合同模板列表页新增上传弹窗
- 合同模板读接口支持地区可见性控制
- 权限种子补齐
这套范围足以让合同模板模块从“只读展示”升级为“可管理上传的地区化模板库”。