Commit Graph

8 Commits

Author SHA1 Message Date
JSLMPR 4d00b5e32b I added an importable Grafana dashboard at dashboards/video-clipping-overview-grafana.json:1 and the companion setup note in docs/dashboards.md:1. The dashboard covers queue backlog and age, DLQ and processing counts, API
request rate and p95 latency, plus CPU and heap usage using the Prometheus and Micrometer metrics already exposed by the service.
2026-07-10 00:14:13 +02:00
JSLMPR 1bd879f1e2 I completed the next plan step, Tenant quotas, and updated the plan to mark it done in docs/video-clipping-service-implementation-plan.md:701.
The implementation adds tenant-aware assets/jobs plus a configurable per-tenant active-job quota. The main enforcement is in src/main/java/org/example/videoclips/application/VideoAssetService.java:165, backed by tenant fields
  added to the domain/persistence model and migration src/main/resources/db/migration/V6__tenant_quota_support.sql:1. Requests can set X-Tenant-Id on asset creation, quota config lives in src/main/java/org/example/videoclips/
  config/VideoClippingProperties.java:39, and quota violations now return 429 via src/main/java/org/example/videoclips/api/ApiExceptionHandler.java:44.
2026-07-09 01:07:07 +02:00
JSLMPR 73070824df I changed the signed clip download flow so it uses the clip’s persisted objectKey instead of deriving a fake path from clipId. The fix is in src/main/java/org/example/videoclips/application/
VideoAssetService.java, src/main/java/org/example/videoclips/storage/ObjectStoragePort.java, src/main/java/org/example/videoclips/storage/InMemoryObjectStorageAdapter.java, and src/main/java/org/
  example/videoclips/storage/S3ObjectStorageAdapter.java.

  I also added focused coverage for this slice:

  - API test for generating a signed URL for an actual produced clip in src/test/java/org/example/videoclips/api/VideoAssetControllerTest.java
  - cleanup job tests for expired clip/object deletion and disabled cleanup in src/test/java/org/example/videoclips/operations/RetentionCleanupJobTest.java
2026-07-09 00:34:14 +02:00
JSLMPR 8cb232d70e Assets and clips now carry expiration timestamps in the domain model:
- src/main/java/org/example/videoclips/domain/VideoAsset.java
  - src/main/java/org/example/videoclips/domain/Clip.java

  That metadata is mapped through the in-memory and JPA repository paths, including:

  - src/main/java/org/example/videoclips/infrastructure/InMemoryVideoAssetRepository.java
  - src/main/java/org/example/videoclips/persistence/JpaVideoClippingRepository.java
  - src/main/java/org/example/videoclips/persistence/entity/VideoAssetEntity.java
  - src/main/java/org/example/videoclips/persistence/entity/ClipEntity.java

  I also added scheduled retention cleanup in src/main/java/org/example/videoclips/operations/RetentionCleanupJob.java, with configuration in src/main/java/org/example/videoclips/config/
  VideoClippingProperties.java and src/main/resources/application.properties. Right now it soft-expires assets by marking them deleted when their retention time passes. Clip retention timestamps
  are now assigned by both clipper adapters so the service has real expiration data to work with.

  What this does not do yet is physically delete expired clip objects or original source objects from object storage. The retention job is metadata-aware now, but object-store deletion still needs
  to be added through the storage port as the next step.
2026-07-09 00:28:05 +02:00
JSLMPR 3d961f2adf The new cleanup job is in src/main/java/org/example/videoclips/operations/LocalArtifactCleanupJob.java. It runs on a schedule and removes expired files from:
- the FFmpeg input directory
  - the FFmpeg output directory
  - tmp/in-memory-storage
  - tmp/stub-output

  The schedule and retention window are now configurable through src/main/java/org/example/videoclips/config/VideoClippingProperties.java and src/main/resources/application.properties via:

  - video-clipping.cleanup.enabled
  - video-clipping.cleanup.local-artifact-poll-interval-ms
  - video-clipping.cleanup.local-artifact-retention-hours

  This closes the first retention slice from the plan on the worker side. It does not yet delete expired original videos or clips from real object storage, and it does not do database-driven
  retention policies. That would be the next cleanup step.
