进件系统,类似于消费金融的贷前,主要功能:收集用户信息,风控审批,通过后给用户分配额度,看似简单的一句话,但细细分析一下,细节很多;比如你怎么保证用户使用的手机号是不是自己的?操作的时候是不是投用别人的证件、手机?联系人信息是否真实有效?申请人信用是否合格?
这就牵扯出来好多的外部依赖:证件扫描识别、手机号是否实名、设备信息上报、征信获取、活体识别、、、当然这些都是业务层面及相关实现,基本所有的贷前系统都是这个路子,目的只有一个证明你是你并且是个值得信赖的人
从零到一,听起来感觉很爽的样子,技术人员都有一个癖好,就是看别人的代码永远是那么不顺眼,总想着从0开始是多么幸福的一件事;但事实并非如此;从0开始意味着你要考虑的事情也会更多,比如:最基础的系统设计,技术选型,交互方式,可复用性,可扩展性,系统健壮性,安全性、、、等等一系列问题;稍有不慎就会成为你口中的垃圾;
从零到一这种快乐与痛苦并存的事情确实不容易碰到,既然碰到了也要摒弃痛苦,享受快感,因为这意味着你又有了吹嘘的资本,麻雀虽小五脏俱全也不无道理
下面详细介绍一下从需求出来到上线的这么一个过程
系统设计
一提到系统设计,相信很多人脑中会立马呈现出很多的图:架构图、时序图、流程图、等等技术出身的我们是不是感觉略显烦躁;就不能安安静静的写个代码吗?但细想如果前期准备不充分,后期坑就时刻围绕着你
架构图
流程解释:
- 整体前后端分离后端统一入口gateway,主要包含加解密、验签、token、日志、限流、容错等实现,可根据实际业务需要增减
- api-service层主要做业务聚合,如果有多个api-service层(不同业务单独部署)可有gateway,如果所有业务都写一个里边那么gateway就可去掉
- apply是进件主服务,设计的时候主要考虑的几点
- 进件入口摒弃差异(如果前端加减字段后端无需改接口,或通过配置即可应对)
- 根据风控需求保存审批数据
- 外部依赖只提供标准api,具体实现由第三方服务实现(因为公司有多个类似业务,所以我们这里提取的公共服务,如果你在的公司业务有限那么可以将这些外围依赖写在对外的gateway里,apply直接调用接口即可,甚至大部分公司都是直接写在apply里实现的)
- 可单独写对外gateway去实现各种前置(如:活体,ocr、风控、实名等等),如果有多个活体也可按需求写一些路由规则,其它依赖也是如此
时序图
流程解释:
- 单独服务apply-third-gateway的目的是,人脸、ocr等都是对接第三方服务,有可能通过外网,可在此服务内进行特殊处理(加解密),如果第三方不止接一家也可做路由
- 活体、ocr等数据最好存在进件,因为这些数据都是为风控准备的
- 征信社保这类数据最好是风控自己做,如果风控不做也可api-service调用,然后入库(mongoDB最好跟业务数据库分开,这种数据报文很复杂,让风控自己解析)
- 图中通知用户中心,admin都是在apply中做的,如果有国际业务(不同国家分开部署,后期业务也不尽相同)可统一在api-service包装通知,apply只做存储和风控调用(风控基本是一套)
功能流程图就不再详细讲解,这个基本是根据各个公司业务产品设计而定
表设计
表名 | 描述 |
user_apply_record | 进件申请流水表(用户基本信息,审批状态,额度等基础查询信息,可供快速查询) |
user_credit_record | 授信审批记录(每次审批的记录信息) |
user_apply_base | 用户进件基本信息(进件的基础信息,个人、家庭、企业、联系人等,只提供风控,后续基本不查,只是备份) |
device_info | 设备信息(本次进件的设备相关,风控数据) |
live_identify | 活体识别信息(本次进件的活体相关) |
user_ocr | ocr信息(证件信息相关) |
step_version | 步骤版本表 |
field_config | 字段配置表 |
解释
- user_apply_record: user_apply_base(1:1)用户每次进件正流程一条数据
- user_apply_record: user_credit_record(1:N)如果一条进件需要多次审核可记录多条
- field_config:配置进件所需要的所有字段,及字段长度、校验规则
CREATE TABLE `field_config` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`field_no` int(11) NOT NULL DEFAULT '0' COMMENT '字段编码',
`field_name` varchar(64) NOT NULL DEFAULT '' COMMENT '字段名',
`field_display_name` varchar(64) NOT NULL DEFAULT '' COMMENT '字段页面展示名',
`field_lenth` int(11) NOT NULL DEFAULT '0' COMMENT '字段长度',
`Whether_empty` tinyint(2) NOT NULL DEFAULT '1' COMMENT '是否可为空0:可空;1:不可空',
`validation_rules` varchar(64) NOT NULL DEFAULT '' COMMENT '验证规则',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1-已删除,0-未删除',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `un_field_no` (`field_no`) USING BTREE,
UNIQUE KEY `un_field_name` (`field_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='字段配置表';
4、step_version:配置步骤,跟前端页面一一对应,包括步骤(页面)中包含哪些字段
CREATE TABLE `step_version` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`group_no` varchar(16) NOT NULL DEFAULT '' COMMENT '分组',
`system_no` int(11) NOT NULL DEFAULT '0' COMMENT '系统号',
`platform` varchar(16) NOT NULL DEFAULT '' COMMENT '平台android,ios,h5',
`app_version` int(11) NOT NULL DEFAULT '0' COMMENT '最小版本',
`max_app_version` int(11) NOT NULL DEFAULT '9999' COMMENT '最大版本',
`step_name` varchar(64) NOT NULL DEFAULT '' COMMENT '步骤名',
`step_no` int(11) NOT NULL DEFAULT '0' COMMENT '当前步骤',
`sub_step` varchar(64) DEFAULT NULL COMMENT '子步骤,标识第三方调用',
`field_no_list` varchar(512) NOT NULL DEFAULT '' COMMENT '包含字段',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1-已删除,0-未删除',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='步骤版本表';
可以通过平台+版本+当前步骤:查询当前步骤需要哪些字段,进而判断是否为空,及其它规则,从而做到入参泛型化,如果产品新增,减少字段,后端配置即可
总结
1、前期想法会多变,相关开发一定要快速同步信息,多讨论
2、外部对接要趁早,沟通成本很高,中间可能埋藏着各种坑