1. Thumbnail lifecycle split across two modules
+Files
+-
+
- crm-file/service/api/FileApi.java — 11 methods, includes
getThumbnail()
+ - crm-file/service/impl/FileApiImpl.java — 551 lines; ~100 lines are thumbnail read/fallback +
- crm-file/task/ThumbnailGenerationTask.java — generation + lock, but no retrieval +
- crm-file/service/ThumbnailPlaceholderService.java, ThumbnailRenderer.java +
No locality: thumbnail bugs span two modules
+Locality: full lifecycle in one module
+Problem: The thumbnail capability has no single module — generation lives in ThumbnailGenerationTask, retrieval and sync-fallback (handlePending, readThumbnail, placeholderOf) lives in FileApiImpl. Understanding thumbnail behavior requires bouncing between two modules. FileApi's interface is 11 methods wide because it carries thumbnail concerns that belong to a separate concern.
Solution: Extract a ThumbnailService module that owns the entire thumbnail lifecycle — generation, retrieval, sync-fallback, placeholder. FileApi narrows to file operations only. FileApiImpl.upload() and completeMultipart() call ThumbnailService.assignInitialStatus() + generate() instead of reaching into ThumbnailGenerationTask directly.
Wins
+-
+
- ▸ locality: thumbnail bugs concentrate in one module +
- ▸ leverage: one ThumbnailService interface, FileApi + FileController both call it +
- ▸ interface shrinks: FileApi drops
getThumbnail
+ - ▸ tests hit one interface for the full lifecycle +
- ▸ FileApiImpl shrinks ~100 lines +