2026-07-09 00:23:41 +02:00
JSLMPR abf1259397 The ClipProcessor symbol issue is fixed now.
The root cause was that ClipProcessor had been updated to call objectStoragePort.uploadGeneratedClip(...), but src/main/java/org/example/videoclips/storage/ObjectStoragePort.java did not yet
  declare that method. I added it to the port and confirmed both adapters implement it:

  - src/main/java/org/example/videoclips/storage/InMemoryObjectStorageAdapter.java
  - src/main/java/org/example/videoclips/storage/S3ObjectStorageAdapter.java

  I also verified the generated-clip contract is aligned across:

  - src/main/java/org/example/videoclips/processing/GeneratedClip.java
  - src/main/java/org/example/videoclips/processing/VideoClipperPort.java
  - src/main/java/org/example/videoclips/processing/StubVideoClipperAdapter.java
  - src/main/java/org/example/videoclips/processing/FfmpegVideoClipperAdapter.java
2026-07-09 00:19:44 +02:00
JSLMPR 66e998ee2a Generated clips now have a persisted object location instead of being metadata-only. I added objectKey to src/main/java/org/example/videoclips/domain/Clip.java, mapped it through JPA in src/main/
java/org/example/videoclips/persistence/entity/ClipEntity.java and src/main/java/org/example/videoclips/persistence/JpaVideoClippingMapper.java, and added the schema migration at src/main/
  resources/db/migration/V5__clip_object_key.sql.

  The clipper contract now returns both metadata and the local file path for each generated clip through src/main/java/org/example/videoclips/processing/GeneratedClip.java and the updated src/main/
  java/org/example/videoclips/processing/VideoClipperPort.java. Both adapters were updated:

  - src/main/java/org/example/videoclips/processing/StubVideoClipperAdapter.java now creates stub local output files
  - src/main/java/org/example/videoclips/processing/FfmpegVideoClipperAdapter.java now returns deterministic local output paths for generated segments

  On the storage side, ObjectStoragePort gained uploadGeneratedClip(...), with implementations in:

  - src/main/java/org/example/videoclips/storage/InMemoryObjectStorageAdapter.java
  - src/main/java/org/example/videoclips/storage/S3ObjectStorageAdapter.java

  And src/main/java/org/example/videoclips/processing/ClipProcessor.java now uploads each generated local file through storage before saving the clip record, so the job path is finally staged input
  -> process -> uploaded output -> persisted clip metadata.

  I also exposed objectKey in the clip response via src/main/java/org/example/videoclips/application/VideoAssetService.java and extended the MockMvc test to assert it exists in src/test/java/org/
  example/videoclips/api/VideoAssetControllerTest.java.
2026-07-09 00:16:49 +02:00
JSLMPR bd620fc773 The storage port now has a real staging operation:
- materializeSourceObject(String sourceObjectKey, Path targetPath) in src/main/java/org/example/videoclips/storage/ObjectStoragePort.java

  Both storage adapters implement it:

  - src/main/java/org/example/videoclips/storage/InMemoryObjectStorageAdapter.java creates a placeholder local file for the default stub flow
  - src/main/java/org/example/videoclips/storage/S3ObjectStorageAdapter.java downloads the object from S3-compatible storage to the worker filesystem

  The processor now uses that seam before clip generation starts. In src/main/java/org/example/videoclips/processing/ClipProcessor.java it resolves the local input path under the configured FFmpeg
  input directory, materializes the source object there, and records a SOURCE_MATERIALIZED job event before invoking the clipper.

  That means the FFmpeg path is no longer relying on a file appearing magically in the input directory. The next concrete step is to finish the output side the same way: persist generated clip
  object keys and push FFmpeg outputs back through the storage port instead of only creating clip metadata in memory.
2026-07-09 00:02:05 +02:00