[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-distributed-certificate-storage":3},{"id":4,"slug":5,"name":6,"summary":7,"stack":8,"background":21,"responsibility":22,"workflow":23,"architecture":31,"highlights":32,"retrospective":41,"repositoryUrl":42,"liveUrl":43,"featured":44},1,"distributed-certificate-storage","业务数据授权去中心化存证系统","面向联盟链业务数据授权与存证的前端系统，覆盖授权确认、链上存证和结果核验，并处理复杂业务状态和长列表性能。",[9,10,11,12,13,14,15,16,17,18,19,20],"Vue 3","Vite","Pinia","Element Plus","Java","Spring Boot","MyBatis-Plus","Redis","SQLite","Oracle","JWT","SM2\u002FSM3","项目面向联盟链中的业务数据授权场景。用户完成数据授权后，系统需要把授权过程、存证结果和核验状态串成一条可追踪链路。\n\n前端重点不是展示后台 CRUD，而是让业务用户理解当前数据走到哪一步、参与者是否完成确认、异常应该从哪个环节处理。\n\n源码中同时存在 coordinator 与 node 两类 Spring Boot 服务，分别承担协调、证书管理和节点存证，前端通过接口与这些服务协作。","参与前端方案设计和主要页面开发。\n\n- 整理授权确认、链上存证和结果核验的状态流\n- 实现接口缓存、并发去重和按 Tag 失效\n- 处理长列表虚拟滚动\n- 记录 Web Vitals、路由耗时和接口耗时\n- 处理证书上传、地址校验和节点通信相关安全边界",[24,25,26,27,28,29,30],"用户发起业务数据授权","系统整理授权主体和数据范围","用户完成授权确认","授权结果进入链上存证","参与节点保存并返回处理状态","用户核验数据和签名结果","异常进入可追踪反馈流程","前端使用 Vue 3、Vite、Pinia 和 Element Plus。接口层封装 TTL 缓存、并发去重、SWR 和 Tag 失效，长列表通过虚拟滚动控制 DOM 数量。\n\n后端拆分为 coordinator 与 node 两类 Spring Boot 服务。coordinator 维护成员、证书和任务状态，node 处理签名、证书校验和数据保存。数据访问使用 MyBatis-Plus，coordinator 使用 Redis 和 Oracle，node 使用 SQLite。\n\n认证和签名链路包含 JWT、SM2\u002FSM3，节点通信使用 HTTP，并对远程地址、证书有效期、签发方和上传文件做校验。",[33,34,35,36,37,38,39,40],"请求缓存使用 TTL、并发去重、SWR 和 Tag 失效","列表使用虚拟滚动，减少长数据下的 DOM 压力","记录 LCP、INP、CLS、路由耗时和 API 耗时","授权、存证、核验和异常页面共用一致的状态反馈","证书上传限制扩展名并验证证书有效期","节点通信前校验远程地址，避免任意内网访问","写操作关联缓存 Tag，保证列表和详情同步刷新","接口异常保留用户输入，并展示可理解的原因","这个项目里，最难的不是页面数量，而是把多个服务返回的数据合并成一致状态。\n\n缓存和虚拟列表提升了性能，但如果状态反馈不一致，用户反而更难判断结果。后面再做业务系统，会更早定义状态机、异常路径和权限边界，不让前端用大量条件判断弥补后端状态不清晰。","https:\u002F\u002Fgithub.com\u002FS1rryNut\u002Fdistributed-certificate-storage",null,true]