mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 22:34:56 +00:00
710 lines
14 KiB
Markdown
710 lines
14 KiB
Markdown
# Complete YAML Entity Schema Specification
|
|
**Version**: 2.0
|
|
**Date**: 2026-02-04
|
|
**Status**: Comprehensive - All Relationship Types + All Features
|
|
|
|
---
|
|
|
|
## Entity Declaration
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
fields:
|
|
role:
|
|
type: enum
|
|
values: [user, admin, moderator] # Fixed set of allowed values
|
|
default: user
|
|
```
|
|
|
|
### Default Values
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
fields:
|
|
tenantId:
|
|
type: uuid
|
|
index: true # Create index on this field
|
|
unique_index: true # Create unique index
|
|
```
|
|
|
|
### Description
|
|
|
|
```yaml
|
|
fields:
|
|
email:
|
|
type: email
|
|
description: "User's email address for login and notifications"
|
|
```
|
|
|
|
---
|
|
|
|
## Indexes
|
|
|
|
### Simple Index
|
|
|
|
```yaml
|
|
indexes:
|
|
- fields: [email] # Single-field index
|
|
```
|
|
|
|
### Composite Index
|
|
|
|
```yaml
|
|
indexes:
|
|
- fields: [tenantId, slug] # Multi-field index
|
|
unique: true # Composite unique constraint
|
|
name: tenant_slug # Optional index name
|
|
```
|
|
|
|
### Named Index
|
|
|
|
```yaml
|
|
indexes:
|
|
- fields: [createdAt, status]
|
|
name: recent_active
|
|
```
|
|
|
|
### Index Types (Database-Specific)
|
|
|
|
```yaml
|
|
indexes:
|
|
- fields: [content]
|
|
type: fulltext # Full-text search index
|
|
name: content_search
|
|
- fields: [location]
|
|
type: spatial # Spatial/GIS index
|
|
```
|
|
|
|
---
|
|
|
|
## Relationships
|
|
|
|
See [RELATIONSHIPS.md](./RELATIONSHIPS.md) for complete relationship specification.
|
|
|
|
### Quick Reference
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
acl:
|
|
publish: # Custom operation
|
|
admin: true
|
|
archive:
|
|
moderator: true
|
|
restore:
|
|
admin: true
|
|
```
|
|
|
|
---
|
|
|
|
## Validation Rules
|
|
|
|
### Field-Level Validation
|
|
|
|
```yaml
|
|
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)
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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()` sets `deletedAt` to current timestamp
|
|
- `list()` automatically filters out deleted records
|
|
- `restore()` operation clears `deletedAt`
|
|
|
|
---
|
|
|
|
## Timestamps
|
|
|
|
### Auto Timestamps
|
|
|
|
```yaml
|
|
entity: Post
|
|
timestamps: true # Auto-add createdAt/updatedAt
|
|
|
|
# Equivalent to:
|
|
fields:
|
|
createdAt:
|
|
type: bigint
|
|
generated: true
|
|
updatedAt:
|
|
type: bigint
|
|
generated: true
|
|
```
|
|
|
|
### Custom Timestamp Fields
|
|
|
|
```yaml
|
|
entity: Post
|
|
timestamps:
|
|
created: created_at # Custom field name
|
|
updated: modified_at
|
|
deleted: deleted_at # For soft deletes
|
|
```
|
|
|
|
---
|
|
|
|
## Tenancy
|
|
|
|
### Multi-Tenant
|
|
|
|
```yaml
|
|
entity: Post
|
|
multi_tenant: true # Auto-add tenantId field
|
|
|
|
# Equivalent to:
|
|
fields:
|
|
tenantId:
|
|
type: uuid
|
|
required: true
|
|
index: true
|
|
```
|
|
|
|
### Tenant Isolation
|
|
|
|
```yaml
|
|
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 disabled
|
|
- `soft`: Default filter by tenantId, but can be overridden
|
|
- `none`: tenantId field exists but no automatic filtering
|
|
|
|
---
|
|
|
|
## Versioning
|
|
|
|
### Optimistic Locking
|
|
|
|
```yaml
|
|
entity: Post
|
|
versioning: true # Add version field for optimistic locking
|
|
|
|
# Equivalent to:
|
|
fields:
|
|
version:
|
|
type: integer
|
|
required: true
|
|
default: 1
|
|
```
|
|
|
|
### Audit Trail
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
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)
|
|
|
|
1. **Database-Specific Extensions**:
|
|
- PostgreSQL: Array types, JSONB operators, full-text search
|
|
- MongoDB: Embedded documents, geospatial queries
|
|
- MySQL: Full-text indexes, spatial types
|
|
|
|
2. **Advanced Validation**:
|
|
- Cross-field validation (`endDate > startDate`)
|
|
- Async validation (unique check via API)
|
|
- Custom validation functions
|
|
|
|
3. **Triggers**:
|
|
- Database-level triggers
|
|
- Application-level event handlers
|
|
|
|
4. **Sharding**:
|
|
- Horizontal partitioning by tenant
|
|
- Range/hash partitioning strategies
|
|
|
|
5. **Graph Queries**:
|
|
- Recursive CTEs for tree structures
|
|
- Graph traversal operations
|