How Multi-Cloud Portability Works
The platform uses a service factory that selects the correct cloud provider implementation based on theCLOUD_PROVIDER environment variable:
To migrate from AWS to OCI: change
CLOUD_PROVIDER=oci in .env and implement the 4 OCI services. The rest of your application requires no changes.Service Provider Mapping
| Interface | AWS | OCI | GCP | Azure |
|---|---|---|---|---|
| StorageService | S3 | Object Storage | Cloud Storage | Blob Storage |
| DatabaseService | RDS PostgreSQL | DB Service | Cloud SQL | DB for PostgreSQL |
| MonitoringService | CloudWatch | Monitoring | Cloud Operations | Azure Monitor |
| AuthService | IAM / Cognito | Identity Cloud Service | Firebase Auth / IAM | Azure Active Directory |
| Container Registry | ECR | OCIR | Artifact Registry | ACR |
| Kubernetes | EKS | OKE | GKE | AKS |
| Load Balancer | ALB / ELB | Load Balancer | Cloud Load Balancing | Azure Load Balancer |
| Secrets | Secrets Manager | Vault Service | Secret Manager | Key Vault |
Backend Service Structure
All cloud provider implementations follow this structure inapp/backend/src/services/:
Using Cloud Services in Your Application
StorageService (S3 / Object Storage)
Upload, download, and manage files in cloud object storage:StorageService Interface Contract
StorageService Interface Contract
DatabaseService (RDS / Cloud SQL)
Execute SQL queries with transaction support:DatabaseService Interface Contract
DatabaseService Interface Contract
MonitoringService (CloudWatch / Cloud Monitoring)
Record metrics, logs, and create alarms:MonitoringService Interface Contract
MonitoringService Interface Contract
AuthService (IAM / Cognito / Azure AD)
Handle authentication and authorization:AuthService Interface Contract
AuthService Interface Contract
Implementing a Cloud Provider
To add support for a new cloud provider (e.g., OCI), implement the four service interfaces.// src/services/providers/oci/oci-storage.service.js
const oci = require('oci-sdk');
class OciStorageService {
constructor() {
this.provider = new oci.common.ConfigFileAuthenticationDetailsProvider();
this.client = new oci.objectstorage.ObjectStorageClient({
authenticationDetailsProvider: this.provider,
});
this.namespace = process.env.OCI_NAMESPACE;
}
async uploadFile(bucketName, key, body, contentType) {
const request = {
namespaceName: this.namespace,
bucketName,
objectName: key,
putObjectBody: body,
contentType,
};
return await this.client.putObject(request);
}
async downloadFile(bucketName, key) {
const request = {
namespaceName: this.namespace,
bucketName,
objectName: key,
};
const response = await this.client.getObject(request);
return response.value;
}
async deleteFile(bucketName, key) {
const request = {
namespaceName: this.namespace,
bucketName,
objectName: key,
};
return await this.client.deleteObject(request);
}
async listFiles(bucketName, prefix = '') {
const request = {
namespaceName: this.namespace,
bucketName,
prefix,
};
const response = await this.client.listObjects(request);
return response.listObjects.objects.map(obj => ({
key: obj.name,
size: obj.size,
lastModified: obj.timeModified,
}));
}
async getSignedUrl(bucketName, key, expiresInSeconds = 3600) {
const request = {
namespaceName: this.namespace,
bucketName,
createPreauthenticatedRequestDetails: {
name: `temp-access-${key}`,
objectName: key,
accessType: 'ObjectRead',
timeExpires: new Date(Date.now() + expiresInSeconds * 1000).toISOString(),
},
};
const response = await this.client.createPreauthenticatedRequest(request);
return `https://objectstorage.${process.env.OCI_REGION}.oraclecloud.com${response.preauthenticatedRequest.accessUri}`;
}
}
module.exports = { OciStorageService };
const PROVIDER = process.env.CLOUD_PROVIDER || 'aws';
// Import OCI services
const { OciStorageService } = require('./providers/oci/oci-storage.service');
const { OciDatabaseService } = require('./providers/oci/oci-database.service');
const { OciMonitoringService } = require('./providers/oci/oci-monitoring.service');
const { OciAuthService } = require('./providers/oci/oci-auth.service');
const PROVIDERS = {
aws: {
storage: () => new (require('./providers/aws/aws-storage.service').AwsStorageService)(),
database: () => new (require('./providers/aws/aws-database.service').AwsDatabaseService)(),
monitoring: () => new (require('./providers/aws/aws-monitoring.service').AwsMonitoringService)(),
auth: () => new (require('./providers/aws/aws-auth.service').AwsAuthService)(),
},
oci: {
storage: () => new OciStorageService(),
database: () => new OciDatabaseService(),
monitoring: () => new OciMonitoringService(),
auth: () => new OciAuthService(),
},
};
function getService(type) {
const provider = PROVIDERS[PROVIDER];
if (!provider) {
throw new Error(`Provider '${PROVIDER}' not implemented. Options: ${Object.keys(PROVIDERS).join(', ')}`);
}
return provider[type]();
}
module.exports = {
getStorageService: () => getService('storage'),
getDatabaseService: () => getService('database'),
getMonitoringService: () => getService('monitoring'),
getAuthService: () => getService('auth'),
};
Cloud Provider Migration
To migrate from one cloud provider to another:cd terraform/environments/prod
# Create new OCI-specific configuration
terraform init
terraform plan -var="cloud_provider=oci"
terraform apply
# S3 (AWS) to OCI Object Storage
rclone sync s3:govtech-documents oci:govtech-documents
# RDS PostgreSQL to OCI Database Service
pg_dump -h <rds-endpoint> govtech_prod | \
psql -h <oci-db-endpoint> govtech_prod
What Changes vs. What Stays the Same
Unchanged During Migration
- Application code (Node.js / React)
- PostgreSQL database schema
- Kubernetes manifests (except storage classes)
- CI/CD pipelines (only registry destination changes)
- Security and compliance policies
Changed During Migration
- Environment variables (endpoint, region, credentials)
- IAM policies (each cloud has its own model)
- Ingress configuration (ALB on AWS, Cloud Load Balancing on GCP, etc.)
- Kubernetes storage classes (gp3 on AWS, pd-ssd on GCP, etc.)
Next Steps
- Review the complete Multi-Cloud Services documentation
- Learn about deployment procedures
- Understand IAM security policies