Skip to content

Commit 3a96722

Browse files
committed
feat: Consolidate ObjectOS into platform-objects and remove legacy references
1 parent 33d6c5c commit 3a96722

17 files changed

Lines changed: 26 additions & 415 deletions

File tree

.github/prompts/schema.prompt.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ Project & Responsibilities
1111
* Rule: All other packages depend on this. No circular dependencies.
1212
* packages/objectql (Data Engine) [Apache 2.0]
1313
* Universal Data Protocol. Compiles GraphQL-like queries into SQL/Redis commands.
14-
* packages/objectos (Business Kernel) [AGPL v3]
15-
* The Crown Jewel. Identity, RBAC, Workflow, and Audit Logging.
16-
* License Note: Strict AGPL to prevent SaaS wrapping by competitors.
14+
* packages/platform-objects (Platform Object Catalog) [Apache 2.0]
15+
* Canonical ObjectStack platform objects for identity, security, audit, tenant, and metadata.
1716
* packages/objectui (Projection Engine) [MIT]
1817
* React/Shadcn UI components for Server-Driven UI (SDUI).
1918
* packages/sdk (Plugin Kit) [MIT]
@@ -179,4 +178,3 @@ When I give you a short command, map it to the following actions:
179178
> *(AI 会自动生成 List 和 Form 的布局结构定义。)*
180179
181180

182-

CHANGELOG.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- **`@objectstack/service-tenant` — system objects now actually register** — `createTenantPlugin()` previously declared its control-plane schemas (`sys_project`, `sys_project_credential`, `sys_project_member`, `sys_package`, `sys_package_version`, `sys_package_installation`, `sys_tenant_database`) via a top-level `objects: [...]` field on the kernel plugin object. The kernel only consumes `plugin.objects` for **nested** plugins inside a parent manifest (`packages/objectql/src/engine.ts` → `registerPlugin()`), so plugins added via `kernel.use(plugin)` had to use the `manifest` service (as `AuthPlugin`/`SecurityPlugin`/`SetupPlugin` already do). The result was that `sys__project` etc. were never registered with `SchemaRegistry`, so `ObjectQL.getDriver('sys__project')` could not match the `namespace: 'sys' → turso` `datasourceMapping` rule (the lookup returned `undefined` and skipped past the namespace check), silently routing every control-plane write to the default driver — typically the in-memory driver. On Vercel each lambda instance has its own memory, so `POST /api/v1/cloud/projects` "succeeded" with HTTP 202 but the row evaporated on cold start, causing the subsequent `GET /api/v1/cloud/projects/:id` to return 404 even though the user/organization writes (registered through the proper path by `AuthPlugin`) were correctly persisted in Turso. The plugin now registers the same set of objects via `ctx.getService('manifest').register({ id: 'com.objectstack.tenant', namespace: 'sys', objects: [...] })` and throws if the manifest service is unavailable, fail-fast instead of silent data loss. Also affected: package install/upgrade endpoints, project credential rotation, project membership reads.
1212

1313
### Changed
14+
- **Platform object definitions consolidated in `@objectstack/platform-objects`** — Removed the now-redundant `@objectstack/objectos` package. Metadata-layer objects (`SysObject`, `SysView`, `SysAgent`, `SysTool`, `SysFlow`) are registered directly from `@objectstack/platform-objects/metadata`, and plugin/service packages no longer re-export platform objects through compatibility `objects` facades.
1415
- **`examples/app-crm` — showcase `fieldGroups` MVP** — The CRM reference example (`Account`, `Contact`, `Opportunity`, `Lead`) now demonstrates the new `fieldGroups` protocol end to end. Each object declares logical groups (e.g., *Basic Information*, *Financials*, *Contact Information*, *Ownership & Status*, *System*) and every field opts in via `group: '<key>'`. No business logic changed — only field-layout metadata — so existing validations, workflows, indexes, and state machines are unaffected. Useful as a reference when designing multi-group forms and detail pages.
1516

