chore: consolidate local WIP (repo cleanup 20260707)
Some checks failed
API CI / API Lint (push) Successful in 47s
API CI / API Type Check (push) Failing after 47s
API CI / API Test (push) Successful in 1m0s
API CI / API Build (push) Failing after 50s
API CI / Build Docker Image (push) Has been skipped
Build Crossplane Provider / build (push) Failing after 5m51s
CD Pipeline / Deploy to Staging (push) Failing after 29s
CI Pipeline / Lint and Type Check (push) Failing after 36s
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Test Backend (push) Failing after 1m33s
CI Pipeline / Test Frontend (push) Failing after 30s
CI Pipeline / Security Scan (push) Failing after 1m16s
Crossplane Provider CI / Go Test (push) Failing after 3m23s
Crossplane Provider CI / Go Lint (push) Failing after 7m27s
Crossplane Provider CI / Go Build (push) Failing after 3m27s
Deploy to Staging / Deploy to Staging (push) Failing after 30s
Portal CI / Portal Lint (push) Failing after 21s
Portal CI / Portal Type Check (push) Failing after 21s
Portal CI / Portal Test (push) Failing after 21s
Portal CI / Portal Build (push) Failing after 22s
Test Suite / frontend-tests (push) Failing after 30s
Test Suite / api-tests (push) Failing after 49s
Test Suite / blockchain-tests (push) Failing after 30s
Type Check / type-check (map[directory:. name:root]) (push) Failing after 23s
Type Check / type-check (map[directory:api name:api]) (push) Failing after 21s
Type Check / type-check (map[directory:portal name:portal]) (push) Failing after 19s
Validate Configuration Files / validate (push) Failing after 1m52s
CD Pipeline / Deploy to Production (push) Has been skipped
Some checks failed
API CI / API Lint (push) Successful in 47s
API CI / API Type Check (push) Failing after 47s
API CI / API Test (push) Successful in 1m0s
API CI / API Build (push) Failing after 50s
API CI / Build Docker Image (push) Has been skipped
Build Crossplane Provider / build (push) Failing after 5m51s
CD Pipeline / Deploy to Staging (push) Failing after 29s
CI Pipeline / Lint and Type Check (push) Failing after 36s
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Test Backend (push) Failing after 1m33s
CI Pipeline / Test Frontend (push) Failing after 30s
CI Pipeline / Security Scan (push) Failing after 1m16s
Crossplane Provider CI / Go Test (push) Failing after 3m23s
Crossplane Provider CI / Go Lint (push) Failing after 7m27s
Crossplane Provider CI / Go Build (push) Failing after 3m27s
Deploy to Staging / Deploy to Staging (push) Failing after 30s
Portal CI / Portal Lint (push) Failing after 21s
Portal CI / Portal Type Check (push) Failing after 21s
Portal CI / Portal Test (push) Failing after 21s
Portal CI / Portal Build (push) Failing after 22s
Test Suite / frontend-tests (push) Failing after 30s
Test Suite / api-tests (push) Failing after 49s
Test Suite / blockchain-tests (push) Failing after 30s
Type Check / type-check (map[directory:. name:root]) (push) Failing after 23s
Type Check / type-check (map[directory:api name:api]) (push) Failing after 21s
Type Check / type-check (map[directory:portal name:portal]) (push) Failing after 19s
Validate Configuration Files / validate (push) Failing after 1m52s
CD Pipeline / Deploy to Production (push) Has been skipped
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
811
docs/phoenix/IMPLEMENTATION_EXAMPLES.md
Normal file
811
docs/phoenix/IMPLEMENTATION_EXAMPLES.md
Normal file
@@ -0,0 +1,811 @@
|
||||
# Phoenix Operating Model - Implementation Examples
|
||||
|
||||
**Practical code examples and implementation patterns for Phoenix operating model**
|
||||
|
||||
This document provides real-world implementation examples for the Phoenix operating model, including entity creation, infrastructure provisioning, CI/CD integration, and deployment patterns.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Entity Creation Examples](#entity-creation-examples)
|
||||
2. [Infrastructure as Code Examples](#infrastructure-as-code-examples)
|
||||
3. [CI/CD Pipeline Examples](#cicd-pipeline-examples)
|
||||
4. [Multi-Region Deployment Examples](#multi-region-deployment-examples)
|
||||
5. [Promotion Flow Examples](#promotion-flow-examples)
|
||||
6. [Integration Examples](#integration-examples)
|
||||
|
||||
---
|
||||
|
||||
## Entity Creation Examples
|
||||
|
||||
### Example 1: Complete Setup for Sovereign Government
|
||||
|
||||
```typescript
|
||||
// Complete setup: Client → Tenant → Subscription → Environment
|
||||
|
||||
// Step 1: Create Client (Billing Profile)
|
||||
const client = await phoenix.commercial.createClient({
|
||||
name: "Government Agency A",
|
||||
legalEntity: {
|
||||
name: "Government Agency A",
|
||||
jurisdiction: "Nation A",
|
||||
registrationNumber: "GOV-001",
|
||||
address: {
|
||||
street: "123 Government St",
|
||||
city: "Capital City",
|
||||
country: "Nation A"
|
||||
}
|
||||
},
|
||||
invoicingConfig: {
|
||||
format: "PDF",
|
||||
frequency: "MONTHLY",
|
||||
currency: "USD",
|
||||
paymentTerms: "Net 30",
|
||||
billingAddress: {
|
||||
street: "123 Government St",
|
||||
city: "Capital City",
|
||||
country: "Nation A"
|
||||
},
|
||||
emailRecipients: ["billing@agency.gov"]
|
||||
}
|
||||
});
|
||||
|
||||
// Step 2: Create Tenant
|
||||
const tenant = await phoenix.tenancy.createTenant({
|
||||
name: "agency-tenant",
|
||||
clientId: client.id,
|
||||
primaryDomains: ["agency.gov", "agency.sankofa.nexus"],
|
||||
identityProvider: {
|
||||
type: "KEYCLOAK",
|
||||
config: {},
|
||||
ssoEnabled: true,
|
||||
mfaRequired: true
|
||||
},
|
||||
rbacNamespace: "agency-namespace",
|
||||
complianceProfile: {
|
||||
standards: ["ISO_27001", "SOC_2", "FEDRAMP"]
|
||||
},
|
||||
dataResidencyFlags: [{
|
||||
region: "region-a",
|
||||
requirement: "REQUIRED",
|
||||
enforcement: "HARD"
|
||||
}],
|
||||
multiRegionEnabled: true
|
||||
});
|
||||
|
||||
// Step 3: Create Subscription
|
||||
const subscription = await phoenix.subscription.createSubscription({
|
||||
name: "production-subscription",
|
||||
tenantId: tenant.id,
|
||||
type: "PRODUCT",
|
||||
serviceBundles: [
|
||||
{
|
||||
service: "COMPUTE",
|
||||
enabled: true,
|
||||
quotas: {
|
||||
vcpu: 100,
|
||||
memory: 512,
|
||||
instances: 50
|
||||
}
|
||||
},
|
||||
{
|
||||
service: "STORAGE",
|
||||
enabled: true,
|
||||
quotas: {
|
||||
total: 10000,
|
||||
perInstance: 500
|
||||
}
|
||||
}
|
||||
],
|
||||
policyPacks: [{
|
||||
name: "security-policy",
|
||||
type: "SECURITY",
|
||||
policies: [],
|
||||
enforcement: "HARD"
|
||||
}]
|
||||
});
|
||||
|
||||
// Step 4: Create Environment
|
||||
const environment = await phoenix.environment.createEnvironment({
|
||||
name: "production-env",
|
||||
subscriptionId: subscription.id,
|
||||
type: "PROD",
|
||||
networkIsolation: {
|
||||
vpcId: "vpc-prod",
|
||||
subnetIds: ["subnet-prod-1", "subnet-prod-2"],
|
||||
firewallRules: []
|
||||
},
|
||||
dataIsolation: {
|
||||
encryptionAtRest: true,
|
||||
encryptionInTransit: true,
|
||||
accessControls: []
|
||||
},
|
||||
deploymentPolicies: [{
|
||||
name: "production-policy",
|
||||
type: "POLICY_DRIVEN",
|
||||
approvalRequired: true,
|
||||
approvers: ["release-manager-1", "release-manager-2"]
|
||||
}],
|
||||
region: "region-a"
|
||||
});
|
||||
|
||||
console.log("Setup complete:", {
|
||||
client: client.id,
|
||||
tenant: tenant.id,
|
||||
subscription: subscription.id,
|
||||
environment: environment.id
|
||||
});
|
||||
```
|
||||
|
||||
### Example 2: Multi-National Government Setup
|
||||
|
||||
```typescript
|
||||
// Setup for multi-national government with multiple regions
|
||||
|
||||
const client = await phoenix.commercial.createClient({
|
||||
name: "International Government",
|
||||
legalEntity: {
|
||||
name: "International Government",
|
||||
jurisdiction: "Multi-National",
|
||||
address: { /* ... */ }
|
||||
},
|
||||
invoicingConfig: { /* ... */ }
|
||||
});
|
||||
|
||||
// Create tenants per nation
|
||||
const nations = ["Nation A", "Nation B", "Nation C"];
|
||||
const tenants = await Promise.all(nations.map(nation =>
|
||||
phoenix.tenancy.createTenant({
|
||||
name: `tenant-${nation.toLowerCase().replace(' ', '-')}`,
|
||||
clientId: client.id,
|
||||
primaryDomains: [`${nation.toLowerCase().replace(' ', '')}.gov`],
|
||||
identityProvider: {
|
||||
type: "KEYCLOAK",
|
||||
config: {},
|
||||
ssoEnabled: true,
|
||||
mfaRequired: true
|
||||
},
|
||||
rbacNamespace: `namespace-${nation.toLowerCase().replace(' ', '-')}`,
|
||||
complianceProfile: {
|
||||
standards: ["ISO_27001", "SOC_2"]
|
||||
},
|
||||
dataResidencyFlags: [{
|
||||
region: `region-${nation.toLowerCase().replace(' ', '-')}`,
|
||||
requirement: "REQUIRED",
|
||||
enforcement: "HARD"
|
||||
}],
|
||||
multiRegionEnabled: true
|
||||
})
|
||||
));
|
||||
|
||||
// Create landing zones per region
|
||||
const landingZones = await Promise.all(tenants.map((tenant, index) =>
|
||||
phoenix.landingZones.createLandingZone({
|
||||
name: `landing-zone-${nations[index].toLowerCase().replace(' ', '-')}`,
|
||||
region: `region-${nations[index].toLowerCase().replace(' ', '-')}`,
|
||||
tenantId: tenant.id,
|
||||
sovereignCloud: true,
|
||||
dataResidency: {
|
||||
requirement: "REQUIRED",
|
||||
enforcement: "HARD"
|
||||
},
|
||||
complianceProfile: {
|
||||
standards: ["ISO_27001", "SOC_2", "FEDRAMP"]
|
||||
}
|
||||
})
|
||||
));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure as Code Examples
|
||||
|
||||
### Terraform Example: Complete Phoenix Setup
|
||||
|
||||
```hcl
|
||||
# terraform/phoenix-setup/main.tf
|
||||
|
||||
# Client (Billing Profile)
|
||||
resource "phoenix_client" "government_agency" {
|
||||
name = "Government Agency A"
|
||||
|
||||
legal_entity {
|
||||
name = "Government Agency A"
|
||||
jurisdiction = "Nation A"
|
||||
registration_number = "GOV-001"
|
||||
address {
|
||||
street = "123 Government St"
|
||||
city = "Capital City"
|
||||
country = "Nation A"
|
||||
}
|
||||
}
|
||||
|
||||
invoicing_config {
|
||||
format = "PDF"
|
||||
frequency = "MONTHLY"
|
||||
currency = "USD"
|
||||
payment_terms = "Net 30"
|
||||
}
|
||||
}
|
||||
|
||||
# Tenant
|
||||
resource "phoenix_tenant" "agency_tenant" {
|
||||
name = "agency-tenant"
|
||||
client_id = phoenix_client.government_agency.id
|
||||
primary_domains = ["agency.gov", "agency.sankofa.nexus"]
|
||||
|
||||
identity_provider {
|
||||
type = "KEYCLOAK"
|
||||
sso_enabled = true
|
||||
mfa_required = true
|
||||
}
|
||||
|
||||
rbac_namespace = "agency-namespace"
|
||||
|
||||
compliance_profile {
|
||||
standards = ["ISO_27001", "SOC_2", "FEDRAMP"]
|
||||
}
|
||||
|
||||
data_residency_flags {
|
||||
region = "region-a"
|
||||
requirement = "REQUIRED"
|
||||
enforcement = "HARD"
|
||||
}
|
||||
|
||||
multi_region_enabled = true
|
||||
}
|
||||
|
||||
# Subscription
|
||||
resource "phoenix_subscription" "production" {
|
||||
name = "production-subscription"
|
||||
tenant_id = phoenix_tenant.agency_tenant.id
|
||||
type = "PRODUCT"
|
||||
|
||||
service_bundles {
|
||||
service = "COMPUTE"
|
||||
enabled = true
|
||||
quotas {
|
||||
vcpu = 100
|
||||
memory = 512
|
||||
instances = 50
|
||||
}
|
||||
}
|
||||
|
||||
service_bundles {
|
||||
service = "STORAGE"
|
||||
enabled = true
|
||||
quotas {
|
||||
total = 10000
|
||||
per_instance = 500
|
||||
}
|
||||
}
|
||||
|
||||
policy_packs {
|
||||
name = "security-policy"
|
||||
type = "SECURITY"
|
||||
enforcement = "HARD"
|
||||
}
|
||||
}
|
||||
|
||||
# Environment
|
||||
resource "phoenix_environment" "production" {
|
||||
name = "production-env"
|
||||
subscription_id = phoenix_subscription.production.id
|
||||
type = "PROD"
|
||||
|
||||
network_isolation {
|
||||
vpc_id = "vpc-prod"
|
||||
subnet_ids = ["subnet-prod-1", "subnet-prod-2"]
|
||||
}
|
||||
|
||||
data_isolation {
|
||||
encryption_at_rest = true
|
||||
encryption_in_transit = true
|
||||
}
|
||||
|
||||
deployment_policies {
|
||||
name = "production-policy"
|
||||
type = "POLICY_DRIVEN"
|
||||
approval_required = true
|
||||
approvers = ["release-manager-1", "release-manager-2"]
|
||||
}
|
||||
|
||||
region = "region-a"
|
||||
}
|
||||
|
||||
# Landing Zone
|
||||
resource "phoenix_landing_zone" "region_a" {
|
||||
name = "landing-zone-region-a"
|
||||
region = "region-a"
|
||||
tenant_id = phoenix_tenant.agency_tenant.id
|
||||
sovereign_cloud = true
|
||||
|
||||
data_residency {
|
||||
requirement = "REQUIRED"
|
||||
enforcement = "HARD"
|
||||
allowed_regions = ["region-a"]
|
||||
}
|
||||
|
||||
compliance {
|
||||
standards = ["ISO_27001", "SOC_2", "FEDRAMP"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pulumi Example: Multi-Region Deployment
|
||||
|
||||
```typescript
|
||||
// pulumi/phoenix-multi-region/index.ts
|
||||
|
||||
import * as phoenix from "@sankofa/phoenix-sdk";
|
||||
|
||||
// Client
|
||||
const client = new phoenix.Client("government-agency", {
|
||||
name: "Government Agency A",
|
||||
legalEntity: {
|
||||
name: "Government Agency A",
|
||||
jurisdiction: "Nation A",
|
||||
address: {
|
||||
street: "123 Government St",
|
||||
city: "Capital City",
|
||||
country: "Nation A"
|
||||
}
|
||||
},
|
||||
invoicingConfig: {
|
||||
format: "PDF",
|
||||
frequency: "MONTHLY",
|
||||
currency: "USD"
|
||||
}
|
||||
});
|
||||
|
||||
// Multi-region tenants
|
||||
const regions = ["region-a", "region-b", "region-c"];
|
||||
const tenants = regions.map(region =>
|
||||
new phoenix.Tenant(`tenant-${region}`, {
|
||||
name: `tenant-${region}`,
|
||||
clientId: client.id,
|
||||
primaryDomains: [`${region}.agency.gov`],
|
||||
identityProvider: {
|
||||
type: "KEYCLOAK",
|
||||
ssoEnabled: true,
|
||||
mfaRequired: true
|
||||
},
|
||||
dataResidencyFlags: [{
|
||||
region: region,
|
||||
requirement: "REQUIRED",
|
||||
enforcement: "HARD"
|
||||
}],
|
||||
multiRegionEnabled: true
|
||||
})
|
||||
);
|
||||
|
||||
// Landing zones per region
|
||||
const landingZones = regions.map((region, index) =>
|
||||
new phoenix.LandingZone(`landing-zone-${region}`, {
|
||||
name: `landing-zone-${region}`,
|
||||
region: region,
|
||||
tenantId: tenants[index].id,
|
||||
sovereignCloud: true,
|
||||
dataResidency: {
|
||||
requirement: "REQUIRED",
|
||||
enforcement: "HARD"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
export const clientId = client.id;
|
||||
export const tenantIds = tenants.map(t => t.id);
|
||||
export const landingZoneIds = landingZones.map(lz => lz.id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Pipeline Examples
|
||||
|
||||
### GitHub Actions: Policy-Driven Promotion
|
||||
|
||||
```yaml
|
||||
# .github/workflows/promote.yml
|
||||
|
||||
name: Promote to Environment
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
from_env:
|
||||
description: 'Source Environment'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- dev
|
||||
- int
|
||||
- uat
|
||||
- staging
|
||||
to_env:
|
||||
description: 'Target Environment'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- int
|
||||
- uat
|
||||
- staging
|
||||
- prod
|
||||
artifact_id:
|
||||
description: 'Artifact ID'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Validate Promotion Policy
|
||||
run: |
|
||||
# Validate promotion is allowed
|
||||
curl -X POST ${{ secrets.PHOENIX_API }}/api/v1/environment/promotions/validate \
|
||||
-H "Authorization: Bearer ${{ secrets.PHOENIX_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"fromEnvironment": "${{ github.event.inputs.from_env }}",
|
||||
"toEnvironment": "${{ github.event.inputs.to_env }}",
|
||||
"artifactId": "${{ github.event.inputs.artifact_id }}"
|
||||
}'
|
||||
|
||||
- name: Request Promotion
|
||||
id: promote
|
||||
run: |
|
||||
RESPONSE=$(curl -X POST ${{ secrets.PHOENIX_API }}/api/v1/environment/promotions \
|
||||
-H "Authorization: Bearer ${{ secrets.PHOENIX_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"artifactId": "${{ github.event.inputs.artifact_id }}",
|
||||
"fromEnvironmentId": "${{ github.event.inputs.from_env }}",
|
||||
"toEnvironmentId": "${{ github.event.inputs.to_env }}"
|
||||
}')
|
||||
echo "promotion_id=$(echo $RESPONSE | jq -r '.id')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check Approval Required
|
||||
if: steps.promote.outputs.promotion_id != ''
|
||||
run: |
|
||||
APPROVAL_REQUIRED=$(curl -s ${{ secrets.PHOENIX_API }}/api/v1/environment/promotions/${{ steps.promote.outputs.promotion_id }} \
|
||||
-H "Authorization: Bearer ${{ secrets.PHOENIX_TOKEN }}" | jq -r '.approvalRequired')
|
||||
|
||||
if [ "$APPROVAL_REQUIRED" = "true" ]; then
|
||||
echo "Approval required. Waiting for approval..."
|
||||
# Wait for approval
|
||||
while true; do
|
||||
STATUS=$(curl -s ${{ secrets.PHOENIX_API }}/api/v1/environment/promotions/${{ steps.promote.outputs.promotion_id }} \
|
||||
-H "Authorization: Bearer ${{ secrets.PHOENIX_TOKEN }}" | jq -r '.status')
|
||||
|
||||
if [ "$STATUS" = "APPROVED" ]; then
|
||||
echo "Promotion approved"
|
||||
break
|
||||
elif [ "$STATUS" = "REJECTED" ]; then
|
||||
echo "Promotion rejected"
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
fi
|
||||
|
||||
- name: Deploy
|
||||
run: |
|
||||
curl -X POST ${{ secrets.PHOENIX_API }}/api/v1/environment/promotions/${{ steps.promote.outputs.promotion_id }}/deploy \
|
||||
-H "Authorization: Bearer ${{ secrets.PHOENIX_TOKEN }}"
|
||||
```
|
||||
|
||||
### GitLab CI: Multi-Stage Promotion
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- promote-dev
|
||||
- promote-int
|
||||
- promote-uat
|
||||
- promote-staging
|
||||
- promote-prod
|
||||
|
||||
variables:
|
||||
PHOENIX_API: "https://api.phoenix.sankofa.nexus"
|
||||
ARTIFACT_REGISTRY: "https://artifacts.phoenix.sankofa.nexus"
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- docker build -t $ARTIFACT_REGISTRY/app:$CI_COMMIT_SHA .
|
||||
- docker push $ARTIFACT_REGISTRY/app:$CI_COMMIT_SHA
|
||||
artifacts:
|
||||
paths:
|
||||
- artifact-id.txt
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- docker run $ARTIFACT_REGISTRY/app:$CI_COMMIT_SHA npm test
|
||||
- docker run $ARTIFACT_REGISTRY/app:$CI_COMMIT_SHA npm run lint
|
||||
|
||||
promote-to-dev:
|
||||
stage: promote-dev
|
||||
script:
|
||||
- |
|
||||
curl -X POST $PHOENIX_API/api/v1/environment/promotions \
|
||||
-H "Authorization: Bearer $PHOENIX_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"artifactId\": \"$(cat artifact-id.txt)\",
|
||||
\"fromEnvironmentId\": \"source\",
|
||||
\"toEnvironmentId\": \"dev-env-id\"
|
||||
}"
|
||||
only:
|
||||
- main
|
||||
- develop
|
||||
|
||||
promote-to-prod:
|
||||
stage: promote-prod
|
||||
script:
|
||||
- |
|
||||
# Production requires approval
|
||||
PROMOTION_ID=$(curl -X POST $PHOENIX_API/api/v1/environment/promotions \
|
||||
-H "Authorization: Bearer $PHOENIX_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"artifactId\": \"$(cat artifact-id.txt)\",
|
||||
\"fromEnvironmentId\": \"staging-env-id\",
|
||||
\"toEnvironmentId\": \"prod-env-id\"
|
||||
}" | jq -r '.id')
|
||||
|
||||
echo "Promotion $PROMOTION_ID requires approval"
|
||||
echo "Waiting for approval..."
|
||||
|
||||
# Wait for approval (with timeout)
|
||||
timeout 3600 bash -c 'until curl -s $PHOENIX_API/api/v1/environment/promotions/$PROMOTION_ID \
|
||||
-H "Authorization: Bearer $PHOENIX_TOKEN" | jq -e ".status == \"APPROVED\""; do sleep 30; done'
|
||||
only:
|
||||
- main
|
||||
when: manual
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multi-Region Deployment Examples
|
||||
|
||||
### Example: Deploy to Multiple Regions
|
||||
|
||||
```typescript
|
||||
// Deploy application to multiple regions with data residency
|
||||
|
||||
const regions = ["region-a", "region-b", "region-c"];
|
||||
|
||||
// Create subscriptions per region
|
||||
const subscriptions = await Promise.all(regions.map(region =>
|
||||
phoenix.subscription.createSubscription({
|
||||
name: `subscription-${region}`,
|
||||
tenantId: tenant.id,
|
||||
type: "PRODUCT",
|
||||
serviceBundles: [{
|
||||
service: "COMPUTE",
|
||||
enabled: true,
|
||||
quotas: {
|
||||
vcpu: 50,
|
||||
memory: 256,
|
||||
instances: 25
|
||||
}
|
||||
}],
|
||||
regions: [region]
|
||||
})
|
||||
));
|
||||
|
||||
// Create environments per region
|
||||
const environments = await Promise.all(regions.map((region, index) =>
|
||||
phoenix.environment.createEnvironment({
|
||||
name: `prod-env-${region}`,
|
||||
subscriptionId: subscriptions[index].id,
|
||||
type: "PROD",
|
||||
region: region,
|
||||
dataIsolation: {
|
||||
encryptionAtRest: true,
|
||||
encryptionInTransit: true,
|
||||
dataBoundaries: [{
|
||||
region: region,
|
||||
enforcement: "HARD"
|
||||
}]
|
||||
}
|
||||
})
|
||||
));
|
||||
|
||||
// Deploy application to each region
|
||||
const deployments = await Promise.all(environments.map(env =>
|
||||
phoenix.environment.deploy({
|
||||
environmentId: env.id,
|
||||
artifactId: "artifact-id",
|
||||
metadata: {
|
||||
version: "1.0.0",
|
||||
region: env.region
|
||||
}
|
||||
})
|
||||
));
|
||||
|
||||
console.log("Deployed to regions:", deployments.map(d => d.region));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Promotion Flow Examples
|
||||
|
||||
### Example: Automated Promotion with Policy Validation
|
||||
|
||||
```typescript
|
||||
// Automated promotion flow with policy validation
|
||||
|
||||
async function promoteArtifact(
|
||||
artifactId: string,
|
||||
fromEnvId: string,
|
||||
toEnvId: string
|
||||
): Promise<PromotionResult> {
|
||||
// Step 1: Validate promotion policy
|
||||
const policyValidation = await phoenix.environment.validatePromotion({
|
||||
fromEnvironmentId: fromEnvId,
|
||||
toEnvironmentId: toEnvId,
|
||||
artifactId: artifactId
|
||||
});
|
||||
|
||||
if (!policyValidation.allowed) {
|
||||
throw new Error(`Promotion not allowed: ${policyValidation.reason}`);
|
||||
}
|
||||
|
||||
// Step 2: Create promotion request
|
||||
const promotion = await phoenix.environment.promoteArtifact({
|
||||
artifactId: artifactId,
|
||||
fromEnvironmentId: fromEnvId,
|
||||
toEnvironmentId: toEnvId,
|
||||
metadata: {
|
||||
version: "1.2.3",
|
||||
changelog: "Production release"
|
||||
}
|
||||
});
|
||||
|
||||
// Step 3: Check if approval required
|
||||
if (promotion.approvalRequired) {
|
||||
console.log("Approval required. Waiting for approval...");
|
||||
|
||||
// Wait for approval (with timeout)
|
||||
const approval = await waitForApproval(promotion.id, 3600000); // 1 hour timeout
|
||||
|
||||
if (approval.status !== "APPROVED") {
|
||||
throw new Error(`Promotion rejected: ${approval.reason}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Deploy
|
||||
const deployment = await phoenix.environment.deploy({
|
||||
environmentId: toEnvId,
|
||||
artifactId: artifactId,
|
||||
promotionId: promotion.id
|
||||
});
|
||||
|
||||
return {
|
||||
promotionId: promotion.id,
|
||||
deploymentId: deployment.id,
|
||||
status: "SUCCESS"
|
||||
};
|
||||
}
|
||||
|
||||
async function waitForApproval(
|
||||
promotionId: string,
|
||||
timeout: number
|
||||
): Promise<ApprovalStatus> {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const promotion = await phoenix.environment.getPromotion(promotionId);
|
||||
|
||||
if (promotion.status === "APPROVED" || promotion.status === "REJECTED") {
|
||||
return {
|
||||
status: promotion.status,
|
||||
reason: promotion.reason
|
||||
};
|
||||
}
|
||||
|
||||
await sleep(30000); // Check every 30 seconds
|
||||
}
|
||||
|
||||
throw new Error("Approval timeout");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Example: Keycloak Integration
|
||||
|
||||
```typescript
|
||||
// Automatic Keycloak realm creation for tenant
|
||||
|
||||
async function createTenantWithKeycloak(tenantData: CreateTenantInput) {
|
||||
// Step 1: Create tenant
|
||||
const tenant = await phoenix.tenancy.createTenant(tenantData);
|
||||
|
||||
// Step 2: Create Keycloak realm (automatic via integration)
|
||||
const keycloakRealm = await phoenix.tenancy.syncKeycloakRealm(tenant.id);
|
||||
|
||||
// Step 3: Configure identity provider
|
||||
if (tenantData.identityProvider.type === "AZURE_AD") {
|
||||
await phoenix.tenancy.configureIdentityProvider(tenant.id, {
|
||||
type: "AZURE_AD",
|
||||
config: {
|
||||
tenantId: tenantData.identityProvider.config.tenantId,
|
||||
clientId: tenantData.identityProvider.config.clientId,
|
||||
clientSecret: tenantData.identityProvider.config.clientSecret
|
||||
},
|
||||
ssoEnabled: true,
|
||||
mfaRequired: true
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
tenant: tenant,
|
||||
keycloakRealm: keycloakRealm
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Proxmox Integration
|
||||
|
||||
```typescript
|
||||
// Provision infrastructure via Proxmox
|
||||
|
||||
async function provisionInfrastructure(
|
||||
environmentId: string,
|
||||
vmSpec: VMSpecification
|
||||
) {
|
||||
const environment = await phoenix.environment.getEnvironment(environmentId);
|
||||
const subscription = await phoenix.subscription.getSubscription(
|
||||
environment.subscriptionId
|
||||
);
|
||||
|
||||
// Check quotas
|
||||
const quotaCheck = await phoenix.subscription.checkQuota(
|
||||
subscription.id,
|
||||
"COMPUTE"
|
||||
);
|
||||
|
||||
if (!quotaCheck.available) {
|
||||
throw new Error(`Quota exceeded: ${quotaCheck.message}`);
|
||||
}
|
||||
|
||||
// Provision VM via Proxmox
|
||||
const vm = await phoenix.infrastructure.proxmox.createVM({
|
||||
environmentId: environmentId,
|
||||
node: vmSpec.node,
|
||||
name: vmSpec.name,
|
||||
vcpus: vmSpec.vcpus,
|
||||
memory: vmSpec.memory,
|
||||
disk: vmSpec.disk,
|
||||
network: vmSpec.network
|
||||
});
|
||||
|
||||
return vm;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **[Operating Model](./OPERATING_MODEL.md)** - Complete operating model
|
||||
- **[API Specification](./API_SPECIFICATION.md)** - Complete API reference
|
||||
- **[MVP Control Plane](./MVP_CONTROL_PLANE.md)** - MVP implementation guide
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-01-09
|
||||
**Version**: 1.0
|
||||
**Status**: Complete Implementation Examples
|
||||
|
||||
Reference in New Issue
Block a user