Stream document uploads and add the HR Training schema

Featurekamo-shared-library
Shipped
August 11, 2026 at 4:20 PM UTC
Author
Kamo
Commit
939ed24

ImageService gains uploadDocumentStreaming, the streaming counterpart of uploadDocument. The buffered form cannot express a large upload at all: readInputStream allocates new byte[size], a Java array tops out at Integer.MAX_VALUE, and MinIOStorageService.upload then allocates a SECOND full copy for cross-node retry. Against a 2Gi container that made a few hundred megabytes the practical ceiling — which is why the imaging multipart cap sat at 500MB while the chat attachment path, which already streams, ran to 3 GiB. The new method hashes once (both digests off one buffer), sniffs the MIME type BEFORE the hash pass so a mislabelled 3 GiB file is rejected without spending a full read on it, and delegates storage to a new storeContentAddressed overload that accepts pre-computed digests so the source is read twice rather than three times. Deliberately not @Transactional: storing gigabytes takes minutes and a transaction held across it pins a pooled connection. Also adds com.kamo.z.shared.hr.training — 20 entities, 11 enums and 20 repositories for the HR Training module, mirroring com.kamo.z.shared.hr.legal's conventions: BaseUuidEntity, an explicit last_modified with touch() because BaseUuidEntity.dateUpdated is dead, pinned columnDefinition on every optional @JoinColumn, and @OnDelete(CASCADE) on the audience FKs because CascadeType.* emits nothing at DDL. Two departures from the legal blueprint, both deliberate: - TrainingAssignmentStatus splits FAILED into FAILED_RETAKE_ALLOWED (open) and FAILED_FINAL (closed), and REMINDABLE_STATES is strictly narrower than OPEN_STATES so a member awaiting grading is never chased. Pinned by TrainingAssignmentStatusTest. - hr_training_notification is a real table with a UNIQUE claim index rather than a Redis SET NX, so "did we tell them on this date" survives a FLUSHDB and is queryable. Answer and attestation repositories extend the bare Repository marker, not JpaRepository, so the batch delete methods that bypass @PreRemove do not exist on the interface. Requires a KamoInitializerService run before any service that reads these tables is deployed.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing