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