services / project-service
Project Service
Project management and file attachment service. Handles all file uploads across ZoneVast with S3/CloudFront delivery. Built with Django REST Framework.
projectfilesuploads3cloudfront
Project Service (zv-project-service)
Project management, settings, and centralized file attachment handling for all ZoneVast services. Files are stored in S3 and served via CloudFront.
Service Info
| Property | Value |
|---|---|
| Framework | Django + DRF |
| Database | PostgreSQL (dev0) |
| S3 Bucket | file-zonevast-eu |
| CloudFront | file.zonevast.com |
Base URLs
| Environment | URL |
|---|---|
| Test (dev) | https://test.zonevast.com/api/v1/project/project/ |
| Production | https://api.zonevast.com/api/v1/project/project/ |
| Local | http://localhost:8070/api/v1/project/project/ |
Required Headers
Authorization: Bearer {accessToken}
X-Project-ID: <project-id>
Content-Type: application/json
File Upload
Method 1: Presigned URL (Recommended)
Step 1: Get presigned URL
curl -X POST https://test.zonevast.com/api/v1/project/project/attachment/presigned-url/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"file_name": "product-image.jpg",
"content_type": "image/jpeg",
"file_size": 102400,
"base_path": "products",
"entity_type": "product"
}'
Response:
{
"upload_url": "https://file-zonevast-eu.s3.amazonaws.com/...",
"fields": { "key": "...", "policy": "..." },
"attachment_id": 42,
"s3_key": "products/abc123-product-image.jpg"
}
Step 2: Upload to S3
curl -X PUT "UPLOAD_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @/path/to/image.jpg
Step 3: Confirm upload
curl -X POST https://test.zonevast.com/api/v1/project/project/attachment/confirm-upload/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>" \
-H "Content-Type: application/json" \
-d '{"attachment_id": 42}'
Method 2: Direct Upload (Testing Only)
curl -X POST https://test.zonevast.com/api/v1/project/project/attachment/direct-upload/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>" \
-F "file=@/path/to/image.jpg" \
-F "base_path=products" \
-F "entity_type=product"
Max ~10MB due to API Gateway payload limit.
Attachment Management
List Attachments
curl "https://test.zonevast.com/api/v1/project/project/attachment/?entity_type=product" \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>"
Get Attachment Details
curl https://test.zonevast.com/api/v1/project/project/attachment/42/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>"
Delete Attachment
curl -X DELETE https://test.zonevast.com/api/v1/project/project/attachment/42/delete/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>"
File URL Format
After upload, files are served at:
https://file.zonevast.com/{s3_key}
Projects
List Projects
curl https://test.zonevast.com/api/v1/project/project/projects/ \
-H "Authorization: Bearer TOKEN"
Create Project
curl -X POST https://test.zonevast.com/api/v1/project/project/projects/ \
-H "Authorization: Bearer TOKEN" \
-H "X-Project-ID: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"title": "My Project",
"username": "my-project",
"template": "default"
}'
Get Project by Username
curl https://test.zonevast.com/api/v1/project/project/projects/by-username/my-project/ \
-H "Authorization: Bearer TOKEN"
Project Settings
# Get settings
curl https://test.zonevast.com/api/v1/project/project/my-project/settings/ \
-H "Authorization: Bearer TOKEN"
# Set settings
curl -X POST https://test.zonevast.com/api/v1/project/project/my-project/settings/ \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"settings": {"theme": "dark", "language": "ar"}}'
Attachment Model
| Field | Type | Notes |
|---|---|---|
original_name | string | Original filename |
file_name | string | Stored filename |
type | enum | image, video, audio, document, other |
mime_type | string | MIME type |
size | number | File size in bytes |
s3_key | string | S3 object key |
upload_status | enum | pending, completed, failed |
hash | string | SHA-256 for deduplication |
entity_type | string | product, order, profile, etc. |
tenant_project_id | number | Multi-tenant isolation |
TypeScript Integration
const PROJECT_BASE = 'https://test.zonevast.com/api/v1/project/project';
async function uploadFile(file: File, entityType: string) {
// Step 1: Get presigned URL
const presignedRes = await fetch(`${PROJECT_BASE}/attachment/presigned-url/`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'X-Project-ID': '<project-id>',
'Content-Type': 'application/json',
},
body: JSON.stringify({
file_name: file.name,
content_type: file.type,
file_size: file.size,
base_path: entityType,
entity_type: entityType,
}),
});
const { upload_url, attachment_id } = await presignedRes.json();
// Step 2: Upload to S3
await fetch(upload_url, {
method: 'PUT',
headers: { 'Content-Type': file.type },
body: file,
});
// Step 3: Confirm
await fetch(`${PROJECT_BASE}/attachment/confirm-upload/`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'X-Project-ID': '<project-id>',
'Content-Type': 'application/json',
},
body: JSON.stringify({ attachment_id }),
});
return attachment_id;
}
Deployment
cd /home/yousef/Documents/workspace/zonevast/services/zv-project-service/
zappa update dev # Deploy to test.zonevast.com
zappa update prod # Deploy to production
zappa tail dev # View logs
Last validated: 2026-04-27