|
| 1 | +# Phase 1 Implementation Summary: Dual-Table Metadata Projection |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Successfully implemented the dual-table projection logic for the metadata service. This establishes the architectural foundation for treating metadata as queryable data following industry best practices from Salesforce, ServiceNow, and Kubernetes. |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +The dual-table pattern maintains two layers: |
| 10 | + |
| 11 | +1. **sys_metadata** (Source of Truth) |
| 12 | + - Package management |
| 13 | + - Version control |
| 14 | + - Deployment tracking |
| 15 | + - History via sys_metadata_history |
| 16 | + |
| 17 | +2. **Type-Specific Tables** (Queryable Projections) |
| 18 | + - sys_object — Object definitions |
| 19 | + - sys_view — View configurations |
| 20 | + - sys_agent — AI agent metadata |
| 21 | + - sys_tool — AI tool registry |
| 22 | + - sys_flow — Automation flows |
| 23 | + |
| 24 | +## Implementation Details |
| 25 | + |
| 26 | +### 1. MetadataProjector Service |
| 27 | + |
| 28 | +Created `packages/metadata/src/projection/metadata-projector.ts` with: |
| 29 | + |
| 30 | +- **Project transformation functions** for each metadata type |
| 31 | +- **Denormalization logic** to flatten complex structures for querying |
| 32 | +- **Support for both IDataDriver and IDataEngine** (ObjectQL) |
| 33 | +- **Automatic CRUD operations** on projection tables |
| 34 | + |
| 35 | +Key methods: |
| 36 | +- `project(type, name, data)` — Create/update projection |
| 37 | +- `deleteProjection(type, name)` — Remove projection |
| 38 | +- `transformToProjection(type, name, data)` — Type-specific transformation |
| 39 | + |
| 40 | +### 2. DatabaseLoader Integration |
| 41 | + |
| 42 | +Updated `packages/metadata/src/loaders/database-loader.ts`: |
| 43 | + |
| 44 | +- Added `enableProjection` configuration option (default: true) |
| 45 | +- Integrated `MetadataProjector` into save() flow |
| 46 | +- Added projection cleanup in delete() flow |
| 47 | +- Projection occurs AFTER sys_metadata save (async safety) |
| 48 | + |
| 49 | +### 3. System Object Registration |
| 50 | + |
| 51 | +Updated `packages/metadata/src/plugin.ts`: |
| 52 | + |
| 53 | +- Added dependency on `@objectstack/objectos` |
| 54 | +- Registered all system objects from SystemObjects registry |
| 55 | +- Objects registered via manifest service during plugin init() |
| 56 | +- Includes: sys_object, sys_view, sys_agent, sys_tool, sys_flow |
| 57 | + |
| 58 | +## Projection Mapping |
| 59 | + |
| 60 | +Each metadata type is projected with denormalized fields for efficient querying: |
| 61 | + |
| 62 | +### Object Projection (object → sys_object) |
| 63 | +- Complex structures (fields, indexes, validations) → JSON columns |
| 64 | +- Capabilities → individual boolean columns for filtering |
| 65 | +- Denormalized field_count for sorting/filtering |
| 66 | + |
| 67 | +### View Projection (view → sys_view) |
| 68 | +- Columns, filters, sort, config → JSON columns |
| 69 | +- Display options → individual columns |
| 70 | +- Object reference for joins |
| 71 | + |
| 72 | +### Agent Projection (agent → sys_agent) |
| 73 | +- Model configuration → individual columns |
| 74 | +- Tools, skills → JSON columns |
| 75 | +- Memory settings → individual columns |
| 76 | + |
| 77 | +### Tool Projection (tool → sys_tool) |
| 78 | +- Parameters schema → JSON column |
| 79 | +- Handler code → text column |
| 80 | + |
| 81 | +### Flow Projection (flow → sys_flow) |
| 82 | +- Nodes, edges, variables → JSON columns |
| 83 | +- Trigger configuration → individual columns |
| 84 | +- Active status for filtering |
| 85 | + |
| 86 | +## Benefits Achieved |
| 87 | + |
| 88 | +1. **Unified Query Protocol**: Metadata can be queried using Object Protocol API |
| 89 | +2. **Studio Auto-Generation**: UI can use `/api/v1/data/sys_*` endpoints |
| 90 | +3. **Efficient Filtering**: Denormalized fields enable fast queries |
| 91 | +4. **Preserved History**: sys_metadata maintains full version control |
| 92 | +5. **Package Tracking**: All projections include package_id and managed_by |
| 93 | + |
| 94 | +## Files Changed |
| 95 | + |
| 96 | +### New Files |
| 97 | +- `packages/metadata/src/projection/metadata-projector.ts` — Projection service |
| 98 | +- `packages/metadata/src/projection/index.ts` — Module exports |
| 99 | + |
| 100 | +### Modified Files |
| 101 | +- `packages/metadata/src/loaders/database-loader.ts` — Added projection integration |
| 102 | +- `packages/metadata/src/plugin.ts` — Registered system objects |
| 103 | +- `packages/metadata/src/index.ts` — Exported projection module |
| 104 | +- `packages/metadata/package.json` — Added @objectstack/objectos dependency |
| 105 | +- `OBJECTOS_IMPLEMENTATION.md` — Updated Phase 1 status |
| 106 | + |
| 107 | +## Usage Example |
| 108 | + |
| 109 | +```typescript |
| 110 | +// Projection happens automatically when saving metadata |
| 111 | +await metadataService.register('object', 'account', { |
| 112 | + name: 'account', |
| 113 | + label: 'Account', |
| 114 | + fields: { /* ... */ }, |
| 115 | + // ... object definition |
| 116 | +}); |
| 117 | + |
| 118 | +// Results in TWO database writes: |
| 119 | +// 1. sys_metadata: Full envelope with JSON payload |
| 120 | +// 2. sys_object: Denormalized projection with queryable columns |
| 121 | + |
| 122 | +// Studio can now query via Object Protocol |
| 123 | +const objects = await client.data.find('sys_object', { |
| 124 | + filter: { namespace: 'crm' }, |
| 125 | + sort: 'name', |
| 126 | +}); |
| 127 | +``` |
| 128 | + |
| 129 | +## Next Steps |
| 130 | + |
| 131 | +Phase 2 will focus on Studio integration: |
| 132 | +- Update Studio to use type-specific table queries |
| 133 | +- Auto-generate metadata management UI |
| 134 | +- Leverage existing grid/form/kanban components |
| 135 | + |
| 136 | +Phase 3 will add: |
| 137 | +- Comprehensive test coverage |
| 138 | +- Documentation updates |
| 139 | +- Migration guides for existing deployments |
0 commit comments