# 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.
