| title | For Platform Architects |
|---|---|
| description | Deep dive into ObjectStack's architecture, design decisions, and how it compares to industry standards. |
Welcome architects! If you're evaluating ObjectStack for your platform or investigating metadata-driven architectures, this guide will help you understand the design philosophy and technical decisions.
ObjectStack is a protocol-first, metadata-driven platform that virtualizes the application stack into three declarative layers:
┌──────────────────────────────────────┐
│ AI Protocol (Optional) │ ← Agent definitions, tools, knowledge
├──────────────────────────────────────┤
│ API Protocol │ ← REST/GraphQL contracts
├──────────────────────────────────────┤
│ UI Layer (ObjectUI) │ ← Server-Driven UI definitions
├──────────────────────────────────────┤
│ Data Layer (ObjectQL) │ ← Schema, queries, business logic
├──────────────────────────────────────┤
│ System Layer (ObjectOS) │ ← Runtime kernel, plugins, drivers
└──────────────────────────────────────┘
Problem: Traditional development couples what you want with how to do it.
ObjectStack Solution: Separate business intent (metadata) from technical execution (kernel).
// INTENT (what you want)
const Task = ObjectSchema.create({
name: 'task',
fields: {
title: Field.text({ required: true }),
}
});
// EXECUTION (handled by kernel)
// ✓ SQL schema generation
// ✓ API route creation
// ✓ Validation logic
// ✓ UI renderingInspired by: Local-First Software Manifesto
Benefits:
- ✅ Offline-capable by default
- ✅ No vendor lock-in
- ✅ Data ownership
- ✅ Instant responsiveness
Like HTTP or SQL, ObjectStack defines a protocol that multiple implementations can follow.
Protocol Definition (this repo)
↓
┌──────────────────────────────────────────────────────┐
│ Implementations (bring your own) │
├──────────────────────────────────────────────────────┤
│ • Kernel: Node.js, Deno, Bun, Go, Python │
│ • Driver: PostgreSQL, MongoDB, Redis, Custom │
│ • Renderer: React, Vue, Flutter, Native │
└──────────────────────────────────────────────────────┘
| Feature | Salesforce | ObjectStack |
|---|---|---|
| Metadata-Driven | ✅ Yes | ✅ Yes |
| Custom Objects | ✅ Yes | ✅ Yes |
| Formula Fields | ✅ Yes | ✅ Yes |
| Workflows | ✅ Yes | ✅ Yes |
| Open Source | ❌ No | ✅ Yes |
| Self-Hosted | ❌ No | ✅ Yes |
| Type-Safe | ❌ No | ✅ TypeScript + Zod |
| Database Agnostic | ❌ No | ✅ Yes (Driver Model) |
ObjectStack = Salesforce's metadata model + Open Source + Type Safety
| Feature | ServiceNow | ObjectStack |
|---|---|---|
| Configuration as Code | ✅ Yes | ✅ Yes |
| Server-Driven UI | ✅ Yes | ✅ Yes |
| Business Rules Engine | ✅ Yes | ✅ Yes |
| Plugin Architecture | ✅ Yes | ✅ Yes |
| Open Protocol | ❌ No | ✅ Yes |
| Local-First | ❌ No | ✅ Yes |
| Modern DX | ✅ TypeScript + JSON |
| Feature | Hasura | ObjectStack |
|---|---|---|
| Auto-Generated API | ✅ Yes | ✅ Yes |
| GraphQL Support | ✅ Yes | ✅ Yes |
| Database First | ✅ Yes | |
| Business Logic | ✅ Built-in (formulas, workflows) | |
| UI Generation | ❌ No | ✅ Yes |
| Multi-DB Support | ✅ Via drivers |
| Feature | Strapi | ObjectStack |
|---|---|---|
| Schema Builder | ✅ Yes | ✅ Yes |
| Auto Admin Panel | ✅ Yes | ✅ Yes |
| API Generation | ✅ Yes | ✅ Yes |
| Business Logic | ✅ Declarative | |
| Type Safety | ✅ Full (Zod) | |
| Enterprise Features | ✅ Workflows, validation, permissions |
Inspired by: SQL, GraphQL, Apache Calcite
Abstraction: Represent queries as an Abstract Syntax Tree (AST).
// High-level query
const query = Query.create({
object: 'order',
filters: { total: { gt: 1000 } },
include: ['customer'],
});
// Compiles to AST
const ast = {
type: 'SELECT',
from: { object: 'order' },
where: {
type: 'BINARY_OP',
operator: 'GT',
left: { type: 'FIELD', name: 'total' },
right: { type: 'LITERAL', value: 1000 },
},
joins: [
{ object: 'customer', type: 'LEFT', on: 'customer_id' },
],
};
// Driver translates AST → SQL/NoSQL/etc.Benefits:
- ✅ Database agnostic (SQL, NoSQL, SaaS APIs)
- ✅ Query optimization at AST level
- ✅ Consistent semantics across backends
Inspired by: Salesforce Lightning, React Server Components, Flutter
Server-Driven UI (SDUI): Client is a "dumb renderer" that interprets JSON configs.
// Server defines UI as JSON
const view = ListView.create({
viewType: 'grid',
columns: [{ field: 'title' }],
});
// Client renders based on schema
<Renderer schema={view} />Benefits:
- ✅ Update UI without app rebuild
- ✅ A/B testing at configuration level
- ✅ Consistent UX across platforms
- ✅ AI can generate/modify UI
Inspired by: Kubernetes, OSGi, Eclipse RCP
Plugin Architecture: Kernel loads and orchestrates plugins.
interface Plugin {
name: string;
version: string;
// Lifecycle hooks
onLoad(kernel: IKernel): void;
onUnload(): void;
// Capabilities
provides?: {
drivers?: Driver[];
apis?: ApiContract[];
ui?: Component[];
};
}Benefits:
- ✅ Modular, composable system
- ✅ Hot-swappable components
- ✅ Ecosystem of community plugins
Decision: All schemas are defined using Zod.
// Source of truth
export const TaskSchema = z.object({
title: z.string().max(200),
status: z.enum(['todo', 'done']),
});
// Derived artifacts
type Task = z.infer<typeof TaskSchema>; // TypeScript type
const jsonSchema = zodToJsonSchema(TaskSchema); // JSON Schema
const sqlSchema = zodToSql(TaskSchema); // SQL DDLBenefits:
- ✅ Runtime validation (Zod validates at runtime)
- ✅ Compile-time types (TypeScript inference)
- ✅ Single source of truth (no drift between types and validators)
- ✅ Tooling ecosystem (JSON Schema for OpenAPI, IDEs, etc.)
Inspired by: Salesforce Formula Fields, Excel Formulas
ObjectStack includes a declarative formula language:
Field.formula({
expression: 'IF(discount_code != NULL, subtotal * 0.9, subtotal)',
})Implementation:
- Parse formula → AST
- Type-check AST
- Compile to JavaScript (or other runtime)
- Execute safely (sandboxed)
Security:
- ✅ No arbitrary code execution
- ✅ Whitelist of allowed functions
- ✅ Type-safe by construction
ObjectStack supports multiple multi-tenancy models:
CREATE SCHEMA tenant_acme;
CREATE SCHEMA tenant_beta;Pros: Strong isolation, easy backup/restore per tenant
Cons: Schema proliferation, migration complexity
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_tenant_id());Pros: Efficient, single schema
Cons: Query performance overhead
Pros: Ultimate isolation
Cons: Resource intensive
ObjectStack Recommendation: Configurable per deployment.
┌─────────────────────────────────────────┐
│ Load Balancer │
└─────────────┬───────────────────────────┘
│
┌─────────┼─────────┬─────────┐
▼ ▼ ▼ ▼
[Kernel] [Kernel] [Kernel] [Kernel] ← Stateless kernels
│ │ │ │
└─────────┴─────────┴─────────┘
│
▼
[Database] ← Centralized or sharded
Stateless Kernel:
- All state in database or cache
- Session in Redis/Memcached
- File uploads in S3/Minio
// Multi-layer cache
const data = await cache.get('order:123') // L1: Redis
?? await dbCache.get('order:123') // L2: DB connection pool
?? await database.query({ ... }); // L3: Source
cache.set('order:123', data, { ttl: 60 });ObjectStack AST allows transparent sharding:
// Driver detects shard key
const driver = new ShardedDriver({
shardKey: 'customer_id',
shards: [db1, db2, db3],
});
// Query automatically routed
await driver.find({
object: 'order',
filters: { customer_id: { eq: 'acme-corp' } }, // → shard 1
});Pluggable providers:
- OAuth 2.0 / OIDC
- SAML
- JWT
- API Keys
- Custom
Multi-level access control:
// Object-level permissions
Permission.create({
profile: 'sales_user',
object: 'opportunity',
create: true,
read: true,
update: { owned: true }, // Only own records
delete: false,
});
// Field-level security
FieldPermission.create({
profile: 'sales_user',
object: 'account',
field: 'annual_revenue',
read: false, // Hidden field
});
// Row-level sharing
SharingRule.create({
object: 'account',
sharedTo: 'sales_team',
accessLevel: 'read',
criteria: { region: 'US' },
});At rest: Database-level encryption (LUKS, TDE)
In transit: TLS 1.3
Field-level: Encrypt sensitive fields (PII)
Field.text({
label: 'SSN',
encrypted: true,
encryptionKey: 'field_encryption_key',
})logger.info('Query executed', {
object: 'order',
duration: 45,
rowsReturned: 100,
userId: 'user-123',
});- Request rate, latency, errors (RED metrics)
- Database query performance
- Cache hit rate
- Formula evaluation time
Distributed tracing across:
- API request
- Kernel processing
- Driver query
- Database execution
- Internal tools (admin panels, dashboards)
- CRUD-heavy applications (CRM, ERP, ticketing)
- Multi-tenant SaaS (need customization per tenant)
- Rapid prototyping (MVP in hours/days)
- Low-code platforms (enable non-developers)
- Real-time gaming (too much abstraction overhead)
- Ultra-high throughput (raw SQL might be faster)
- Greenfield with simple needs (might be overkill)
Existing App
↓
1. Wrap existing DB with ObjectStack driver
2. Generate ObjectStack schemas from DB
3. Replace one module at a time
4. Gradual migration
// Use ObjectStack for new features
const newFeature = ObjectSchema.create({ ... });
// Keep existing code for legacy features
app.get('/legacy', legacyController);- Architecture Diagrams - Visual reference
- Development Roadmap - Future plans
- Contributing Guide - How to contribute