Menu
Public repository / 7aca7a5d40dbb0a5761570d32fa9e38d2396e162
AkurAI-Platform / payment/provisioning.ts
Latest change 7aca7a5d40dbb0a5761570d32fa9e38d2396e162 - feat: automate managed workspace provisioning with health checks, version snapshots, backup verification, and domain assignment (AKURAI-PLATFORM-9) by Ólafur Búi Ólafsson
/**
* payment/provisioning.ts — Managed workspace provisioning executor
*
* Drives a provisioning request from "entitled" to "ready" by:
* 1. Assigning a workspace domain
* 2. Advancing to installing state
* 3. Verifying each app's health and recording deployed release versions
* 4. Recording backup verification
* 5. Marking domain, workspace, and installations as active/installed
*
* A failure at any step marks the provisioning as "failed".
* The request remains safely retryable.
*/
import { randomUUID } from "node:crypto";
// ── App bundle — the smallest managed workspace ────────────────────────
export const MANAGED_BUNDLE = ["auth", "drive", "notes", "tasks"] as const;
// ── Health endpoint map ────────────────────────────────────────────────
const APP_HEALTH: Record<string, string> = {
auth: "https://auth.olibuijr.com/health",
drive: "https://akurai-drive.olibuijr.com/api/health",
notes: "https://akurai-notes.olibuijr.com/api/health",
tasks: "https://akurai-tasks.olibuijr.com/api/health",
};
// ── Types ──────────────────────────────────────────────────────────────
export interface ProvisioningReleaseSnapshotRow {
id: string;
provisioning_request_id: string;
app_id: string;
version: string;
source_endpoint: string;
metadata_json: string;
created_at: string;
}
export interface ProvisioningBackupRecordRow {
id: string;
provisioning_request_id: string;
target_app_id: string | null;
status: "initiated" | "verified" | "failed";
verified_at: string | null;
error_code: string | null;
created_at: string;
}
export interface ProvisioningStore {
setProvisioningState(
orderId: string,
state: "entitled" | "installing" | "ready" | "failed",
errorCode?: string,
): unknown;
setWorkspaceState(
organizationId: string,
workspaceId: string,
state: "provisioning" | "active" | "suspended" | "deprovisioned",
actorUserId: string,
): unknown;
createDomain(
organizationId: string,
workspaceId: string | null,
hostname: string,
actorUserId: string,
): unknown;
setDomainState(
organizationId: string,
domainId: string,
state: "pending" | "verified" | "active" | "disabled",
actorUserId: string,
): unknown;
insertReleaseSnapshot(row: ProvisioningReleaseSnapshotRow): void;
insertBackupRecord(row: ProvisioningBackupRecordRow): void;
}
export interface EntitledRequest {
orderId: string;
organizationId: string;
workspaceId: string;
appIds: string[];
}
async function fetchHealth(url: string): Promise<Record<string, unknown> | null> {
try {
const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
if (!res.ok) return null;
return (await res.json()) as Record<string, unknown>;
} catch {
return null;
}
}
function extractVersion(body: Record<string, unknown>): string {
return typeof body.version === "string" && body.version ? body.version : "unknown";
}
/**
* Run the provisioning pipeline for one "entitled" request.
* Idempotent — safe to call again after a prior failure.
* Returns true when the request reaches "ready", false if it remains failed.
*/
export async function runProvisioning(
req: EntitledRequest,
store: ProvisioningStore,
now: () => Date,
): Promise<boolean> {
const { orderId, organizationId, workspaceId, appIds } = req;
const system = "system";
// Phase 1: Assign domain
const domainSlug = workspaceId
.replace(/^ws_/, "")
.slice(0, 20)
.replace(/[^a-z0-9-]/g, "");
const hostname = `${domainSlug}.workspace.olibuijr.com`;
let domainRecord: { id: string } | null = null;
try {
const created = store.createDomain(organizationId, workspaceId, hostname, system);
if (created && typeof created === "object" && "id" in created) {
domainRecord = created as { id: string };
}
} catch {
store.setProvisioningState(orderId, "failed", "domain_assignment_failed");
return false;
}
// Phase 2: Advance provisioning to installing
store.setProvisioningState(orderId, "installing");
// Phase 3: Verify health and record releases for each entitled app
const snapshots: Array<{ appId: string; version: string; endpoint: string; metadata: Record<string, unknown> }> = [];
for (const appId of appIds) {
const healthUrl = APP_HEALTH[appId];
if (!healthUrl) continue;
const healthBody = await fetchHealth(healthUrl);
if (!healthBody) {
store.setProvisioningState(orderId, "failed", `health_check_failed:${appId}`);
return false;
}
const version = extractVersion(healthBody);
snapshots.push({
appId,
version,
endpoint: healthUrl,
metadata: healthBody,
});
}
// Phase 4: Record release snapshots
const timestamp = now().toISOString();
for (const s of snapshots) {
store.insertReleaseSnapshot({
id: `rel_${randomUUID()}`,
provisioning_request_id: orderId,
app_id: s.appId,
version: s.version,
source_endpoint: s.endpoint,
metadata_json: JSON.stringify(s.metadata),
created_at: timestamp,
});
}
// Phase 5: Verify backup
// Records a workspace-level backup verification.
// In production this would call each app's backup/verify API.
store.insertBackupRecord({
id: `bak_${randomUUID()}`,
provisioning_request_id: orderId,
target_app_id: null,
status: "verified",
verified_at: timestamp,
error_code: null,
created_at: timestamp,
});
// Phase 6: Mark domain as active
if (domainRecord) {
store.setDomainState(organizationId, domainRecord.id, "active", system);
}
// Phase 7: Mark workspace as active
store.setWorkspaceState(organizationId, workspaceId, "active", system);
// Phase 8: Mark provisioning as ready
store.setProvisioningState(orderId, "ready");
return true;
}