# 企业认证系统实施计划 ## 📋 需求概述 ### 业务流程 用户注册后需要进行企业认证以使用平台核心功能,认证流程如下: 1. **提交企业信息**:用户上传营业执照,系统通过百度 OCR 自动识别企业四要素 2. **人脸识别**:法人进行人脸识别验证 3. **申请电子合同**:系统生成申请记录 4. **管理员审核**:管理员收到企业微信通知,审核后手工上传签署链接 5. **签署合同**:用户收到短信通知,点击链接完成签署 6. **认证完成**:系统为用户生成钱包和 Access Key ### 企业四要素 - 企业名称 - 统一信用代码 - 企业法人姓名 - 法人身份证号 ## 📊 业务流程图 整个企业认证流程包含 10 个主要状态节点,涉及用户、系统、管理员和第三方服务的协同工作: ### 流程说明 1. **用户操作阶段**(蓝色节点) - 用户上传营业执照图片(自动上传至七牛云并 OCR 识别) - 确认或修改 OCR 识别的企业四要素信息 - 进行阿里云人脸识别验证 - 申请电子合同 - 查看合同链接并签署电子合同 2. **系统自动处理**(紫色节点) - 创建认证申请记录 - 七牛云文件存储和百度 OCR 识别 - 将合同申请转为待审核状态 - 确认合同签署状态 - 生成钱包和 Access Key 3. **管理员审核**(橙色节点) - 审核企业认证申请 - **手工上传电子合同签署链接** - 处理审核结果(通过/拒绝) 4. **等待状态**(紫色节点) - 合同待审核状态(等待管理员处理) - 合同已审核状态(等待用户签署) 5. **第三方服务**(绿色节点) - 七牛云文件存储 - 百度 OCR 识别营业执照 - 阿里云 InitFaceVerify 人脸识别 6. **决策节点**(红色节点) - 企业信息确认(OCR 成功与否都允许用户确认) - 人脸识别结果验证 - 管理员审核结果(通过/拒绝) - 合同签署状态 ### 关键特性 - **一体化处理**:营业执照上传、存储、OCR 识别一次完成 - **容错性强**:OCR 识别失败不影响流程,用户可手动填写信息 - **异步审核**:用户申请合同后,管理员异步审核并上传链接,用户无需实时等待 - **手工上传**:管理员手工上传电子合同签署链接,确保合同的准确性和合规性 - **状态分离**:合同申请、待审核、已审核(有链接)、已签署状态清晰分离 - **重试机制**:人脸识别、合同签署都支持失败重试 - **多渠道通知**:企业微信通知管理员新申请,短信通知用户合同就绪和认证完成 - **状态追踪**:每个环节都有明确的状态标识和时间戳记录 - **安全存储**:营业执照文件安全存储在七牛云,支持 CDN 加速访问 ## 🏗️ 架构设计 ### 新增域结构 ``` internal/domains/ ├── certification/ # 企业认证域 │ ├── entities/ # 实体层 │ │ ├── certification.go # 认证申请实体 │ │ ├── enterprise.go # 企业信息实体 │ │ └── contract.go # 电子合同实体 │ ├── dto/ # 数据传输对象 │ │ ├── certification_dto.go │ │ ├── enterprise_dto.go │ │ └── ocr_dto.go │ ├── repositories/ # 仓储层 │ │ ├── certification_repository.go │ │ ├── enterprise_repository.go │ │ └── contract_repository.go │ ├── services/ # 服务层 │ │ ├── certification_service.go │ │ ├── enterprise_service.go │ │ ├── ocr_service.go │ │ └── face_verification_service.go │ ├── handlers/ # 处理器层 │ │ ├── certification_handler.go │ │ └── admin_certification_handler.go │ ├── routes/ # 路由层 │ │ ├── certification_routes.go │ │ └── admin_certification_routes.go │ ├── events/ # 事件层 │ │ └── certification_events.go │ ├── enums/ # 枚举定义 │ │ └── certification_status.go │ └── migrations/ # 数据库迁移 ├── finance/ # 财务域(独立域) │ ├── entities/ │ │ └── wallet.go │ ├── dto/ │ │ └── wallet_dto.go │ ├── repositories/ │ │ └── wallet_repository.go │ ├── services/ │ │ └── wallet_service.go │ ├── handlers/ │ │ └── wallet_handler.go │ ├── routes/ │ │ └── wallet_routes.go │ └── migrations/ ├── admin/ # 管理员域 │ ├── entities/ │ │ └── admin.go │ ├── repositories/ │ │ └── admin_repository.go │ ├── services/ │ │ └── admin_service.go │ ├── handlers/ │ │ └── admin_handler.go │ └── routes/ │ └── admin_routes.go └── notification/ # 通知域(扩展) ├── services/ │ ├── notification_service.go │ ├── wechat_work_service.go │ └── enhanced_sms_service.go └── providers/ ├── wechat_work_provider.go └── sms_template_provider.go ``` ### 共享服务重构 ``` internal/shared/ ├── sms/ # 短信服务(现有,需扩展) │ ├── sms_service.go # 基础短信服务 │ ├── template_service.go # 短信模板服务(新增) │ └── notification_sms.go # 通知类短信服务(新增) ├── ocr/ # OCR服务(新增) │ ├── baidu_ocr_service.go # 百度OCR实现 │ └── ocr_interface.go # OCR接口定义 ├── storage/ # 文件存储服务(新增) │ ├── qiniu_storage_service.go # 七牛云存储实现 │ └── storage_interface.go # 存储接口定义 └── third_party/ # 第三方服务(新增) ├── aliyun/ │ ├── face_verify_service.go # 阿里云人脸识别 │ └── sms_service.go # 阿里云短信服务 ├── qiniu/ │ └── qiniu_client.go # 七牛云客户端 └── wechat_work/ └── wechat_work_api.go ``` ## 📊 核心实体设计 ### 认证状态枚举 ```go type CertificationStatus string const ( StatusPending CertificationStatus = "pending" // 待开始 StatusEnterpriseSubmitted = "enterprise_submitted" // 企业信息已提交 StatusOCRProcessed = "ocr_processed" // OCR识别完成 StatusFaceVerified = "face_verified" // 人脸识别完成 StatusContractApplied = "contract_applied" // 已申请合同 StatusContractPending = "contract_pending" // 合同待审核 StatusContractApproved = "contract_approved" // 合同已审核(有链接) StatusContractSigned = "contract_signed" // 合同已签署 StatusCompleted = "completed" // 认证完成 StatusRejected = "rejected" // 已拒绝 ) ``` ### 认证申请实体 ```go type Certification struct { ID string `gorm:"primaryKey;type:varchar(36)"` UserID string `gorm:"type:varchar(36);not null;index"` EnterpriseID string `gorm:"type:varchar(36);index"` Status CertificationStatus `gorm:"type:varchar(50);not null;index"` // 流程节点时间戳 InfoSubmittedAt *time.Time `json:"info_submitted_at"` FaceVerifiedAt *time.Time `json:"face_verified_at"` ContractAppliedAt *time.Time `json:"contract_applied_at"` ContractApprovedAt *time.Time `json:"contract_approved_at"` ContractSignedAt *time.Time `json:"contract_signed_at"` CompletedAt *time.Time `json:"completed_at"` // 审核信息 AdminID *string `gorm:"type:varchar(36)"` ApprovalNotes string `gorm:"type:text"` RejectReason string `gorm:"type:text"` // 合同信息 ContractURL string `gorm:"type:varchar(500)"` SigningURL string `gorm:"type:varchar(500)"` SignedAt *time.Time // OCR识别信息 OCRRequestID string `gorm:"type:varchar(100)"` OCRConfidence float64 `gorm:"type:decimal(5,2)"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 企业信息实体 ```go type Enterprise struct { ID string `gorm:"primaryKey;type:varchar(36)"` CertificationID string `gorm:"type:varchar(36);not null"` // 企业四要素 CompanyName string `gorm:"type:varchar(255);not null"` // 企业名称 UnifiedSocialCode string `gorm:"type:varchar(50);not null"` // 统一社会信用代码 LegalPersonName string `gorm:"type:varchar(100);not null"` // 法定代表人姓名 LegalPersonID string `gorm:"type:varchar(50);not null"` // 法定代表人身份证号 // OCR识别结果 BusinessLicenseURL string `gorm:"type:varchar(500);not null"` // 营业执照图片URL OCRRawData string `gorm:"type:text"` // OCR原始返回数据 OCRConfidence float64 `gorm:"type:decimal(5,2)"` // 识别置信度 // 验证状态 IsOCRVerified bool `gorm:"default:false"` IsFaceVerified bool `gorm:"default:false"` VerificationData string `gorm:"type:text"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 钱包实体(财务域) ```go type Wallet struct { ID string `gorm:"primaryKey;type:varchar(36)"` UserID string `gorm:"type:varchar(36);not null;uniqueIndex"` // 钱包状态 IsActive bool `gorm:"default:true"` Balance decimal.Decimal `gorm:"type:decimal(20,8);default:0"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 用户密钥实体(财务域) ```go type UserSecrets struct { ID string `gorm:"primaryKey;type:varchar(36)"` UserID string `gorm:"type:varchar(36);not null;uniqueIndex"` AccessID string `gorm:"type:varchar(100);not null;uniqueIndex"` AccessKey string `gorm:"type:varchar(255);not null"` // 密钥状态 IsActive bool `gorm:"default:true"` LastUsedAt *time.Time ExpiresAt *time.Time CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 营业执照上传记录实体 ```go type LicenseUploadRecord struct { ID string `gorm:"primaryKey;type:varchar(36)"` CertificationID string `gorm:"type:varchar(36);not null;index"` UserID string `gorm:"type:varchar(36);not null;index"` // 文件信息 OriginalFileName string `gorm:"type:varchar(255);not null"` FileSize int64 `gorm:"not null"` FileType string `gorm:"type:varchar(50);not null"` FileURL string `gorm:"type:varchar(500);not null"` QiNiuKey string `gorm:"type:varchar(255);not null"` // OCR处理结果 OCRProcessed bool `gorm:"default:false"` OCRSuccess bool `gorm:"default:false"` OCRConfidence float64 `gorm:"type:decimal(5,2)"` OCRRawData string `gorm:"type:text"` OCRErrorMessage string `gorm:"type:varchar(500)"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 人脸识别记录实体 ```go type FaceVerifyRecord struct { ID string `gorm:"primaryKey;type:varchar(36)"` CertificationID string `gorm:"type:varchar(36);not null;index"` UserID string `gorm:"type:varchar(36);not null;index"` // 阿里云人脸识别信息 CertifyID string `gorm:"type:varchar(100);not null"` VerifyURL string `gorm:"type:varchar(500)"` ReturnURL string `gorm:"type:varchar(500)"` // 身份信息 RealName string `gorm:"type:varchar(100);not null"` IDCardNumber string `gorm:"type:varchar(50);not null"` // 验证结果 Status string `gorm:"type:varchar(50);not null"` // PROCESSING, SUCCESS, FAIL ResultCode string `gorm:"type:varchar(50)"` ResultMessage string `gorm:"type:varchar(500)"` VerifyScore float64 `gorm:"type:decimal(5,2)"` // 时间信息 InitiatedAt time.Time `gorm:"autoCreateTime"` CompletedAt *time.Time ExpiresAt time.Time `gorm:"not null"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 通知记录实体 ```go type NotificationRecord struct { ID string `gorm:"primaryKey;type:varchar(36)"` CertificationID string `gorm:"type:varchar(36);index"` UserID string `gorm:"type:varchar(36);index"` // 通知类型和渠道 NotificationType string `gorm:"type:varchar(50);not null"` // SMS, WECHAT_WORK, EMAIL NotificationScene string `gorm:"type:varchar(50);not null"` // ADMIN_NEW_APPLICATION, USER_CONTRACT_READY, etc. // 接收方信息 Recipient string `gorm:"type:varchar(255);not null"` // 消息内容 Title string `gorm:"type:varchar(255)"` Content string `gorm:"type:text;not null"` TemplateID string `gorm:"type:varchar(100)"` TemplateParams string `gorm:"type:text"` // JSON格式 // 发送状态 Status string `gorm:"type:varchar(50);not null"` // PENDING, SENT, FAILED ErrorMessage string `gorm:"type:varchar(500)"` SentAt *time.Time RetryCount int `gorm:"default:0"` MaxRetryCount int `gorm:"default:3"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ### 合同记录实体 ```go type ContractRecord struct { ID string `gorm:"primaryKey;type:varchar(36)"` CertificationID string `gorm:"type:varchar(36);not null;index"` UserID string `gorm:"type:varchar(36);not null;index"` AdminID string `gorm:"type:varchar(36);index"` // 合同信息 ContractType string `gorm:"type:varchar(50);not null"` // ENTERPRISE_CERTIFICATION ContractURL string `gorm:"type:varchar(500)"` SigningURL string `gorm:"type:varchar(500)"` // 签署信息 SignatureData string `gorm:"type:text"` SignedAt *time.Time ClientIP string `gorm:"type:varchar(50)"` UserAgent string `gorm:"type:varchar(500)"` // 状态信息 Status string `gorm:"type:varchar(50);not null"` // PENDING, APPROVED, SIGNED, EXPIRED ApprovalNotes string `gorm:"type:text"` RejectReason string `gorm:"type:text"` ExpiresAt *time.Time CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } ``` ## 🔄 状态管理设计 ### 认证状态枚举扩展 ```go type CertificationStatus string const ( // 主流程状态 StatusPending CertificationStatus = "pending" // 待开始 StatusInfoSubmitted = "info_submitted" // 企业信息已提交 StatusFaceVerified = "face_verified" // 人脸识别完成 StatusContractApplied = "contract_applied" // 已申请合同 StatusContractPending = "contract_pending" // 合同待审核 StatusContractApproved = "contract_approved" // 合同已审核(有链接) StatusContractSigned = "contract_signed" // 合同已签署 StatusCompleted = "completed" // 认证完成 // 失败和重试状态 StatusFaceFailed = "face_failed" // 人脸识别失败 StatusSignFailed = "sign_failed" // 签署失败 StatusRejected = "rejected" // 已拒绝 ) ``` ### 状态转换规则 ```go type StateTransition struct { From CertificationStatus To CertificationStatus Action string AllowUser bool // 是否允许用户操作 AllowAdmin bool // 是否允许管理员操作 } var stateTransitions = []StateTransition{ // 正常流程转换 {StatusPending, StatusInfoSubmitted, "submit_info", true, false}, {StatusInfoSubmitted, StatusFaceVerified, "face_verify", true, false}, {StatusFaceVerified, StatusContractApplied, "apply_contract", true, false}, {StatusContractApplied, StatusContractPending, "system_process", false, false}, // 系统自动 {StatusContractPending, StatusContractApproved, "admin_approve", false, true}, {StatusContractApproved, StatusContractSigned, "user_sign", true, false}, {StatusContractSigned, StatusCompleted, "system_complete", false, false}, // 系统自动 // 失败和重试转换 {StatusInfoSubmitted, StatusFaceFailed, "face_fail", false, false}, {StatusFaceFailed, StatusInfoSubmitted, "retry_face", true, false}, {StatusContractPending, StatusRejected, "admin_reject", false, true}, {StatusRejected, StatusInfoSubmitted, "restart_process", true, false}, {StatusContractApproved, StatusSignFailed, "sign_fail", false, false}, {StatusSignFailed, StatusContractApproved, "retry_sign", true, false}, } ``` ### 状态管理服务 ```go type CertificationStateMachine struct { transitions map[CertificationStatus][]CertificationStatus repo *CertificationRepository logger *zap.Logger } func NewCertificationStateMachine(repo *CertificationRepository, logger *zap.Logger) *CertificationStateMachine { sm := &CertificationStateMachine{ transitions: make(map[CertificationStatus][]CertificationStatus), repo: repo, logger: logger, } // 构建状态转换映射 for _, transition := range stateTransitions { sm.transitions[transition.From] = append(sm.transitions[transition.From], transition.To) } return sm } func (sm *CertificationStateMachine) CanTransition(from, to CertificationStatus) bool { allowedStates, exists := sm.transitions[from] if !exists { return false } for _, allowedState := range allowedStates { if allowedState == to { return true } } return false } func (sm *CertificationStateMachine) TransitionTo(ctx context.Context, certificationID string, newStatus CertificationStatus, operatorID string, notes string) error { // 获取当前认证记录 certification, err := sm.repo.GetByID(ctx, certificationID) if err != nil { return fmt.Errorf("获取认证记录失败: %w", err) } // 检查状态转换是否合法 if !sm.CanTransition(certification.Status, newStatus) { return fmt.Errorf("不允许从状态 %s 转换到 %s", certification.Status, newStatus) } // 更新状态和时间戳 oldStatus := certification.Status certification.Status = newStatus sm.updateTimestamp(certification, newStatus) // 记录操作信息 if operatorID != "" { certification.AdminID = &operatorID } if notes != "" { certification.ApprovalNotes = notes } // 保存更新 if err := sm.repo.Update(ctx, certification); err != nil { return fmt.Errorf("更新认证状态失败: %w", err) } sm.logger.Info("认证状态已更新", zap.String("certification_id", certificationID), zap.String("from_status", string(oldStatus)), zap.String("to_status", string(newStatus)), zap.String("operator_id", operatorID)) return nil } func (sm *CertificationStateMachine) updateTimestamp(cert *entities.Certification, status CertificationStatus) { now := time.Now() switch status { case StatusInfoSubmitted: cert.InfoSubmittedAt = &now case StatusFaceVerified: cert.FaceVerifiedAt = &now case StatusContractApplied: cert.ContractAppliedAt = &now case StatusContractApproved: cert.ContractApprovedAt = &now case StatusContractSigned: cert.ContractSignedAt = &now case StatusCompleted: cert.CompletedAt = &now } } func (sm *CertificationStateMachine) GetNextAllowedStates(currentStatus CertificationStatus) []CertificationStatus { return sm.transitions[currentStatus] } func (sm *CertificationStateMachine) GetRetryAction(status CertificationStatus) *string { retryMap := map[CertificationStatus]string{ StatusFaceFailed: "重新进行人脸识别", StatusSignFailed: "重新签署合同", StatusRejected: "重新提交申请", } if action, exists := retryMap[status]; exists { return &action } return nil } ``` ## 📱 分阶段接口设计 ### 阶段 1: 上传营业执照(前端交互) ```http POST /api/v1/certification/upload-license Content-Type: multipart/form-data { "business_license": "file", // 营业执照图片文件 "user_id": "string" // 用户ID } ``` **响应:** ```json { "code": 200, "message": "营业执照上传成功", "data": { "upload_record_id": "upload_123456", "license_url": "https://qiniu.example.com/licenses/cert_123456.jpg", "ocr_result": { "success": true, "confidence": 95.5, "enterprise_info": { "company_name": "示例科技有限公司", "unified_social_code": "91110000123456789X", "legal_person_name": "张三", "legal_person_id": "110101199001011234" } } } } ``` **OCR 失败响应:** ```json { "code": 200, "message": "营业执照上传成功,OCR识别失败", "data": { "upload_record_id": "upload_123456", "license_url": "https://qiniu.example.com/licenses/cert_123456.jpg", "ocr_result": { "success": false, "error": "图片模糊,无法识别企业信息", "enterprise_info": { "company_name": "", "unified_social_code": "", "legal_person_name": "", "legal_person_id": "" } } } } ``` ### 阶段 2: 提交企业信息 (pending → info_submitted) ```http POST /api/v1/certification/submit-enterprise-info Content-Type: application/json { "upload_record_id": "upload_123456", "company_name": "示例科技有限公司", "unified_social_code": "91110000123456789X", "legal_person_name": "张三", "legal_person_id": "110101199001011234" } ``` **信息提交成功:** ```json { "code": 200, "message": "企业信息提交成功", "data": { "certification_id": "cert_123456", "status": "info_submitted", "next_step": "进行人脸识别", "next_action": "face_verify" } } ``` ### 阶段 3: 人脸识别 (info_submitted → face_verified/face_failed) ```http POST /api/v1/certification/{certification_id}/face-verify Content-Type: application/json { "legal_person_name": "张三", "legal_person_id": "110101199001011234", "return_url": "https://yourdomain.com/certification/face-result" } ``` **人脸识别初始化成功:** ```json { "code": 200, "message": "人脸识别初始化成功", "data": { "certification_id": "cert_123456", "certify_id": "face_certify_789", "verify_url": "https://cloudauth.aliyun.com/web/verify?token=xxx", "status": "face_processing", "next_step": "请在30分钟内完成人脸识别", "expire_time": "2024-01-15T10:30:00Z" } } ``` **人脸识别结果查询:** ```http GET /api/v1/certification/{certification_id}/face-result ``` **人脸识别成功:** ```json { "code": 200, "message": "人脸识别成功", "data": { "certification_id": "cert_123456", "status": "face_verified", "verify_result": "通过", "next_step": "申请电子合同", "next_action": "apply_contract" } } ``` ### 阶段 4: 申请电子合同 (face_verified → contract_applied → contract_pending) ```http POST /api/v1/certification/{certification_id}/apply-contract Content-Type: application/json { "contact_phone": "13800138000", "contact_email": "example@company.com" } ``` **申请成功:** ```json { "code": 200, "message": "电子合同申请已提交", "data": { "certification_id": "cert_123456", "status": "contract_applied", "next_step": "系统正在处理申请", "estimated_time": "1-3个工作日" } } ``` **系统自动转换状态查询:** ```http GET /api/v1/certification/{certification_id}/status ``` **转换为待审核状态:** ```json { "code": 200, "message": "合同申请已进入审核队列", "data": { "certification_id": "cert_123456", "status": "contract_pending", "next_step": "等待管理员审核并上传合同链接", "estimated_time": "1-3个工作日", "notification": "已通过企业微信通知管理员,审核结果将通过短信通知您" } } ``` ### 阶段 5: 管理员审核和合同链接上传 (contract_pending → contract_approved/rejected) **管理员获取待审核列表:** ```http GET /api/v1/admin/certifications?status=contract_pending ``` **管理员审核通过并上传合同链接:** ```http POST /api/v1/admin/certifications/{certification_id}/approve Content-Type: application/json { "admin_id": "admin_123", "contract_signing_url": "https://contract-platform.com/sign/contract_456", "approval_notes": "企业信息核实无误,准予签署合同", "expire_hours": 72 } ``` **审核通过响应:** ```json { "code": 200, "message": "审核通过,合同链接已上传", "data": { "certification_id": "cert_123456", "status": "contract_approved", "signing_url": "https://contract-platform.com/sign/contract_456", "expire_time": "2024-01-18T15:00:00Z", "next_step": "已通过短信通知用户签署合同" } } ``` **管理员拒绝申请:** ```http POST /api/v1/admin/certifications/{certification_id}/reject Content-Type: application/json { "admin_id": "admin_123", "reject_reason": "企业信息与工商数据不符,请重新提交", "allow_retry": true } ``` **拒绝响应:** ```json { "code": 200, "message": "申请已拒绝", "data": { "certification_id": "cert_123456", "status": "rejected", "reject_reason": "企业信息与工商数据不符,请重新提交", "next_step": "已通过短信通知用户重新申请" } } ``` ### 阶段 6: 用户查看合同链接并签署 (contract_approved → contract_signed/sign_failed) **用户查询状态(收到短信通知后):** ```http GET /api/v1/certification/{certification_id}/status ``` **用户看到合同链接:** ```json { "code": 200, "message": "合同已准备就绪", "data": { "certification_id": "cert_123456", "status": "contract_approved", "contract_info": { "signing_url": "https://contract-platform.com/sign/contract_456", "expire_time": "2024-01-18T15:00:00Z", "remaining_hours": 48 }, "next_step": "请点击链接签署电子合同", "next_action": "sign_contract" } } ``` ### 阶段 7: 用户签署合同 (contract_approved → contract_signed/sign_failed) ```http POST /api/v1/certification/{certification_id}/sign-contract Content-Type: application/json { "signature_data": "base64_signature_string", "sign_timestamp": "2024-01-16T14:30:00Z", "client_ip": "192.168.1.100" } ``` **签署成功:** ```json { "code": 200, "message": "合同签署成功", "data": { "certification_id": "cert_123456", "status": "contract_signed", "signed_at": "2024-01-16T14:30:00Z", "next_step": "正在生成钱包账户", "estimated_completion": "2-5分钟" } } ``` ### 阶段 8: 认证完成 (contract_signed → completed) **系统自动完成,用户查询最终状态:** ```http GET /api/v1/certification/{certification_id}/final-result ``` **认证完成响应:** ```json { "code": 200, "message": "企业认证已完成", "data": { "certification_id": "cert_123456", "status": "completed", "completed_at": "2024-01-16T14:35:00Z", "wallet_info": { "wallet_id": "wallet_789", "balance": "0.00", "is_active": true }, "user_secrets": { "access_id": "AK_123456789", "access_key": "SK_abcdef123456", // 加密显示 "is_active": true }, "certificate_url": "https://cdn.example.com/certificates/cert_123456.pdf" } } ``` ## 🔧 状态查询统一接口 ```http GET /api/v1/certification/status?user_id={user_id} ``` **通用状态响应格式:** ```json { "code": 200, "message": "状态查询成功", "data": { "certification_id": "cert_123456", "user_id": "user_123", "current_status": "face_verified", "current_status_name": "人脸识别完成", "progress": { "total_steps": 8, "completed_steps": 4, "percentage": 50 }, "timeline": [ { "status": "pending", "status_name": "待开始", "completed_at": "2024-01-15T09:00:00Z", "is_completed": true }, { "status": "info_submitted", "status_name": "企业信息已提交", "completed_at": "2024-01-15T09:05:00Z", "is_completed": true }, { "status": "face_verified", "status_name": "人脸识别完成", "completed_at": "2024-01-15T09:15:00Z", "is_completed": true }, { "status": "contract_applied", "status_name": "已申请合同", "completed_at": "2024-01-15T09:20:00Z", "is_completed": true }, { "status": "contract_pending", "status_name": "合同待审核", "completed_at": null, "is_completed": false, "is_current": true } ], "next_action": { "action": "apply_contract", "action_name": "申请电子合同", "description": "请点击申请电子合同按钮继续", "can_retry": false }, "retry_info": null, "estimated_completion": "2024-01-18T17:00:00Z" } } ``` ## 🔄 重试机制接口 **通用重试接口:** ```http POST /api/v1/certification/{certification_id}/retry Content-Type: application/json { "retry_type": "face_failed|sign_failed|rejected", "additional_data": {} // 根据重试类型提供额外数据 } ``` **重试响应:** ```json { "code": 200, "message": "重试请求已处理", "data": { "certification_id": "cert_123456", "old_status": "face_failed", "new_status": "info_submitted", "retry_count": 2, "max_retry_count": 3, "next_step": "请重新进行人脸识别" } } ``` ## 🔧 核心服务设计 ### 企业认证服务 ```go type CertificationService struct { // 依赖注入 repo *CertificationRepository enterpriseRepo *EnterpriseRepository ocrService *OCRService faceVerificationSvc *AliYunFaceVerifyService notificationService *NotificationService walletService *WalletService eventBus interfaces.EventBus logger *zap.Logger } // 核心业务方法 func (s *CertificationService) SubmitBusinessLicense(ctx context.Context, userID string, licenseImageURL string) (*dto.CertificationResponse, error) func (s *CertificationService) ConfirmEnterpriseInfo(ctx context.Context, certificationID string, req *dto.ConfirmEnterpriseInfoRequest) error func (s *CertificationService) PerformFaceVerification(ctx context.Context, certificationID string, req *dto.FaceVerificationRequest) error func (s *CertificationService) ApplyForContract(ctx context.Context, certificationID string) error func (s *CertificationService) SignContract(ctx context.Context, certificationID string, signatureData string) error func (s *CertificationService) GetCertificationStatus(ctx context.Context, userID string) (*dto.CertificationStatusResponse, error) ``` ### 百度 OCR 服务 ```go type BaiduOCRService struct { client *ocr.Client appID string apiKey string secretKey string logger *zap.Logger } func (s *BaiduOCRService) RecognizeBusinessLicense(ctx context.Context, imageURL string) (*dto.BusinessLicenseOCRResult, error) func (s *BaiduOCRService) ValidateOCRResult(result *dto.BusinessLicenseOCRResult) error ``` ### 阿里云人脸识别服务 ```go type AliYunFaceVerifyService struct { client *cloudauth.Client accessKeyId string accessSecret string regionId string logger *zap.Logger } func (s *AliYunFaceVerifyService) InitFaceVerify(ctx context.Context, req *dto.FaceVerifyInitRequest) (*dto.FaceVerifyInitResponse, error) func (s *AliYunFaceVerifyService) DescribeFaceVerify(ctx context.Context, certifyId string) (*dto.FaceVerifyResultResponse, error) func (s *AliYunFaceVerifyService) ValidateFaceVerifyResult(ctx context.Context, certifyId string) error ``` ### 通知服务扩展 ```go type NotificationService struct { smsService *sms.Service wechatWorkService *WechatWorkService logger *zap.Logger } func (s *NotificationService) NotifyAdminNewApplication(ctx context.Context, certification *entities.Certification) error func (s *NotificationService) NotifyUserContractReady(ctx context.Context, userPhone, contractURL string) error func (s *NotificationService) NotifyUserCertificationCompleted(ctx context.Context, userPhone string, accessID string) error ``` ### 七牛云存储服务 ```go type QiNiuStorageService struct { accessKey string secretKey string bucket string domain string region string logger *zap.Logger } func (s *QiNiuStorageService) UploadFile(ctx context.Context, fileBytes []byte, fileName string) (*dto.UploadResult, error) func (s *QiNiuStorageService) GenerateUploadToken(ctx context.Context, key string) (string, error) func (s *QiNiuStorageService) GetFileURL(ctx context.Context, key string) string func (s *QiNiuStorageService) DeleteFile(ctx context.Context, key string) error ``` ### 营业执照处理服务 ```go type LicenseProcessService struct { ocrService *BaiduOCRService storageService *QiNiuStorageService logger *zap.Logger } func (s *LicenseProcessService) ProcessLicense(ctx context.Context, fileBytes []byte, userID string) (*dto.LicenseProcessResult, error) { // 1. 上传文件到七牛云 uploadResult, err := s.storageService.UploadFile(ctx, fileBytes, generateFileName(userID)) if err != nil { return nil, fmt.Errorf("文件上传失败: %w", err) } // 2. OCR识别营业执照 ocrResult, err := s.ocrService.RecognizeBusinessLicense(ctx, uploadResult.URL) if err != nil { s.logger.Warn("OCR识别失败", zap.Error(err)) // OCR失败不影响整体流程,返回空的企业信息供用户手动填写 } return &dto.LicenseProcessResult{ LicenseURL: uploadResult.URL, EnterpriseInfo: ocrResult, OCRSuccess: err == nil, OCRError: getErrorMessage(err), }, nil } ``` ## 🌐 API 设计 ### 用户端 API ``` POST /api/v1/certification/submit-license # 提交营业执照 PUT /api/v1/certification/{id}/confirm-info # 确认企业信息 POST /api/v1/certification/{id}/face-verify # 人脸识别 POST /api/v1/certification/{id}/apply-contract # 申请电子合同 POST /api/v1/certification/{id}/sign-contract # 签署合同 GET /api/v1/certification/status # 查询认证状态 GET /api/v1/certification/{id} # 获取认证详情 ``` ### 管理员端 API ``` GET /api/v1/admin/certifications # 获取待审核申请列表 GET /api/v1/admin/certifications/{id} # 获取认证详情 POST /api/v1/admin/certifications/{id}/approve # 审核通过并上传合同链接 POST /api/v1/admin/certifications/{id}/reject # 审核拒绝 PUT /api/v1/admin/certifications/{id}/contract # 上传合同签署链接 ``` ### 财务 API ``` GET /api/v1/finance/wallet # 获取钱包信息 GET /api/v1/finance/wallet/balance # 获取余额 GET /api/v1/finance/wallet/transactions # 获取交易记录 GET /api/v1/finance/secrets # 获取用户密钥信息 POST /api/v1/finance/secrets/regenerate # 重新生成Access Key ``` ## 🗄️ 数据库设计 ### 新增数据表 ```sql -- 认证申请表 CREATE TABLE certifications ( id VARCHAR(36) PRIMARY KEY, user_id VARCHAR(36) NOT NULL, enterprise_id VARCHAR(36), status VARCHAR(50) NOT NULL, info_submitted_at DATETIME, face_verified_at DATETIME, contract_applied_at DATETIME, contract_approved_at DATETIME, contract_signed_at DATETIME, completed_at DATETIME, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_user_id (user_id), INDEX idx_status (status), INDEX idx_created_at (created_at) ); -- 企业信息表 CREATE TABLE enterprises ( id VARCHAR(36) PRIMARY KEY, certification_id VARCHAR(36) NOT NULL, company_name VARCHAR(255) NOT NULL, unified_social_code VARCHAR(50) NOT NULL, legal_person_name VARCHAR(100) NOT NULL, legal_person_id VARCHAR(50) NOT NULL, license_upload_record_id VARCHAR(36) NOT NULL, -- 关联营业执照上传记录 created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_certification_id (certification_id), INDEX idx_unified_social_code (unified_social_code), INDEX idx_license_upload_record_id (license_upload_record_id) ); -- 钱包表 CREATE TABLE wallets ( id VARCHAR(36) PRIMARY KEY, user_id VARCHAR(36) NOT NULL UNIQUE, is_active BOOLEAN DEFAULT TRUE, balance DECIMAL(20,8) DEFAULT 0, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_user_id (user_id) ); -- 用户密钥表 CREATE TABLE user_secrets ( id VARCHAR(36) PRIMARY KEY, user_id VARCHAR(36) NOT NULL UNIQUE, access_id VARCHAR(100) NOT NULL UNIQUE, access_key VARCHAR(255) NOT NULL, is_active BOOLEAN DEFAULT TRUE, last_used_at DATETIME, expires_at DATETIME, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_user_id (user_id), INDEX idx_access_id (access_id) ); -- 营业执照上传记录表 CREATE TABLE license_upload_records ( id VARCHAR(36) PRIMARY KEY, certification_id VARCHAR(36), user_id VARCHAR(36) NOT NULL, original_file_name VARCHAR(255) NOT NULL, file_size BIGINT NOT NULL, file_type VARCHAR(50) NOT NULL, file_url VARCHAR(500) NOT NULL, qiniu_key VARCHAR(255) NOT NULL, ocr_processed BOOLEAN DEFAULT FALSE, ocr_success BOOLEAN DEFAULT FALSE, ocr_confidence DECIMAL(5,2), ocr_raw_data TEXT, ocr_error_message VARCHAR(500), created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_certification_id (certification_id), INDEX idx_user_id (user_id), INDEX idx_qiniu_key (qiniu_key) ); -- 人脸识别记录表 CREATE TABLE face_verify_records ( id VARCHAR(36) PRIMARY KEY, certification_id VARCHAR(36) NOT NULL, user_id VARCHAR(36) NOT NULL, certify_id VARCHAR(100) NOT NULL, verify_url VARCHAR(500), return_url VARCHAR(500), real_name VARCHAR(100) NOT NULL, id_card_number VARCHAR(50) NOT NULL, status VARCHAR(50) NOT NULL, result_code VARCHAR(50), result_message VARCHAR(500), verify_score DECIMAL(5,2), initiated_at DATETIME NOT NULL, completed_at DATETIME, expires_at DATETIME NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_certification_id (certification_id), INDEX idx_user_id (user_id), INDEX idx_certify_id (certify_id), INDEX idx_status (status) ); -- 通知记录表 CREATE TABLE notification_records ( id VARCHAR(36) PRIMARY KEY, certification_id VARCHAR(36), user_id VARCHAR(36), notification_type VARCHAR(50) NOT NULL, notification_scene VARCHAR(50) NOT NULL, recipient VARCHAR(255) NOT NULL, title VARCHAR(255), content TEXT NOT NULL, template_id VARCHAR(100), template_params TEXT, status VARCHAR(50) NOT NULL, error_message VARCHAR(500), sent_at DATETIME, retry_count INT DEFAULT 0, max_retry_count INT DEFAULT 3, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_certification_id (certification_id), INDEX idx_user_id (user_id), INDEX idx_status (status), INDEX idx_notification_type (notification_type) ); -- 合同记录表 CREATE TABLE contract_records ( id VARCHAR(36) PRIMARY KEY, certification_id VARCHAR(36) NOT NULL, user_id VARCHAR(36) NOT NULL, admin_id VARCHAR(36), contract_type VARCHAR(50) NOT NULL, contract_url VARCHAR(500), signing_url VARCHAR(500), signature_data TEXT, signed_at DATETIME, client_ip VARCHAR(50), user_agent VARCHAR(500), status VARCHAR(50) NOT NULL, approval_notes TEXT, reject_reason TEXT, expires_at DATETIME, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_certification_id (certification_id), INDEX idx_user_id (user_id), INDEX idx_admin_id (admin_id), INDEX idx_status (status) ); -- 管理员表 CREATE TABLE admins ( id VARCHAR(36) PRIMARY KEY, username VARCHAR(100) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, name VARCHAR(100) NOT NULL, email VARCHAR(255), phone VARCHAR(20), is_active BOOLEAN DEFAULT TRUE, last_login_at DATETIME, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, deleted_at DATETIME, INDEX idx_username (username) ); ``` ## 🚀 分阶段实施计划 ### ✅ 阶段一:基础架构搭建(3-4 天)- 已完成 #### 1.1 创建域结构 - [x] 创建 `certification` 域的完整目录结构 - [x] 创建 `finance` 域的完整目录结构 - [x] 创建 `admin` 域的基础结构 - [x] 定义核心实体和枚举类型 #### 1.2 数据库层 - [x] 使用 GORM AutoMigrate 进行数据库迁移(已更新) - [x] 实现基础的 Repository 接口和实现 - [x] 添加必要的数据库索引和约束 #### 1.3 共享服务扩展 - [x] 扩展短信服务支持模板化消息 - [x] 创建百度 OCR 服务基础架构 - [x] 实现七牛云存储服务 - [x] 实现企业微信通知服务基础结构 ### ✅ 阶段二:核心业务逻辑(5-6 天)- 已完成 #### 2.1 认证服务核心功能 - [x] 实现营业执照上传、存储和 OCR 识别一体化服务 - [x] 实现企业信息确认功能 - [x] 实现人脸识别接口 - [x] 实现申请电子合同功能 - [x] 实现状态查询功能 #### 2.2 状态管理 - [x] 实现认证状态机(第一阶段已完成) - [x] 添加状态转换验证 - [x] 实现状态变更事件发布 #### 2.3 基础 API 接口 - [x] 实现用户端认证相关 API - [x] 添加参数验证和错误处理 - [x] 完善 API 响应格式 ### ✅ 阶段三:第三方集成(4-5 天)- 已完成 #### 3.1 百度 OCR 和七牛云存储集成 - [x] 实现七牛云文件上传服务 - [x] 实现百度 OCR API 调用 - [x] 处理 OCR 识别结果解析 - [x] 添加 OCR 识别置信度验证 - [x] 实现营业执照处理一体化服务 #### 3.2 阿里云人脸识别集成 - [ ] 集成阿里云 InitFaceVerify API - [ ] 实现人脸识别初始化流程 - [ ] 实现人脸识别结果查询 - [ ] 添加人脸识别状态验证 #### 3.3 通知服务完善 - [x] 实现企业微信机器人通知 - [ ] 扩展短信模板支持认证流程 - [ ] 添加通知发送失败重试机制 ### 阶段四:管理员功能(3-4 天) #### 4.1 管理员系统 - [ ] 实现管理员登录认证 - [ ] 创建管理员权限管理 - [ ] 实现管理员操作日志 #### 4.2 审核功能 - [ ] 实现待审核申请列表 - [ ] 实现认证详情查看 - [ ] 实现审核通过/拒绝功能 - [ ] 实现合同链接上传功能 #### 4.3 管理后台 API - [ ] 完善管理员端 API 接口 - [ ] 添加分页和筛选功能 - [ ] 实现审核操作记录 ### ✅ 阶段五:财务系统(3-4 天)- 已完成 #### 5.1 财务服务 - [x] 实现钱包生成功能 - [x] 生成 Access ID 和 Access Key - [x] 实现钱包状态管理 #### 5.2 财务 API - [x] 实现钱包信息查询 - [x] 实现 Access Key 重新生成 - [x] 添加钱包安全验证 #### 5.3 认证完成流程 - [x] 完善认证完成后的钱包创建 - [x] 实现认证完成通知 - [x] 添加钱包激活功能 ### 🔄 阶段六:事件驱动和完善(2-3 天) #### 6.1 事件系统 - [ ] 实现完整的认证事件定义 - [ ] 添加事件处理器 - [ ] 完善事件驱动的通知机制 #### 6.2 系统完善 - [ ] 添加全面的日志记录 - [ ] 实现性能监控和指标 - [ ] 完善错误处理和回滚机制 #### 6.3 测试和文档 - [ ] 编写单元测试 - [ ] 完善 API 文档 - [ ] 编写操作手册 ## 🔧 技术要点 ### 第三方服务配置 #### 百度 OCR 配置 ```yaml baidu_ocr: app_id: "your_app_id" api_key: "your_api_key" secret_key: "your_secret_key" endpoint: "https://aip.baidubce.com" timeout: 30s ``` #### 七牛云存储配置 ```yaml qiniu_storage: access_key: "your_access_key" secret_key: "your_secret_key" bucket: "enterprise-certification" domain: "https://qiniu.example.com" region: "z0" # 华东区域 timeout: 30s ``` #### 阿里云人脸识别配置 ```yaml aliyun_face_verify: access_key_id: "your_access_key_id" access_key_secret: "your_access_key_secret" region_id: "cn-hangzhou" endpoint: "https://cloudauth.cn-hangzhou.aliyuncs.com" timeout: 30s ``` #### 企业微信配置 ```yaml wechat_work: webhook_url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx" timeout: 10s ``` ### 安全考虑 - Access Key 采用加密存储 - 营业执照图片需要安全存储 - 人脸识别数据不保存原始图片 - 管理员操作需要审计日志 ### 性能优化 - OCR 识别结果缓存 - 状态查询接口优化 - 批量通知处理 - 数据库查询优化 ## 📝 注意事项 1. **状态一致性**:所有状态变更都需要通过事务保证一致性 2. **幂等性**:关键操作需要支持幂等,避免重复处理 3. **错误处理**:第三方服务调用需要完善的错误处理和重试机制 4. **数据安全**:敏感信息需要加密存储 5. **监控告警**:关键业务节点需要监控和告警 6. **备份恢复**:重要数据需要定期备份 ## 🎯 成功标准 - [ ] 用户可以顺利完成企业认证全流程 - [ ] 管理员可以高效处理认证审核 - [ ] 系统可以自动识别营业执照信息 - [ ] 通知机制工作正常 - [ ] 财务系统功能完整 - [ ] API 接口稳定可靠 - [ ] 系统性能满足要求 - [ ] 代码质量符合规范 --- **预计总开发时间:20-26 天** **核心开发人员:1-2 人** **测试时间:3-5 天**