Skip to content

Commit 330f3fa

Browse files
feat: add isSystem field to Project and provisionSystemProject function
- Added isSystem field to ProjectSchema in cloud/project.zod.ts - Added is_system field to sys_project object schema - Implemented provisionSystemProject() method for bootstrapping platform - System project uses well-known ID and operates on control plane DB - Idempotent provisioning - returns existing if already created Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com>
1 parent 1b85503 commit 330f3fa

3 files changed

Lines changed: 149 additions & 0 deletions

File tree

packages/services/service-tenant/src/objects/sys-project.object.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ export const SysProject = ObjectSchema.create({
9090
description: 'Whether this is the default project for the organization. Exactly one per org.',
9191
}),
9292

93+
is_system: Field.boolean({
94+
label: 'Is System',
95+
required: true,
96+
defaultValue: false,
97+
description: 'Whether this is a system project (platform infrastructure, not user data).',
98+
}),
99+
93100
region: Field.text({
94101
label: 'Region',
95102
required: false,

packages/services/service-tenant/src/project-provisioning.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,145 @@ export class ProjectProvisioningService {
480480
return credential;
481481
}
482482

483+
/**
484+
* Provision the built-in system project during platform bootstrap.
485+
* This project contains system-level packages and operates on the control plane DB.
486+
*
487+
* @returns The provisioned system project or existing if already created (idempotent)
488+
*/
489+
async provisionSystemProject(): Promise<ProvisionProjectResponse> {
490+
const SYSTEM_PROJECT_ID = '00000000-0000-0000-0000-000000000001';
491+
const PLATFORM_ORG_ID = '00000000-0000-0000-0000-000000000000';
492+
const startedAt = Date.now();
493+
const warnings: string[] = [];
494+
495+
// Check if system project already exists (idempotent operation)
496+
if (this.config.controlPlaneDriver) {
497+
try {
498+
const existing = await this.config.controlPlaneDriver.findOne('project', {
499+
where: { id: SYSTEM_PROJECT_ID },
500+
});
501+
502+
if (existing) {
503+
// System project already exists - return it
504+
const credentialId = randomUUID();
505+
const nowIso = new Date().toISOString();
506+
507+
return {
508+
project: {
509+
id: existing.id,
510+
organizationId: existing.organization_id,
511+
slug: existing.slug,
512+
displayName: existing.display_name,
513+
projectType: existing.project_type,
514+
isDefault: existing.is_default,
515+
isSystem: existing.is_system ?? true,
516+
region: existing.region,
517+
plan: existing.plan,
518+
status: existing.status,
519+
createdBy: existing.created_by,
520+
createdAt: existing.created_at,
521+
updatedAt: existing.updated_at,
522+
databaseUrl: existing.database_url,
523+
databaseDriver: existing.database_driver,
524+
storageLimitMb: existing.storage_limit_mb,
525+
provisionedAt: existing.provisioned_at,
526+
metadata: existing.metadata ? JSON.parse(existing.metadata) : undefined,
527+
hostname: existing.hostname,
528+
},
529+
credential: {
530+
id: credentialId,
531+
projectId: SYSTEM_PROJECT_ID,
532+
secretCiphertext: '',
533+
encryptionKeyId: this.encryptor.keyId,
534+
authorization: 'full_access',
535+
status: 'active',
536+
createdAt: nowIso,
537+
},
538+
durationMs: Date.now() - startedAt,
539+
warnings: ['System project already exists'],
540+
};
541+
}
542+
} catch (error) {
543+
// Project not found - proceed with creation
544+
}
545+
}
546+
547+
// Create new system project
548+
const nowIso = new Date().toISOString();
549+
const credentialId = randomUUID();
550+
551+
const project: Project = {
552+
id: SYSTEM_PROJECT_ID,
553+
organizationId: PLATFORM_ORG_ID,
554+
slug: 'system',
555+
displayName: 'System',
556+
projectType: 'production',
557+
isDefault: false,
558+
isSystem: true,
559+
region: this.config.defaultRegion,
560+
plan: 'enterprise',
561+
status: 'active',
562+
createdBy: 'system',
563+
createdAt: nowIso,
564+
updatedAt: nowIso,
565+
metadata: {
566+
description: 'Built-in system project for platform infrastructure',
567+
protected: true,
568+
},
569+
databaseUrl: undefined,
570+
databaseDriver: undefined,
571+
storageLimitMb: undefined,
572+
provisionedAt: nowIso,
573+
hostname: 'system.objectstack.internal',
574+
};
575+
576+
const credential: ProjectCredential = {
577+
id: credentialId,
578+
projectId: SYSTEM_PROJECT_ID,
579+
secretCiphertext: '',
580+
encryptionKeyId: this.encryptor.keyId,
581+
authorization: 'full_access',
582+
status: 'active',
583+
createdAt: nowIso,
584+
};
585+
586+
// Persist to control plane
587+
if (this.config.controlPlaneDriver) {
588+
try {
589+
await this.config.controlPlaneDriver.create('project', {
590+
id: project.id,
591+
organization_id: project.organizationId,
592+
slug: project.slug,
593+
display_name: project.displayName,
594+
project_type: project.projectType,
595+
is_default: project.isDefault,
596+
is_system: project.isSystem,
597+
region: project.region,
598+
plan: project.plan,
599+
status: project.status,
600+
created_by: project.createdBy,
601+
created_at: project.createdAt,
602+
updated_at: project.updatedAt,
603+
database_url: project.databaseUrl,
604+
database_driver: project.databaseDriver,
605+
storage_limit_mb: project.storageLimitMb,
606+
provisioned_at: project.provisionedAt,
607+
metadata: project.metadata ? JSON.stringify(project.metadata) : null,
608+
hostname: project.hostname,
609+
});
610+
611+
warnings.push('System project created successfully');
612+
} catch (error) {
613+
throw new Error(
614+
`Failed to persist system project: ${error instanceof Error ? error.message : String(error)}`,
615+
);
616+
}
617+
}
618+
619+
return { project, credential, durationMs: Date.now() - startedAt, warnings };
620+
}
621+
483622
registerAdapter(adapter: ProjectDatabaseAdapter): void {
484623
this.adapters.set(adapter.driver, adapter);
485624
}

packages/spec/src/cloud/project.zod.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ export const ProjectSchema = z.object({
8383
/** Whether this is the organization's **default** project. Exactly one per org. */
8484
isDefault: z.boolean().default(false).describe('Whether this is the default project for the organization'),
8585

86+
/** Whether this is a system project (platform infrastructure, not user data). */
87+
isSystem: z.boolean().default(false).describe('Whether this is a system project (platform infrastructure, not user data)'),
88+
8689
/** Region where the physical database is deployed. */
8790
region: z.string().optional().describe('Region where the physical database is deployed (e.g. us-east-1)'),
8891

0 commit comments

Comments
 (0)