项目:X-Pan | 版本:v1.2 | 生成日期:2026-10-06 | 依据:源码分析
本文是全文档集(00-20 共 21 篇)的收官件,承担三个检索职能:术语表把散落在各篇的项目特有词汇收进一处(每个术语给定义、源码落点与深读篇目);反向索引回答"我手上有一个源码文件,该读哪几篇"——它与各篇目录的"篇目 → 内容"正向阅读互为补集;任务阅读路径回答"我要做某件事,最少读哪几篇、按什么顺序"。使用本文的正确姿势是按需跳转而非通读:术语表在首次遇到陌生词时查,反向索引在读码迷路时查,任务路径在开工前查。三条路径的写法刻意保持"篇目引用 + 具体动作"的密度差——动作是可以立刻执行的(打开某文件第几行、跑某条命令),篇目引用是纵深材料(理解为什么这样动),先动作后纵深能保证路径在最短时间内产生第一次有效进展。全文档集以源码为唯一事实来源,本文标注的篇目引用在源码演进后可能滞后,发现冲突以代码为准并回改对应篇目。
| 术语 | 定义 | 源码落点 | 深读 |
|---|---|---|---|
| 秒传 | 客户端对全文件预计算 MD5(identifier),服务端命中既有物理记录即零字节传输完成上传,只新增一条逻辑引用 | UserFileServiceImpl.secUpload 第 260 行起 | 《05》流程一、《16》ADR-007 |
| 分片上传 | 大文件切为固定 5MB 逐片上传(forceChunkSize 强制,除末片),三端协议常量 | useUploader.ts、app_config.dart、FileChunkUploadPO | 《10》第 1 节、《16》ADR-008 |
| 断点续传 | 凭 GET /file/chunk-upload 返回的 uploadedChunks 只补传缺失片,跨会话/跨重启恢复 | UserFileServiceImpl.getUploadedChunks 第 334 行 | 《05》流程一、《02》2.5 |
| identifier | 32 位 MD5 十六进制串,贯穿秒传键、分片对象路径、去重分组键的全局标识;入参强制正则白名单防路径穿越 | FileChunkUploadPO.identifier、db.sql x_pan_file.identifier | 《08》第 3 节 |
| composeObject | MinIO 的服务端合并 API:在存储内部把多个源对象拼接为目标对象,字节不经应用;要求除末源外每源 ≥5MB | MinIOStorageEngine.mergeByComposeObject 第 256 行 | 《18》走读二 |
| 快路径 / 慢路径 | 合并的两条实现:全部非末分片 ≥5MB 走 composeObject(快);否则回退"逐片下载→本地拼接→整体上传"(慢) | MinIOStorageEngine 第 187-213 行、mergeByDownloadAndUpload 第 298 行 | 《10》第 1 节、《16》ADR-008 |
| 50MB 阈值 | 下载路由分界:≥pan.storage.minio.large-file-threshold 走 302 预签名直链,否则应用流式代理 | FileController.download 第 216 行起 | 《16》ADR-003 |
| 预签名 URL | 服务端用 S3 凭证签发的限时直访 URL(下载 1 小时 / 上传 PUT 已备未接线),浏览器直连 MinIO 绕开应用带宽 | MinIOStorageEngine.generatePresignedGetUrl/PutUrl | 《10》第 3 节 |
| ptoken | 预览专用短期凭证:JWT 内嵌 fileId,5 分钟有效,供 <img>/<video> 免登录直出内容流 | FileController.previewUrl/previewStream | 《08》第 4 节 |
| 两表模型 | 逻辑文件(x_pan_user_file,谁的目录下叫什么)与物理文件(x_pan_file,字节本体)分离,real_file_id 关联——秒传/复制零拷贝/去重的数据基础 | db.sql 第 10/103 行 | 《04》第 1 节 |
| realPath | 物理对象名(MinIO 桶内 key 或本地路径),存于 x_pan_file.real_path,引擎可换而元数据不变 | MinIOStorageEngine.buildObjectName 第 593 行 | 《04》1.2 |
| 孤儿对象 | "有对象无记录"的存储泄漏(上传中断/清理异常残留),每日 3 点兜底清扫 | common/gc/OrphanFileGc.java | 《04》第 4 节 |
| 私有桶策略 | MinIO 三桶(files/chunks/thumbs)禁匿名直访,一切读取凭预签名或 ptoken | MinIOStorageEngine 类注释 | 《01》第 3 节 |
| 术语 | 定义 | 源码落点 | 深读 |
|---|---|---|---|
| 雪花 ID | hutool Snowflake 生成的 64 位有序主键,workerId/datacenterId 由 XPAN_SNOWFLAKE_* 环境变量预留(0-31) | framework/core/.../IdUtil.java 第 35 行 | 《16》ADR-004 |
| 加密 ID | 对外暴露的主键经 AES-128 加密 + 无填充 URL-safe Base64 的形态,防遍历不防持有;解密侧强制 8 字节校验 | IdUtil.encrypt/decrypt、IdEncryptSerializer | 《03》第 1 节、《19》第 0 节 |
| clientId | 端标识:Web 存 Cookie、移动端存 Keychain/Keystore 且终身稳定,作为会话槽位键的一部分实现多端并存互不踢线 | token_storage.dart、CommonLoginAspect.buildLoginCacheKey | 《08》第 1 节 |
| 会话槽位 | Redis 键 USER_LOGIN_{userId}_{clientId} 存当前有效 token,请求时严格比对——"服务端可吊销"语义的实现点 | CommonLoginAspect.checkAndSaveUserId 第 124 行 | 《18》走读三 |
| 滑动续期 | JWT 内嵌 RENEWAL_TIME(有效期中点),越过即签发新 token 并经 New-Access-Token 响应头下发,客户端无感换发 | CommonLoginAspect.tryRenewToken 第 164 行 | 《08》第 1 节 |
| _PREV 键 | 续期时保留的上一版 token(USER_LOGIN_..._PREV),兼容续期窗口内在途请求不 401 | tryRenewToken 第 189 行 | 《18》3.3 |
| code=10 | NEED_LOGIN 统一重登录信号:Web 清 Cookie 跳登录页、Flutter 抛 NeedReloginException 广播全局重登录 | ResponseCode、两端拦截器 | 《03》第 5 节 |
| SafeOrderBy | 排序字段白名单(filename/file_size/update_time/create_time 等),非法字段静默忽略防注入 | UserFileServiceImpl 排序路径 | 《03》第 7 节 |
| 审计四件套 | create_user/create_time/update_user/update_time 全表统一审计列,ON UPDATE CURRENT_TIMESTAMP 由库兜底 | db.sql 各表 | 《04》第 5 节 |
| 术语 | 定义 | 源码落点 | 深读 |
|---|---|---|---|
| 保险箱 | 独立 PBKDF2 密码的隐私隔离区:文件 parent_id=-2 从列表消失、出口复检解锁态、拒绝参与分享 | VaultConstants.VAULT_PARENT_ID、VaultServiceImpl | 《07》2.7、《08》第 3 节 |
| 回收站(软删除) | 删除置 del_flag=1 + delete_time,30 天可还原;全库唯一使用软删除的表 | UserFileServiceImpl.deleteFile、CleanExpireRecycleFileTask | 《05》流程五 |
| 提取码 | 分享的 4-8 位口令,校验通过签发独立 Share-Token JWT(1 小时);与登录 token 完全独立、不落 Redis | ShareServiceImpl.checkShareCode 第 187 行 | 《19》第 9 节 |
| Share-Token | 分享域短期凭证:@NeedShareCode 方法由切面解析出 shareId 放入 ShareIdUtil;失效走 code=5/6/7 三态 | ShareCodeAspect 第 97 行 | 《08》第 4 节 |
| SSRF 逐跳校验 | 离线下载的"创建时校验 + 手动重定向逐跳复检(≤5 跳)"双保险,拒内网 IP/云元数据/危险协议 | OfflineTaskServiceImpl.validateUrl 第 524 行 | 《08》第 5 节 |
| 防爆破锁定 | 登录/密保/提取码/保险箱四处的失败计数(≥5 锁 15 分钟),统一用原生 INCR + 仅首次 EXPIRE | RedisRateLimiter、各 Service recordXxxFail | 《08》第 1 节 |
| fail-open | 限流器在 Redis 故障时放行的降级策略("避免限流拖垮服务"),代价是故障+攻击叠加时裸奔 | RedisRateLimiter.tryAcquire 第 65 行 | 《16》ADR-009 |
| TOCTOU | time-of-check to time-of-use 竞态:秒传"查物理文件"与物理删除"判无引用"若不互斥会挂到已删对象——B7 修复共用 identifier 锁 | UserFileServiceImpl.secUpload 第 261 行注释 | 《16》ADR-007 |
| del_flag 入唯一键 | uk_user_parent_folder_name(user_id,parent_id,folder_flag,filename,del_flag):未删同名唯一、已删可与新上传共存 | db.sql 第 123-124 行 | 《16》ADR-005 |
| 术语 | 定义 | 源码落点 | 深读 |
|---|---|---|---|
| 模块化单体 | 单 Spring Boot 进程(8081)+ 17 个按微服务风格切分的模块包;模块间只有接口注入与 Spring 事件两条通道 | XPanServerLauncher、server/pom.xml | 《16》ADR-001 |
| framework/server 分层 | framework 七个 Maven 模块是不感知业务的平台件,server 以 Maven 依赖复用;依赖方向恒定不可反向 | framework/、server/pom.xml | 《01》第 3 节、《16》ADR-002 |
| 存储引擎抽象 | StorageEngine 六操作接口 + 模板方法 + @ConditionalOnProperty 装配,业务零感知介质 | storage-engine-core/StorageEngine.java | 《16》ADR-003、《11》SOP-5 |
| 熔断(Resilience4j) | 只护两个不可控下游:minioStorage(30s 半开)与 offlineDownload;fallback 仅在 doStore | MinIOStorageEngine.doStore 第 113 行 | 《16》ADR-009 |
| 固定窗口限流 | Redis INCR + 首次 EXPIRE 的固定窗口计数,key `xpan:rl:{scope}:{u:userId | ip:ip}`,四 scope 阈值可配 | RedisRateLimiter.java |
| 纠删码 | MinIO 4 节点集群的冗余编码(注释自述等价 RAID5:任意 2 节点宕可读、1 节点宕可写) | deploy/docker-compose.yml | 《10》第 3 节 |
| traceId | 全链路追踪标识:后端 MDC 注入、三端请求头 X-Pan-Trace-Id、日志 pattern 串联——跨端排障第一步对齐它 | common/log/LogMdcFilter.java | 《12》第 1 节 |
| 三份同源配置 | 同一逻辑配置的三个物理存在(运行时 yaml/打包模板/CI yaml)必须语义同步,漂移是"本地好生产坏"的经典根因 | application.yaml、distribution/conf/application.yaml、application-ci.yaml | 《14》第 4 节 |
| 密钥红线 | 任何 yaml 禁止密钥默认值,只允许 ${ENV:} 空兜底;JWT/AES/DB/Redis/MinIO 七个 XPAN_* 变量缺失即启动失败 | DEV_GUIDELINES.md 第一节、AesKeyConfig | 《06》第 3 节、《14》第 1 节 |
术语使用中的三个易混点值得单独澄清。"物理文件"不等于"文件内容"——它是 x_pan_file 表里的一行元数据,字节本体在 MinIO/本地盘,所以"删物理文件"通常是删记录 + 删对象两步且后者受引用计数保护。"clientId"不是设备序列号——它由客户端自行生成并长期稳定,同一台设备重装 App 可能变化(移动端持久化在 Keychain/Keystore,Web 清 Cookie 即变化),"设备管理"页面的记录以登录时上报为准。"断点续传"与"秒传"是两个正交机制——前者解决"传了一半怎么办",后者解决"别人传过没有",一个 5GB 文件完全可能"秒传命中"而从未触发分片,也可能"秒传未命中 + 断点续传"组合出现。另有一个高频误读需要预防:把"回收站"理解为独立存储位置。回收站不是另一块存储——文件进入回收站只是 x_pan_user_file 上 del_flag 与 delete_time 两个字段的变化,物理对象原地未动,配额照计;所谓"彻底删除后释放空间"释放的是"不再被任何逻辑记录引用的物理对象",若同一物理文件仍被秒传复用,空间不会减少。理解了这一点,"删除后马上上传大文件提示配额不足"就不是 bug 而是设计的必然结果。
下表按"后端框架层 → 后端 common → 后端 modules → 资源与配置 → Web 前端 → 移动端"分组,路径省略公共前缀(后端为 x-pan/x-pan-parent/,前端为 x-pan/x-pan-fronted/,移动端为 x-pan/x-pan-mobile/)。"篇目"列按深读优先排列;无对应专篇的文件以最近的相关篇目兜底。
| # | 源码文件(相对路径) | 篇目 |
|---|---|---|
| 1 | framework/core/src/main/java/com/xiaoye/pan/core/utils/IdUtil.java | 16(ADR-004)、19、04 |
| 2 | framework/core/src/main/java/com/xiaoye/pan/core/utils/JwtUtil.java | 08(第 1 节)、16(ADR-006) |
| 3 | framework/core/src/main/java/com/xiaoye/pan/core/utils/PasswordUtil.java | 08(第 1 节) |
| 4 | framework/core/src/main/java/com/xiaoye/pan/core/response/R.java | 03(第 1 节)、19(第 0 节) |
| 5 | framework/core/src/main/java/com/xiaoye/pan/core/response/ResponseCode.java | 03(第 5 节)、15(第 1 节) |
| 6 | framework/web/src/main/java/com/xiaoye/pan/web/cors/CorsFilter.java | 08(第 2 节)、13(D14) |
| 7 | framework/web/src/main/java/com/xiaoye/pan/web/log/HttpLogFilter.java | 10(第 4 节)、07(第 3 节) |
| 8 | framework/web/src/main/java/com/xiaoye/pan/web/exception/WebExceptionHandler.java | 03(第 5 节)、12(第 8 节) |
| 9 | framework/web/src/main/java/com/xiaoye/pan/web/serializer/IdEncryptSerializer.java | 03(第 1 节)、04(1.1) |
| 10 | framework/cache/cache-redis/src/main/java/com/xiaoye/pan/cache/redis/config/RedisCacheConfig.java | 08(第 1 节)、10(第 2 节) |
| 11 | framework/storage-engine/storage-engine-core/src/main/java/com/xiaoye/pan/storage/engine/core/StorageEngine.java | 16(ADR-003)、01(第 3 节)、11(SOP-5) |
| 12 | framework/storage-engine/storage-engine-minio/src/main/java/com/xiaoye/pan/storage/engine/minio/MinIOStorageEngine.java | 18(走读二)、16(ADR-008/009)、10(第 1/3 节) |
| 13 | framework/storage-engine/storage-engine-minio/src/main/java/com/xiaoye/pan/storage/engine/minio/config/MinIOStorageEngineProperties.java | 06(3.2)、14(第 1 节) |
| 14 | framework/storage-engine/storage-engine-local/src/main/java/com/xiaoye/pan/storage/engine/local/LocalStorageEngine.java | 09(CI 本地引擎)、11(SOP-5) |
| 15 | framework/schedule/src/main/java/com/xiaoye/pan/schedule/ScheduleManager.java | 07(第 3 节) |
| 16 | framework/swagger2/src/main/java/com/xiaoye/pan/swagger2/Swagger2Config.java | 03(开头)、14(profile) |
| 17 | framework/orm/mybatis-plus/src/main/java/com/xiaoye/pan/orm/mp/generate/CodeGenerator.java | 07(第 3 节) |
| 18 | server/src/main/java/com/xiaoye/pan/server/XPanServerLauncher.java | 01(第 1 节)、00(第 4 节) |
| 19 | server/src/main/java/com/xiaoye/pan/server/common/aspect/CommonLoginAspect.java | 18(走读三)、08(第 1 节)、16(ADR-006) |
| 20 | server/src/main/java/com/xiaoye/pan/server/common/aspect/ShareCodeAspect.java | 08(第 4 节)、05(流程三) |
| 21 | server/src/main/java/com/xiaoye/pan/server/common/annotation/LoginIgnore.java | 03(第 1 节)、15(第 8 节) |
| 22 | server/src/main/java/com/xiaoye/pan/server/common/ratelimit/RedisRateLimiter.java | 18(3.4 关联)、08(第 2 节)、16(ADR-009) |
| 23 | server/src/main/java/com/xiaoye/pan/server/common/resilience/CircuitBreakerFallback.java | 01(第 6 节)、16(ADR-009) |
| 24 | server/src/main/java/com/xiaoye/pan/server/common/websocket/NotificationWebSocketHandler.java | 15(第 6 节)、19(第 11 节)、08(第 6 节) |
| 25 | server/src/main/java/com/xiaoye/pan/server/common/websocket/Notifier.java | 05(流程一/三)、07(第 4 节) |
| 26 | server/src/main/java/com/xiaoye/pan/server/common/listenner/file/FilePhysicalDeleteEventListener.java | 05(流程五)、16(ADR-007)、04(第 4 节) |
| 27 | server/src/main/java/com/xiaoye/pan/server/common/event/file/FilePhysicalDeleteEvent.java | 05(流程五)、07(第 4 节) |
| 28 | server/src/main/java/com/xiaoye/pan/server/common/schedule/task/CleanExpireChunkFileTask.java | 04(第 4 节)、10(第 3 节) |
| 29 | server/src/main/java/com/xiaoye/pan/server/common/schedule/task/CleanExpireRecycleFileTask.java | 05(流程五)、13(D10) |
| 30 | server/src/main/java/com/xiaoye/pan/server/common/gc/OrphanFileGc.java | 04(第 4 节)、12(第 6 节) |
| 31 | server/src/main/java/com/xiaoye/pan/server/common/config/AesKeyConfig.java | 06(第 6 节)、14(第 1 节) |
| 32 | server/src/main/java/com/xiaoye/pan/server/common/config/ThreadPoolConfig.java | 01(第 4 节)、10(第 4 节) |
| 33 | server/src/main/java/com/xiaoye/pan/server/common/migration/StorageMigrationRunner.java | 13(D11)、11(SOP-5) |
| 34 | server/src/main/java/com/xiaoye/pan/server/common/log/LogMdcFilter.java | 12(第 1 节) |
| 35 | server/src/main/java/com/xiaoye/pan/server/modules/user/controller/UserController.java | 15(第 2 节)、19(第 1 节)、03(2.1) |
| 36 | server/src/main/java/com/xiaoye/pan/server/modules/user/service/impl/UserServiceImpl.java | 05(流程二)、07(2.1) |
| 37 | server/src/main/java/com/xiaoye/pan/server/modules/file/controller/FileController.java | 15(第 3 节)、03(2.2)、16(ADR-003) |
| 38 | server/src/main/java/com/xiaoye/pan/server/modules/file/service/impl/UserFileServiceImpl.java | 05(流程一/五)、07(2.3)、16(ADR-007) |
| 39 | server/src/main/java/com/xiaoye/pan/server/modules/file/service/impl/FileChunkServiceImpl.java | 18(走读一)、07(2.3) |
| 40 | server/src/main/java/com/xiaoye/pan/server/modules/file/service/impl/FileServiceImpl.java | 05(流程一)、18(6 节关联) |
| 41 | server/src/main/java/com/xiaoye/pan/server/modules/share/service/impl/ShareServiceImpl.java | 05(流程三)、07(2.4)、15(第 4 节) |
| 42 | server/src/main/java/com/xiaoye/pan/server/modules/offline/service/impl/OfflineTaskServiceImpl.java | 08(第 5 节)、05(流程四)、07(2.6) |
| 43 | server/src/main/java/com/xiaoye/pan/server/modules/vault/service/impl/VaultServiceImpl.java | 07(2.7)、08(第 3 节) |
| 44 | server/src/main/java/com/xiaoye/pan/server/modules/webdav/WebDavController.java | 16(ADR-010)、15(第 7 节)、08(第 6 节) |
| 45 | server/src/main/java/com/xiaoye/pan/server/modules/recycle/service/impl/RecycleServiceImpl.java | 05(流程五)、07(2.5) |
| 46 | server/src/main/resources/application.yaml | 06(3.2)、14(第 1/4 节) |
| 47 | server/src/main/resources/application-ci.yaml | 09(第 3 节)、14(第 4 节) |
| 48 | server/src/main/resources/logback-spring.xml | 12(第 1 节)、17(2.1 节 logstash 项) |
| 49 | distribution/conf/db.sql | 04(全篇)、16(ADR-004/005) |
| 50 | x-pan-parent/pom.xml | server/pom.xml | 17(第 1 节)、00(3.1) |
| 51 | x-pan-fronted/src/composables/useUploader.ts | 05(流程一)、10(第 1 节)、02(1.9) |
| 52 | x-pan-fronted/src/utils/http.ts | 03(第 7 节)、08(第 1 节) |
| 53 | x-pan-fronted/src/stores/file.ts | 02(1.8)、07(第 6 节)、09(第 6 节) |
| 54 | x-pan-fronted/src/composables/useWebSocket.ts | 07(第 6 节)、15(第 6 节) |
| 55 | x-pan-fronted/nginx.conf | vite.config.ts | 03(第 3 节)、10(第 5 节)、06(4.1) |
| 56 | x-pan-fronted/package.json | 17(2.4)、00(3.2) |
| 57 | x-pan-mobile/lib/core/network/http_client.dart | 02(2.2)、08(第 1 节)、17(2.5) |
| 58 | x-pan-mobile/lib/core/config/app_config.dart | 06(2.3)、17(2.5) |
| 59 | x-pan-mobile/lib/services/upload_service.dart | 05(流程一)、02(2.5) |
| 60 | x-pan-mobile/lib/core/storage/token_storage.dart | 08(第 8 节)、13(D16) |
| 61 | x-pan-mobile/lib/providers/auth_provider.dart | 02(2.2)、07(第 7 节) |
| 62 | x-pan-mobile/pubspec.yaml | 17(第 3 节) |
索引之外补两句读法。其一,三端各自的"入口级"文件(XPanServerLauncher.java、src/main.ts、lib/main.dart)适合作为读码起点,顺 Bean 装配与拦截器注册向下展开;而表内被最多篇目引用的四个文件(CommonLoginAspect、MinIOStorageEngine、UserFileServiceImpl、useUploader.ts)就是本项目的"四大件",吃透它们等于吃透一半架构——18 篇已带码走读其中两个,另两个的机制散见《05》《07》,可按同法自行推演。其二,反向索引刻意没有收录 Controller 之下的每一个 Mapper/entity/converter——它们是机械的分层产物,命名即含义(XxxMapper 对表、XxxConverter 是 MapStruct 接口、XxxContext 是服务层入参),读任何 Service 实现时遇到它们顺藤摸瓜即可;真正值得进索引的是"行为有出处、改动有约束"的文件,判断标准是:这个文件里有没有一条注释在解释"为什么"。
最少五步:先读《05-核心流程》流程一建立"先问、再传、后合"的分段心智模型,用任务面板状态把 bug 定位到段(解析中/上传中/合并中);再查《12-FAQ与故障排查》第 4 节上传表与第 5 节决策树——413、锁竞争繁忙、断点续传不跳片、99% 卡住四个高频现象都有现成根因;涉及服务端行为读《18-代码走读实录》走读一(分片锁与合并判定)与走读二(composeObject 与慢路径),涉及客户端读《10-性能设计与优化》第 1 节(5MB 强制、并发 3、函数式 headers 的理由);改代码前过《11-扩展开发指南》"动代码前五问"(identifier 是否进存储路径、是否绕过唯一键幂等);最后按《09-测试与质量保障》第 2 节的 uploadWithChunkTest 范式补回归用例——注意独立线程与测试事务可见性的坑。定位阶段还有两个实用抓手:服务端日志按 X-Pan-Trace-Id 一次 grep 到位(《12》第 1 节的排障走查),浏览器 Network 面板看最后失败的请求落在 sec-upload/chunk-upload/merge 哪一段。修 bug 时最容易踩的两条红线:不要给分片接口加"方法级 synchronized"(会把不同文件的并发压成串行,正确做法沿走读一的键粒度锁扩展),不要把 uploadedChunks 的判定改成"客户端本地计数"(服务端连续性校验是防坏文件的最后防线)。若 bug 指向"多实例部署后才出现",直接跳《13-技术债务与演进建议》D12,那是三处 JVM 锁的已知边界。
按《11-扩展开发指南》SOP-5 为主线:OSS/FastDFS 是"解注释 + 补配置"的接线活,自研介质(SFTP/Azure Blob 等)走"新模块 → 实现 StorageEngine 六操作 + 继承模板 → @ConditionalOnProperty 装配"的完整流程。动工前必读三篇打底:《16-决策记录ADR》ADR-003 理解抽象的收益与代价(接口是按文件网盘形状设计的,不支持服务端合并的介质要自行降级);《04-数据模型》1.2 理解 realPath 与桶规划(存量对象迁移是切换的真实前置);《10-性能设计与优化》第 3 节理解下载路径的 50MB 路由与预签名语义(replaceEndpoint 的签名绑定陷阱在《18》走读二有行级说明)。落码时记住两条硬约束:MinIO 与 Local 双实现必须同时落(CI 与本地模式走 Local 引擎,application-ci.yaml 强制关闭 MinIO,单实现等于让一半环境坏死);熔断要对照 MinIOStorageEngine.doStore 的 @CircuitBreaker + @Retry 给新引擎等价保护(ADR-009)。配置面遵循《14》的"三份同源"原则(运行时 yaml/打包模板/CI yaml 同步改)。完成后必做:存量迁移工具验证(《13》D11 的 StorageMigrationRunner ⚠️ 待确认完成度,实测前不得用于生产),以及《10》第 7 节预留的预签名 PUT 直传评估——若新介质支持服务端合并与预签名,把这两个能力接进 FileController 的可选注入路径,业务侧才能享受与 MinIO 同级的性能形态。
以《06-部署运行》第 8 节清单为骨架(数据库脚本、七个密钥、MinIO 三桶、Nginx 两 location、健康探针、CI 绿、雪花 workerId),补三篇的专属视角:《14-配置与环境详解》第 4 节三环境差异矩阵逐行核对(profile、密钥来源、中间件寻址、文档开关),并用三个"探针"自检环境纯度(/doc.html 应关、yaml 无明文地址、错误响应不泄堆栈);《08-安全与权限设计》第 7 节密钥治理(.env 权限收紧、run-local.sh 不落生产机、AES 密钥视同不可逆资产);《12-FAQ与故障排查》第 2 节启动失败三段判别法(静态块/数据源/compose 编排对应三个责任边界)。有几项容易被清单遗漏的核对点在此强调:pan.storage.minio.public-endpoint 必须是浏览器可达的公网入口(302 直链下发给的就是它);Prometheus 的五条 MinIO 告警规则加载后应在 Grafana 面板确认可见(没有告警的熔断等于没有熔断);限流四 scope 阈值若按业务调整过,确认打包模板同步(《14》第 5 节的变更规程)。上线后四步验证:health、登录、上传小文件、打开分享链接——分别验证密钥、会话链路、存储链路、XPAN_SHARE_HOST。
先立威胁模型再查代码:《08-安全与权限设计》第 3、4 节给出分享域的全部防线位置(归属校验、保险箱隔离、Share-Token 与登录 token 隔离、防爆破),第 5 节给失效三态语义;对照《05-核心流程》流程三确认"创建 → 提取码 → 浏览/转存/下载"每一步的校验点。具体疑点按越权面大小排序排查:保险箱文件是否可经分享流出(checkShareFileOwnership 在创建时拒绝 parentId=-2,核对 ShareServiceImpl 现状);匿名下载是否绕过登录(/share/file/download 设计为免登录 + Share-Token,核对 @NeedShareCode 注解在位,同时确认 Controller 未被移出 controller/ 子包——包结构即鉴权边界,见 ADR-001);ptoken 是否可跨文件复用(previewStream 比对 token 内 fileId 与请求 fileId 一致);转存是否校验了目标配额(ShareSavePO 路径走 saveUserFile 的配额校验);移动端 shareToken 存储是否按分享隔离(《13》D16 ⚠️ 待确认项,后端 ShareIdUtil 与归属校验会兜底拒绝错配 token,风险主要是体验而非越权)。真实报文对照《15-接口全量参考》第 4 节与《19-数据契约与示例集》第 8-9 节。定性结论回到《16-决策记录ADR》ADR-006 理解凭证设计边界——分享域的一切"看似过严"的拒绝都是 ADR 代价侧的刻意选择,排查的终点往往是确认"这是防线在工作"而不是"这里有漏洞"。
21 篇文档各自的最佳打开方式已在《00-项目总览》第 6 节按角色给出,本文最后补一条维护契约:本套文档的生命力取决于三件事的同步纪律——源码变更时先改对应篇目再合码(尤其"四大件"与 db.sql);发现漂移时在涉及篇目加 ⚠️ 标注并回溯根因(本套新增的五篇已示范两处修正:《19》对 sec-upload 入参与响应语义的校准、《16》对 WebDAV 能力边界的收窄);新增决策按《16》的五段结构落 ADR 并同步 DEV_GUIDELINES.md 红线。术语表会随业务膨胀、索引会随重构漂移,但"以源码为准、标注待确认、代价写明处"这三条原则不变——它们也是这套代码库本身写给维护者的三条承诺。