Storage Service¶
The storage service provides tenant-scoped document management using AWS S3.
Source: backend/app/services/storage_service.py
Overview¶
The storage service handles file uploads, downloads, and management for application documents, company logos, and exported reports. All files are organized by tenant to enforce multi-tenant isolation.
Key Path Convention¶
All S3 keys follow a tenant-scoped prefix pattern:
For example:
s3://carbon-connect-documents/tenant-abc123/applications/executive-summary.pdf
s3://carbon-connect-documents/tenant-abc123/logos/company-logo.png
s3://carbon-connect-documents/tenant-abc123/reports/carbon-audit-2024.xlsx
This ensures strict tenant isolation at the storage layer.
Features¶
| Feature | Description |
|---|---|
| Upload | Upload files with automatic key generation |
| Download | Stream file downloads |
| Presigned URLs | Generate time-limited signed URLs for direct browser access |
| Delete | Remove files by key |
| List | List files within a tenant prefix |
| Tenant isolation | All operations are scoped to tenant ID |
| Content type detection | Automatic MIME type detection from file extension |
Usage¶
from backend.app.services.storage_service import StorageService, get_storage_service
storage = get_storage_service()
# Upload a document
key = await storage.upload_file(
tenant_id="abc123",
category="applications",
filename="proposal.pdf",
content=file_bytes,
content_type="application/pdf",
)
# Generate presigned URL (valid for 1 hour)
url = await storage.get_presigned_url(key, expiration=3600)
# Download a file
content = await storage.download_file(key)
# List files in a category
files = await storage.list_files(
tenant_id="abc123",
category="applications",
)
# Delete a file
await storage.delete_file(key)
S3 Buckets¶
The infrastructure provisions two S3 buckets:
| Bucket | Purpose | Lifecycle |
|---|---|---|
documents | Application documents, reports, exports | Standard -> Intelligent-Tiering -> Glacier |
media | Company logos, profile images | Standard (no lifecycle) |
Lifecycle Policies¶
Document storage follows a cost-optimized lifecycle:
Configuration¶
| Environment Variable | Description | Default |
|---|---|---|
AWS_S3_DOCUMENTS_BUCKET | Documents bucket name | carbon-connect-{env}-documents |
AWS_S3_MEDIA_BUCKET | Media bucket name | carbon-connect-{env}-media |
AWS_S3_REGION | S3 region | eu-north-1 |
S3_PRESIGNED_URL_EXPIRY | Presigned URL expiration (seconds) | 3600 |
Security¶
- All buckets have public access blocked by default
- Files are encrypted at rest using AES-256 (S3 managed keys)
- Presigned URLs have configurable expiration times
- IAM policies restrict access to the ECS task role
- Cross-tenant access is prevented by validating
tenant_idin all operations
Integration¶
flowchart LR
A[Frontend] -->|Upload| B[API Endpoint]
B -->|Store| C[S3 Bucket]
B -->|Save metadata| D[(PostgreSQL)]
A -->|View| E[Presigned URL]
C -->|Serve| E