# MinIO Setup Technical Specification

## Project Status

Starting MinIO integration from scratch. Previous implementation had compatibility issues with bucket policies in SNSD mode. New implementation uses SNMD (Single Node Multi Drive) configuration with presigned URLs for reliable file access.

## Architecture Overview

### Storage Strategy

- **Mode**: SNMD (4 virtual drives) for full S3 compatibility
- **Access Method**: Presigned URLs only (no bucket policies)
- **Bucket Structure**: Single bucket `banatie` with path-based organization
- **File Organization**: `orgId/projectId/category/year-month/filename`

### Technology Stack

- MinIO latest (`quay.io/minio/minio:latest`)
- Docker Compose for orchestration
- PostgreSQL for application data
- Express.js API with TypeScript

## Configuration Files Status

### Completed Files

- `docker-compose.yml` - SNMD configuration with 4 virtual drives
- `.env.docker` - Environment variables for development
- `src/services/MinioStorageService.ts` - Updated service implementation
- `src/services/StorageFactory.ts` - Service factory configuration
- `src/routes/images.ts` - Presigned URL endpoints

### Integration Requirements

#### 1. Update Application Router

Add images router to main application in `src/app.ts`:

```typescript
import { imagesRouter } from './routes/images';

// Add to routes section
app.use('/api', imagesRouter);
```

#### 2. Environment Variables Update

Update existing `.env` file with MinIO configuration:

```bash
# Add to existing .env file
MINIO_ROOT_USER=banatie_admin
MINIO_ROOT_PASSWORD=banatie_storage_secure_key_2024
STORAGE_TYPE=minio
MINIO_ENDPOINT=minio:9000
MINIO_ACCESS_KEY=banatie_service
MINIO_SECRET_KEY=banatie_service_key_2024
MINIO_USE_SSL=false
MINIO_BUCKET_NAME=banatie
MINIO_PUBLIC_URL=http://localhost:9000
API_BASE_URL=http://localhost:3000
DEFAULT_ORG_ID=default
DEFAULT_PROJECT_ID=main
DEFAULT_USER_ID=system
PRESIGNED_URL_EXPIRY=86400
```

#### 3. Database Script Update

Update `scripts/init-db.sql` to use new database name `banatie` instead of previous naming.

#### 4. Service Dependencies Update

Update existing image generation services to use new storage configuration:

```typescript
// In ImageGenService.ts or similar
const storageService = StorageFactory.getInstance();
const uploadResult = await storageService.uploadFile(
  orgId,
  projectId,
  'generated',
  filename,
  buffer,
  'image/png',
);
// Use uploadResult.url (returns API URL for presigned access)
```

## Setup Instructions

### 1. Directory Structure

Create required directories:

```bash
mkdir -p data/storage/{drive1,drive2,drive3,drive4}
mkdir -p data/postgres
```

### 2. Service Startup

```bash
# Start all services
docker-compose up -d

# Verify services are healthy
docker-compose ps

# Check MinIO logs
docker logs banatie-storage

# Check initialization logs
docker logs banatie-storage-init
```

### 3. Verification Steps

#### MinIO Console Access

- URL: http://localhost:9001
- Username: banatie_admin
- Password: banatie_storage_secure_key_2024

#### Test Presigned URL Generation

```bash
# Test image upload endpoint
curl -X POST http://localhost:3000/api/upload \
  -F "files=@test.png" \
  -F "category=generated"

# Test presigned URL access
curl -I "http://localhost:3000/api/images/default/main/generated/test-image.png"
# Should return 302 redirect to presigned URL
```

#### Verify SNMD Mode

```bash
# Check MinIO is in erasure coding mode
docker exec banatie-storage mc admin info local
# Should show 4 drives and erasure coding information
```

## Integration Testing

### Required Tests

1. **Storage Service Initialization**
   - Verify StorageFactory creates MinioStorageService
   - Confirm bucket creation and accessibility

2. **File Upload/Download Cycle**
   - Upload file via StorageService
   - Generate presigned URL
   - Verify file accessibility via presigned URL

3. **API Endpoint Testing**
   - Test `/api/images/:orgId/:projectId/:category/:filename`
   - Verify 302 redirect to presigned URL
   - Test fallback direct streaming

4. **Error Handling**
   - Test invalid file paths
   - Test expired presigned URLs
   - Test MinIO connection failures

### Test Script Template

```bash
#!/bin/bash
# test-minio-integration.sh

echo "Testing MinIO Integration"

# Test 1: Upload file
UPLOAD_RESPONSE=$(curl -s -X POST http://localhost:3000/api/upload \
  -F "files=@test.png" \
  -F "category=generated")

echo "Upload Response: $UPLOAD_RESPONSE"

# Extract URL from response
FILE_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.files[0].url')

# Test 2: Access via presigned URL
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$FILE_URL")

if [ "$HTTP_CODE" = "302" ]; then
  echo "SUCCESS: Presigned URL redirect working"
else
  echo "FAILURE: Expected 302, got $HTTP_CODE"
fi
```

## Production Considerations

### Environment Differences

Development and production use identical configuration with different values:

```bash
# Production .env differences
API_BASE_URL=https://api.yourdomain.com
MINIO_PUBLIC_URL=https://storage.yourdomain.com:9000
MINIO_USE_SSL=true
```

### Security Notes

- All passwords use environment variables (no hardcoded values)
- Presigned URLs expire after 24 hours by default
- Service user has minimal required permissions
- MinIO admin access separate from application access

### Scaling Path

- Current SNMD setup supports development and small production loads
- Can migrate to distributed MinIO cluster when needed
- Presigned URL architecture remains unchanged during scaling

## Troubleshooting

### Common Issues

1. **403 Errors**: Check presigned URL generation and MinIO service user permissions
2. **404 Errors**: Verify file paths and bucket configuration
3. **Connection Errors**: Confirm MinIO service health and network connectivity

### Debug Commands

```bash
# Check MinIO health
docker exec banatie-storage mc admin info local

# List bucket contents
docker exec banatie-storage mc ls storage/banatie --recursive

# Check service logs
docker logs banatie-storage
docker logs banatie-app
```

### Recovery Procedures

```bash
# Reset MinIO data (development only)
docker-compose down
rm -rf data/storage/*
docker-compose up -d

# Recreate bucket structure
docker exec banatie-storage mc mb storage/banatie
```

## Implementation Priority

### Phase 1 (Immediate)

1. Update app.ts with images router
2. Update environment configuration
3. Test basic upload/download functionality

### Phase 2 (Next)

1. Update existing image generation services
2. Implement comprehensive error handling
3. Add integration tests

### Phase 3 (Future)

1. Add monitoring and logging
2. Implement file cleanup policies
3. Add CDN integration capability

## Acceptance Criteria

Integration is complete when:

- [ ] All services start successfully via docker-compose
- [ ] MinIO operates in SNMD mode with 4 drives
- [ ] Image upload returns API URL format
- [ ] API URLs redirect to working presigned URLs
- [ ] Generated images accessible via presigned URLs
- [ ] Error handling provides meaningful responses
- [ ] Integration tests pass consistently

## Notes

This implementation prioritizes simplicity and reliability over advanced features. The presigned URL approach ensures consistent behavior across different MinIO configurations and provides a foundation for future enhancements without requiring architectural changes.
