Service Integration
How ZoneVast services communicate, required headers, multi-tenancy, environment routing, and cross-service authentication patterns.
Service Integration
ZoneVast uses a microservices architecture. This page explains how services communicate, how to route requests, and how authentication works across services.
Architecture Overview
Client (Mobile/Web)
│
▼
API Gateway (test.zonevast.com)
│
├── /api/v1/auth/auth/ → zv-auth-service (Django)
├── /auth/api/v2/auth/ → zv-flex-auth-service (NestJS)
├── /api/v1/project/project/ → zv-project-service (Django)
│
▼
PostgreSQL (per-service databases)
Each service has its own database and handles a specific domain. The API Gateway routes requests based on URL path prefix.
Required Headers
Every authenticated request must include:
Authorization: Bearer <access-token>
X-Project-ID: <project-id>
Content-Type: application/json
See Headers & Authentication for the full reference.
Multi-Tenancy (Project Isolation)
All data is scoped to a project. The X-Project-ID header determines which project's data is accessed.
How It Works
- Project Creation — Create a project via the Project Service to get a project ID.
- Auth Tokens — JWT tokens include the project ID. The token is scoped to a specific project.
- Data Isolation — Every database query filters by project ID. Users in Project A cannot access Project B's data.
- Cross-Project Switching — Users can be members of multiple projects. Use a different token or switch project context.
Project in JWT
Django (zv-auth-service):
{
"user_id": 1,
"project_id": 11,
"username": "admin"
}
NestJS (zv-flex-auth-service):
{
"sub": "user-uuid",
"projectId": 11,
"project_id": 11,
"role": "customer"
}
Important: The
X-Project-IDheader must match the project in the JWT. A mismatch results in a 403 error.
Environment Routing
Requests are routed based on the environment:
|| Environment | Base URL | Use Case |
||-------------|----------|----------|
|| Test (Dev) | https://test.zonevast.com | Development and testing |
|| Production | https://api.zonevast.com | Live production traffic |
|| Local | http://localhost:{port} | Local development |
Service URL Patterns
Each service has a unique path prefix on the gateway:
https://test.zonevast.com/api/v1/auth/auth/ # Auth Service
https://test.zonevast.com/auth/api/v2/auth/ # Flex Auth Service
https://test.zonevast.com/api/v1/project/project/ # Project Service
Cross-Service Authentication
All services validate JWT tokens the same way:
- Client obtains a token from an auth service
- Client includes the token in
Authorization: Bearer {token}for any service - The target service validates the JWT signature and expiry
- If valid, the request proceeds with the user's identity from the token
Token Validation Differences
|| Aspect | Django Services | NestJS Services |
||--------|----------------|-----------------|
|| Validation | JWTAuthenticationWithoutDB — no DB lookup | JwtAuthGuard — varies by service |
|| DB Lookup | No (token-only validation for Lambda) | Some do DB lookup, some don't |
|| Project check | Middleware extracts X-Project-ID | ProjectGuard validates header |
Integration Flow Example
A typical user registration and data access flow:
Step 1: Register
POST /auth/api/v2/auth/register-init
→ Sends OTP to phone
Step 2: Verify & Get Token
POST /auth/api/v2/auth/register-verify
→ Returns { user, tokens: { accessToken, refreshToken } }
Step 3: Create Project
POST /api/v1/project/project/projects/
Headers: Authorization: Bearer {token}
→ Returns { id: 42, title: "My Project", ... }
Step 4: Upload File
POST /api/v1/project/project/attachment/presigned-url/
Headers: Authorization: Bearer {token}, X-Project-ID: 42
→ Returns presigned S3 URL
Step 5: Access Data
GET /api/v1/project/project/projects/
Headers: Authorization: Bearer {token}, X-Project-ID: 42
→ Returns projects scoped to project 42
Error Handling Across Services
When chaining service calls, handle errors at each step:
async function registerAndSetup(phone: string, otp: string) {
// Step 1: Verify registration
const authRes = await fetch('https://test.zonevast.com/auth/api/v2/auth/register-verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone, otp }),
});
if (!authRes.ok) {
const error = await authRes.json();
throw new Error(`Auth failed: ${error.message || error.detail}`);
}
const { tokens, user } = await authRes.json();
// Step 2: Create project
const projectRes = await fetch('https://test.zonevast.com/api/v1/project/project/projects/', {
method: 'POST',
headers: {
'Authorization': `Bearer ${tokens.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ title: 'My Project', username: `user-${user.id}`, template: 'default' }),
});
if (!projectRes.ok) {
const error = await projectRes.json();
throw new Error(`Project creation failed: ${error.detail || error.message}`);
}
const project = await projectRes.json();
return { tokens, user, project };
}
What's Next
- Headers & Authentication — Full auth reference
- File Uploads — How to upload files
- Error Responses — Error format across services