1617
### Added
@@ -21,21 +22,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2122
- Supported migrations at this layer: add / rename / delete / reorder groups (by editing the `fieldGroups` array) and assigning an existing field to a group (by editing `Field.group`). Explicit per-field in-group ordering is deferred to a future iteration.
2223
- New `ObjectFieldGroup` / `ObjectFieldGroupInput` type exports alongside the schema.
2324
- Tests: 12 new round-trip cases in `packages/spec/src/data/object.test.ts` covering minimal/full-group parsing, required fields, snake_case key validation, declaration-order preservation, duplicate-key rejection, `Field.group` referencing, and `ObjectSchema.create()` integration.
24-
### Fixed
25-
- **Doubly-prefixed FQN for `@objectstack/objectos` system objects** — The ObjectOS-layer object definitions (`SysObject`, `SysView`, `SysAgent`, `SysTool`, `SysFlow`, `SysMetadata`) were being registered with fully-qualified names like `sys__sys_object`, `sys__sys_view`, `sys__sys_metadata`, because each object hard-coded a `sys_` prefix into its `name` **and** its manifest was registered under `namespace: 'sys'`, causing `SchemaRegistry.computeFQN(namespace, name)` to apply the prefix twice. The object `name` values are now the unprefixed short form (`object`, `view`, `agent`, `tool`, `flow`, `metadata`), producing the correct FQNs (`sys__object`, `sys__view`, `sys__agent`, `sys__tool`, `sys__flow`). `SysMetadata` (which would collide with the canonical `sys__metadata` owned by `@objectstack/metadata`) is now exported separately and excluded from the auto-registered `SystemObjects` catalog to avoid ownership conflicts; consumers that need it can still import it directly. See `packages/objectos/src/objects/*.ts` and `packages/objectos/src/registry.ts`.
26-
2725
### Added
2826
- **Environment-per-database multi-tenancy (`service-tenant` v4.1)** — Refactored the multi-tenant architecture from "per-organization database" to **per-environment database** high-isolation, with a hard split between Control Plane (environment registry / addressing / credentials / RBAC) and Data Plane (one physical database per environment). See [`docs/adr/0002-environment-database-isolation.md`](docs/adr/0002-environment-database-isolation.md) for the full rationale and trade-offs.
2927
- **Zod protocol schemas** (`packages/spec/src/cloud/environment.zod.ts`): `EnvironmentSchema`, `EnvironmentDatabaseSchema`, `DatabaseCredentialSchema`, `EnvironmentMemberSchema`, `EnvironmentTypeSchema`, `EnvironmentStatusSchema`, `EnvironmentRoleSchema`, `DatabaseCredentialStatusSchema`, `ProvisionEnvironmentRequest/ResponseSchema`, `ProvisionOrganizationRequest/ResponseSchema`. `TenantDatabaseSchema` is now marked `@deprecated`.
3028
- **Control-plane objects** (`packages/services/service-tenant/src/objects/`): `sys_environment` (UNIQUE `(organization_id, slug)`), `sys_environment_database` (UNIQUE `environment_id` — exactly one DB per environment), `sys_database_credential` (rotatable, encrypted, with `active` / `rotating` / `revoked` lifecycle), `sys_environment_member` (UNIQUE `(environment_id, user_id)`, owner / admin / maker / reader / guest). Every field carries `.describe()` metadata and every uniqueness constraint is explicit.
3129
- **`EnvironmentProvisioningService`** (`packages/services/service-tenant/src/environment-provisioning.ts`): `provisionOrganization()` bootstraps a new org with a default environment and DB in one call; `provisionEnvironment()` allocates any subsequent dev / test / sandbox / preview environment; `rotateCredential()` mints a new `active` credential and revokes the previous one. Pluggable `EnvironmentDatabaseAdapter` (initial `turso`; `libsql` / `sqlite` / `postgres` drop in without core changes) and `SecretEncryptor` hooks.
32-
- **Tenant plugin wiring**: `createTenantPlugin()` now registers all four new control-plane objects out of the box, plus `sys_tenant_database` as a v4.x shim (opt out via `registerLegacyTenantDatabase: false`).
30+
- **Tenant plugin wiring**: `createTenantPlugin()` now registers the current control-plane objects directly from `@objectstack/platform-objects/tenant`.
3331
- **v4 → v5 migration skeleton** (`packages/services/service-tenant/migrations/v4-to-v5-env-migration.ts`): idempotent, non-destructive, re-encrypts credentials with the current KMS key, reuses existing physical DBs as each org's new `prod` environment DB — no data movement required.
3432
- **Tests**: 22 new schema round-trip tests in `packages/spec/src/cloud/environment.test.ts`, 10 new provisioning tests in `packages/services/service-tenant/src/environment-provisioning.test.ts` covering organization bootstrap, environment creation, default-environment invariants, adapter routing, credential rotation, and encryption hooks.
3533

