Receipt Storage Repository
Component Detail
Description
Manages file upload and retrieval operations against Supabase Storage using an org/user/claim-scoped path strategy. Enforces access boundaries so receipts are only accessible to the owning organization and authorized users. Provides signed URLs for secure display in the UI.
receipt-storage-repository
Summaries
The Receipt Storage Repository ensures that expense receipts are stored securely in the cloud and accessible only to authorized personnel within the correct organization. By scoping file storage paths to org, user, and claim identifiers, the system prevents cross-organizational data exposure — a critical requirement for any multi-tenant financial product. Signed URL generation means receipt images are never exposed through persistent public links, reducing the risk of unauthorized access. Reliable upload progress streaming ensures employees are not left uncertain about whether their receipt was successfully attached, reducing support inquiries and resubmissions.
This component integrates directly with Supabase Storage, introducing an external service dependency that should be validated early in the project. Storage bucket configuration, access policy setup, and RLS (Row Level Security) rules in Supabase must be in place before integration testing can proceed — coordinate with whoever owns the Supabase project configuration. The signed URL expiry duration is a policy decision that should be confirmed with stakeholders before implementation. File size and type enforcement adds a validation surface that needs test cases covering oversized files, unsupported types, and boundary sizes.
Medium complexity overall, but the external dependency elevates delivery risk slightly. Ensure a test Supabase environment is available for the development team.
The Receipt Storage Repository wraps Supabase Storage with an org/user/claim-scoped path strategy built by `buildStoragePath(orgId, userId, claimId, fileName)`. Upload operations should use the Supabase client's resumable upload API where available to support large files and poor network conditions. `getUploadProgressStream()` should map Supabase's upload progress callbacks to a reactive stream for consumption by `receipt-attachment-service`. Signed URL generation via `getSignedUrl(storagePath, expiry)` must use Supabase's `createSignedUrl` method — never expose raw storage paths to the UI layer.
`deleteReceipt` must handle the case where the file no longer exists (e.g., already deleted) gracefully without throwing. `fileExists` is a cheap metadata check useful for idempotent retry logic. Enforce MIME type and file size constraints at this layer as a last-resort guard, even if compression has already run.
Responsibilities
- Upload receipt files to Supabase Storage with org/user/claim path scoping
- Generate signed download URLs for displaying receipts
- Delete receipt files when claims are cancelled or attachments removed
- Stream upload progress for non-blocking UI feedback
- Enforce file size and type constraints before upload
Interfaces
uploadReceipt(orgId, userId, claimId, file)
getSignedUrl(storagePath, {Duration expiry})
deleteReceipt(storagePath)
getUploadProgressStream()
buildStoragePath(orgId, userId, claimId, fileName)
fileExists(storagePath)