Svdvd-349 Jun 2026

The note was a key.

: Offer your opinion on the product's quality, performance, and value. Be specific about what you liked and disliked. SVDVD-349

| # | Given | When | Then | |---|-------|------|------| | | A document with ≥ 2 attachments is opened in the viewer. | The UI renders. | The toolbar shows a primary‑styled button labelled “Download All Attachments”. | | AC‑2 | The button is clicked. | The client calls the zip‑endpoint. | A download prompt appears with filename Document_<docId>_attachments_<timestamp>.zip . | | AC‑3 | The zip contains every attachment (including hidden ones the user can view). | The download completes. | The ZIP’s internal structure mirrors the original ordering (e.g., attachments/001‑Invoice.pdf ). | | AC‑4 | The total size of all attachments exceeds 500 MB . | The user clicks the button. | The API returns HTTP 413 with JSON error: "PayloadTooLarge", message: "Attachments exceed 500 MB limit." and the UI shows a toast: “Too many files – please download individually or request a larger bundle via Support.” | | AC‑5 | The request is made by a user lacking download permission for one of the attachments. | The API processes the request. | The response is HTTP 403, and the UI disables the button (grayed out) with tooltip “You do not have permission to download all files.” | | AC‑6 | The request is made on a mobile Safari browser. | The response returns a streaming ZIP. | The browser shows the native “Share / Save to Files” dialog (no “download‑blocked” warnings). | | AC‑7 | The zip is generated successfully. | The user opens it locally. | A manifest.txt file exists at the root, containing lines: <checksum> <size> <relative‑path> . | | AC‑8 | Automated test suite runs. | All unit, integration, and end‑to‑end tests pass. | Coverage for the new endpoint ≥ 90 %, UI interaction tests pass on Chrome, Firefox, Safari, Edge. | The note was a key

| Layer | Details | |------|----------| | | GET /api/v1/documents/docId/attachments/zip | | Auth | Inherit existing JWT + RBAC. Verify DOWNLOAD_ATTACHMENT permission for each attachment; if any fail → 403. | | Streaming | Use Spring Boot (or equivalent) ResponseBodyEmitter / StreamingResponseBody to stream ZIP on‑the‑fly (no temporary files). | | Zip Creation | - Use java.util.zip.ZipOutputStream (or Apache Commons Compress). - Add manifest.txt as the first entry. - Preserve original filenames; if duplicate names exist, prefix with numeric index. | | Size Guard | Before streaming, compute total size via metadata query. If > 500 MB → 413. | | Error Handling | Convert checked exceptions to JSON error responses via @ControllerAdvice . | | Rate Limiting | Apply existing per‑user API rate limiter (e.g., 10 zip requests/min). | | Metrics | Increment attachments.zip.request counter, record duration, success/failure tags. | | # | Given | When | Then

This blog post explores the technical specifications, performance capabilities, and practical applications of the