172 lines
5.7 KiB
Markdown
172 lines
5.7 KiB
Markdown
# MinIO Document Storage Setup Summary
|
|
|
|
## Problem
|
|
Documents uploaded to MinIO were returning `AccessDenied` errors when users tried to download them from the admin documents page.
|
|
|
|
## Root Cause
|
|
The `xpeditis-documents` bucket did not have a public read policy configured, which prevented direct URL access to uploaded documents.
|
|
|
|
## Solution Implemented
|
|
|
|
### 1. Fixed Dummy URLs in Database
|
|
**Script**: `fix-dummy-urls.js`
|
|
- Updated 2 bookings that had dummy URLs (`https://dummy-storage.com/...`)
|
|
- Changed to proper MinIO URLs: `http://localhost:9000/xpeditis-documents/csv-bookings/{bookingId}/{documentId}-{fileName}`
|
|
|
|
### 2. Uploaded Test Documents
|
|
**Script**: `upload-test-documents.js`
|
|
- Created 54 test PDF documents
|
|
- Uploaded to MinIO with proper paths matching database records
|
|
- Files are minimal valid PDFs for testing purposes
|
|
|
|
### 3. Set Bucket Policy for Public Read Access
|
|
**Script**: `set-bucket-policy.js`
|
|
- Configured the `xpeditis-documents` bucket with a policy allowing public read access
|
|
- Policy applied:
|
|
```json
|
|
{
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Effect": "Allow",
|
|
"Principal": "*",
|
|
"Action": ["s3:GetObject"],
|
|
"Resource": ["arn:aws:s3:::xpeditis-documents/*"]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Verification
|
|
|
|
### Test Document Download
|
|
```bash
|
|
# Test with curl (should return HTTP 200 OK)
|
|
curl -I http://localhost:9000/xpeditis-documents/csv-bookings/70f6802a-f789-4f61-ab35-5e0ebf0e29d5/eba1c60f-c749-4b39-8e26-dcc617964237-Document_Export.pdf
|
|
|
|
# Download actual file
|
|
curl -o test.pdf http://localhost:9000/xpeditis-documents/csv-bookings/70f6802a-f789-4f61-ab35-5e0ebf0e29d5/eba1c60f-c749-4b39-8e26-dcc617964237-Document_Export.pdf
|
|
```
|
|
|
|
### Frontend Verification
|
|
1. Navigate to: http://localhost:3000/dashboard/admin/documents
|
|
2. Click the "Download" button on any document
|
|
3. Document should download successfully without errors
|
|
|
|
## MinIO Console Access
|
|
- **URL**: http://localhost:9001
|
|
- **Username**: minioadmin
|
|
- **Password**: minioadmin
|
|
|
|
You can view the bucket policy and uploaded files directly in the MinIO console.
|
|
|
|
## Files Created
|
|
- `apps/backend/fix-dummy-urls.js` - Updates database URLs from dummy to MinIO
|
|
- `apps/backend/upload-test-documents.js` - Uploads test PDFs to MinIO
|
|
- `apps/backend/set-bucket-policy.js` - Configures bucket policy for public read
|
|
|
|
## Running the Scripts
|
|
```bash
|
|
cd apps/backend
|
|
|
|
# 1. Fix database URLs (run once)
|
|
node fix-dummy-urls.js
|
|
|
|
# 2. Upload test documents (run once)
|
|
node upload-test-documents.js
|
|
|
|
# 3. Set bucket policy (run once)
|
|
node set-bucket-policy.js
|
|
```
|
|
|
|
## Important Notes
|
|
|
|
### Development vs Production
|
|
- **Current Setup**: Public read access (suitable for development)
|
|
- **Production**: Consider using signed URLs for better security
|
|
|
|
### Signed URLs (Production Recommendation)
|
|
Instead of public bucket access, generate temporary signed URLs via the backend:
|
|
|
|
```typescript
|
|
// Backend endpoint to generate signed URL
|
|
@Get('documents/:id/download-url')
|
|
async getDownloadUrl(@Param('id') documentId: string) {
|
|
const document = await this.documentsService.findOne(documentId);
|
|
const signedUrl = await this.storageService.getSignedUrl(document.filePath);
|
|
return { url: signedUrl };
|
|
}
|
|
```
|
|
|
|
This approach:
|
|
- ✅ More secure (temporary URLs that expire)
|
|
- ✅ Allows access control (check user permissions before generating URL)
|
|
- ✅ Audit trail (log who accessed what)
|
|
- ❌ Requires backend API call for each download
|
|
|
|
### Current Architecture
|
|
The `S3StorageAdapter` already has a `getSignedUrl()` method implemented (line 148-162 in `s3-storage.adapter.ts`), so migrating to signed URLs in the future is straightforward.
|
|
|
|
## Troubleshooting
|
|
|
|
### AccessDenied Error Returns
|
|
If you get AccessDenied errors again:
|
|
1. Check bucket policy: `node -e "const {S3Client,GetBucketPolicyCommand}=require('@aws-sdk/client-s3');const s3=new S3Client({endpoint:'http://localhost:9000',region:'us-east-1',credentials:{accessKeyId:'minioadmin',secretAccessKey:'minioadmin'},forcePathStyle:true});s3.send(new GetBucketPolicyCommand({Bucket:'xpeditis-documents'})).then(r=>console.log(r.Policy))"`
|
|
2. Re-run: `node set-bucket-policy.js`
|
|
|
|
### Document Not Found
|
|
If document URLs return 404:
|
|
1. Check MinIO console (http://localhost:9001)
|
|
2. Verify file exists in bucket
|
|
3. Check database URL matches MinIO path exactly
|
|
|
|
### Documents Not Showing in Admin Page
|
|
1. Verify bookings exist: `SELECT id, documents FROM csv_bookings WHERE documents IS NOT NULL`
|
|
2. Check frontend console for errors
|
|
3. Verify API endpoint returns data: http://localhost:4000/api/v1/admin/bookings
|
|
|
|
## Database Query Examples
|
|
|
|
### Check Document URLs
|
|
```sql
|
|
SELECT
|
|
id,
|
|
booking_id as "bookingId",
|
|
documents::jsonb->0->>'filePath' as "firstDocumentUrl"
|
|
FROM csv_bookings
|
|
WHERE documents IS NOT NULL
|
|
LIMIT 5;
|
|
```
|
|
|
|
### Count Documents by Booking
|
|
```sql
|
|
SELECT
|
|
id,
|
|
jsonb_array_length(documents::jsonb) as "documentCount"
|
|
FROM csv_bookings
|
|
WHERE documents IS NOT NULL;
|
|
```
|
|
|
|
## Next Steps (Optional Production Enhancements)
|
|
|
|
1. **Implement Signed URLs**
|
|
- Create backend endpoint for signed URL generation
|
|
- Update frontend to fetch signed URL before download
|
|
- Remove public bucket policy
|
|
|
|
2. **Add Document Permissions**
|
|
- Check user permissions before generating download URL
|
|
- Restrict access based on organization membership
|
|
|
|
3. **Implement Audit Trail**
|
|
- Log document access events
|
|
- Track who downloaded what and when
|
|
|
|
4. **Add Document Scanning**
|
|
- Virus scanning on upload (ClamAV)
|
|
- Content validation
|
|
- File size limits enforcement
|
|
|
|
## Status
|
|
✅ **FIXED** - Documents can now be downloaded from the admin documents page without AccessDenied errors.
|