Backend: Zapisnici photos
GitHub Issue: #199
Last modified with commit 7a580a0 on
by Aljaž.
Backend task for the Fotografije of the pickup and return forms (POST /drivepark/records/{recordId}/photos, DELETE and download of a photo) – check the API spec and DB structure, validate type, size and count, allow changes only while the stage is open, implement, and verify against the spec.
Docs: Zapisnik o preuzimanju (pickup form), Zapisnik o vraćanju (return form)
Spec: POST /drivepark/records/{recordId}/photos (uploadDriveParkRecordPhotos), DELETE /drivepark/records/{recordId}/photos/{photoId} (deleteDriveParkRecordPhoto), GET /drivepark/records/{recordId}/photos/{photoId}/download (downloadDriveParkRecordPhoto), DriveParkRecordPhoto, DriveParkPhotoInvalid, DriveParkRecordConflict in api-docs/openapi.yaml
DB: DriveParkRecordPhotos in api/database/pending_schema.sql (-- DRIVE PARK --)
1. Double check API spec and DB structure
- Rules: JPG, PNG, HEIC; at most 10 MB per file; at most 20 photos per record; removable until the stage is completed. Check the docs, the spec and the schema comment agree. The specification document doesn’t define these rules (docs: recommended values), so confirm them.
- Count limit: the pickup form says “Up to 20 photos per record”, and the return form says “the same upload rules apply”. The spec follows the docs: 20 per record, both stages together. Confirm it isn’t meant as 20 per stage.
- Photos need a saved record: the upload needs a record id, so on a new pickup record the frontend must save a draft first when the user picks files. Docs and Figma don’t mention this side effect. Confirm with the project manager.
- Stage rule: pickup photos only while Draft (
record_not_draft), return photos only while Preuzeto (record_not_picked_up). - PDF and e-mail: whether photos are part of the PDF is not specified (docs: recommended not). Confirm.
- HEIC: browsers can’t show HEIC. Decide whether the frontend shows HEIC as a link only, or the backend converts it.
- Roles and permissions:
drivepark.access.
2. Implementation
- Roles and permissions: require
drivepark.access→ 403. - Upload: validate every file first (content type and extension → 400
file_type_not_allowed; size → 400file_too_large; existing + new > 20 → 400too_many_files; no files → 400validation_error). If any fails, store nothing. Lock the record row (UPDLOCK) while counting, so two parallel uploads can’t pass 20. Upload to thedriveparkcontainer (with the validated content type as the blob’sContentType; the row stores onlyFileNameandBlobName), insert all rows in one statement. Response 201 with the photos. - Delete: check the stage rule → 409; delete the row, then the blob. Unknown id or a photo of another record → 404. Success → 204.
- Download: stream the blob with the content type from the blob’s properties and
Content-DispositionwithFileName(asdownloadBtcTrainingSignatureFile).
3. Verify implementation against spec
- Routes,
stagequery parameter, multipart body and response shapes match the three operations. - Every
errorvalue inDriveParkPhotoInvalidandDriveParkRecordConflictcan be produced; no undocumented ones. - A PDF → 400
file_type_not_allowed; an 11 MB JPG → 400file_too_large; a 21st photo → 400too_many_files, and nothing of that upload is stored. - Pickup photo on a Preuzeto record → 409; return photo on a Draft → 409.
Done when
Photos can be added to and removed from an open pickup or return, and opened from the forms and view pages.