Files
tyapi-server/多平台签署整合实现方案.md
2026-07-24 23:27:17 +08:00

716 lines
29 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签宝 + 法大大)
> 面向 **tyapi**(天远数据)企业入驻流程的改造设计,供评审后决定实施范围与优先级。
> 关联代码:`tyapi-server`(认证域 + `internal/shared/esign`)、`tyapi-frontend``pages/certification`)。
> **本文档仅方案,未改代码;确认后按分期实施。**
---
## 0. 本平台可行性结论tyapi
### 0.1 结论摘要
| 维度 | 结论 | 说明 |
|------|------|------|
| 整体可行性 | **可行** | 入驻状态机、审核→认证→签署链路与文档假设一致,具备抽象多平台的条件 |
| 抽象层改造 | **高可行** | `CertificationApplicationServiceImpl` 已集中调用 `esignClient`,适合抽 `SignPlatformProvider` |
| 法大大接入 | **可行,依赖外部准备** | 需 AppID/模板/沙箱/回调公网;技术映射清晰,联调工期独立 |
| e签宝前端隐藏 | **可行且推荐** | 后端保留 e签宝 Provider存量/兜底);前端不展示 e签宝选项新用户走法大大 |
| 存量影响 | **可控** | 历史与进行中记录默认 `sign_platform=esign`,行为与现网一致 |
### 0.2 与文档原稿的差异(重要)
原稿部分内容来自 **hyapi / 海宇** 语境,**不能直接当作 tyapi 已完成项**
| 项 | 原稿表述 | tyapi 实际 |
|----|----------|------------|
| Phase 1~4 勾选 | 多项已打勾 | **均未落地**(无 `sign_platform` 字段、无 Fadada、无 PlatformSelect、无 SelectSignPlatform API |
| 包路径 | `hyapi-server/...` | `tyapi-server/...` |
| 合同名 / 回调域名 | 海宇 / `haiyudata.com` | 天远 / `console.tianyuanapi.com` |
| e签宝包位置 | 文中写 `infrastructure/external/esign` | 现网为 `internal/shared/esign`(另有 `infrastructure/external/esign/certification_esign_service.go` |
实施时以 **本节 + 下文路径** 为准,不以原稿勾选状态为准。
### 0.3 现网关键触点(改造锚点)
**后端(已绑定 e签宝**
- `AdminApproveSubmitRecord`:审核通过后**立即** `esignClient.GenerateEnterpriseAuth`,写入 `auth_url``info_submitted`
- `ConfirmAuth` / 企业认证轮询:`QueryOrgIdentityInfo`
- `ApplyContract` / 合同生成与签署:`FillTemplate` / `CreateSignFlow` / `GetSignURL`
- 签署完成:`QuerySignFlowDetail` / `DownloadSignedFile`
- 配置:`config.yaml``esign.*`(沙箱 `smlopenapi.esign.cn`,模板与合同名已是天远业务)
**前端:**
- 步骤:`enterprise_info``manual_review``enterprise_verify``contract_sign``completed`
- **无**平台选择步;`auth_url` / `contract_sign_url` 直接 iframe
**数据模型:**
- `certifications``auth_flow_id` / `auth_url` / `contract_file_id` / `esign_flow_id` / `contract_sign_url`
- **无** `sign_platform` 字段
### 0.4 产品决策(已定)
| 决策项 | 结论 |
|--------|------|
| 平台选择时机 | **A**:审核通过后、生成认证链接前(见 2.2 |
| 是否新增 `platform_pending` | **否**:用 metadata 驱动(见 4.3 做法 1 |
| e签宝 是否保留 | **后端保留,前端隐藏**(见 0.5、7.7 |
| 审核通过后行为 | **不立即调第三方**;等用户完成平台确认(对用户侧可自动确认法大大,见 0.5 |
| 法大大接入 | 优先官方 Go SDK若 SDK 不适配再自研 HTTP与现 esign 包风格一致) |
### 0.5 e签宝「前端隐藏」含义本期落地口径
**目标:** 新用户入驻流程中**看不到、选不到 e签宝**对外只走法大大。e签宝代码与配置保留用于
1. 存量 / 进行中且已是 e签宝链路的用户继续完成
2. 管理端排查、必要时管理员重置后内部指定平台
3. 后续若需临时打开双平台,只改配置与前端可见列表,无需重写 Provider
**推荐交互(隐藏后「单可见平台」):**
```
审核通过
→ GET /sign-platforms 返回可见列表(仅 fadadaesign 标记 hidden 或不下发)
→ 可见平台仅 1 个时:前端不展示 PlatformSelect 步骤,自动 POST select-sign-platform=fadada
→ 直接进入企业认证 iframe法大大 auth_url
```
| 规则 | 说明 |
|------|------|
| `sign_platform.enabled` | 配置仍可含 `esign`(后端可用) |
| `sign_platform.visible` / `frontend_hidden` | 控制前端是否展示;本期 `esign` 隐藏 |
| `GET /sign-platforms` | 默认只返回 **可见** 平台;管理端或内部调试可另开参数看全部 |
| `POST /select-sign-platform` | 拒绝用户选择 `hidden` 平台(除非管理员接口) |
| 步骤条 | 单可见平台时:**不增加**「选择签署平台」步骤,用户感知与现网一致(审核后直接认证) |
| 双可见平台时 | 才展示 `PlatformSelect.vue`(预留能力,本期不启用) |
> 这样「多平台架构」一次到位,但 **本期用户体验 ≈ 只接法大大**,改动面主要在后端抽象 + 法大大联调,前端几乎无新增步骤。
---
## 1. 背景与目标
### 1.1 现状
当前企业入驻的**企业实名认证 + 合同签署**全流程绑定在 **e签宝** 单一平台:
- 管理员审核通过后,直接调用 e签宝 `/v3/org-auth-url` 生成 `auth_url`
- 企业认证、模板填单、签署流程、回调/轮询均硬编码在 `CertificationApplicationServiceImpl` + `internal/shared/esign`
### 1.2 目标
1. `certifications` 主表新增 **`sign_platform`(签署平台)** 字段
2. 审核通过后按配置完成平台确认(本期:**自动法大大**;预留多平台选择)
3. 根据 `sign_platform` 发放对应的**企业认证链接**与**合同签署链接**
4. 复用现有状态机;存量 e签宝用户零感迁移
5. e签宝 **前端隐藏**,后端 Provider 保留
### 1.3 非目标(本期可不做)
- 同一用户在不同平台各签一份合同
- 签署中途切换平台(选定后锁定,除非管理员重置)
- 替换掉 e签宝 的全部历史数据
- 向普通用户展示 e签宝 选项(本期明确不做)
---
## 2. 改造后流程设计
### 2.1 主流程(本期:自动法大大)
```
填写企业信息
→ 人工审核info_pending_review
→ 【内部】确认 sign_platform=fadada前端无选择页或静默 select
→ 企业实名认证info_submitted + auth_url
→ 合同预览与签署enterprise_verified → contract_applied → completed
```
若未来 `visible` 含多个平台,再插入「选择签署平台」步骤(见 7.1)。
### 2.2 平台确认时机(推荐方案 A
| 方案 | 时机 | 优点 | 缺点 |
|------|------|------|------|
| **A推荐** | 审核通过后、生成认证链接前确认平台 | 认证与签署同一平台;不浪费第三方调用 | 若多平台可见则多一步 |
| B | 提交企业信息时一并选择 | 步骤少 | 审核拒绝后需重选;用户尚不清楚平台差异 |
| C | 仅合同阶段选平台,认证仍固定 e签宝 | 改动小 | 法大大合同要求法大大侧企业实名,链路不完整 |
**推荐采用方案 A**,状态流转如下:
```mermaid
flowchart TD
A[info_pending_review] --> B[管理员审核通过]
B --> C{sign_platform 已选择?}
C -->|否| D{可见平台数量}
D -->|仅 1 个| E[前端静默 POST select-sign-platform]
D -->|多个| F[展示 PlatformSelect]
E --> G[写入 sign_platform]
F --> G
G --> H[按平台生成 auth_url]
C -->|是| H
H --> I[info_submitted + auth_url]
I --> J[iframe 企业认证]
J --> K[enterprise_verified + 生成合同]
K --> L[apply-contract 按平台发起签署]
L --> M[completed]
```
### 2.3 平台锁定规则
| 规则 | 说明 |
|------|------|
| 可选/可确认时机 | 审核通过后 ~ `info_submitted` 之前(`sign_platform` 为空) |
| 锁定时机 | 写入 `sign_platform` 并生成该平台认证链接后 |
| 不可变更 | 进入 `info_submitted` 后用户不可自行切换 |
| 管理员重置 | 可将 `sign_platform` 置空并回到待确认状态(见 4.4 |
| 前端隐藏 | 普通用户不可选 `esign`;存量 `sign_platform=esign` 仍按 e签宝 Provider 跑完 |
---
## 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
// tyapi-server/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;
-- contract_infos 若存在同理
```
> 注意:若采用「全表 NULL→esign」迁移则**新用户在审核通过前**也会被刷成 esign。更稳妥做法
> - 迁移只刷 **已进入 `info_submitted` 及之后** 的记录;或
> - 迁移后审核通过且仍为 NULL 的走「待确认平台」逻辑(本期自动 fadada
> **推荐:仅迁移「已有 auth_url / esign_flow_id / 已完成链路」的记录为 esign其余保持 NULL。**
---
## 4. 后端架构改造
### 4.1 核心思路签署平台抽象层Strategy + Registry
将 e签宝 特有逻辑从 `CertificationApplicationServiceImpl` 中抽离:
```
internal/domains/certification/ports/sign_platform_provider.go # 接口
internal/infrastructure/external/esign/esign_provider.go # e签宝 Provider封装 shared/esign
internal/infrastructure/external/fadada/fadada_provider.go # 法大大 Provider
internal/infrastructure/external/signplatform/registry.go # 按 sign_platform 路由
```
> 现有 HTTP/业务封装继续放在 `internal/shared/esign`Provider 是薄适配层,避免一次性搬迁全部 esign 包。
**接口草案:**
```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
}
```
调用改为:
```go
provider := s.platformRegistry.Get(cert.SignPlatform)
provider.GenerateEnterpriseAuth(...)
```
### 4.2 需改造的后端触点(按优先级)
| 方法 | 现状 | 改造 |
|------|------|------|
| `AdminApproveSubmitRecord` | 立即 `esignClient.GenerateEnterpriseAuth` | 审核通过后**不立即**生成链接;仅更新审核态,等平台确认 |
| **新增** `SelectSignPlatform` | 无 | 写 `sign_platform` → provider 生成 `auth_url``info_submitted`;拒绝普通用户选 hidden 平台 |
| `ConfirmAuth` / 企业认证完成检查 | 查 e签宝 identity | `QueryOrgVerified` |
| `generateAndAddContractFile` | e签宝 FillTemplate | `GenerateContractFile` |
| `ApplyContract` / 签署 URL | e签宝 SignFlow | `CreateSignFlow` |
| `checkAndUpdateSignStatus` | e签宝 QuerySignFlowDetail | `QuerySignStatus` |
| `handleContractAfterSignComplete` | e签宝 DownloadSignedFile | `DownloadSignedFiles` |
| e签宝回调 | 现有回调入口 | 保留 `/callbacks/esign`;新增 `/callbacks/fadada` |
### 4.3 状态机微调(推荐做法 1不新增状态
- 管理员审核通过后:保持 `info_pending_review`,或进入 `info_submitted``auth_url` 为空
- `details` metadata 驱动前端:
```json
{
"status": "info_pending_review",
"metadata": {
"manual_review_status": "approved",
"need_select_platform": true,
"available_platforms": ["fadada"],
"auto_select_platform": "fadada"
}
}
```
| 字段 | 含义 |
|------|------|
| `need_select_platform` | 是否还需确认平台(`sign_platform` 为空) |
| `available_platforms` | **前端可见**平台列表(本期仅 `fadada` |
| `auto_select_platform` | 可见仅 1 个时下发,前端可静默提交 |
**不推荐**本期新增 `platform_pending` 状态(改状态机、步骤映射、管理端筛选成本高)。
### 4.4 新增 API
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/v1/certifications/sign-platforms` | 返回**可见**平台列表;可带 `include_hidden`(仅管理员) |
| POST | `/api/v1/certifications/select-sign-platform` | 确认平台并生成认证链接 |
| POST | `/api/v1/certifications/callbacks/fadada` | 法大大回调 |
| POST | `/api/v1/certifications/admin/reset-sign-platform` | 管理员重置平台(可选) |
| POST | `/api/v1/certifications/admin/select-sign-platform` | 管理员可指定含 esign 的平台(可选,运维用) |
**`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 管理员审核逻辑调整
```
审核通过 → 仅更新 submit_record.manual_review_status = approved
→ 认证状态:保持 info_pending_review或 info_submitted 无 auth_url
→ 不调用任何第三方
用户侧确认平台(本期自动 fadada→ SelectSignPlatform → provider → auth_url → info_submitted
```
管理端列表建议展示 `sign_platform` 列(含存量 `esign`),便于客服排查。
---
## 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 |
| 应用模板 / 签署模板 | 对应《天远数据API合作协议》 |
| 测试环境域名 | 沙箱联调 |
| 回调地址 | `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` | `/sign-task/create` 或 create-with-template |
| 获取签署链接 | `POST /v3/sign-flow/{id}/sign-url` | `/sign-task/actor/get-url` |
| 查询签署状态 | `GET /v3/sign-flow/{id}/detail` | `/sign-task/app/get-detail` |
| 下载已签文件 | `GET /v3/sign-flow/{id}/file-download-url` | `/sign-task/owner/get-download-url` |
| 回调 | 现有 e签宝回调 | `X-FASC-*` HMAC-SHA256 验签 + ParseCallback |
> 具体路径以法大大 v5.1 文档为准;实施时按官方 SDK 方法名落地。
### 5.4 法大大合同模板控件
模板 ID、控件 fieldId 以法大大控制台实际创建为准,写入 `config.yaml``fadada.contract_fields`(或等价结构)。
业务字段应对齐现网 e签宝 控件语义(协议编号、甲乙方信息、签署日期等),日期格式与现网一致:`2006年01月02日`
> 原稿中的法大大 fieldId 示例来自他站模板,**不可直接用于 tyapi**;上线前需在法大大新建天远模板并回填配置。
### 5.5 法大大 SDK 目录规划
```
tyapi-server/internal/shared/fadada/ # 或 infrastructure/external/fadada/
├── client.go
├── 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"] # 后端已注册、可路由的平台
visible: ["fadada"] # 前端可见(本期隐藏 e签宝
default: "fadada" # 可见仅 1 个或自动确认时使用
esign:
# 保持现有配置不变(存量链路)
...
fadada:
app_id: ""
app_secret: ""
server_url: "https://api.fadada.com" # 以官方文档为准
open_corp_id: ""
template_id: ""
contract:
name: "天远数据API合作协议"
expire_days: 7
auth:
redirect_url: "https://console.tianyuanapi.com/certification/callback/fadada/auth"
sign:
redirect_url: "https://console.tianyuanapi.com/certification/callback/fadada/sign"
callback:
enabled: true
```
### 6.2 Go Config 结构
```go
type SignPlatformConfig struct {
Enabled []string `mapstructure:"enabled"`
Visible []string `mapstructure:"visible"` // 前端可见;空则等同 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 / Auth / Sign / Callback 与 esign 段对称
}
```
**可见性规则:**
- `visible` 必须是 `enabled` 的子集
- 用户 `SelectSignPlatform`:只能选 `visible` 中的值
- 管理员接口:可选 `enabled` 中的任意值(含隐藏的 esign
---
## 7. 前端改造
### 7.1 组件与步骤
```
certification/components/
├── PlatformSelect.vue # 预留:仅当 available_platforms.length > 1 时使用
├── EnterpriseVerify.vue # 改造:兼容不同平台 iframe / 跳转
├── ContractSign.vue # 改造:按平台展示签署页(多数情况仍为 iframe
└── ...
```
**本期步骤条(与现网一致,不增加平台选择步):**
```javascript
const certificationSteps = [
{ key: 'enterprise_info', title: '填写企业信息' },
{ key: 'manual_review', title: '人工审核' },
// 不展示 platform_select单可见平台自动确认
{ key: 'enterprise_verify', title: '企业认证' },
{ key: 'contract_sign', title: '签署合同' },
{ key: 'completed', title: '完成' },
]
```
多平台可见时再插入:
```javascript
{ key: 'platform_select', title: '选择签署平台' }
```
### 7.2 步骤路由逻辑(`setCurrentStepByStatus`
```javascript
// 审核已通过,尚未确认平台
if (
status === 'info_pending_review' &&
metadata.manual_review_status === 'approved' &&
!data.sign_platform
) {
const platforms = metadata.available_platforms || []
if (platforms.length <= 1 && metadata.auto_select_platform) {
// 静默确认,不进入 platform_select
await certificationApi.selectSignPlatform({
sign_platform: metadata.auto_select_platform,
})
await getCertificationDetails()
return
}
currentStep.value = 'platform_select'
return
}
```
### 7.3 PlatformSelect.vue仅多可见平台
- 调用 `GET /sign-platforms`(仅可见项)
- 卡片:名称、说明、合规提示
- 确认 → `POST /select-sign-platform` → 跳转 `enterprise_verify`
### 7.4 API 封装
```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`
建议扩展:
- `/certification/callback/esign/auth` | `.../sign`(兼容旧 redirect可 301/同组件)
- `/certification/callback/fadada/auth` | `.../sign`
`IframeCallback.vue` 可增加 `platform` 参数,`postMessage` 携带 `{ type: 'CHECK_STATUS', scene, platform }`
### 7.6 管理端
`certification-reviews/index.vue` 增加「签署平台」列;详情展示平台与第三方 flow ID。
管理员重置/指定平台时可看到 **含 e签宝** 的完整 `enabled` 列表。
### 7.7 e签宝前端隐藏清单验收标准
| 检查项 | 期望 |
|--------|------|
| 用户步骤条 | 无「e签宝」文案、无平台二选一单可见时 |
| `GET /sign-platforms` | 不含 esign`hidden: true` 且前端过滤) |
| 用户误传 `sign_platform=esign` | 后端 4xx提示平台不可用 |
| 存量 esign 用户 | 仍能打开 e签宝认证/签署 iframe流程可完成 |
| 文案 | 企业认证/签署页不出现「e签宝」品牌可选统一写「完成企业认证」 |
---
## 8. 回调与轮询策略
| 环节 | e签宝存量 | 法大大(新用户) | 统一策略 |
|------|---------------|------------------|----------|
| 企业认证完成 | 回调 + 轮询 identity | 认证回调 + 轮询 | 双保险 |
| 合同签署完成 | `confirm-sign` / details 轮询 | 同左 | `GET /details` 按平台同步 |
| 验签 | 现网若未开须补齐 | **必须实现** | 生产两平台均开启验签 |
---
## 9. 实施分期建议tyapi 现状:全部未做)
### Phase 0 — 准备1~2 天)
- [ ] 法大大开户、应用、AppID/AppSecret/openCorpId
- [ ] 创建天远合作协议模板,控件与业务字段对齐
- [ ] 确认沙箱与回调公网可达
### Phase 1 — 抽象层 + 数据字段3~5 天)
- [ ] `certifications.sign_platform` 及子表字段
- [ ] `SignPlatform` 枚举 + `SignPlatformProvider` 接口
- [ ] 现有 e签宝 逻辑迁入 / 适配为 `EsignProvider`(行为不变)
- [ ] `PlatformRegistry` 注入容器
- [ ] 历史数据迁移(仅存量链路刷 `esign`,见 3.4
- [ ] 回归e签宝全流程无回归
### Phase 2 — 平台确认流程 + 前端隐藏2~3 天)
- [ ] `SelectSignPlatform` + `GetSignPlatforms`visible / auto_select
- [ ] 调整 `AdminApproveSubmitRecord`(审核后不调第三方)
- [ ] 前端:单可见平台静默 select**不展示 e签宝**
- [ ] 预留 `PlatformSelect.vue`(多平台时再用)
- [ ] 配置 `enabled` / `visible` / `default`
### Phase 3 — 法大大 Provider5~8 天)
- [ ] HTTP/SDK 封装 + `FadadaProvider`
- [ ] 企业认证链接、实名查询
- [ ] 模板填单、签署任务、状态查询、文件下载
- [ ] `/callbacks/fadada` + 验签
- [ ] 沙箱端到端联调
### Phase 4 — 收尾2~3 天)
- [ ] 管理端展示 `sign_platform` / 重置能力
- [ ] e签宝回调验签补齐安全债
- [ ] Swagger / 运维文档
- [ ] 生产配置与灰度(建议先灰度新用户自动 fadada
**预估总工期12~18 个工作日**1 人全职,含联调;法大大审核/模板配置时间另计)。
因本期前端不展示选择页,**Phase 2 前端工作量低于原稿**。
---
## 10. 风险与注意事项
| 风险 | 说明 | 缓解 |
|------|------|------|
| 两平台企业实名不互通 | 选法大大必须在法大大完成企业认证 | 新用户统一法大大;存量继续 e签宝 |
| 模板不一致 | 天远需在法大大单独建模板 | 上线前法务对齐检查清单 |
| 签署状态码差异 | e签宝与法大大状态码不同 | 封装在 Provider 内,对外统一 `SignStatusResult` |
| 经办人信息 | 现网 e签宝用法人作经办人 | 法大大侧同步规则并确认字段映射 |
| 合同文件过期 | e签宝约 50 分钟过期重生成 | 法大大侧确认过期策略并在 Provider 实现 |
| 误迁移把新单刷成 esign | 全表 UPDATE 过宽 | 按 3.4 推荐:只刷已进入签署链路的记录 |
| 前端隐藏但配置仍开 esign | 用户直接调 API 选 esign | `SelectSignPlatform` 校验 `visible` |
| 静默 auto-select 失败 | 审核通过后卡在待确认 | details 重试 + 明确错误提示 + 客服可管理员指定 |
---
## 11. 决策记录
| 编号 | 议题 | 结论 |
|------|------|------|
| Q1 | 平台确认时机 | **A** 审核通过后、生成链接前 |
| Q2 | 是否新增 `platform_pending` | **否**metadata 驱动 |
| Q3 | e签宝是否保留 | **后端保留 + 前端隐藏**;新用户默认/仅可见法大大 |
| Q4 | 审核通过后行为 | **不生成链接**,等平台确认(可自动) |
| Q5 | 法大大接入方式 | **优先官方 Go SDK**,不适配则自研 HTTP |
| Q6 | 合同模板 | **法大大新建天远等价模板**(不可复用他站 fieldId |
---
## 12. 文件改动清单(实施时参考)
### 后端tyapi-server
| 文件 | 改动类型 |
|------|----------|
| `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` | 新增(适配 `shared/esign` |
| `shared/fadada/*``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` | `sign_platform` + `fadada` |
| `container/container.go` | 注册 Provider + Registry |
### 前端tyapi-frontend
| 文件 | 改动类型 |
|------|----------|
| `pages/certification/index.vue` | 审核通过后静默 select步骤映射 |
| `pages/certification/components/PlatformSelect.vue` | 预留(多可见平台) |
| `pages/certification/IframeCallback.vue` | 支持多平台 callback path |
| `src/api/index.js` | 新增 API |
| `src/router/index.js` | 扩展 callback 路由 |
| `pages/admin/certification-reviews/index.vue` | 展示 / 可选重置 sign_platform |
---
## 13. 总结
本次改造的核心不是「立刻砍掉 e签宝」而是
1. **主表增加 `sign_platform`**,区分存量 e签宝与新用户法大大
2. **抽象 `SignPlatformProvider`**e签宝现网实现迁入/适配为 Provider
3. **审核通过后确认平台再发链接**;本期通过配置 **前端隐藏 e签宝 + 自动法大大**,用户无感多一步
4. **新增法大大 Provider**,与 e签宝并行于后端
对存量 e签宝用户零影响新用户只走法大大后续若要双平台可选只需把 `esign` 加入 `visible` 并启用 `PlatformSelect`
---
## 14. 待你拍板后再改代码的事项
确认本方案后,建议按下列顺序开工(仍等你明确说「开始改代码」):
1. Phase 0法大大账号与天远模板是否已就绪
2. Phase 1是否先只做抽象 + e签宝 Provider 回归,再看法大大?
3. 迁移策略是否采用 **3.4 推荐(只刷存量链路)**
4. 回调域名是否继续用 `console.tianyuanapi.com`
*文档已按 tyapi 现状与「e签宝前端隐藏」决策修订确认后进入开发。*
)