36-
### Deprecated
37-
- **`TenantDatabaseSchema` / `sys_tenant_database`** — Superseded by the environment-per-database model above. The schema and object remain registered in v4.x as a deprecation shim; both will be removed in **v5.0**. Consumers should migrate by running `migrateV4ToV5Environments()` before upgrading to v5.0.
38-
3934
### Changed
4035
- **Polished `examples/app-crm` dashboards** — Rewrote `executive`, `sales`, and `service` dashboards and added a new unified `crm` overview dashboard, modeled after the reference implementation at [objectstack-ai/objectui/examples/crm](https://github.com/objectstack-ai/objectui/tree/main/examples/crm/src/dashboards). The dashboards now use the framework's first-class metadata fields instead of ad-hoc hex strings stuffed into `options.color`:
4136
- Semantic `colorVariant` tokens (`success`/`warning`/`danger`/`blue`/`teal`/`purple`/`orange`) replace raw hex codes

apps/server/objectstack.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ const basePlugins: BasePluginsFactory = async ({ projectId, project }) => {
177177
return [
178178
new ObjectQLPlugin({ environmentId: projectId }),
179179
new MetadataPlugin({ watch: false, environmentId: projectId, organizationId: orgId }),
180-
createTenantPlugin({ registerSystemObjects: true, registerLegacyTenantDatabase: false }),
180+
createTenantPlugin({ registerSystemObjects: true }),
181181
new AuthPlugin({ secret: authSecret, baseUrl }),
182182
new SecurityPlugin(),
183183
new AuditPlugin(),

apps/server/server/control-plane-preset.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export interface ControlPlanePresetConfig {
2525
authSecret: string;
2626
baseUrl: string;
2727
registerSystemObjects?: boolean;
28-
registerLegacyTenantDatabase?: boolean;
2928
authPlugins?: Record<string, unknown>;
3029
}
3130

@@ -128,7 +127,6 @@ export function createControlPlanePlugins(cfg: ControlPlanePresetConfig): any[]
128127
const { createTenantPlugin } = await import('@objectstack/service-tenant');
129128
return createTenantPlugin({
130129
registerSystemObjects: cfg.registerSystemObjects ?? true,
131-
registerLegacyTenantDatabase: cfg.registerLegacyTenantDatabase ?? false,
132130
});
133131
}),
134132

apps/studio/server/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ async function ensureKernel(): Promise<ObjectKernel> {
142142
await kernel.use(new SecurityPlugin());
143143
await kernel.use(new AuditPlugin());
144144
await kernel.use(new FeedServicePlugin());
145-
await kernel.use(createTenantPlugin({ registerSystemObjects: true, registerLegacyTenantDatabase: false }));
145+
await kernel.use(createTenantPlugin({ registerSystemObjects: true }));
146146
await kernel.use(new MetadataPlugin({ watch: false }));
147147
await kernel.use(new AIServicePlugin());
148148
await kernel.use(new AutomationServicePlugin());

packages/metadata/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
],
4040
"dependencies": {
4141
"@objectstack/core": "workspace:*",
42-
"@objectstack/objectos": "workspace:*",
4342
"@objectstack/platform-objects": "workspace:*",
4443
"@objectstack/spec": "workspace:*",
4544
"@objectstack/types": "workspace:*",

packages/metadata/src/plugin.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@ import { NodeMetadataManager } from './node-metadata-manager.js';
77
import { MemoryLoader } from './loaders/memory-loader.js';
88
import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';
99
import type { MetadataPluginConfig } from '@objectstack/spec/kernel';
10-
import { SysMetadataObject, SysMetadataHistoryObject } from '@objectstack/platform-objects/metadata';
11-
import { SystemObjects } from '@objectstack/objectos';
10+
import {
11+
SysAgent,
12+
SysFlow,
13+
SysMetadataObject,
14+
SysMetadataHistoryObject,
15+
SysObject,
16+
SysTool,
17+
SysView,
18+
} from '@objectstack/platform-objects/metadata';
19+
20+
const queryableMetadataObjects = [SysObject, SysView, SysFlow, SysAgent, SysTool];
1221

1322
// Map from ObjectStackDefinition field name to MetadataType name
1423
const ARTIFACT_FIELD_TO_TYPE: Record<string, string> = {
@@ -108,20 +117,20 @@ export class MetadataPlugin implements Plugin {
108117
objects: [SysMetadataObject, SysMetadataHistoryObject],
109118
});
110119

111-
// Register the queryable system objects from @objectstack/objectos
120+
// Register the queryable metadata-layer platform objects.
112121
manifestService.register({
113-
id: 'com.objectstack.objectos',
114-
name: 'ObjectOS System Objects',
122+
id: 'com.objectstack.metadata-objects',
123+
name: 'Metadata Platform Objects',
115124
version: '1.0.0',
116125
type: 'plugin',
117126
scope: 'system',
118127
defaultDatasource: 'cloud',
119-
objects: Object.values(SystemObjects),
128+
objects: queryableMetadataObjects,
120129
});
121130

122131
ctx.logger.info('Registered system metadata objects', {
123132
metadata: ['sys_metadata', 'sys_metadata_history'],
124-
objectos: Object.keys(SystemObjects),
133+
queryable: queryableMetadataObjects.map((object) => object.name),
125134
});
126135
} catch {
127136
// ObjectQL not loaded yet — objects will be discovered via legacy fallback

packages/objectos/README.md

Lines changed: 0 additions & 85 deletions
This file was deleted.

packages/objectos/package.json

Lines changed: 0 additions & 60 deletions
This file was deleted.

packages/objectos/src/index.ts

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)