mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 14:25:02 +00:00
14 KiB
14 KiB
Complete YAML Entity Schema Specification
Version: 2.0 Date: 2026-02-04 Status: Comprehensive - All Relationship Types + All Features
Entity Declaration
entity: EntityName
version: "1.0"
description: "Entity purpose"
package: package_name # Optional - which package owns this entity
table: custom_table_name # Optional - override default table name
Field Types
Primitive Types
| Type | Description | Prisma | SQL | MongoDB |
|---|---|---|---|---|
uuid |
UUID v4 | String | UUID | String |
cuid |
CUID (Collision-resistant UID) | String | VARCHAR | String |
string |
Short text (< 255 chars) | String | VARCHAR | String |
text |
Long text (unlimited) | String | TEXT | String |
email |
Email address | String | VARCHAR | String |
url |
URL | String | VARCHAR | String |
integer |
32-bit integer | Int | INTEGER | Number |
bigint |
64-bit integer | BigInt | BIGINT | Long |
float |
Floating point | Float | FLOAT | Double |
decimal |
Fixed-point decimal | Decimal | DECIMAL | Decimal128 |
boolean |
True/false | Boolean | BOOLEAN | Boolean |
timestamp |
Unix timestamp (milliseconds) | BigInt | BIGINT | Date |
date |
Date only (YYYY-MM-DD) | DateTime | DATE | Date |
datetime |
Date + time | DateTime | TIMESTAMP | Date |
json |
JSON object | Json | JSONB | Object |
enum |
Enum with fixed values | String | ENUM | String |
bytes |
Binary data | Bytes | BYTEA | Binary |
Special Types
| Type | Description | Example |
|---|---|---|
slug |
URL-friendly identifier | my-article-title |
phone |
Phone number | +1-555-0123 |
currency |
Money amount (uses Decimal) | 19.99 |
color |
Hex color code | #FF5733 |
coordinates |
Lat/long (uses Json) | {lat: 37.7749, lng: -122.4194} |
Field Attributes
Required Attributes
fields:
id:
type: uuid
primary: true # Is this the primary key?
required: true # Can this field be null?
unique: true # Must values be unique?
generated: true # Auto-generated by database?
nullable: false # Explicit nullable (opposite of required)
Constraints
fields:
username:
type: string
min_length: 3 # Minimum string length
max_length: 50 # Maximum string length
pattern: "^[a-zA-Z0-9_]+$" # Regex validation
min: 0 # Minimum number value
max: 100 # Maximum number value
Enum Values
fields:
role:
type: enum
values: [user, admin, moderator] # Fixed set of allowed values
default: user
Default Values
fields:
status:
type: string
default: draft # Default value for new records
isActive:
type: boolean
default: true
viewCount:
type: integer
default: 0
metadata:
type: json
default: {}
Index Hints
fields:
tenantId:
type: uuid
index: true # Create index on this field
unique_index: true # Create unique index
Description
fields:
email:
type: email
description: "User's email address for login and notifications"
Indexes
Simple Index
indexes:
- fields: [email] # Single-field index
Composite Index
indexes:
- fields: [tenantId, slug] # Multi-field index
unique: true # Composite unique constraint
name: tenant_slug # Optional index name
Named Index
indexes:
- fields: [createdAt, status]
name: recent_active
Index Types (Database-Specific)
indexes:
- fields: [content]
type: fulltext # Full-text search index
name: content_search
- fields: [location]
type: spatial # Spatial/GIS index
Relationships
See RELATIONSHIPS.md for complete relationship specification.
Quick Reference
relations:
# Belongs to (N:1)
author:
type: belongs-to
entity: User
foreign_key: authorId
on_delete: cascade # cascade | set_null | restrict | no_action
on_update: cascade
# Has many (1:N)
posts:
type: has-many
entity: Post
foreign_key: authorId
cascade_delete: true
# Many-to-many (M:N)
roles:
type: many-to-many
entity: Role
through: UserRole
foreign_key: userId
target_key: roleId
# Self-referential
parent:
type: belongs-to
entity: Category
foreign_key: parentId
nullable: true
# Polymorphic
commentable:
type: polymorphic
foreign_key: commentableId
type_key: commentableType
entities: [Post, Video, Product]
Access Control (ACL)
Simple ACL
acl:
create:
public: true # Anyone can create
read:
user: true # Authenticated users can read
update:
admin: true # Only admins can update
delete:
admin: true
Row-Level Security
acl:
read:
self: true # User can read own records
row_level: "userId = $user.id"
update:
self: true
row_level: "userId = $user.id OR role = 'admin'"
delete:
admin: true
moderator: true
row_level: "authorId = $user.id"
Role Hierarchy
acl:
create:
user: true # user, moderator, admin, god can create
read:
public: true # Everyone (including unauthenticated)
update:
moderator: true # moderator, admin, god can update
delete:
admin: true # admin, god can delete
Custom Permissions
acl:
publish: # Custom operation
admin: true
archive:
moderator: true
restore:
admin: true
Validation Rules
Field-Level Validation
fields:
email:
type: email
validation:
- rule: email # Built-in email validation
message: "Invalid email address"
- rule: regex
pattern: "^[^@]+@[^@]+\\.[^@]+$"
message: "Must be a valid email format"
age:
type: integer
validation:
- rule: range
min: 18
max: 120
message: "Age must be between 18 and 120"
username:
type: string
validation:
- rule: length
min: 3
max: 20
- rule: regex
pattern: "^[a-zA-Z0-9_]+$"
message: "Only letters, numbers, and underscores allowed"
- rule: blacklist
values: [admin, root, system]
message: "Username is reserved"
Built-in Validation Rules
| Rule | Parameters | Description |
|---|---|---|
required |
- | Field must have a value |
email |
- | Valid email format |
url |
- | Valid URL format |
length |
min, max | String length range |
range |
min, max | Number range |
regex |
pattern | Regular expression match |
enum |
values | Must be one of values |
unique |
- | Value must be unique |
blacklist |
values | Value cannot be in list |
whitelist |
values | Value must be in list |
Hooks (Lifecycle Events)
hooks:
beforeCreate:
- validate_email # Function name in runtime
- generate_slug
afterCreate:
- send_welcome_email
- create_profile
beforeUpdate:
- validate_changes
afterUpdate:
- invalidate_cache
beforeDelete:
- check_dependencies
afterDelete:
- cleanup_files
Soft Deletes
entity: Post
soft_delete: true # Enable soft deletes
deleted_at_field: deletedAt # Field name (default: deletedAt)
fields:
deletedAt:
type: bigint
nullable: true
description: "Timestamp when record was soft-deleted"
When soft_delete: true:
delete()setsdeletedAtto current timestamplist()automatically filters out deleted recordsrestore()operation clearsdeletedAt
Timestamps
Auto Timestamps
entity: Post
timestamps: true # Auto-add createdAt/updatedAt
# Equivalent to:
fields:
createdAt:
type: bigint
generated: true
updatedAt:
type: bigint
generated: true
Custom Timestamp Fields
entity: Post
timestamps:
created: created_at # Custom field name
updated: modified_at
deleted: deleted_at # For soft deletes
Tenancy
Multi-Tenant
entity: Post
multi_tenant: true # Auto-add tenantId field
# Equivalent to:
fields:
tenantId:
type: uuid
required: true
index: true
Tenant Isolation
entity: Post
multi_tenant: true
tenant_field: organizationId # Custom tenant field name
tenant_isolation: strict # strict | soft | none
Isolation Levels:
strict: All queries automatically filter by tenantId, cannot be disabledsoft: Default filter by tenantId, but can be overriddennone: tenantId field exists but no automatic filtering
Versioning
Optimistic Locking
entity: Post
versioning: true # Add version field for optimistic locking
# Equivalent to:
fields:
version:
type: integer
required: true
default: 1
Audit Trail
entity: Post
audit_trail: true # Track all changes
# Creates PostHistory table with:
# - historyId (primary key)
# - postId (FK to Post)
# - changes (JSON of field changes)
# - changedBy (userId)
# - changedAt (timestamp)
# - operation (create/update/delete)
Caching
entity: User
cache:
enabled: true
ttl: 3600 # Cache lifetime in seconds
strategy: write-through # write-through | write-behind | cache-aside
key_pattern: "user:{id}" # Redis key pattern
Computed Fields
entity: User
computed:
fullName:
type: string
expression: "firstName || ' ' || lastName"
description: "Computed from firstName + lastName"
age:
type: integer
expression: "EXTRACT(YEAR FROM AGE(CURRENT_DATE, birthDate))"
Polymorphic Types
entity: Media
polymorphic_type: true # This entity can be referenced polymorphically
fields:
id: {type: uuid, primary: true}
type: {type: enum, values: [image, video, audio]}
url: {type: string, required: true}
Complete Example
entity: BlogPost
version: "2.0"
description: "Blog post with comments and tags"
package: blog_forge
table: blog_posts # Custom table name
timestamps: true # Auto createdAt/updatedAt
soft_delete: true # Enable soft deletes
multi_tenant: true # Add tenantId
versioning: true # Optimistic locking
audit_trail: true # Track changes
fields:
id:
type: cuid
primary: true
generated: true
title:
type: string
required: true
max_length: 200
description: "Post title"
validation:
- rule: length
min: 10
max: 200
slug:
type: slug
unique: true
generated: true
description: "URL-friendly identifier"
content:
type: text
required: true
validation:
- rule: length
min: 100
message: "Content must be at least 100 characters"
status:
type: enum
values: [draft, published, archived]
default: draft
index: true
authorId:
type: uuid
required: true
index: true
categoryId:
type: cuid
nullable: true
viewCount:
type: integer
default: 0
min: 0
publishedAt:
type: bigint
nullable: true
metadata:
type: json
default: {}
indexes:
- fields: [slug]
unique: true
- fields: [status, publishedAt]
name: published_posts
- fields: [authorId, createdAt]
name: author_recent
relations:
author:
type: belongs-to
entity: User
foreign_key: authorId
on_delete: restrict
category:
type: belongs-to
entity: Category
foreign_key: categoryId
nullable: true
on_delete: set_null
comments:
type: has-many
entity: Comment
foreign_key: postId
cascade_delete: true
tags:
type: many-to-many
entity: Tag
through: PostTag
foreign_key: postId
target_key: tagId
acl:
create:
user: true
read:
public: true
update:
self: true
row_level: "authorId = $user.id"
moderator: true
delete:
self: true
row_level: "authorId = $user.id"
admin: true
publish:
moderator: true
hooks:
beforeCreate:
- generate_slug
- set_published_date
afterCreate:
- notify_subscribers
beforeUpdate:
- validate_status_transition
afterUpdate:
- invalidate_cache
beforeDelete:
- archive_content
cache:
enabled: true
ttl: 1800
strategy: write-through
computed:
readTime:
type: integer
expression: "LENGTH(content) / 200"
description: "Estimated read time in minutes"
Migration from Prisma YAML
Since C++ DBAL can now generate Prisma schema from YAML, the existing prisma/schema.yaml is redundant.
Before (dual maintenance):
dbal/shared/api/schema/entities/*.yaml ← Source of truth
prisma/schema.yaml ← Manually kept in sync
prisma/schema.prisma ← Generated from schema.yaml
After (single source):
dbal/shared/api/schema/entities/*.yaml ← ONLY source of truth
/tmp/dbal-prisma/schema.prisma ← Auto-generated by C++ DBAL
Action: Delete prisma/schema.yaml and prisma/codegen/ scripts. Use C++ DBAL generator instead.
Future Features (TODO)
-
Database-Specific Extensions:
- PostgreSQL: Array types, JSONB operators, full-text search
- MongoDB: Embedded documents, geospatial queries
- MySQL: Full-text indexes, spatial types
-
Advanced Validation:
- Cross-field validation (
endDate > startDate) - Async validation (unique check via API)
- Custom validation functions
- Cross-field validation (
-
Triggers:
- Database-level triggers
- Application-level event handlers
-
Sharding:
- Horizontal partitioning by tenant
- Range/hash partitioning strategies
-
Graph Queries:
- Recursive CTEs for tree structures
- Graph traversal operations