2026-08-23
-
Cloudflare R2 Object Storage Migration:
- Complete Local Disk Elimination: Fully migrated all file uploads from local disk storage to Cloudflare R2 (
software.amazon.awssdk:s3,R2FileStorageServiceImpl.java). - Environment-Isolated Buckets: Production uses
ranlanka-crmand local development usesranlanka-crm-devconfigured viaapp.storage.r2.*. - Dual Database Backups: Enhanced
scripts/backup-db.shto upload independent 7-slot rotating database snapshots (ranlanka-db-backup-day{1-7}.sql.gz) to both Google Drive and Cloudflare R2 buckets in isolated execution blocks.
- Complete Local Disk Elimination: Fully migrated all file uploads from local disk storage to Cloudflare R2 (
-
Document Architecture & Deterministic R2 Hierarchy (Task 17):
- Flyway Migration (
V78__documents_metadata_and_annotations.sql): Added metadata columnsoriginal_filename,annotated_filename,description,file_size_bytes,content_type,sub_category,visa_request_id,flight_request_id,linked_group_id, and addedtickettodoc_typeenum. - Human-Readable R2 Customer Folder Hierarchy:
- Customer Folders:
customers/{name}_{customerId}/...(e.g.customers/Hashir_Silva_e547bb27-463b-4c47-bcfb-4a5f6e80b2a1/visas/...) for human-readable bucket inspection while ensuring zero UUID collisions. - Issued Visas:
customers/{name}_{customerId}/visas/{visaRequestId}/issued_visa/{annotatedFileName} - Visa Supporting Docs:
customers/{name}_{customerId}/visas/{visaRequestId}/supporting_docs/{annotatedFileName} - Issued Tickets:
customers/{name}_{customerId}/tickets/{flightRequestId}/issued_ticket/{annotatedFileName} - Booking Docs:
customers/{name}_{customerId}/tickets/{flightRequestId}/booking_docs/{annotatedFileName} - Passports:
customers/{name}_{customerId}/passports/{annotatedFileName} - General Docs:
customers/{name}_{customerId}/documents/{docType}/{annotatedFileName}
- Customer Folders:
- Deterministic File Naming Engine (
DocumentNamingHelper.java): Formats clean, standardized filenames (e.g.2026-08-23_eVisa_business_3M_SE_<customerId>.pdf,2026-08-23_Ticket_EK_PNR-ABC123_<customerId>.pdf,2026-08-23_passport_N8912345_<customerId>.pdf). Queries live request details (country, visa type, validity, airline, PNR) dynamically before generating final keys. - Presigned Download Headers:
presignDownloadUrl(...)passes S3responseContentDisposition("attachment; filename=\"...\"; filename*=UTF-8''...")with sanitized ASCII fallbacks and RFC 6266 URL encoding so downloads automatically save with structured names and block header injection.
- Flyway Migration (
-
Customer Dossier “Documents & Files” Tab:
- Tabular File Vault (
CustomerDocumentsTab.tsx): High-performance tabular file order (no slow thumbnail previews) displaying annotated names, category badges, staff descriptions, file sizes, upload timestamps, direct download buttons, and soft-delete actions. - Document Upload Modal (
UploadDocumentModal.tsx): Drag-and-drop file picker with category selection, request linking (to existing visas/flights), staff description input, and live auto-generated filename and R2 path preview with custom override support.
- Tabular File Vault (
-
Issue & Update Visa / Flight Ticket PDF Workflows:
- Validation Before Upload: Form validation executes strictly before any file is uploaded to storage, preventing orphaned uploads if required fields are missing or invalid.
- Issue / Update Visa Flow (
VisaDetailPanel.tsx): Integrated multi-file dropzone intoIssueVisaWithPdfSection. Displays all existing files with file sizes, download buttons, and Delete actions with styled ReactConfirmModal. - Issue / Update Ticket Flow (
FlightDetailPanel.tsx): Integrated multi-file dropzone intoIssueTicketWithPdfSection. Displays all existing files with file sizes, download buttons, and Delete actions with styled ReactConfirmModal. - Permanent Deletion on Request Purge: Deleting a flight or visa request permanently purges all attached documents from Cloudflare R2 and deletes rows from PostgreSQL. General customer document deletion preserves soft-delete (
deleted_at).
-
File Upload Security & Robustness Hardenings:
- Deterministic Magic-Byte Verification (
R2FileStorageServiceImpl.java): Validates byte signatures for PDF (%PDF-), PNG (89 50 4E 47), and JPEG (FF D8 FF). Rejects polyglot files and enforces cross-extension matching (disguised files like.exeor.htmlnamed.pdfare blocked). - Header Injection Prevention: Strips control characters (
\r\n\t\0), quotes, and slashes from presigned Content-Disposition headers. - Client-Side Validation (
fileValidation.ts): Rejects files exceeding 25MB or containing dangerous extensions (.exe,.bat,.cmd,.sh,.js,.html,.svg,.php) before sending network requests. - Safe Browser Downloader (
downloadUtils.ts): Validates download URL protocols (https:,http:,blob:), enforcesrel="noopener noreferrer", and safely removes temporary anchor elements infinallyblocks. - Resilient Multi-File Upload Loop: Per-file error tracking preserves only failed files in UI state for retry, and aborts issuance if any file upload fails.
- React Compiler Optimization: Fixed dependency inference mismatch (
cardId) across booking panels so React Compiler preserves memoization.
- Deterministic Magic-Byte Verification (
Last updated on