Files
hyapi-server/docs/多平台签署整合实现方案.md
2026-07-21 15:53:29 +08:00

620 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 多平台签署整合实现方案e签宝 + 法大大)
> 基于现有企业入驻流程的改造设计,供评审后决定实施范围与优先级。
> 关联文档:[企业入驻-e签宝功能分析.md](./企业入驻-e签宝功能分析.md)
---
## 1. 背景与目标
### 1.1 现状
当前企业入驻的**企业实名认证 + 合同签署**全流程绑定在 **e签宝** 单一平台:
- 管理员审核通过后,直接调用 e签宝 `/v3/org-auth-url` 生成 `auth_url`
- 企业认证、模板填单、签署流程、回调/轮询均硬编码在 `CertificationApplicationServiceImpl` + `internal/shared/esign`
### 1.2 目标
1. `certifications` 主表新增 **`sign_platform`(签署平台)** 字段
2. 管理员审核通过后,**由用户选择签署平台**e签宝 / 法大大)
3. 根据所选平台发放对应的**企业认证链接**与**合同签署链接**
4. 尽量复用现有状态机,降低对已完成用户的影响
### 1.3 非目标(本期可不做)
- 同一用户在不同平台各签一份合同
- 签署中途切换平台(选定后锁定,除非管理员重置)
- 替换掉 e签宝 的全部历史数据
---
## 2. 改造后流程设计
### 2.1 新增步骤:选择签署平台
在「人工审核通过」与「企业认证 iframe」之间插入一步
```
填写企业信息
→ 人工审核info_pending_review
→ 【新增】选择签署平台info_submitted 前/后,见 2.2
→ 企业实名认证info_submitted
→ 合同预览与签署enterprise_verified → contract_applied → completed
```
### 2.2 平台选择时机(推荐方案)
| 方案 | 时机 | 优点 | 缺点 |
|------|------|------|------|
| **A推荐** | 审核通过后、生成认证链接前,用户主动选择 | 符合需求;认证与签署同一平台;不浪费第三方调用 | 多一个前端步骤 |
| B | 提交企业信息时一并选择 | 步骤少 | 审核拒绝后需重选;用户尚不清楚平台差异 |
| C | 仅合同阶段选择,认证仍固定 e签宝 | 改动小 | 法大大合同要求法大大侧企业实名,链路不完整 |
**推荐采用方案 A**,状态流转如下:
```mermaid
flowchart TD
A[info_pending_review] --> B[管理员审核通过]
B --> C{sign_platform 已选择?}
C -->|否| D[前端展示平台选择页<br/>POST /select-sign-platform]
D --> E[写入 sign_platform]
E --> F[按平台生成 auth_url]
C -->|是| F
F --> G[info_submitted + auth_url]
G --> H[iframe 企业认证]
H --> I[enterprise_verified + 生成合同]
I --> J[apply-contract 按平台发起签署]
J --> K[completed]
```
### 2.3 平台锁定规则
| 规则 | 说明 |
|------|------|
| 可选时机 | `info_pending_review` 审核通过后 ~ `info_submitted` 之前(`sign_platform` 为空) |
| 锁定时机 | 用户确认平台后写入 `sign_platform`,并生成该平台认证链接 |
| 不可变更 | 进入 `info_submitted` 后不允许用户自行切换 |
| 管理员重置 | 仅管理员可将 `sign_platform` 置空并重置到待选平台状态(见 4.3 |
---
## 3. 数据库变更
### 3.1 `certifications` 主表
新增字段:
```sql
ALTER TABLE certifications
ADD COLUMN sign_platform VARCHAR(20) DEFAULT NULL
COMMENT '签署平台: esign | fadadaNULL 表示尚未选择';
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `sign_platform` | varchar(20), nullable | `esign` / `fadada` / `NULL` |
**现有 e签宝 字段复用策略(推荐不重命名):**
| 现有字段 | 多平台语义 |
|----------|------------|
| `auth_flow_id` | 第三方企业认证流程 ID平台无关 |
| `auth_url` | 第三方企业认证页面 URL |
| `contract_file_id` | 第三方合同文件 ID |
| `esign_flow_id` | 第三方签署流程 ID建议后续迭代改名为 `sign_flow_id` |
| `contract_sign_url` | 第三方签署页面 URL |
> 首期可保留 `esign_flow_id` 列名不动,避免大面积迁移;在代码层用 `SignFlowID` 别名理解即可。
### 3.2 子记录表(建议同步加平台字段)
| 表 | 变更 |
|----|------|
| `esign_contract_generate_records` | 新增 `sign_platform varchar(20)`;后期可重命名为 `contract_generate_records` |
| `esign_contract_sign_records` | 新增 `sign_platform varchar(20)`;后期可重命名为 `contract_sign_records` |
| `contract_infos` | 新增 `sign_platform varchar(20)`,便于历史合同溯源 |
### 3.3 枚举定义Go
```go
// internal/domains/certification/enums/sign_platform.go
type SignPlatform string
const (
SignPlatformEsign SignPlatform = "esign"
SignPlatformFadada SignPlatform = "fadada"
)
func IsValidSignPlatform(p SignPlatform) bool { ... }
```
### 3.4 历史数据迁移
```sql
-- 已有认证记录默认归属 e签宝
UPDATE certifications SET sign_platform = 'esign' WHERE sign_platform IS NULL;
UPDATE esign_contract_generate_records SET sign_platform = 'esign' WHERE sign_platform IS NULL;
UPDATE esign_contract_sign_records SET sign_platform = 'esign' WHERE sign_platform IS NULL;
UPDATE contract_infos SET sign_platform = 'esign' WHERE sign_platform IS NULL;
```
对于**进行中**且 `sign_platform IS NULL` 的记录:迁移后视为已选 e签宝与当前行为一致。
---
## 4. 后端架构改造
### 4.1 核心思路签署平台抽象层Strategy + Registry
将 e签宝 特有逻辑从 `CertificationApplicationServiceImpl` 中抽离,定义统一接口:
```
internal/domains/certification/ports/sign_platform_provider.go # 接口(端口)
internal/infrastructure/external/esign/esign_provider.go # e签宝 实现
internal/infrastructure/external/fadada/fadada_provider.go # 法大大 实现
internal/infrastructure/external/signplatform/registry.go # 按 sign_platform 路由
```
**接口草案:**
```go
type SignPlatformProvider interface {
Platform() enums.SignPlatform
// 企业实名
GenerateEnterpriseAuth(ctx context.Context, req *EnterpriseAuthRequest) (*AuthLinkResult, error)
QueryOrgVerified(ctx context.Context, req *OrgIdentityQuery) (bool, error)
// 合同
GenerateContractFile(ctx context.Context, req *ContractGenerateRequest) (*ContractFileResult, error)
CreateSignFlow(ctx context.Context, req *SignFlowCreateRequest) (*SignFlowResult, error)
QuerySignStatus(ctx context.Context, flowID string) (*SignStatusResult, error)
DownloadSignedFiles(ctx context.Context, flowID string) ([]*SignedFile, error)
// 回调
ParseCallback(ctx context.Context, raw []byte, headers map[string]string) (*CallbackEvent, error)
VerifyCallback(ctx context.Context, raw []byte, headers map[string]string) error
}
```
`CertificationApplicationServiceImpl` 中所有 `s.esignClient.XXX()` 改为:
```go
provider := s.platformRegistry.Get(cert.SignPlatform)
provider.GenerateEnterpriseAuth(...)
```
### 4.2 需改造的后端触点(按优先级)
| 方法 | 现状 | 改造 |
|------|------|------|
| `AdminApproveSubmitRecord` | 直接 `esignClient.GenerateEnterpriseAuth` | 审核通过后**不立即**生成链接;仅将状态保持在「待选平台」或新增中间状态 |
| **新增** `SelectSignPlatform` | 无 | 用户选择平台 → 写 `sign_platform` → 调 provider 生成 `auth_url``info_submitted` |
| `ConfirmAuth` / `checkAndCompleteEnterpriseVerification` | 查 e签宝 identity | 调当前 provider 的 `QueryOrgVerified` |
| `generateAndAddContractFile` | e签宝 FillTemplate | 调 provider 的 `GenerateContractFile` |
| `ApplyContract` / `generateContractAndSignURL` | e签宝 SignFlow | 调 provider 的 `CreateSignFlow` |
| `checkAndUpdateSignStatus` | e签宝 QuerySignFlowDetail | 调 provider 的 `QuerySignStatus` |
| `handleContractAfterSignComplete` | e签宝 DownloadSignedFile | 调 provider 的 `DownloadSignedFiles` |
| `HandleEsignCallback` | 仅处理 e签宝 | 拆为 `/callbacks/esign` + `/callbacks/fadada`,或统一入口按 header/字段分发 |
### 4.3 状态机微调(可选两种做法)
**做法 1最小改动推荐不新增状态**
- 管理员审核通过后,认证状态仍为 `info_pending_review` 或新增语义:`info_submitted``sign_platform=NULL``auth_url` 为空
- 前端根据 `metadata.need_select_platform=true` 展示平台选择页
- 用户选完平台后才进入 `info_submitted`(有 `auth_url`
**做法 2新增状态 `platform_pending`**
- 语义更清晰,但需改 `certification_status.go`、前端步骤映射、管理端筛选
- 适合后续平台数量继续增加时
**推荐做法 1**,通过 metadata 驱动前端,避免状态机膨胀:
```json
{
"status": "info_pending_review",
"metadata": {
"manual_review_status": "approved",
"need_select_platform": true,
"available_platforms": ["esign", "fadada"]
}
}
```
或审核通过后直接将状态推到 `info_submitted`,但 `auth_url` 为空、`need_select_platform=true`
### 4.4 新增 API
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/certifications/sign-platforms` | 返回可选平台列表(名称、图标、说明、是否可用) |
| POST | `/api/v1/certifications/select-sign-platform` | 用户选择平台,生成认证链接 |
| POST | `/api/v1/certifications/callbacks/fadada` | 法大大回调(与 esign 并列) |
| POST | `/api/v1/certifications/admin/reset-sign-platform` | 管理员重置平台选择(可选) |
**`SelectSignPlatform` 请求体:**
```json
{
"sign_platform": "fadada"
}
```
**响应(与现有 details 结构对齐):**
```json
{
"status": "info_submitted",
"sign_platform": "fadada",
"metadata": {
"auth_url": "https://...",
"next_action": "请完成企业认证"
}
}
```
**`apply-contract` / `confirm-sign` / `confirm-auth`**:无需改路径,内部按 `cert.SignPlatform` 路由。
### 4.5 管理员审核逻辑调整
当前 `AdminApproveSubmitRecord` 审核通过后会**立即**调用 e签宝。改造后
```
审核通过 → 仅更新 submit_record.manual_review_status = approved
→ 认证状态:保持 info_pending_review或推到 info_submitted 但无 auth_url
→ 不调用任何第三方
用户选择平台 → SelectSignPlatform → 调对应 provider → 写入 auth_url → info_submitted
```
管理员后台可展示 `sign_platform` 列,便于客服排查。
---
## 5. 法大大接入方案
### 5.1 平台与文档
- 产品:法大大 **FASC OpenAPI v5.1**(公有云)
- 开放平台:`https://cloud.fadada.com` / 开发文档 `https://dev.fadada.com`
- 参考 SDK`fasc-openapi-go-sdk`(官方 Go SDK建议优先使用
### 5.2 需准备的法大大侧资源
| 资源 | 用途 |
|------|------|
| AppID / AppSecret | API 鉴权 |
| openCorpId | 接入企业(海宇数据自身)在法大大侧的企业 ID |
| 应用模板 / 签署模板 | 对应合作协议 PDF 模板 |
| 测试环境域名 | 沙箱联调 |
| 回调地址 | `https://{domain}/api/v1/certifications/callbacks/fadada` |
### 5.3 法大大 API 与 e签宝 映射
| 业务步骤 | e签宝现有 | 法大大 FASC待接 |
|----------|---------------|---------------------|
| 获取企业认证链接 | `POST /v3/org-auth-url` | `Corp` 模块 - 获取企业认证/授权 URL |
| 查询企业是否已实名 | `GET /v3/organizations/identity-info` | `Corp` 模块 - 查询企业认证状态 |
| 模板生成合同文件 | `POST /v3/files/create-by-doc-template` | `AppTemplate` + `Doc` 模块 - 填写模板生成文档 |
| 创建签署流程 | `POST /v3/sign-flow/create-by-file` | `fadada.CreateSignFlow``/sign-task/create``/sign-task/create-with-template` |
| 获取签署链接 | `POST /v3/sign-flow/{id}/sign-url` | `fadada.GetSignURL``/sign-task/actor/get-url` |
| 查询签署状态 | `GET /v3/sign-flow/{id}/detail` | `fadada.QuerySignStatus``/sign-task/app/get-detail``task_finished`/`sign_completed`=完成) |
| 下载已签文件 | `GET /v3/sign-flow/{id}/file-download-url` | `fadada.DownloadSignedFiles``/sign-task/owner/get-download-url` |
| 回调 | `AUTH_PASS` 等 | `fadada.VerifyCallback` + `ParseCallback``X-FASC-*` HMAC-SHA256 |
> 具体接口路径以法大大 v5.1 文档为准;上表为模块级映射,实施时按官方 SDK 方法名落地。
### 5.4 法大大合同模板控件
模板 ID`1784013372537192273``config.yaml``fadada.template_id`
| 业务字段 | e签宝 控件 key | 法大大控件编码 (fieldId) | 配置键 |
|----------|----------------|--------------------------|--------|
| 协议编号 | `xybh` | 多控件同值(见 `config.yaml` `agreement_no` 列表) | `agreement_no` |
| 签订日期 | (系统) | `2039326319` | `contract_date` |
| 甲方企业名 | `jfqym` / `jfqym2` | `6920634255` | `party_a_name` |
| 甲方统一信用代码 | `jftyshxydm` | `8702060291` | `party_a_uscc` |
| 甲方联系地址 | `jflxdz` | `4557539440` | `party_a_address` |
| 甲方授权代表/法人 | `jfsqdb` | `8627432823` | `party_a_rep` |
| 甲方签署日期 | `qsrq1` / `qsrq3` | `6047306418` | `party_a_sign_date` |
| 乙方签署日期 | `qsrq2` | `3849218908` | `party_b_sign_date` |
日期格式与现网一致:`2006年01月02日`。实现:`fadada.Client.FillTemplate` / `FillSignTaskFields`
### 5.5 法大大 SDK 目录规划
```
hyapi-server/internal/shared/fadada/ # 或 infrastructure/external/fadada/
├── client.go # 封装官方 SDK Client
├── config.go
├── corp_service.go # 企业认证
├── signtask_service.go # 签署任务
├── template_service.go # 模板/文档
├── callback.go # 回调解析与验签
└── provider.go # 实现 SignPlatformProvider
```
---
## 6. 配置变更
### 6.1 config.yaml 新增法大大段
```yaml
# 签署平台全局开关
sign_platform:
enabled: ["esign", "fadada"] # 前端可选列表
default: "" # 空=强制用户选择
esign:
# 保持现有配置不变
...
fadada:
app_id: ""
app_secret: ""
server_url: "https://api.fadada.com" # 以官方文档为准
open_corp_id: "" # 海宇数据在法大大的企业 ID
template_id: "" # 应用签署模板 ID
contract:
name: "海宇数据-合作协议"
expire_days: 7
auth:
redirect_url: "https://console.haiyudata.com/certification/callback/fadada/auth"
sign:
redirect_url: "https://console.haiyudata.com/certification/callback/fadada/sign"
callback:
enabled: true
```
### 6.2 Go Config 结构
```go
type SignPlatformConfig struct {
Enabled []string `mapstructure:"enabled"`
Default string `mapstructure:"default"`
}
type FadadaConfig struct {
AppID string `mapstructure:"app_id"`
AppSecret string `mapstructure:"app_secret"`
ServerURL string `mapstructure:"server_url"`
OpenCorpID string `mapstructure:"open_corp_id"`
TemplateID string `mapstructure:"template_id"`
Contract ContractConfig `mapstructure:"contract"`
Auth AuthConfig `mapstructure:"auth"`
Sign SignConfig `mapstructure:"sign"`
Callback CallbackConfig `mapstructure:"callback"`
}
```
---
## 7. 前端改造
### 7.1 新增步骤与组件
```
certification/components/
├── PlatformSelect.vue # 【新增】签署平台选择
├── EnterpriseVerify.vue # 改造:支持不同平台 iframe / 跳转方式
├── ContractSign.vue # 改造:按平台展示签署页
└── ...
```
**步骤条调整:**
```javascript
const certificationSteps = [
{ key: 'enterprise_info', title: '填写企业信息', ... },
{ key: 'manual_review', title: '人工审核', ... },
{ key: 'platform_select', title: '选择签署平台', ... }, // 新增
{ key: 'enterprise_verify', title: '企业认证', ... },
{ key: 'contract_sign', title: '签署合同', ... },
{ key: 'completed', title: '完成', ... },
]
```
### 7.2 步骤路由逻辑(`setCurrentStepByStatus`
```javascript
// 审核已通过,但未选平台
if (status === 'info_pending_review' && metadata.manual_review_status === 'approved' && !data.sign_platform) {
currentStep.value = 'platform_select'
return
}
// 或status === 'info_submitted' && !metadata.auth_url && metadata.need_select_platform
```
### 7.3 PlatformSelect.vue 交互
- 调用 `GET /sign-platforms` 获取可选平台卡片e签宝 / 法大大)
- 每张卡片展示:平台名称、说明、预计耗时、合规提示
- 用户点击「确认选择」→ `POST /select-sign-platform`
- 成功后跳转 `enterprise_verify`iframe 加载返回的 `auth_url`
### 7.4 API 封装(`src/api/index.js`
```javascript
export const certificationApi = {
// ...existing
getSignPlatforms: () => request.get('/certifications/sign-platforms'),
selectSignPlatform: (data) => request.post('/certifications/select-sign-platform', data),
}
```
### 7.5 回调路由扩展
现有:
- `/certification/callback/auth`
- `/certification/callback/sign`
建议扩展(便于各平台 redirect_url 分离统计):
- `/certification/callback/esign/auth`
- `/certification/callback/esign/sign`
- `/certification/callback/fadada/auth`
- `/certification/callback/fadada/sign`
`IframeCallback.vue` 可增加 `platform` 路由参数,回调后 `postMessage` 携带 `{ type: 'CHECK_STATUS', scene, platform }`
### 7.6 管理端
`certification-reviews/index.vue` 列表增加「签署平台」列;详情展示平台与第三方 flow ID方便客服排查。
---
## 8. 回调与轮询策略
| 环节 | e签宝现有 | 法大大(新增) | 统一策略 |
|------|---------------|----------------|----------|
| 企业认证完成 | 回调 `AUTH_PASS` + 轮询 identity | 法大大认证回调 + 轮询认证状态 | 两平台均保留「回调 + 轮询」双保险 |
| 合同签署完成 | 主要依赖 `confirm-sign` 轮询 | 同上 | `GET /details` 时按平台自动同步 |
| 验签 | 当前已注释 | **必须实现** | 生产环境两个平台都开启验签 |
---
## 9. 实施分期建议
### Phase 0 — 准备1~2 天)
- [ ] 法大大开放平台开户、创建应用、获取 AppID/AppSecret/openCorpId
- [ ] 在法大大创建合作协议模板(控件与海宇业务字段对齐)
- [ ] 确认沙箱环境与回调公网可达
### Phase 1 — 抽象层 + 数据字段3~5 天)
- [x] `certifications.sign_platform` 及子表字段
- [x] `SignPlatform` 枚举 + `SignPlatformProvider` 接口
- [x] 将现有 e签宝 逻辑迁入 `EsignProvider`(行为不变)
- [x] `PlatformRegistry` 注入容器
- [ ] 历史数据迁移脚本AutoMigrate 已加列;存量可按需刷 `esign`
- [ ] 回归测试:现有 e签宝 全流程无回归
### Phase 2 — 平台选择流程2~3 天)
- [x] 后端 `SelectSignPlatform` + `GetSignPlatforms`
- [x] 调整 `AdminApproveSubmitRecord`(审核后不立即调第三方)
- [x] 前端 `PlatformSelect.vue` + 步骤条改造
- [ ] 仅 e签宝 模式下验证「先选平台 → 再认证 → 再签署」
### Phase 3 — 法大大 Provider5~8 天)
- [x] 接入 HTTP/SDK 封装,实现 `FadadaProvider`(骨架 + OpenAPI 封装)
- [x] 企业认证链接、实名查询(代码层)
- [x] 模板填单、签署任务、状态查询、文件下载(代码层)
- [x] `/callbacks/fadada` + 验签钩子
- [ ] 法大大沙箱端到端联调(需有效凭证与模板)
### Phase 4 — 收尾2~3 天)
- [x] 管理端展示 `sign_platform` / 待选平台
- [ ] 启用 e签宝 回调验签(安全债补齐)
- [ ] 文档与 Swagger 更新
- [ ] 生产配置与灰度发布
**预估总工期12~18 个工作日**1 人全职,含联调;法大大审核/模板配置时间另计)
---
## 10. 风险与注意事项
| 风险 | 说明 | 缓解 |
|------|------|------|
| 两平台企业实名不互通 | 选法大大则必须在法大大完成企业认证 | 平台选择页明确提示;选定后锁定 |
| 模板不一致 | 两份模板需法务分别审核 | 上线前做法务对齐检查清单 |
| 签署状态码差异 | e签宝 `2`=完成;法大大状态码不同 | 封装在各自 Provider 内,对外统一 `SignStatusResult` |
| 经办人信息 | 当前 e签宝 用法人作经办人 | 法大大侧同步规则;授权代表字段映射需确认 |
| 合同文件过期 | e签宝 50 分钟过期重生成 | 法大大侧确认是否有过期策略,在 Provider 实现 |
| 进行中的用户 | 迁移时默认 `esign` | 仅新用户或管理员重置后才出现平台选择 |
---
## 11. 待你决策的问题
在动手写代码前,建议确认以下事项:
### Q1. 平台选择时机
- [ ] **A. 审核通过后由用户选择**(推荐)
- [ ] B. 提交企业信息时选择
- [ ] C. 其他___________
### Q2. 是否新增状态 `platform_pending`
- [ ] **A. 不新增,用 metadata 驱动**(推荐,改动小)
- [ ] B. 新增独立状态
### Q3. e签宝 是否继续保留
- [ ] **A. 双平台并存,用户可选**(推荐)
- [ ] B. 新用户仅法大大e签宝 仅维护存量
- [ ] C. 全量迁移到法大大
### Q4. 管理员审核后行为
- [ ] **A. 审核通过不生成链接,等用户选平台**(推荐)
- [ ] B. 审核通过默认 e签宝 并生成链接,用户可在认证前改选法大大
### Q5. 法大大接入方式
- [ ] **A. 官方 Go SDK**(推荐)
- [ ] B. 自研 HTTP 封装(与 esign 包一致)
### Q6. 合同模板
- [ ] A. 法大大新建一份等价模板
- [ ] B. 非法大大模板,改用上传 PDF 方式发起签署
---
## 12. 文件改动清单(实施时参考)
### 后端
| 文件 | 改动类型 |
|------|----------|
| `domains/certification/entities/certification.go` | 新增 `SignPlatform` 字段 |
| `domains/certification/enums/sign_platform.go` | 新增 |
| `domains/certification/ports/sign_platform_provider.go` | 新增接口 |
| `infrastructure/external/esign/esign_provider.go` | 从 service_impl 抽取 |
| `infrastructure/external/fadada/*` | 新增 |
| `application/certification/certification_application_service_impl.go` | 改为调 registry |
| `application/certification/dto/commands/` | 新增 `SelectSignPlatformCommand` |
| `infrastructure/http/routes/certification_routes.go` | 新增路由 |
| `infrastructure/http/handlers/certification_handler.go` | 新增 handler |
| `config/config.go` + `config.yaml` | 新增 fadada / sign_platform 配置 |
| `container/container.go` | 注册 FadadaProvider + Registry |
### 前端
| 文件 | 改动类型 |
|------|----------|
| `pages/certification/index.vue` | 步骤与状态映射 |
| `pages/certification/components/PlatformSelect.vue` | 新增 |
| `pages/certification/IframeCallback.vue` | 支持多平台 |
| `src/api/index.js` | 新增 API |
| `src/router/index.js` | 扩展 callback 路由 |
| `pages/admin/certification-reviews/index.vue` | 展示 sign_platform |
---
## 13. 总结
本次改造的核心不是「替换 e签宝」而是
1. **主表增加 `sign_platform`**,记录用户选择的签署平台
2. **抽象 `SignPlatformProvider`**,将 e签宝 现有实现原样迁入
3. **审核通过后增加平台选择步骤**,再按平台发放认证/签署链接
4. **新增法大大 Provider**,与 e签宝 并行
这样对存量 e签宝 用户零影响,新用户可自由选择;后续若再接入第三方,只需新增 Provider 实现并加入 `enabled` 列表。
---
*请确认第 11 节中的决策项后,可据此进入具体开发。*