Skip to content

Commit 713445f

Browse files
authored
Merge pull request #795 from objectstack-ai/copilot/define-protocol-level-schemas
2 parents f112dbf + 0fa5203 commit 713445f

23 files changed

+2496
-2
lines changed

docs/NEXT_STEP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103

104104
**Checklist:**
105105

106-
- [ ] Create deployment protocol with packages, validation, rollback, and history
106+
- [x] Create deployment protocol with packages, validation, rollback, and history — ✅ `system/deploy-bundle.zod.ts` (DeployBundle, MigrationPlan, DeployDiff, DeployValidationResult)
107107
- [ ] Create sandbox management with metadata/data cloning and PII masking
108108
- [ ] Create fiscal year and business calendar protocol
109109
- [ ] Enhance audit trail with structured query protocol
@@ -147,7 +147,7 @@
147147
**Checklist:**
148148

149149
- [ ] Create IAuditService contract for audit trail querying and management
150-
- [ ] Create IDeploymentService contract for package deployment and rollback
150+
- [x] Create IDeploymentService contract for package deployment and rollback — ✅ `contracts/deploy-pipeline-service.ts` (IDeployPipelineService) + `contracts/schema-diff-service.ts` (ISchemaDiffService)
151151
- [ ] Create ISLAService contract for SLA evaluation and escalation
152152
- [ ] Create ISchedulerService contract for scheduled job management
153153
- [ ] Create IDocumentService contract for document generation
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* IAppLifecycleService - App Marketplace Installation Contract
5+
*
6+
* Defines the interface for installing, upgrading, and uninstalling
7+
* marketplace apps into tenant databases.
8+
*
9+
* An app installation:
10+
* 1. Checks compatibility with the tenant environment
11+
* 2. Applies schema changes (creates tables, indexes)
12+
* 3. Seeds initial data
13+
* 4. Registers metadata (objects, views, flows) in the tenant registry
14+
*/
15+
16+
import type { AppManifest, AppCompatibilityCheck, AppInstallResult } from '../system/app-install.zod.js';
17+
18+
// ==========================================================================
19+
// Service Interface
20+
// ==========================================================================
21+
22+
export interface IAppLifecycleService {
23+
/**
24+
* Check whether an app is compatible with a tenant's environment.
25+
* Validates kernel version, existing objects, dependencies, and quotas.
26+
*
27+
* @param tenantId - Target tenant
28+
* @param manifest - App manifest to check
29+
* @returns Compatibility check result
30+
*/
31+
checkCompatibility(tenantId: string, manifest: AppManifest): Promise<AppCompatibilityCheck>;
32+
33+
/**
34+
* Install an app into a tenant's database.
35+
* Applies schema changes, seeds data, and registers metadata.
36+
*
37+
* @param tenantId - Target tenant
38+
* @param manifest - App manifest
39+
* @param config - Optional configuration overrides
40+
* @returns Installation result
41+
*/
42+
installApp(tenantId: string, manifest: AppManifest, config?: Record<string, unknown>): Promise<AppInstallResult>;
43+
44+
/**
45+
* Uninstall an app from a tenant's database.
46+
* Removes metadata registrations. Optionally drops tables.
47+
*
48+
* @param tenantId - Target tenant
49+
* @param appId - App to uninstall
50+
* @param dropTables - Whether to drop database tables (default: false)
51+
* @returns Whether the uninstallation succeeded
52+
*/
53+
uninstallApp(tenantId: string, appId: string, dropTables?: boolean): Promise<{ success: boolean }>;
54+
55+
/**
56+
* Upgrade an installed app to a new version.
57+
* Applies schema migrations and updates metadata.
58+
*
59+
* @param tenantId - Target tenant
60+
* @param manifest - New version app manifest
61+
* @returns Installation result for the upgrade
62+
*/
63+
upgradeApp(tenantId: string, manifest: AppManifest): Promise<AppInstallResult>;
64+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* IDeployPipelineService - Metadata-Driven Deployment Pipeline Contract
5+
*
6+
* Orchestrates the complete deployment lifecycle:
7+
* 1. Validate bundle (Zod schema validation)
8+
* 2. Plan deployment (introspect → diff → generate migrations)
9+
* 3. Execute deployment (apply migrations → register metadata)
10+
* 4. Rollback on failure
11+
*
12+
* Target: 2-5 second deployments for schema changes.
13+
* No Docker builds, no CI/CD pipelines — just metadata push.
14+
*/
15+
16+
import type {
17+
DeployBundle,
18+
DeployValidationResult,
19+
MigrationPlan,
20+
DeployStatus,
21+
} from '../system/deploy-bundle.zod.js';
22+
23+
// ==========================================================================
24+
// Types
25+
// ==========================================================================
26+
27+
/**
28+
* Deployment execution result.
29+
*/
30+
export interface DeployExecutionResult {
31+
/** Unique deployment identifier */
32+
deploymentId: string;
33+
/** Final deployment status */
34+
status: DeployStatus;
35+
/** Total execution duration in milliseconds */
36+
durationMs: number;
37+
/** Number of DDL statements executed */
38+
statementsExecuted: number;
39+
/** Error message if deployment failed */
40+
error?: string;
41+
/** Timestamp of deployment completion (ISO 8601) */
42+
completedAt: string;
43+
}
44+
45+
// ==========================================================================
46+
// Service Interface
47+
// ==========================================================================
48+
49+
export interface IDeployPipelineService {
50+
/**
51+
* Validate a deploy bundle against Zod schemas.
52+
* Checks object definitions, view configs, flow definitions, and permissions.
53+
*
54+
* @param bundle - Deploy bundle to validate
55+
* @returns Validation result with issues list
56+
*/
57+
validateBundle(bundle: DeployBundle): DeployValidationResult;
58+
59+
/**
60+
* Plan a deployment by introspecting the current schema and generating
61+
* a migration plan for the diff.
62+
*
63+
* @param tenantId - Target tenant
64+
* @param bundle - Deploy bundle to plan for
65+
* @returns Migration plan with ordered DDL statements
66+
*/
67+
planDeployment(tenantId: string, bundle: DeployBundle): Promise<MigrationPlan>;
68+
69+
/**
70+
* Execute a deployment plan against a tenant's database.
71+
* Applies DDL statements and registers metadata changes.
72+
*
73+
* @param tenantId - Target tenant
74+
* @param plan - Migration plan to execute
75+
* @returns Execution result with deployment ID and status
76+
*/
77+
executeDeployment(tenantId: string, plan: MigrationPlan): Promise<DeployExecutionResult>;
78+
79+
/**
80+
* Rollback a previous deployment.
81+
* Executes reverse DDL statements and restores previous metadata state.
82+
*
83+
* @param tenantId - Target tenant
84+
* @param deploymentId - Deployment to rollback
85+
*/
86+
rollbackDeployment(tenantId: string, deploymentId: string): Promise<void>;
87+
}

packages/spec/src/contracts/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,11 @@ export * from './workflow-service.js';
3535
export * from './feed-service.js';
3636
export * from './export-service.js';
3737
export * from './package-service.js';
38+
39+
// Provisioning & Deployment
40+
export * from './turso-platform.js';
41+
export * from './provisioning-service.js';
42+
export * from './schema-diff-service.js';
43+
export * from './deploy-pipeline-service.js';
44+
export * from './tenant-router.js';
45+
export * from './app-lifecycle-service.js';
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* IProvisioningService - Tenant Provisioning Service Contract
5+
*
6+
* Defines the interface for the "Register → Instant ObjectOS" provisioning pipeline.
7+
* Manages the complete tenant lifecycle: create → active → suspend → resume → destroy.
8+
*
9+
* The provisioning service orchestrates:
10+
* 1. Turso database creation via ITursoPlatformService
11+
* 2. Schema synchronization via ISchemaDiffService
12+
* 3. Seed data population
13+
* 4. Tenant record registration in the control plane
14+
*
15+
* Follows Dependency Inversion Principle - consumers depend on this interface,
16+
* not on concrete provisioning implementations.
17+
*/
18+
19+
import type {
20+
TenantProvisioningRequest,
21+
TenantProvisioningResult,
22+
TenantProvisioningStatus,
23+
TenantPlan,
24+
} from '../system/provisioning.zod.js';
25+
26+
// ==========================================================================
27+
// Service Interface
28+
// ==========================================================================
29+
30+
export interface IProvisioningService {
31+
/**
32+
* Provision a new tenant with an isolated database.
33+
* Creates the Turso database, syncs schema, seeds data, and registers the tenant.
34+
* Target latency: 2-5 seconds.
35+
*
36+
* @param request - Provisioning request with org, plan, and region
37+
* @returns Provisioning result with tenant ID, connection URL, and step statuses
38+
*/
39+
provisionTenant(request: TenantProvisioningRequest): Promise<TenantProvisioningResult>;
40+
41+
/**
42+
* Suspend a tenant (e.g., unpaid, policy violation).
43+
* Revokes tokens and sets the database to read-only mode.
44+
*
45+
* @param tenantId - Tenant to suspend
46+
*/
47+
suspendTenant(tenantId: string): Promise<void>;
48+
49+
/**
50+
* Resume a previously suspended tenant.
51+
* Restores full read-write access and issues new tokens.
52+
*
53+
* @param tenantId - Tenant to resume
54+
*/
55+
resumeTenant(tenantId: string): Promise<void>;
56+
57+
/**
58+
* Permanently destroy a tenant and its database.
59+
* Optionally creates a final backup before deletion.
60+
* Respects the grace period defined in lifecycle hooks.
61+
*
62+
* @param tenantId - Tenant to destroy
63+
*/
64+
destroyTenant(tenantId: string): Promise<void>;
65+
66+
/**
67+
* Get the current provisioning status of a tenant.
68+
*
69+
* @param tenantId - Tenant to query
70+
* @returns Current provisioning status
71+
*/
72+
getTenantStatus(tenantId: string): Promise<TenantProvisioningStatus>;
73+
74+
/**
75+
* Migrate a tenant to a different subscription plan.
76+
* Updates quotas and resource limits accordingly.
77+
*
78+
* @param tenantId - Tenant to migrate
79+
* @param newPlan - Target subscription plan
80+
*/
81+
migrateTenantPlan(tenantId: string, newPlan: TenantPlan): Promise<void>;
82+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* ISchemaDiffService - Schema Introspection & Diff Contract
5+
*
6+
* Compares the desired metadata state (ObjectStack object definitions)
7+
* against the current database schema and generates DDL migration plans.
8+
*
9+
* Pipeline: Introspect Current → Diff vs Desired → Generate Migrations → Apply
10+
*
11+
* This service is dialect-aware and generates DDL appropriate for the
12+
* target database (PostgreSQL, SQLite/Turso, MySQL, etc.).
13+
*/
14+
15+
import type { DeployDiff, MigrationPlan } from '../system/deploy-bundle.zod.js';
16+
import type { SQLDialect } from '../data/driver-sql.zod.js';
17+
18+
// ==========================================================================
19+
// Types
20+
// ==========================================================================
21+
22+
/**
23+
* Introspected schema representation of the current database state.
24+
*/
25+
export interface IntrospectedSchema {
26+
/** Object/table names and their column definitions */
27+
tables: Record<string, IntrospectedTable>;
28+
/** Database dialect */
29+
dialect: string;
30+
/** Introspection timestamp (ISO 8601) */
31+
introspectedAt: string;
32+
}
33+
34+
/**
35+
* Introspected table (current database state).
36+
*/
37+
export interface IntrospectedTable {
38+
/** Table name */
39+
name: string;
40+
/** Column definitions */
41+
columns: IntrospectedColumn[];
42+
/** Index definitions */
43+
indexes: IntrospectedIndex[];
44+
}
45+
46+
/**
47+
* Introspected column definition.
48+
*/
49+
export interface IntrospectedColumn {
50+
/** Column name */
51+
name: string;
52+
/** SQL data type */
53+
type: string;
54+
/** Whether the column is nullable */
55+
nullable: boolean;
56+
/** Default value expression */
57+
defaultValue?: string;
58+
/** Whether this column is a primary key */
59+
primaryKey: boolean;
60+
}
61+
62+
/**
63+
* Introspected index definition.
64+
*/
65+
export interface IntrospectedIndex {
66+
/** Index name */
67+
name: string;
68+
/** Columns included in the index */
69+
columns: string[];
70+
/** Whether the index enforces uniqueness */
71+
unique: boolean;
72+
}
73+
74+
/**
75+
* Migration apply result.
76+
*/
77+
export interface MigrationApplyResult {
78+
/** Whether all migrations applied successfully */
79+
success: boolean;
80+
/** Number of statements executed */
81+
statementsExecuted: number;
82+
/** Total execution duration in milliseconds */
83+
durationMs: number;
84+
/** Error message if a statement failed */
85+
error?: string;
86+
/** Index of the failed statement (if any) */
87+
failedAtIndex?: number;
88+
}
89+
90+
// ==========================================================================
91+
// Service Interface
92+
// ==========================================================================
93+
94+
export interface ISchemaDiffService {
95+
/**
96+
* Introspect the current database schema.
97+
* Reads table definitions, columns, indexes from the live database.
98+
*
99+
* @param driver - Data driver to introspect
100+
* @returns Current schema representation
101+
*/
102+
introspect(driver: unknown): Promise<IntrospectedSchema>;
103+
104+
/**
105+
* Compute the diff between current schema and desired object definitions.
106+
*
107+
* @param current - Introspected current schema
108+
* @param desired - Desired ObjectStack object definitions
109+
* @returns Schema diff describing all changes
110+
*/
111+
diff(current: IntrospectedSchema, desired: Record<string, unknown>[]): DeployDiff;
112+
113+
/**
114+
* Generate SQL migration statements from a schema diff.
115+
* Output is dialect-specific (PostgreSQL, SQLite, etc.).
116+
*
117+
* @param diff - Schema diff to generate migrations for
118+
* @param dialect - Target SQL dialect
119+
* @returns Ordered migration plan
120+
*/
121+
generateMigrations(diff: DeployDiff, dialect: SQLDialect): MigrationPlan;
122+
123+
/**
124+
* Apply a migration plan to the database.
125+
* Executes statements in order within a transaction (when supported).
126+
*
127+
* @param driver - Data driver to apply migrations to
128+
* @param plan - Migration plan to execute
129+
* @returns Apply result with success status and timing
130+
*/
131+
applyMigrations(driver: unknown, plan: MigrationPlan): Promise<MigrationApplyResult>;
132+
}

0 commit comments

Comments
 (0)