From 21ae2c08849ec8580b3c66c54ab16d5ac6c79ba1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:10:51 +0000 Subject: [PATCH 1/6] Initial plan From 24ae995a6338008678c9312ad4dd2d33664a9395 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:20:04 +0000 Subject: [PATCH 2/6] Add comprehensive field types guide and update READMEs Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- README.md | 54 +- content/docs/guides/field-types.cn.mdx | 756 +++++++++++++++++++++++++ content/docs/guides/field-types.mdx | 756 +++++++++++++++++++++++++ content/docs/guides/meta.cn.json | 3 +- content/docs/guides/meta.json | 1 + examples/todo/README.md | 77 ++- 6 files changed, 1623 insertions(+), 24 deletions(-) create mode 100644 content/docs/guides/field-types.cn.mdx create mode 100644 content/docs/guides/field-types.mdx diff --git a/README.md b/README.md index e510bf1..385cdca 100644 --- a/README.md +++ b/README.md @@ -29,31 +29,55 @@ The official documentation is built with Fumadocs and Next.js. | **[`@objectstack/spec`](packages/spec)** | **THE PROTOCOL**. Contains all Zod definitions, Types, and JSON Schemas. | 🟢 **Active** | | **[`@objectstack/docs`](apps/docs)** | Documentation site built with Fumadocs and Next.js. | 🟢 **Active** | | `content/docs/` | Documentation content (MDX files). Shared resource. | 🟢 **Active** | +| **Examples** | Reference implementations demonstrating protocol features | | +| └─ [`examples/crm`](examples/crm) | **Full-featured CRM** - 6 objects, workflows, validations, views, dashboards, reports | 🟢 **Complete** | +| └─ [`examples/todo`](examples/todo) | **Quick-start** - Simple task management with 7 field types | 🟢 **Active** | +| └─ [`examples/host`](examples/host) | Server runtime with kernel/plugin loading pattern | 🟡 **Experimental** | +| └─ [`examples/plugin-bi`](examples/plugin-bi) | Business Intelligence plugin example | 🟡 **Experimental** | | *Other packages* | *Legacy/Migration in progress* | 🟡 *Legacy* | ## 🛠️ The Protocol Architecture -The ObjectStack Protocol (`@objectstack/spec`) is divided into three layers: +The ObjectStack Protocol (`@objectstack/spec`) is divided into five core modules: ### 1. Data Protocol (ObjectQL) -Defines the "Shape of Data". -- **Schema:** Objects, Fields, Validation. -- **Logic:** Formulas, Rollups. -- **Security:** Permissions, Sharing Rules. -- **Query:** Abstract Syntax Tree (AST) for unified data access. +Defines the "Shape of Data" and business logic. +- **Schema:** Objects, Fields (23+ types including text, number, select, lookup, formula, autonumber, etc.) +- **Logic:** Workflows, Triggers, Validation Rules, Formulas +- **Security:** Permissions, Sharing Rules +- **Query:** Abstract Syntax Tree (AST) for unified data access across drivers +- **Automation:** Flow definitions, Dataset mappings ### 2. UI Protocol (ObjectUI) -Defines the "Shape of Interaction". -- **Views:** Grids, Kanbans, Calendars. -- **Pages:** FlexiPage layouts (Regions & Components). -- **Navigation:** Apps, Navigation. -- **Analytics:** Reports, Dashboards. +Defines the "Shape of Interaction" for rendering interfaces. +- **Views:** Grid, Kanban, Calendar, Gantt, List configurations +- **Pages:** FlexiPage layouts with regions and components +- **Navigation:** App menus and navigation structures +- **Analytics:** Reports (Tabular, Summary, Matrix), Dashboards with widgets +- **Actions:** Script, URL, Modal, Flow-triggered actions +- **Theming:** Color palettes, typography, breakpoints, animations ### 3. System Protocol (ObjectOS) -Defines the "Runtime Environment". -- **Manifest:** Application packaging (`objectstack.config.ts`). -- **Identity:** Auth, Roles, Territories. -- **Integration:** Webhooks, ETL Mappings. +Defines the "Runtime Environment" and platform capabilities. +- **Manifest:** Application packaging (`objectstack.config.ts`) +- **Identity:** Authentication, Roles, Territories, Licenses +- **Integration:** Webhooks, API contracts, ETL Mappings +- **Datasource:** Driver definitions for SQL, NoSQL, SaaS connectors +- **Discovery:** Plugin discovery and loading mechanisms +- **I18n:** Translation and internationalization support + +### 4. AI Protocol +Defines AI agent integration capabilities. +- **Agent:** AI agent definitions and configurations +- **Tools:** AI tool integrations +- **Knowledge:** Knowledge base structures +- **Models:** AI model configurations + +### 5. API Protocol +Defines standardized API contracts. +- **Envelopes:** Response structures (BaseResponse, ListRecordResponse, etc.) +- **Requests:** Request payloads (CreateRequest, UpdateRequest, BulkRequest, etc.) +- **Contracts:** API endpoint definitions and specifications ## 🚀 Development diff --git a/content/docs/guides/field-types.cn.mdx b/content/docs/guides/field-types.cn.mdx new file mode 100644 index 0000000..df623d3 --- /dev/null +++ b/content/docs/guides/field-types.cn.mdx @@ -0,0 +1,756 @@ +--- +title: 字段类型参考 +description: ObjectStack 所有字段类型的完整指南,包含示例和配置选项 +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +# 字段类型参考 + +ObjectStack 支持 **30+ 种字段类型**,涵盖文本、数字、日期、选择、关联、媒体、计算和增强类型。本指南为每种类型提供实用示例。 + +## 核心文本字段 + +### Text (文本) +单行文本输入,用于短字符串。 + +```typescript +import { Field } from '@objectstack/spec'; + +// 基础文本字段 +name: Field.text({ + label: '姓名', + required: true, + maxLength: 255, +}) + +// 可搜索文本字段 +account_name: Field.text({ + label: '账户名称', + searchable: true, + unique: true, +}) +``` + +**配置选项:** +- `required` - 设为必填字段 +- `maxLength` - 最大字符限制 +- `minLength` - 最小字符限制 +- `searchable` - 启用全文搜索 +- `unique` - 强制唯一性约束 +- `defaultValue` - 设置默认值 + +--- + +### Textarea (多行文本) +多行文本输入,用于较长内容。 + +```typescript +description: Field.textarea({ + label: '描述', + maxLength: 5000, + rows: 5, // UI 初始高度提示 +}) +``` + +--- + +### Email (电子邮件) +带验证的电子邮件地址字段。 + +```typescript +email: Field.email({ + label: '电子邮件', + required: true, + unique: true, +}) +``` + + + 自动验证邮箱格式:`user@domain.com` + + +--- + +### URL (网址) +网站/链接字段,带 URL 验证。 + +```typescript +website: Field.url({ + label: '网站', + placeholder: 'https://example.com', +}) +``` + +--- + +### Phone (电话) +带格式验证的电话号码字段。 + +```typescript +phone: Field.phone({ + label: '电话号码', + format: 'international', // 或 'us', 'uk' +}) +``` + +--- + +### Password (密码) +带加密的安全密码字段。 + +```typescript +api_key: Field.password({ + label: 'API 密钥', + encryption: true, // 静态加密 + readonly: true, +}) +``` + + + 密码字段在 UI 中自动掩码,如果 `encryption: true` 则加密存储 + + +--- + +## 富内容字段 + +### Markdown +支持预览的 Markdown 文本编辑器。 + +```typescript +documentation: Field.markdown({ + label: '文档', + description: '支持完整 Markdown 语法', +}) +``` + +--- + +### HTML +原始 HTML 编辑器(谨慎使用)。 + +```typescript +html_content: Field.html({ + label: 'HTML 内容', + description: '原始 HTML - 渲染前需要净化', +}) +``` + + + 渲染前务必净化 HTML 内容,防止 XSS 攻击 + + +--- + +### Rich Text (富文本) +带格式化工具栏的所见即所得编辑器。 + +```typescript +notes: Field.richtext({ + label: '备注', + description: '富文本支持格式化、列表、链接', +}) +``` + +**支持:** +- 粗体、斜体、下划线 +- 标题、列表、引用 +- 链接和图片 +- 表格 + +--- + +## 数字字段 + +### Number (数字) +整数或小数的数值字段。 + +```typescript +quantity: Field.number({ + label: '数量', + min: 0, + max: 1000, + defaultValue: 1, +}) + +// 小数 +temperature: Field.number({ + label: '温度', + precision: 5, // 总位数 + scale: 2, // 小数位 +}) +``` + +--- + +### Currency (货币) +带货币符号的金额值。 + +```typescript +annual_revenue: Field.currency({ + label: '年收入', + precision: 18, + scale: 2, + min: 0, +}) +``` + +**显示:** `$1,234.56`(带货币符号格式化) + +--- + +### Percent (百分比) +百分比值(0-100 或 0-1)。 + +```typescript +probability: Field.percent({ + label: '赢单概率', + min: 0, + max: 100, + scale: 1, // 一位小数 +}) +``` + +**显示:** `75.5%` + +--- + +## 日期和时间字段 + +### Date (日期) +日期选择器(无时间组件)。 + +```typescript +due_date: Field.date({ + label: '截止日期', + defaultValue: 'today', +}) + +birthday: Field.date({ + label: '生日', + min: '1900-01-01', + max: 'today', +}) +``` + +**格式:** `YYYY-MM-DD` + +--- + +### DateTime (日期时间) +支持时区的日期时间选择器。 + +```typescript +created_at: Field.datetime({ + label: '创建时间', + readonly: true, + defaultValue: 'now', +}) +``` + +**格式:** `YYYY-MM-DD HH:mm:ss` + +--- + +### Time (时间) +时间选择器(无日期组件)。 + +```typescript +meeting_time: Field.time({ + label: '会议时间', + format: '24h', // 或 '12h' +}) +``` + +**格式:** `HH:mm:ss` + +--- + +## 布尔字段 + +### Boolean (布尔值) +真/假值的复选框。 + +```typescript +is_active: Field.boolean({ + label: '激活', + defaultValue: true, +}) + +is_completed: Field.boolean({ + label: '已完成', + defaultValue: false, +}) +``` + +**显示:** 复选框或切换开关 + +--- + +## 选择字段 + +### Select (选择) +带预定义选项的下拉菜单。 + +```typescript +// 简单选项(字符串数组) +priority: Field.select({ + label: '优先级', + options: ['低', '中', '高', '紧急'], +}) + +// 高级选项(带值和颜色) +status: Field.select({ + label: '状态', + options: [ + { label: '开放', value: 'open', color: '#00AA00', default: true }, + { label: '进行中', value: 'in_progress', color: '#FFA500' }, + { label: '已关闭', value: 'closed', color: '#999999' }, + ], +}) + +// 多选 +tags: Field.select({ + label: '标签', + multiple: true, // 允许多选 + options: ['错误', '功能', '增强', '文档'], +}) +``` + +**配置:** +- `options` - 字符串标签数组或选项对象 +- `multiple` - 允许多选(存储为数组) +- `color` - 徽章和图表的颜色 + +--- + +## 关联字段 + +### Lookup (查找) +引用另一个对象(多对一)。 + +```typescript +// 基础查找 +account: Field.lookup('account', { + label: '账户', + required: true, +}) + +// 过滤查找 +contact: Field.lookup('contact', { + label: '联系人', + referenceFilters: ['account_id = $parent.account_id'], // 按父记录过滤 +}) + +// 多重查找 +related_cases: Field.lookup('case', { + label: '相关案例', + multiple: true, // 多对多 +}) +``` + +**配置:** +- `reference` - 目标对象名称(snake_case) +- `referenceFilters` - 查找对话框的过滤条件 +- `deleteBehavior` - `'set_null'`、`'cascade'` 或 `'restrict'` +- `multiple` - 允许多个引用 + +--- + +### Master-Detail (主从) +带级联删除的父子关系。 + +```typescript +account: Field.masterDetail('account', { + label: '账户', + required: true, + deleteBehavior: 'cascade', // 删除父记录时删除子记录 + writeRequiresMasterRead: true, // 安全强制 +}) +``` + + + **主从关系 vs 查找:** + - **主从关系:** 紧密耦合,级联删除,子记录继承安全性 + - **查找:** 松散耦合,删除时置空,独立安全性 + + +--- + +## 媒体字段 + +### Image (图片) +带预览的图片上传。 + +```typescript +product_image: Field.image({ + label: '产品图片', + multiple: false, + maxFileSize: 5 * 1024 * 1024, // 5MB + acceptedFormats: ['image/jpeg', 'image/png', 'image/webp'], +}) + +// 多图片 +gallery: Field.image({ + label: '图库', + multiple: true, + maxFiles: 10, +}) +``` + +--- + +### File (文件) +任意文件类型的文件上传字段。 + +```typescript +attachment: Field.file({ + label: '附件', + maxFileSize: 25 * 1024 * 1024, // 25MB + acceptedFormats: ['application/pdf', 'application/msword'], +}) +``` + +--- + +### Avatar (头像) +个人资料图片/头像上传。 + +```typescript +profile_picture: Field.avatar({ + label: '头像', + maxFileSize: 2 * 1024 * 1024, // 2MB + cropAspectRatio: 1, // 正方形裁剪 +}) +``` + +--- + +## 计算字段 + +### Formula (公式) +基于表达式的计算字段。 + +```typescript +full_name: Field.formula({ + label: '全名', + expression: 'CONCAT(first_name, " ", last_name)', + readonly: true, +}) + +full_address: Field.formula({ + label: '完整地址', + expression: 'CONCAT(street, ", ", city, ", ", state, " ", postal_code)', +}) + +days_open: Field.formula({ + label: '开放天数', + expression: 'DAYS_BETWEEN(created_at, NOW())', + type: 'number', +}) +``` + + + 公式字段自动计算且只读。可用函数请参见 [公式函数](/docs/references/data/formulas)。 + + +--- + +### Summary (汇总) +从关联记录聚合数据。 + +```typescript +total_opportunities: Field.summary({ + label: '总机会金额', + summaryOperations: { + object: 'opportunity', + field: 'amount', + function: 'sum', + }, +}) + +open_cases_count: Field.summary({ + label: '开放案例数', + summaryOperations: { + object: 'case', + field: 'id', + function: 'count', + }, +}) +``` + +**可用函数:** +- `count` - 计数关联记录 +- `sum` - 求和数值字段 +- `avg` - 平均数值字段 +- `min` - 最小值 +- `max` - 最大值 + +--- + +### Autonumber (自动编号) +自动递增的唯一标识符。 + +```typescript +account_number: Field.autonumber({ + label: '账户编号', + format: 'ACC-{0000}', // ACC-0001, ACC-0002, 等 +}) + +case_id: Field.autonumber({ + label: '案例 ID', + format: 'CASE-{YYYY}-{00000}', // CASE-2024-00001 +}) +``` + +**格式标记:** +- `{0000}` - 补零数字 +- `{YYYY}` - 年份 +- `{MM}` - 月份 +- `{DD}` - 日期 + +--- + +## 增强字段类型 + +### Location (位置) +带地图显示的 GPS 坐标。 + +```typescript +coordinates: Field.location({ + label: '位置', + displayMap: true, + allowGeocoding: true, // 将地址转换为坐标 +}) +``` + +**数据结构:** +```typescript +{ + latitude: 37.7749, + longitude: -122.4194, + altitude: 100, // 可选 + accuracy: 10, // 可选(米) +} +``` + +--- + +### Address (地址) +结构化地址字段。 + +```typescript +billing_address: Field.address({ + label: '账单地址', + addressFormat: 'us', // 'us'、'uk' 或 'international' +}) +``` + +**数据结构:** +```typescript +{ + street: '123 Main St', + city: 'San Francisco', + state: 'CA', + postalCode: '94105', + country: 'United States', + countryCode: 'US', + formatted: '123 Main St, San Francisco, CA 94105', +} +``` + +--- + +### Code (代码) +带语法高亮的代码编辑器。 + +```typescript +code_snippet: Field.code('javascript', { + label: '代码片段', + lineNumbers: true, + theme: 'monokai', +}) + +sql_query: Field.code('sql', { + label: 'SQL 查询', + readonly: false, +}) +``` + +**支持的语言:** +- `javascript`、`typescript`、`python`、`java`、`sql`、`html`、`css`、`json`、`yaml`、`markdown` 等 + +--- + +### Color (颜色) +支持多种格式的颜色选择器。 + +```typescript +category_color: Field.color({ + label: '分类颜色', + colorFormat: 'hex', // 'hex'、'rgb'、'rgba'、'hsl' + presetColors: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'], + allowAlpha: false, +}) + +theme_color: Field.color({ + label: '主题颜色', + colorFormat: 'rgba', + allowAlpha: true, // 支持透明度 +}) +``` + +--- + +### Rating (评分) +星级评分字段。 + +```typescript +priority: Field.rating(3, { + label: '优先级', + description: '1-3 星', +}) + +satisfaction: Field.rating(5, { + label: '客户满意度', + allowHalf: true, // 允许 0.5 增量 +}) +``` + +**配置:** +- 第一个参数:`maxRating`(默认:5) +- `allowHalf` - 允许半星评分(例如 3.5) + +--- + +### Signature (签名) +数字签名捕获。 + +```typescript +customer_signature: Field.signature({ + label: '客户签名', + required: true, + readonly: false, +}) +``` + +**存储为:** Base64 编码的图片数据 + +--- + +## 字段配置参考 + +### 通用属性 + +所有字段都支持这些通用属性: + +```typescript +{ + // 标识 + name: 'field_name', // snake_case 机器名称 + label: '字段标签', // 人类可读标签 + description: '帮助文本', // 工具提示/帮助文本 + + // 约束 + required: false, // 是否必填 + unique: false, // 强制唯一性 + defaultValue: null, // 默认值 + + // UI 行为 + hidden: false, // 从默认 UI 隐藏 + readonly: false, // UI 中只读 + searchable: false, // 启用搜索索引 + + // 数据库 + index: false, // 创建数据库索引 + externalId: false, // 用于 upsert 操作 + encryption: false, // 静态加密 +} +``` + +--- + +## 最佳实践 + +### 命名约定 + +```typescript +// ✅ 正确:字段名使用 snake_case +account_name: Field.text({ label: '账户名称' }) +annual_revenue: Field.currency({ label: '年收入' }) + +// ❌ 错误:camelCase 或 PascalCase +accountName: Field.text({ label: '账户名称' }) +AnnualRevenue: Field.currency({ label: '年收入' }) +``` + +### 必填字段 + +```typescript +// ✅ 正确:必填关键字段 +name: Field.text({ + label: '名称', + required: true, + maxLength: 255, +}) + +// ✅ 正确:可选字段提供灵活性 +middle_name: Field.text({ + label: '中间名', + required: false, +}) +``` + +### 可搜索字段 + +```typescript +// ✅ 正确:关键字段可搜索 +account_name: Field.text({ + searchable: true, + label: '账户名称', +}) + +// ❌ 错误:不要索引大文本字段 +description: Field.textarea({ + searchable: true, // 可能影响性能 +}) +``` + +### 默认值 + +```typescript +// ✅ 正确:使用有意义的默认值 +status: Field.select({ + options: [ + { label: '开放', value: 'open', default: true }, + { label: '关闭', value: 'closed' }, + ], +}) + +created_at: Field.datetime({ + defaultValue: 'now', + readonly: true, +}) +``` + +--- + +## CRM 示例 + +参见 **[CRM 示例](/examples/crm)** 了解所有字段类型的实际使用: + +- **账户:** 自动编号、公式、货币、带颜色的选择 +- **联系人:** 主从关系、公式(全名)、头像、电子邮件、电话 +- **机会:** 工作流自动化、状态机、百分比、日期时间 +- **案例:** 评分(满意度)、SLA 跟踪、公式计算 +- **任务:** 代码、颜色、评分、位置、签名 + +--- + +## 下一步 + +- [对象架构指南](/docs/guides/object-schema) +- [验证规则](/docs/guides/validation-rules) +- [工作流自动化](/docs/guides/workflows) +- [字段 API 参考](/docs/references/data/core/Field) diff --git a/content/docs/guides/field-types.mdx b/content/docs/guides/field-types.mdx new file mode 100644 index 0000000..be8a9c3 --- /dev/null +++ b/content/docs/guides/field-types.mdx @@ -0,0 +1,756 @@ +--- +title: Field Types Reference +description: Complete guide to all ObjectStack field types with examples and configuration options +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +# Field Types Reference + +ObjectStack supports **30+ field types** covering text, numbers, dates, selections, relationships, media, calculations, and enhanced types. This guide provides practical examples for each type. + +## Core Text Fields + +### Text +Single-line text input for short strings. + +```typescript +import { Field } from '@objectstack/spec'; + +// Basic text field +name: Field.text({ + label: 'Full Name', + required: true, + maxLength: 255, +}) + +// Searchable text field +account_name: Field.text({ + label: 'Account Name', + searchable: true, + unique: true, +}) +``` + +**Configuration Options:** +- `required` - Make field mandatory +- `maxLength` - Maximum character limit +- `minLength` - Minimum character limit +- `searchable` - Enable full-text search +- `unique` - Enforce uniqueness constraint +- `defaultValue` - Set default value + +--- + +### Textarea +Multi-line text input for longer content. + +```typescript +description: Field.textarea({ + label: 'Description', + maxLength: 5000, + rows: 5, // UI hint for initial height +}) +``` + +--- + +### Email +Email address field with validation. + +```typescript +email: Field.email({ + label: 'Email Address', + required: true, + unique: true, +}) +``` + + + Automatically validates email format: `user@domain.com` + + +--- + +### URL +Website/link field with URL validation. + +```typescript +website: Field.url({ + label: 'Website', + placeholder: 'https://example.com', +}) +``` + +--- + +### Phone +Phone number field with format validation. + +```typescript +phone: Field.phone({ + label: 'Phone Number', + format: 'international', // or 'us', 'uk' +}) +``` + +--- + +### Password +Secure password field with encryption. + +```typescript +api_key: Field.password({ + label: 'API Key', + encryption: true, // Encrypt at rest + readonly: true, +}) +``` + + + Password fields are automatically masked in UI and encrypted if `encryption: true` + + +--- + +## Rich Content Fields + +### Markdown +Markdown text editor with preview. + +```typescript +documentation: Field.markdown({ + label: 'Documentation', + description: 'Supports full Markdown syntax', +}) +``` + +--- + +### HTML +Raw HTML editor (use with caution). + +```typescript +html_content: Field.html({ + label: 'HTML Content', + description: 'Raw HTML - sanitize before rendering', +}) +``` + + + Always sanitize HTML content before rendering to prevent XSS attacks + + +--- + +### Rich Text +WYSIWYG editor with formatting toolbar. + +```typescript +notes: Field.richtext({ + label: 'Notes', + description: 'Rich text with formatting, lists, links', +}) +``` + +**Supports:** +- Bold, italic, underline +- Headings, lists, quotes +- Links and images +- Tables + +--- + +## Number Fields + +### Number +Numeric field for integers or decimals. + +```typescript +quantity: Field.number({ + label: 'Quantity', + min: 0, + max: 1000, + defaultValue: 1, +}) + +// Decimal numbers +temperature: Field.number({ + label: 'Temperature', + precision: 5, // Total digits + scale: 2, // Decimal places +}) +``` + +--- + +### Currency +Monetary value with currency symbol. + +```typescript +annual_revenue: Field.currency({ + label: 'Annual Revenue', + precision: 18, + scale: 2, + min: 0, +}) +``` + +**Display:** `$1,234.56` (formatted with currency symbol) + +--- + +### Percent +Percentage value (0-100 or 0-1). + +```typescript +probability: Field.percent({ + label: 'Win Probability', + min: 0, + max: 100, + scale: 1, // One decimal place +}) +``` + +**Display:** `75.5%` + +--- + +## Date & Time Fields + +### Date +Date picker (no time component). + +```typescript +due_date: Field.date({ + label: 'Due Date', + defaultValue: 'today', +}) + +birthday: Field.date({ + label: 'Birthday', + min: '1900-01-01', + max: 'today', +}) +``` + +**Format:** `YYYY-MM-DD` + +--- + +### DateTime +Date and time picker with timezone support. + +```typescript +created_at: Field.datetime({ + label: 'Created At', + readonly: true, + defaultValue: 'now', +}) +``` + +**Format:** `YYYY-MM-DD HH:mm:ss` + +--- + +### Time +Time picker (no date component). + +```typescript +meeting_time: Field.time({ + label: 'Meeting Time', + format: '24h', // or '12h' +}) +``` + +**Format:** `HH:mm:ss` + +--- + +## Boolean Field + +### Boolean +Checkbox for true/false values. + +```typescript +is_active: Field.boolean({ + label: 'Active', + defaultValue: true, +}) + +is_completed: Field.boolean({ + label: 'Completed', + defaultValue: false, +}) +``` + +**Display:** Checkbox or toggle switch + +--- + +## Selection Fields + +### Select +Dropdown with predefined options. + +```typescript +// Simple options (string array) +priority: Field.select({ + label: 'Priority', + options: ['Low', 'Medium', 'High', 'Critical'], +}) + +// Advanced options (with values and colors) +status: Field.select({ + label: 'Status', + options: [ + { label: 'Open', value: 'open', color: '#00AA00', default: true }, + { label: 'In Progress', value: 'in_progress', color: '#FFA500' }, + { label: 'Closed', value: 'closed', color: '#999999' }, + ], +}) + +// Multi-select +tags: Field.select({ + label: 'Tags', + multiple: true, // Allow multiple selections + options: ['Bug', 'Feature', 'Enhancement', 'Documentation'], +}) +``` + +**Configuration:** +- `options` - Array of string labels or option objects +- `multiple` - Allow multiple selections (stores as array) +- `color` - Color for badges and charts + +--- + +## Relational Fields + +### Lookup +Reference to another object (many-to-one). + +```typescript +// Basic lookup +account: Field.lookup('account', { + label: 'Account', + required: true, +}) + +// Filtered lookup +contact: Field.lookup('contact', { + label: 'Contact', + referenceFilters: ['account_id = $parent.account_id'], // Filter by parent +}) + +// Multiple lookup +related_cases: Field.lookup('case', { + label: 'Related Cases', + multiple: true, // Many-to-many +}) +``` + +**Configuration:** +- `reference` - Target object name (snake_case) +- `referenceFilters` - Filter criteria for lookup dialog +- `deleteBehavior` - `'set_null'`, `'cascade'`, or `'restrict'` +- `multiple` - Allow multiple references + +--- + +### Master-Detail +Parent-child relationship with cascade delete. + +```typescript +account: Field.masterDetail('account', { + label: 'Account', + required: true, + deleteBehavior: 'cascade', // Delete children when parent deleted + writeRequiresMasterRead: true, // Security enforcement +}) +``` + + + **Master-Detail vs Lookup:** + - **Master-Detail:** Tight coupling, cascade deletes, child inherits security + - **Lookup:** Loose coupling, set null on delete, independent security + + +--- + +## Media Fields + +### Image +Image upload with preview. + +```typescript +product_image: Field.image({ + label: 'Product Image', + multiple: false, + maxFileSize: 5 * 1024 * 1024, // 5MB + acceptedFormats: ['image/jpeg', 'image/png', 'image/webp'], +}) + +// Multiple images +gallery: Field.image({ + label: 'Gallery', + multiple: true, + maxFiles: 10, +}) +``` + +--- + +### File +File upload field for any file type. + +```typescript +attachment: Field.file({ + label: 'Attachment', + maxFileSize: 25 * 1024 * 1024, // 25MB + acceptedFormats: ['application/pdf', 'application/msword'], +}) +``` + +--- + +### Avatar +Profile picture/avatar upload. + +```typescript +profile_picture: Field.avatar({ + label: 'Profile Picture', + maxFileSize: 2 * 1024 * 1024, // 2MB + cropAspectRatio: 1, // Square crop +}) +``` + +--- + +## Calculated Fields + +### Formula +Calculated field based on expression. + +```typescript +full_name: Field.formula({ + label: 'Full Name', + expression: 'CONCAT(first_name, " ", last_name)', + readonly: true, +}) + +full_address: Field.formula({ + label: 'Full Address', + expression: 'CONCAT(street, ", ", city, ", ", state, " ", postal_code)', +}) + +days_open: Field.formula({ + label: 'Days Open', + expression: 'DAYS_BETWEEN(created_at, NOW())', + type: 'number', +}) +``` + + + Formula fields are automatically calculated and readonly. See [Formula Functions](/docs/references/data/formulas) for available functions. + + +--- + +### Summary (Rollup) +Aggregate data from related records. + +```typescript +total_opportunities: Field.summary({ + label: 'Total Opportunities', + summaryOperations: { + object: 'opportunity', + field: 'amount', + function: 'sum', + }, +}) + +open_cases_count: Field.summary({ + label: 'Open Cases', + summaryOperations: { + object: 'case', + field: 'id', + function: 'count', + }, +}) +``` + +**Available Functions:** +- `count` - Count related records +- `sum` - Sum numeric field +- `avg` - Average numeric field +- `min` - Minimum value +- `max` - Maximum value + +--- + +### Autonumber +Auto-incrementing unique identifier. + +```typescript +account_number: Field.autonumber({ + label: 'Account Number', + format: 'ACC-{0000}', // ACC-0001, ACC-0002, etc. +}) + +case_id: Field.autonumber({ + label: 'Case ID', + format: 'CASE-{YYYY}-{00000}', // CASE-2024-00001 +}) +``` + +**Format Tokens:** +- `{0000}` - Zero-padded number +- `{YYYY}` - Year +- `{MM}` - Month +- `{DD}` - Day + +--- + +## Enhanced Field Types + +### Location +GPS coordinates with map display. + +```typescript +coordinates: Field.location({ + label: 'Location', + displayMap: true, + allowGeocoding: true, // Convert address to coordinates +}) +``` + +**Data Structure:** +```typescript +{ + latitude: 37.7749, + longitude: -122.4194, + altitude: 100, // Optional + accuracy: 10, // Optional (meters) +} +``` + +--- + +### Address +Structured address field. + +```typescript +billing_address: Field.address({ + label: 'Billing Address', + addressFormat: 'us', // 'us', 'uk', or 'international' +}) +``` + +**Data Structure:** +```typescript +{ + street: '123 Main St', + city: 'San Francisco', + state: 'CA', + postalCode: '94105', + country: 'United States', + countryCode: 'US', + formatted: '123 Main St, San Francisco, CA 94105', +} +``` + +--- + +### Code +Code editor with syntax highlighting. + +```typescript +code_snippet: Field.code('javascript', { + label: 'Code Snippet', + lineNumbers: true, + theme: 'monokai', +}) + +sql_query: Field.code('sql', { + label: 'SQL Query', + readonly: false, +}) +``` + +**Supported Languages:** +- `javascript`, `typescript`, `python`, `java`, `sql`, `html`, `css`, `json`, `yaml`, `markdown`, and more + +--- + +### Color +Color picker with multiple formats. + +```typescript +category_color: Field.color({ + label: 'Category Color', + colorFormat: 'hex', // 'hex', 'rgb', 'rgba', 'hsl' + presetColors: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'], + allowAlpha: false, +}) + +theme_color: Field.color({ + label: 'Theme Color', + colorFormat: 'rgba', + allowAlpha: true, // Support transparency +}) +``` + +--- + +### Rating +Star rating field. + +```typescript +priority: Field.rating(3, { + label: 'Priority', + description: '1-3 stars', +}) + +satisfaction: Field.rating(5, { + label: 'Customer Satisfaction', + allowHalf: true, // Allow 0.5 increments +}) +``` + +**Configuration:** +- First parameter: `maxRating` (default: 5) +- `allowHalf` - Allow half-star ratings (e.g., 3.5) + +--- + +### Signature +Digital signature capture. + +```typescript +customer_signature: Field.signature({ + label: 'Customer Signature', + required: true, + readonly: false, +}) +``` + +**Stored as:** Base64-encoded image data + +--- + +## Field Configuration Reference + +### Common Properties + +All fields support these common properties: + +```typescript +{ + // Identity + name: 'field_name', // snake_case machine name + label: 'Field Label', // Human-readable label + description: 'Help text', // Tooltip/help text + + // Constraints + required: false, // Is mandatory + unique: false, // Enforce uniqueness + defaultValue: null, // Default value + + // UI Behavior + hidden: false, // Hide from default UI + readonly: false, // Read-only in UI + searchable: false, // Enable search indexing + + // Database + index: false, // Create database index + externalId: false, // Use for upsert operations + encryption: false, // Encrypt at rest +} +``` + +--- + +## Best Practices + +### Naming Conventions + +```typescript +// ✅ GOOD: snake_case for field names +account_name: Field.text({ label: 'Account Name' }) +annual_revenue: Field.currency({ label: 'Annual Revenue' }) + +// ❌ BAD: camelCase or PascalCase +accountName: Field.text({ label: 'Account Name' }) +AnnualRevenue: Field.currency({ label: 'Annual Revenue' }) +``` + +### Required Fields + +```typescript +// ✅ GOOD: Require essential fields +name: Field.text({ + label: 'Name', + required: true, + maxLength: 255, +}) + +// ✅ GOOD: Optional fields for flexibility +middle_name: Field.text({ + label: 'Middle Name', + required: false, +}) +``` + +### Searchable Fields + +```typescript +// ✅ GOOD: Make key fields searchable +account_name: Field.text({ + searchable: true, + label: 'Account Name', +}) + +// ❌ BAD: Don't index large text fields +description: Field.textarea({ + searchable: true, // Can impact performance +}) +``` + +### Default Values + +```typescript +// ✅ GOOD: Use meaningful defaults +status: Field.select({ + options: [ + { label: 'Open', value: 'open', default: true }, + { label: 'Closed', value: 'closed' }, + ], +}) + +created_at: Field.datetime({ + defaultValue: 'now', + readonly: true, +}) +``` + +--- + +## Examples from CRM + +See the **[CRM Example](/examples/crm)** for real-world usage of all field types: + +- **Account:** Autonumber, formula, currency, select with colors +- **Contact:** Master-detail, formula (full_name), avatar, email, phone +- **Opportunity:** Workflow automation, state machine, percent, datetime +- **Case:** Rating (satisfaction), SLA tracking, formula calculations +- **Task:** Code, color, rating, location, signature + +--- + +## Next Steps + +- [Object Schema Guide](/docs/guides/object-schema) +- [Validation Rules](/docs/guides/validation-rules) +- [Workflow Automation](/docs/guides/workflows) +- [Field API Reference](/docs/references/data/core/Field) diff --git a/content/docs/guides/meta.cn.json b/content/docs/guides/meta.cn.json index 2e84624..4a4c3e3 100644 --- a/content/docs/guides/meta.cn.json +++ b/content/docs/guides/meta.cn.json @@ -5,6 +5,7 @@ "getting-started", "installation", "project-structure", + "field-types", "custom-driver" ] -} +} \ No newline at end of file diff --git a/content/docs/guides/meta.json b/content/docs/guides/meta.json index 1618fe0..039cc8f 100644 --- a/content/docs/guides/meta.json +++ b/content/docs/guides/meta.json @@ -5,6 +5,7 @@ "getting-started", "installation", "project-structure", + "field-types", "custom-driver" ] } \ No newline at end of file diff --git a/examples/todo/README.md b/examples/todo/README.md index 0e13bac..ad11a6f 100644 --- a/examples/todo/README.md +++ b/examples/todo/README.md @@ -1,16 +1,77 @@ -# ObjectStack CRM Example +# ObjectStack Todo Example -This is a reference implementation of a simple CRM schema using the ObjectStack Protocol. +A minimal example demonstrating the ObjectStack Protocol with a simple Task management application. -## Structure +## 🎯 Purpose -* `src/domains/crm/` - Contains the Object definitions (`Account`, `Contact`, `Opportunity`). -* `objectstack.config.ts` - The application manifest that bundles the objects into an app. +This example serves as a **quick-start reference** for learning ObjectStack basics. It demonstrates: +- Simple object definition with essential field types +- Basic configuration using `objectstack.config.ts` +- Minimal setup to get started quickly -## Usage +For a **comprehensive example** with advanced features (workflows, validations, multiple views, dashboards), see the **[CRM Example](../crm/)**. -This package is part of the `examples` workspace. To build it and verify types: +## 📂 Structure + +``` +examples/todo/ +├── src/ +│ ├── domains/ +│ │ └── todo/ +│ │ └── task.object.ts # Task object definition +│ └── client-test.ts # Client SDK usage example +├── objectstack.config.ts # Application manifest +└── README.md # This file +``` + +## 📋 Features Demonstrated + +### Object Definition +- **Task Object** (`todo_task`) with essential and advanced field types + +### Field Types Covered +- ✅ **Text** (`subject`) - Task title (required field) +- ✅ **Date** (`due_date`) - Due date tracking +- ✅ **Boolean** (`is_completed`) - Completion status with default value +- ✅ **Rating** (`priority`) - 3-star priority rating system +- ✅ **Color** (`category_color`) - Color picker with HEX format and preset colors +- ✅ **Code** (`code_snippet`) - JavaScript code editor with line numbers +- ✅ **Rich Text** (`notes`) - Formatted text with full editor capabilities + +### Configuration Features +- Object capabilities: `apiEnabled`, `trackHistory` +- Custom icon (`check-square`) +- Name field configuration +- Commented action example showing future extensibility + +## 💡 Usage + +This package is part of the `examples` workspace. To build and verify: ```bash -pnpm build +# Install dependencies (from monorepo root) +pnpm install + +# Build the example +pnpm --filter @objectstack/example-todo build + +# Run type checking +pnpm --filter @objectstack/example-todo typecheck ``` + +## 📖 Learning Path + +1. **Start Here** - Simple task object, basic configuration +2. **Next Step** - [CRM Example](../crm/) - Advanced features, workflows, validations, UI components +3. **Then** - [Official Documentation](../../content/docs/) - Complete protocol reference + +## 🔗 Related Resources + +- [Getting Started Guide](../../content/docs/guides/getting-started.mdx) +- [Object Schema Reference](../../packages/spec/src/data/object.zod.ts) +- [Field Types Reference](../../packages/spec/src/data/field.zod.ts) +- [CRM Example](../crm/README.md) - Full-featured reference implementation + +## 📝 License + +MIT From 0105d71e3e37ba7345860bed05c040bccdcb7eef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:22:31 +0000 Subject: [PATCH 3/6] Update Getting Started guides with comprehensive examples Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/guides/getting-started.cn.mdx | 254 +++++++++++++++++++-- content/docs/guides/getting-started.mdx | 244 ++++++++++++++++++-- 2 files changed, 461 insertions(+), 37 deletions(-) diff --git a/content/docs/guides/getting-started.cn.mdx b/content/docs/guides/getting-started.cn.mdx index 49b95de..fface86 100644 --- a/content/docs/guides/getting-started.cn.mdx +++ b/content/docs/guides/getting-started.cn.mdx @@ -3,12 +3,12 @@ title: 快速开始 description: 5 分钟内构建你的第一个 ObjectStack 应用程序 --- -ObjectStack 是一个协议,但 `@objectstack/spec` 是提供 Zod schemas 和严格类型的参考实现库,用于构建有效的元数据。 +ObjectStack 是协议优先的平台。`@objectstack/spec` 包提供了 Zod 模式和严格的 TypeScript 类型来构建有效的元数据定义。 -## 初始化你的项目 +## 初始化项目 你可以从头开始或将 ObjectStack 添加到现有的 TypeScript 项目中。 @@ -22,44 +22,251 @@ npx tsc --init -## 定义你的第一个对象 +## 定义第一个对象 -创建一个名为 `src/objects/contact.schema.ts` 的文件。 -这就是 **Zod 优先定义** 的强大之处。你可以开箱即用地获得自动完成和验证。 +创建文件 `src/domains/crm/contact.object.ts`。 +这就是 **Zod 优先定义** 的强大之处。你可以获得开箱即用的自动完成和验证。 ```typescript import { ObjectSchema, Field } from '@objectstack/spec'; export const Contact = ObjectSchema.create({ name: 'contact', - label: 'Contact', + label: '联系人', + pluralLabel: '联系人', + icon: 'user', + description: '与账户关联的人员', + nameField: 'full_name', + fields: { - first_name: Field.text({ label: 'First Name', required: true }), - last_name: Field.text({ label: 'Last Name', required: true }), - email: Field.text({ format: 'email' }), - type: Field.select(['Customer', 'Partner', 'Vendor']), + // 基本信息 + first_name: Field.text({ + label: '名', + required: true, + maxLength: 100, + }), + + last_name: Field.text({ + label: '姓', + required: true, + maxLength: 100, + }), + + // 公式字段 - 自动计算 + full_name: Field.formula({ + label: '全名', + expression: 'CONCAT(first_name, " ", last_name)', + }), + + // 联系信息 + email: Field.email({ + label: '电子邮件', + unique: true, + }), + + phone: Field.phone({ + label: '电话', + }), + + // 带预定义选项的选择字段 + type: Field.select({ + label: '联系人类型', + options: [ + { label: '客户', value: 'customer', default: true }, + { label: '合作伙伴', value: 'partner' }, + { label: '供应商', value: 'vendor' }, + ], + }), + + // 与账户的关系 + account: Field.masterDetail('account', { + label: '账户', + required: true, + deleteBehavior: 'cascade', + }), }, + enable: { - api: true, - audit: true + apiEnabled: true, + trackHistory: true, } }); ``` + +## 添加账户对象 + +创建 `src/domains/crm/account.object.ts` 作为父对象: + +```typescript +import { ObjectSchema, Field } from '@objectstack/spec'; + +export const Account = ObjectSchema.create({ + name: 'account', + label: '账户', + pluralLabel: '账户', + icon: 'building', + nameField: 'name', + + fields: { + // 自动编号字段 + account_number: Field.autonumber({ + label: '账户编号', + format: 'ACC-{0000}', + }), + + name: Field.text({ + label: '账户名称', + required: true, + searchable: true, + maxLength: 255, + }), + + // 货币字段 + annual_revenue: Field.currency({ + label: '年收入', + min: 0, + }), + + // 带自定义颜色的选择字段(用于看板) + type: Field.select({ + label: '账户类型', + options: [ + { label: '潜在客户', value: 'prospect', color: '#FFA500', default: true }, + { label: '客户', value: 'customer', color: '#00AA00' }, + { label: '合作伙伴', value: 'partner', color: '#0000FF' }, + ], + }), + }, + + enable: { + apiEnabled: true, + trackHistory: true, + } +}); +``` + + + +## 创建应用程序清单 + +创建 `objectstack.config.ts` 将对象打包到应用中: + +```typescript +import { defineManifest } from '@objectstack/spec'; +import { Account } from './src/domains/crm/account.object'; +import { Contact } from './src/domains/crm/contact.object'; + +export default defineManifest({ + name: 'my_crm', + label: '我的 CRM', + version: '1.0.0', + description: '简单的 CRM 应用程序', + + objects: [Account, Contact], + + navigation: { + tabs: [ + { + label: '销售', + items: [ + { type: 'object', object: 'account' }, + { type: 'object', object: 'contact' }, + ], + }, + ], + }, +}); +``` + + ## 验证协议 -创建一个构建脚本 `src/build.ts` 来验证你的定义是否符合 ObjectStack 协议。 +创建构建脚本 `src/build.ts` 来验证你的定义: ```typescript -import { Contact } from './objects/contact.schema'; +import config from '../objectstack.config'; -// 如果你的 schema 无效,这将抛出 ZodError -const protocol = Contact.parse(Contact); +// 如果模式无效,这将抛出 ZodError +console.log(`✅ 应用 '${config.label}' 有效!`); +console.log(`📦 对象: ${config.objects.map(o => o.name).join(', ')}`); -console.log(`✅ Object '${protocol.name}' is valid ObjectStack Metadata!`); -console.log(JSON.stringify(protocol, null, 2)); +// 导出为 JSON 供运行时使用 +import fs from 'fs'; +fs.writeFileSync( + 'dist/manifest.json', + JSON.stringify(config, null, 2) +); +``` + +运行它: + +```bash +npx tsx src/build.ts +``` + + + +## 探索高级功能 + +现在你有了一个可工作的应用,探索高级功能: + +### 1. 添加验证规则 + +```typescript +validations: [ + { + name: 'unique_email', + type: 'unique', + fields: ['email'], + message: '电子邮件已存在', + }, + { + name: 'positive_revenue', + type: 'script', + expression: 'annual_revenue >= 0', + message: '收入必须为正数', + }, +] +``` + +### 2. 添加工作流规则 + +```typescript +workflows: [ + { + name: 'update_last_activity', + trigger: 'on_update', + actions: [ + { + type: 'field_update', + field: 'last_activity_date', + value: 'TODAY()', + }, + ], + }, +] +``` + +### 3. 配置视图 + +```typescript +views: { + list: { + type: 'grid', + columns: ['account_number', 'name', 'type', 'annual_revenue'], + filters: [ + { field: 'type', operator: '=', value: 'customer' } + ], + }, + kanban: { + type: 'kanban', + groupBy: 'type', + columns: ['name', 'annual_revenue'], + }, +} ``` @@ -68,10 +275,15 @@ console.log(JSON.stringify(protocol, null, 2)); 现在你有了有效的元数据,你可以: -1. **生成 SQL**:使用协议编译器(即将推出)生成 `CREATE TABLE` 语句。 -2. **生成 UI**:将 JSON 传入 `` React 组件。 -3. **部署**:将 JSON 推送到 ObjectOS 内核。 +1. **探索示例**:查看 [CRM 示例](/examples/crm) 了解完整功能实现 +2. **学习字段类型**:参见 [字段类型指南](/docs/guides/field-types) 了解所有 30+ 种字段类型 +3. **构建 UI**:使用 ObjectStack 运行时的元数据来生成界面 +4. **部署**:推送到 ObjectStack 内核用于生产环境 +**其他资源:** +- [对象模式参考](/docs/references/data/core/Object) +- [验证规则](/docs/guides/validation-rules) +- [工作流自动化](/docs/guides/workflows) diff --git a/content/docs/guides/getting-started.mdx b/content/docs/guides/getting-started.mdx index ebdb5ca..21654c3 100644 --- a/content/docs/guides/getting-started.mdx +++ b/content/docs/guides/getting-started.mdx @@ -3,7 +3,7 @@ title: Getting Started description: Build your first ObjectStack application in 5 minutes. --- -ObjectStack is a protocol, but `@objectstack/spec` is the reference implementation library that provides the Zod schemas and strict types to build valid metadata. +ObjectStack is a protocol-first platform. The `@objectstack/spec` package provides Zod schemas and strict TypeScript types to build valid metadata definitions. @@ -24,7 +24,7 @@ npx tsc --init ## Define your first Object -Create a file named `src/objects/contact.schema.ts`. +Create a file named `src/domains/crm/contact.object.ts`. This is where the power of **Zod-First Definition** comes in. You get autocomplete and validation out of the box. ```typescript @@ -33,33 +33,240 @@ import { ObjectSchema, Field } from '@objectstack/spec'; export const Contact = ObjectSchema.create({ name: 'contact', label: 'Contact', + pluralLabel: 'Contacts', + icon: 'user', + description: 'People associated with accounts', + nameField: 'full_name', + fields: { - first_name: Field.text({ label: 'First Name', required: true }), - last_name: Field.text({ label: 'Last Name', required: true }), - email: Field.text({ format: 'email' }), - type: Field.select(['Customer', 'Partner', 'Vendor']), + // Basic Information + first_name: Field.text({ + label: 'First Name', + required: true, + maxLength: 100, + }), + + last_name: Field.text({ + label: 'Last Name', + required: true, + maxLength: 100, + }), + + // Formula field - automatically calculated + full_name: Field.formula({ + label: 'Full Name', + expression: 'CONCAT(first_name, " ", last_name)', + }), + + // Contact Information + email: Field.email({ + label: 'Email', + unique: true, + }), + + phone: Field.phone({ + label: 'Phone', + }), + + // Selection with predefined options + type: Field.select({ + label: 'Contact Type', + options: [ + { label: 'Customer', value: 'customer', default: true }, + { label: 'Partner', value: 'partner' }, + { label: 'Vendor', value: 'vendor' }, + ], + }), + + // Relationship to Account + account: Field.masterDetail('account', { + label: 'Account', + required: true, + deleteBehavior: 'cascade', + }), }, + enable: { - api: true, - audit: true + apiEnabled: true, + trackHistory: true, } }); ``` + +## Add an Account Object + +Create `src/domains/crm/account.object.ts` for the parent object: + +```typescript +import { ObjectSchema, Field } from '@objectstack/spec'; + +export const Account = ObjectSchema.create({ + name: 'account', + label: 'Account', + pluralLabel: 'Accounts', + icon: 'building', + nameField: 'name', + + fields: { + // Autonumber field + account_number: Field.autonumber({ + label: 'Account Number', + format: 'ACC-{0000}', + }), + + name: Field.text({ + label: 'Account Name', + required: true, + searchable: true, + maxLength: 255, + }), + + // Currency field + annual_revenue: Field.currency({ + label: 'Annual Revenue', + min: 0, + }), + + // Select with custom colors (for kanban boards) + type: Field.select({ + label: 'Account Type', + options: [ + { label: 'Prospect', value: 'prospect', color: '#FFA500', default: true }, + { label: 'Customer', value: 'customer', color: '#00AA00' }, + { label: 'Partner', value: 'partner', color: '#0000FF' }, + ], + }), + }, + + enable: { + apiEnabled: true, + trackHistory: true, + } +}); +``` + + + +## Create Application Manifest + +Create `objectstack.config.ts` to bundle your objects into an app: + +```typescript +import { defineManifest } from '@objectstack/spec'; +import { Account } from './src/domains/crm/account.object'; +import { Contact } from './src/domains/crm/contact.object'; + +export default defineManifest({ + name: 'my_crm', + label: 'My CRM', + version: '1.0.0', + description: 'Simple CRM application', + + objects: [Account, Contact], + + navigation: { + tabs: [ + { + label: 'Sales', + items: [ + { type: 'object', object: 'account' }, + { type: 'object', object: 'contact' }, + ], + }, + ], + }, +}); +``` + + ## Validate the Protocol -Create a build script `src/build.ts` to verify your definitions comply with the ObjectStack Protocol. +Create a build script `src/build.ts` to verify your definitions: ```typescript -import { Contact } from './objects/contact.schema'; +import config from '../objectstack.config'; // This will throw a ZodError if your schema is invalid -const protocol = Contact.parse(Contact); +console.log(`✅ App '${config.label}' is valid!`); +console.log(`📦 Objects: ${config.objects.map(o => o.name).join(', ')}`); -console.log(`✅ Object '${protocol.name}' is valid ObjectStack Metadata!`); -console.log(JSON.stringify(protocol, null, 2)); +// Export as JSON for runtime use +import fs from 'fs'; +fs.writeFileSync( + 'dist/manifest.json', + JSON.stringify(config, null, 2) +); +``` + +Run it: + +```bash +npx tsx src/build.ts +``` + + + +## Explore Advanced Features + +Now that you have a working app, explore advanced features: + +### 1. Add Validation Rules + +```typescript +validations: [ + { + name: 'unique_email', + type: 'unique', + fields: ['email'], + message: 'Email already exists', + }, + { + name: 'positive_revenue', + type: 'script', + expression: 'annual_revenue >= 0', + message: 'Revenue must be positive', + }, +] +``` + +### 2. Add Workflow Rules + +```typescript +workflows: [ + { + name: 'update_last_activity', + trigger: 'on_update', + actions: [ + { + type: 'field_update', + field: 'last_activity_date', + value: 'TODAY()', + }, + ], + }, +] +``` + +### 3. Configure Views + +```typescript +views: { + list: { + type: 'grid', + columns: ['account_number', 'name', 'type', 'annual_revenue'], + filters: [ + { field: 'type', operator: '=', value: 'customer' } + ], + }, + kanban: { + type: 'kanban', + groupBy: 'type', + columns: ['name', 'annual_revenue'], + }, +} ``` @@ -68,10 +275,15 @@ console.log(JSON.stringify(protocol, null, 2)); Now that you have valid metadata, you can: -1. **Generate SQL**: Use the Protocol Compiler (Coming Soon) to generate `CREATE TABLE` statements. -2. **Generate UI**: Feed the JSON into the `` React component. -3. **Deploy**: Push the JSON to an ObjectOS Kernel. +1. **Explore Examples**: Check out the [CRM Example](/examples/crm) for a full-featured implementation +2. **Learn Field Types**: See the [Field Types Guide](/docs/guides/field-types) for all 30+ field types +3. **Build UI**: Use the metadata with ObjectStack runtime to generate interfaces +4. **Deploy**: Push to an ObjectStack kernel for production use +**Additional Resources:** +- [Object Schema Reference](/docs/references/data/core/Object) +- [Validation Rules](/docs/guides/validation-rules) +- [Workflow Automation](/docs/guides/workflows) From 1fecbe6373090d71f8310b2084d5b81e0c0ab2c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:24:32 +0000 Subject: [PATCH 4/6] Add comprehensive Workflows and Validation Rules guide Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/guides/meta.cn.json | 1 + content/docs/guides/meta.json | 1 + content/docs/guides/workflows-validation.mdx | 734 +++++++++++++++++++ 3 files changed, 736 insertions(+) create mode 100644 content/docs/guides/workflows-validation.mdx diff --git a/content/docs/guides/meta.cn.json b/content/docs/guides/meta.cn.json index 4a4c3e3..5b9af6d 100644 --- a/content/docs/guides/meta.cn.json +++ b/content/docs/guides/meta.cn.json @@ -6,6 +6,7 @@ "installation", "project-structure", "field-types", + "workflows-validation", "custom-driver" ] } \ No newline at end of file diff --git a/content/docs/guides/meta.json b/content/docs/guides/meta.json index 039cc8f..a63739a 100644 --- a/content/docs/guides/meta.json +++ b/content/docs/guides/meta.json @@ -6,6 +6,7 @@ "installation", "project-structure", "field-types", + "workflows-validation", "custom-driver" ] } \ No newline at end of file diff --git a/content/docs/guides/workflows-validation.mdx b/content/docs/guides/workflows-validation.mdx new file mode 100644 index 0000000..8d1fbe3 --- /dev/null +++ b/content/docs/guides/workflows-validation.mdx @@ -0,0 +1,734 @@ +--- +title: Validation Rules & Workflows +description: Complete guide to validation rules and workflow automation in ObjectStack +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +# Validation Rules & Workflows + +ObjectStack provides powerful **validation rules** and **workflow automation** to enforce business logic and automate repetitive tasks. This guide covers all validation types and workflow patterns with practical examples. + +## Validation Rules + +Validation rules ensure data quality by checking record values before save. They can be defined at the object level and execute automatically. + +### Types of Validation Rules + +ObjectStack supports **7 validation types**, each optimized for specific use cases: + +1. **Script Validation** - Generic formula-based validation +2. **Uniqueness Validation** - Enforce unique constraints +3. **State Machine Validation** - Control state transitions +4. **Format Validation** - Regex or format checking +5. **Cross-Field Validation** - Compare multiple fields +6. **Async Validation** - Remote API validation +7. **Custom Validator** - User-defined functions + +--- + +## 1. Script Validation + +Generic formula-based validation for any business logic. + +### Configuration + +```typescript +import { ObjectSchema, Field } from '@objectstack/spec'; + +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + amount: Field.currency({ label: 'Amount' }), + probability: Field.percent({ label: 'Probability' }), + close_date: Field.date({ label: 'Close Date' }), + }, + + validations: [ + { + name: 'positive_amount', + type: 'script', + condition: 'amount < 0', // When TRUE, validation FAILS + message: 'Amount must be greater than or equal to 0', + severity: 'error', + active: true, + }, + { + name: 'probability_range', + type: 'script', + condition: 'probability < 0 OR probability > 100', + message: 'Probability must be between 0 and 100', + severity: 'error', + }, + { + name: 'future_close_date', + type: 'script', + condition: 'close_date < TODAY()', + message: 'Close date cannot be in the past', + severity: 'warning', // Warning instead of error + }, + ], +}); +``` + + + **Important:** The `condition` is inverted logic - it defines when validation **FAILS**. If the condition evaluates to `TRUE`, the validation error is shown. + + +### Expression Examples + +```typescript +// Number comparisons +condition: 'revenue < 1000' +condition: 'quantity <= 0' +condition: 'discount > 50' + +// String checks +condition: 'LEN(name) < 3' +condition: 'ISBLANK(description)' +condition: 'NOT(CONTAINS(email, "@"))' + +// Date validations +condition: 'end_date < start_date' +condition: 'due_date < TODAY()' +condition: 'DAYS_BETWEEN(start_date, end_date) > 365' + +// Complex logic +condition: 'stage = "Closed Won" AND amount = 0' +condition: '(priority = "High" OR priority = "Critical") AND NOT(ISBLANK(assigned_to))' +``` + +--- + +## 2. Uniqueness Validation + +Optimized validation for enforcing unique constraints, better than script validation for uniqueness checks. + +### Configuration + +```typescript +export const Account = ObjectSchema.create({ + name: 'account', + label: 'Account', + + fields: { + name: Field.text({ label: 'Account Name' }), + email: Field.email({ label: 'Email' }), + account_number: Field.text({ label: 'Account Number' }), + active: Field.boolean({ label: 'Active' }), + }, + + validations: [ + // Single field uniqueness + { + name: 'unique_email', + type: 'unique', + fields: ['email'], + message: 'Email address already exists', + caseSensitive: false, // Ignore case + }, + + // Compound uniqueness (multiple fields) + { + name: 'unique_account_number', + type: 'unique', + fields: ['account_number'], + message: 'Account number must be unique', + caseSensitive: true, + }, + + // Scoped uniqueness (unique within subset) + { + name: 'unique_name_active', + type: 'unique', + fields: ['name'], + scope: 'active = true', // Only check uniqueness among active accounts + message: 'Active account with this name already exists', + }, + ], +}); +``` + +### Use Cases + +- Email addresses +- Username fields +- Product SKUs +- Invoice numbers +- Unique combinations (e.g., name + region) + +--- + +## 3. State Machine Validation + +Control allowed state transitions to prevent invalid workflow progressions. + +### Configuration + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + stage: Field.select({ + label: 'Stage', + options: [ + { label: 'Prospecting', value: 'prospecting' }, + { label: 'Qualification', value: 'qualification' }, + { label: 'Proposal', value: 'proposal' }, + { label: 'Negotiation', value: 'negotiation' }, + { label: 'Closed Won', value: 'closed_won' }, + { label: 'Closed Lost', value: 'closed_lost' }, + ], + }), + }, + + validations: [ + { + name: 'stage_transition', + type: 'state_machine', + field: 'stage', + message: 'Invalid stage transition', + transitions: { + // From -> To (allowed states) + 'prospecting': ['qualification', 'closed_lost'], + 'qualification': ['prospecting', 'proposal', 'closed_lost'], + 'proposal': ['qualification', 'negotiation', 'closed_lost'], + 'negotiation': ['proposal', 'closed_won', 'closed_lost'], + 'closed_won': [], // No transitions allowed (terminal state) + 'closed_lost': [], // No transitions allowed (terminal state) + }, + }, + ], +}); +``` + +### Diagram + +``` +Prospecting → Qualification → Proposal → Negotiation → Closed Won + ↓ ↓ ↓ ↓ + Closed Lost ← Closed Lost ← Closed Lost ← Closed Lost +``` + +--- + +## 4. Format Validation + +Validate field formats using regex or predefined patterns. + +### Configuration + +```typescript +export const Contact = ObjectSchema.create({ + name: 'contact', + label: 'Contact', + + fields: { + phone: Field.phone({ label: 'Phone' }), + website: Field.url({ label: 'Website' }), + postal_code: Field.text({ label: 'Postal Code' }), + json_data: Field.textarea({ label: 'JSON Data' }), + }, + + validations: [ + // Regex validation + { + name: 'us_postal_code', + type: 'format', + field: 'postal_code', + regex: '^\\d{5}(-\\d{4})?$', // 12345 or 12345-6789 + message: 'Invalid US postal code format', + }, + + // Predefined format + { + name: 'valid_phone', + type: 'format', + field: 'phone', + format: 'phone', + message: 'Invalid phone number format', + }, + + { + name: 'valid_json', + type: 'format', + field: 'json_data', + format: 'json', + message: 'Invalid JSON format', + }, + ], +}); +``` + +### Available Formats + +- `email` - Email address +- `url` - Website URL +- `phone` - Phone number +- `json` - Valid JSON + +--- + +## 5. Cross-Field Validation + +Validate relationships between multiple fields. + +### Configuration + +```typescript +export const Event = ObjectSchema.create({ + name: 'event', + label: 'Event', + + fields: { + start_date: Field.datetime({ label: 'Start Date' }), + end_date: Field.datetime({ label: 'End Date' }), + min_attendees: Field.number({ label: 'Min Attendees' }), + max_attendees: Field.number({ label: 'Max Attendees' }), + budget: Field.currency({ label: 'Budget' }), + actual_cost: Field.currency({ label: 'Actual Cost' }), + }, + + validations: [ + { + name: 'end_after_start', + type: 'cross_field', + fields: ['start_date', 'end_date'], + condition: 'end_date <= start_date', + message: 'End date must be after start date', + }, + + { + name: 'max_greater_than_min', + type: 'cross_field', + fields: ['min_attendees', 'max_attendees'], + condition: 'max_attendees < min_attendees', + message: 'Maximum attendees must be greater than minimum', + }, + + { + name: 'budget_check', + type: 'cross_field', + fields: ['budget', 'actual_cost'], + condition: 'actual_cost > budget', + message: 'Actual cost exceeds budget', + severity: 'warning', // Allow save but warn + }, + ], +}); +``` + +--- + +## 6. Async Validation + +Validate data against external APIs or databases. + +### Configuration + +```typescript +export const User = ObjectSchema.create({ + name: 'user', + label: 'User', + + fields: { + username: Field.text({ label: 'Username' }), + tax_id: Field.text({ label: 'Tax ID' }), + }, + + validations: [ + { + name: 'check_username_availability', + type: 'async', + field: 'username', + validatorUrl: '/api/validate/username', + timeout: 5000, + debounce: 500, // Wait 500ms after typing stops + message: 'Username is already taken', + params: { + minLength: 3, + }, + }, + + { + name: 'verify_tax_id', + type: 'async', + field: 'tax_id', + validatorFunction: 'validateTaxId', // Custom function + timeout: 10000, + message: 'Invalid tax ID', + }, + ], +}); +``` + +--- + +## 7. Custom Validator + +User-defined validation logic with code references. + +### Configuration + +```typescript +export const Order = ObjectSchema.create({ + name: 'order', + label: 'Order', + + fields: { + items: Field.textarea({ label: 'Order Items (JSON)' }), + total: Field.currency({ label: 'Total' }), + }, + + validations: [ + { + name: 'validate_order_total', + type: 'custom', + validatorFunction: 'validateOrderTotal', + message: 'Order total does not match line items', + params: { + includeTax: true, + includeShipping: true, + }, + }, + ], +}); +``` + +--- + +## Workflow Automation + +Workflows automate actions when records are created, updated, or deleted. + +### Workflow Components + +1. **Trigger** - When to execute (on_create, on_update, on_delete, schedule) +2. **Criteria** - Condition to check (optional) +3. **Actions** - What to execute (field_update, email_alert, etc.) + +--- + +## Workflow Examples + +### 1. Field Update on Create + +```typescript +export const Lead = ObjectSchema.create({ + name: 'lead', + label: 'Lead', + + fields: { + status: Field.select({ + options: ['New', 'Contacted', 'Qualified', 'Converted'], + }), + created_date: Field.datetime({ label: 'Created Date' }), + last_contacted: Field.datetime({ label: 'Last Contacted' }), + }, + + workflows: [ + { + name: 'set_default_status', + objectName: 'lead', + triggerType: 'on_create', + actions: [ + { + name: 'set_status_new', + type: 'field_update', + field: 'status', + value: 'New', + }, + { + name: 'set_created_date', + type: 'field_update', + field: 'created_date', + value: 'NOW()', + }, + ], + active: true, + }, + ], +}); +``` + +--- + +### 2. Conditional Workflow + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + stage: Field.select({ options: ['...'] }), + amount: Field.currency({ label: 'Amount' }), + owner: Field.lookup('user', { label: 'Owner' }), + approved: Field.boolean({ label: 'Approved' }), + }, + + workflows: [ + { + name: 'require_approval_large_deals', + objectName: 'opportunity', + triggerType: 'on_update', + criteria: 'amount > 100000 AND stage = "Closed Won"', // Only for big deals + actions: [ + { + name: 'set_approval_required', + type: 'field_update', + field: 'approved', + value: 'false', + }, + { + name: 'notify_manager', + type: 'email_alert', + template: 'approval_required_email', + recipients: ['sales_manager@company.com'], + }, + ], + active: true, + }, + ], +}); +``` + +--- + +### 3. Email Alert Workflow + +```typescript +export const Case = ObjectSchema.create({ + name: 'case', + label: 'Case', + + fields: { + priority: Field.select({ options: ['Low', 'Medium', 'High', 'Critical'] }), + status: Field.select({ options: ['Open', 'In Progress', 'Resolved'] }), + contact: Field.lookup('contact', { label: 'Contact' }), + }, + + workflows: [ + { + name: 'escalate_critical_cases', + objectName: 'case', + triggerType: 'on_create_or_update', + criteria: 'priority = "Critical" AND status = "Open"', + actions: [ + { + name: 'notify_support_team', + type: 'email_alert', + template: 'critical_case_alert', + recipients: ['support_team@company.com', 'manager@company.com'], + }, + ], + active: true, + }, + ], +}); +``` + +--- + +### 4. Update Timestamp Workflow + +```typescript +export const Account = ObjectSchema.create({ + name: 'account', + label: 'Account', + + fields: { + last_activity_date: Field.datetime({ label: 'Last Activity' }), + last_modified_date: Field.datetime({ label: 'Last Modified' }), + }, + + workflows: [ + { + name: 'update_last_activity', + objectName: 'account', + triggerType: 'on_update', + actions: [ + { + name: 'set_last_activity', + type: 'field_update', + field: 'last_activity_date', + value: 'NOW()', + }, + ], + active: true, + }, + ], +}); +``` + +--- + +## Best Practices + +### Validation Rules + +1. **Use Specific Types**: Use `unique` instead of `script` for uniqueness, `state_machine` instead of complex conditions +2. **Clear Messages**: Provide actionable error messages that guide users +3. **Severity Levels**: Use `warning` for soft validations, `error` for hard stops +4. **Performance**: Avoid complex formulas in validations, use indexes for uniqueness checks +5. **Testing**: Test all edge cases and state transitions + +### Workflows + +1. **Criteria First**: Use criteria to limit workflow execution, not blanket triggers +2. **Avoid Loops**: Be careful with `on_update` workflows that update the same record +3. **Batch-Safe**: Ensure workflows can handle bulk operations +4. **Error Handling**: Workflows should not block saves on non-critical failures +5. **Audit Trail**: Use field updates to maintain audit logs (last_modified_by, etc.) + +--- + +## Formula Functions Reference + +Common functions used in validation conditions and workflow criteria: + +### String Functions +- `CONCAT(str1, str2, ...)` - Concatenate strings +- `LEN(str)` - String length +- `ISBLANK(str)` - Check if empty +- `CONTAINS(str, substring)` - Check if contains +- `UPPER(str)`, `LOWER(str)` - Case conversion + +### Date Functions +- `TODAY()` - Current date +- `NOW()` - Current datetime +- `DAYS_BETWEEN(date1, date2)` - Days between dates +- `ADDDAYS(date, num)` - Add days to date + +### Logic Functions +- `AND(cond1, cond2, ...)` - Logical AND +- `OR(cond1, cond2, ...)` - Logical OR +- `NOT(cond)` - Logical NOT +- `IF(condition, true_value, false_value)` - Conditional + +### Number Functions +- `ABS(num)` - Absolute value +- `ROUND(num, decimals)` - Round number +- `MAX(num1, num2, ...)` - Maximum +- `MIN(num1, num2, ...)` - Minimum + +--- + +## Real-World Example: CRM Opportunity + +Complete example combining validations and workflows: + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + name: Field.text({ label: 'Name', required: true }), + account: Field.lookup('account', { label: 'Account', required: true }), + amount: Field.currency({ label: 'Amount' }), + close_date: Field.date({ label: 'Close Date' }), + probability: Field.percent({ label: 'Probability' }), + stage: Field.select({ + options: [ + { label: 'Prospecting', value: 'prospecting' }, + { label: 'Qualification', value: 'qualification' }, + { label: 'Proposal', value: 'proposal' }, + { label: 'Negotiation', value: 'negotiation' }, + { label: 'Closed Won', value: 'closed_won' }, + { label: 'Closed Lost', value: 'closed_lost' }, + ], + }), + approved: Field.boolean({ label: 'Approved' }), + last_stage_change: Field.datetime({ label: 'Last Stage Change' }), + }, + + validations: [ + // Basic validations + { + name: 'positive_amount', + type: 'script', + condition: 'amount < 0', + message: 'Amount must be positive', + }, + + // State machine + { + name: 'stage_progression', + type: 'state_machine', + field: 'stage', + message: 'Invalid stage transition', + transitions: { + 'prospecting': ['qualification', 'closed_lost'], + 'qualification': ['prospecting', 'proposal', 'closed_lost'], + 'proposal': ['qualification', 'negotiation', 'closed_lost'], + 'negotiation': ['proposal', 'closed_won', 'closed_lost'], + 'closed_won': [], + 'closed_lost': [], + }, + }, + + // Cross-field validation + { + name: 'probability_stage_match', + type: 'cross_field', + fields: ['stage', 'probability'], + condition: 'stage = "Closed Won" AND probability < 100', + message: 'Closed Won opportunities must have 100% probability', + }, + ], + + workflows: [ + // Update timestamp on stage change + { + name: 'track_stage_changes', + objectName: 'opportunity', + triggerType: 'on_update', + criteria: 'ISCHANGED(stage)', + actions: [ + { + name: 'update_timestamp', + type: 'field_update', + field: 'last_stage_change', + value: 'NOW()', + }, + ], + }, + + // Require approval for large deals + { + name: 'large_deal_approval', + objectName: 'opportunity', + triggerType: 'on_update', + criteria: 'amount > 500000 AND stage = "Negotiation"', + actions: [ + { + name: 'request_approval', + type: 'field_update', + field: 'approved', + value: 'false', + }, + { + name: 'notify_exec_team', + type: 'email_alert', + template: 'large_deal_approval', + recipients: ['ceo@company.com', 'cfo@company.com'], + }, + ], + }, + ], +}); +``` + +--- + +## Next Steps + +- [Field Types Guide](/docs/guides/field-types) +- [Object Schema Reference](/docs/references/data/core/Object) +- [Formula Functions](/docs/references/data/formulas) +- [CRM Example](/examples/crm) - See validations and workflows in action From a4ba6fc51daba72a130dcad2303a0721705a76f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:26:33 +0000 Subject: [PATCH 5/6] Add comprehensive View Configuration guide Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/guides/meta.cn.json | 1 + content/docs/guides/meta.json | 1 + content/docs/guides/view-configuration.mdx | 807 +++++++++++++++++++++ 3 files changed, 809 insertions(+) create mode 100644 content/docs/guides/view-configuration.mdx diff --git a/content/docs/guides/meta.cn.json b/content/docs/guides/meta.cn.json index 5b9af6d..b769a4f 100644 --- a/content/docs/guides/meta.cn.json +++ b/content/docs/guides/meta.cn.json @@ -6,6 +6,7 @@ "installation", "project-structure", "field-types", + "view-configuration", "workflows-validation", "custom-driver" ] diff --git a/content/docs/guides/meta.json b/content/docs/guides/meta.json index a63739a..78b2596 100644 --- a/content/docs/guides/meta.json +++ b/content/docs/guides/meta.json @@ -6,6 +6,7 @@ "installation", "project-structure", "field-types", + "view-configuration", "workflows-validation", "custom-driver" ] diff --git a/content/docs/guides/view-configuration.mdx b/content/docs/guides/view-configuration.mdx new file mode 100644 index 0000000..dad717a --- /dev/null +++ b/content/docs/guides/view-configuration.mdx @@ -0,0 +1,807 @@ +--- +title: View Configuration +description: Complete guide to configuring Grid, Kanban, Calendar, Gantt views and forms in ObjectStack +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +# View Configuration Guide + +ObjectStack provides **5 list view types** and **3 form layouts** to visualize and interact with data. This guide covers all configuration options with practical examples. + +## List View Types + +1. **Grid** - Traditional table/spreadsheet view +2. **Kanban** - Card-based workflow board +3. **Calendar** - Date-based visualization +4. **Gantt** - Timeline/project management view +5. **Map** - Geographic location view + +--- + +## 1. Grid View + +Traditional table view with rows and columns. + +### Basic Configuration + +```typescript +import { ObjectSchema, Field } from '@objectstack/spec'; + +export const Account = ObjectSchema.create({ + name: 'account', + label: 'Account', + + fields: { + account_number: Field.autonumber({ label: 'Account Number', format: 'ACC-{0000}' }), + name: Field.text({ label: 'Account Name' }), + type: Field.select({ + label: 'Type', + options: [ + { label: 'Customer', value: 'customer' }, + { label: 'Partner', value: 'partner' }, + ], + }), + annual_revenue: Field.currency({ label: 'Annual Revenue' }), + industry: Field.select({ label: 'Industry', options: ['Tech', 'Finance', 'Healthcare'] }), + created_at: Field.datetime({ label: 'Created' }), + }, + + views: { + list: { + type: 'grid', + columns: ['account_number', 'name', 'type', 'annual_revenue', 'industry'], + sort: [ + { field: 'created_at', order: 'desc' } + ], + }, + }, +}); +``` + +### Advanced Grid Configuration + +```typescript +views: { + // Default grid view + list: { + type: 'grid', + columns: ['name', 'type', 'annual_revenue', 'owner'], + + // Filter configuration + filter: [ + { field: 'type', operator: '=', value: 'customer' }, + { field: 'annual_revenue', operator: '>', value: 100000 }, + ], + + // Sorting + sort: [ + { field: 'annual_revenue', order: 'desc' }, + { field: 'name', order: 'asc' }, + ], + + // Search configuration + searchableFields: ['name', 'account_number'], + }, + + // Additional named views + listViews: { + // High-value customers + high_value: { + name: 'high_value', + label: 'High Value Customers', + type: 'grid', + columns: ['name', 'annual_revenue', 'owner', 'last_activity'], + filter: [ + { field: 'type', operator: '=', value: 'customer' }, + { field: 'annual_revenue', operator: '>=', value: 500000 }, + ], + sort: [{ field: 'annual_revenue', order: 'desc' }], + }, + + // Recently created + recent: { + name: 'recent', + label: 'Recently Created', + type: 'grid', + columns: ['name', 'type', 'created_at', 'owner'], + sort: [{ field: 'created_at', order: 'desc' }], + }, + }, +} +``` + +### Filter Operators + +Available filter operators: + +```typescript +// Comparison +{ field: 'amount', operator: '=', value: 1000 } +{ field: 'amount', operator: '!=', value: 0 } +{ field: 'amount', operator: '>', value: 5000 } +{ field: 'amount', operator: '>=', value: 1000 } +{ field: 'amount', operator: '<', value: 10000 } +{ field: 'amount', operator: '<=', value: 50000 } + +// String +{ field: 'name', operator: 'contains', value: 'tech' } +{ field: 'name', operator: 'startsWith', value: 'A' } +{ field: 'name', operator: 'endsWith', value: 'Inc' } + +// NULL checks +{ field: 'description', operator: 'isNull' } +{ field: 'description', operator: 'isNotNull' } + +// Multi-value +{ field: 'type', operator: 'in', value: ['customer', 'partner'] } +{ field: 'type', operator: 'notIn', value: ['former'] } +``` + +--- + +## 2. Kanban View + +Card-based workflow board grouped by a select field. + +### Basic Configuration + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + name: Field.text({ label: 'Opportunity Name' }), + stage: Field.select({ + label: 'Stage', + options: [ + { label: 'Prospecting', value: 'prospecting', color: '#FFA500' }, + { label: 'Qualification', value: 'qualification', color: '#FFD700' }, + { label: 'Proposal', value: 'proposal', color: '#4169E1' }, + { label: 'Negotiation', value: 'negotiation', color: '#9370DB' }, + { label: 'Closed Won', value: 'closed_won', color: '#00AA00' }, + { label: 'Closed Lost', value: 'closed_lost', color: '#DC143C' }, + ], + }), + amount: Field.currency({ label: 'Amount' }), + account: Field.lookup('account', { label: 'Account' }), + close_date: Field.date({ label: 'Close Date' }), + }, + + views: { + list: { + type: 'kanban', + columns: ['name', 'account', 'amount', 'close_date'], // Fields shown on cards + + kanban: { + groupByField: 'stage', // Creates columns for each stage + summarizeField: 'amount', // Sum amounts at top of each column + }, + }, + }, +}); +``` + +### Advanced Kanban + +```typescript +views: { + listViews: { + sales_pipeline: { + name: 'sales_pipeline', + label: 'Sales Pipeline', + type: 'kanban', + + // Card fields + columns: ['name', 'account', 'amount', 'probability', 'owner'], + + // Kanban configuration + kanban: { + groupByField: 'stage', + summarizeField: 'amount', // Show total $ per column + }, + + // Filter to active opportunities only + filter: [ + { field: 'is_active', operator: '=', value: true }, + ], + + // Sort cards within columns + sort: [ + { field: 'amount', order: 'desc' }, + ], + }, + }, +} +``` + +### Kanban Features + +- **Drag & Drop**: Users can drag cards between columns (updates `groupByField`) +- **Column Headers**: Show count and sum (if `summarizeField` defined) +- **Colors**: Use option colors from select field for column headers +- **Filters**: Apply filters to show subset of records + +--- + +## 3. Calendar View + +Date-based visualization for events, tasks, and deadlines. + +### Basic Configuration + +```typescript +export const Event = ObjectSchema.create({ + name: 'event', + label: 'Event', + + fields: { + title: Field.text({ label: 'Event Title' }), + start_date: Field.datetime({ label: 'Start Date' }), + end_date: Field.datetime({ label: 'End Date' }), + event_type: Field.select({ + label: 'Type', + options: [ + { label: 'Meeting', value: 'meeting', color: '#4169E1' }, + { label: 'Webinar', value: 'webinar', color: '#00AA00' }, + { label: 'Conference', value: 'conference', color: '#FFA500' }, + ], + }), + location: Field.text({ label: 'Location' }), + }, + + views: { + list: { + type: 'calendar', + columns: ['title', 'location'], // Extra fields shown in tooltip + + calendar: { + startDateField: 'start_date', // Required + endDateField: 'end_date', // Optional (single-day events if omitted) + titleField: 'title', // Event label + colorField: 'event_type', // Color events by type + }, + }, + }, +}); +``` + +### Single-Day Events + +For tasks or activities without end dates: + +```typescript +export const Task = ObjectSchema.create({ + name: 'task', + label: 'Task', + + fields: { + subject: Field.text({ label: 'Subject' }), + due_date: Field.date({ label: 'Due Date' }), + priority: Field.select({ + options: [ + { label: 'High', value: 'high', color: '#DC143C' }, + { label: 'Normal', value: 'normal', color: '#4169E1' }, + { label: 'Low', value: 'low', color: '#999999' }, + ], + }), + }, + + views: { + list: { + type: 'calendar', + columns: ['subject'], + + calendar: { + startDateField: 'due_date', + // No endDateField - shows as single-day events + titleField: 'subject', + colorField: 'priority', + }, + }, + }, +}); +``` + +### Calendar Features + +- **Multiple Views**: Month, Week, Day, Agenda +- **Color Coding**: By select field option colors +- **Multi-Day Events**: Span multiple days if `endDateField` provided +- **Drag & Drop**: Update dates by dragging events +- **Filters**: Show subset of events + +--- + +## 4. Gantt View + +Timeline/project management view for tasks with dependencies. + +### Configuration + +```typescript +export const ProjectTask = ObjectSchema.create({ + name: 'project_task', + label: 'Project Task', + + fields: { + task_name: Field.text({ label: 'Task Name' }), + start_date: Field.date({ label: 'Start Date' }), + end_date: Field.date({ label: 'End Date' }), + progress: Field.percent({ label: 'Progress' }), + dependencies: Field.text({ label: 'Dependencies' }), // Comma-separated task IDs + assigned_to: Field.lookup('user', { label: 'Assigned To' }), + }, + + views: { + list: { + type: 'gantt', + columns: ['task_name', 'assigned_to'], // Shown in left panel + + gantt: { + startDateField: 'start_date', // Required + endDateField: 'end_date', // Required + titleField: 'task_name', // Bar label + progressField: 'progress', // Optional (shows % complete) + dependenciesField: 'dependencies', // Optional (draws arrows) + }, + + sort: [ + { field: 'start_date', order: 'asc' }, + ], + }, + }, +}); +``` + +### Gantt Features + +- **Timeline Bars**: Visual representation of task duration +- **Progress Indicator**: Shows completion percentage +- **Dependencies**: Arrows between related tasks +- **Critical Path**: Highlight blocking tasks +- **Drag & Drop**: Adjust dates and dependencies +- **Zoom Levels**: Day, Week, Month, Quarter, Year + +--- + +## 5. Map View + +Geographic visualization for location-based data. + +### Configuration + +```typescript +export const Store = ObjectSchema.create({ + name: 'store', + label: 'Store', + + fields: { + store_name: Field.text({ label: 'Store Name' }), + address: Field.address({ label: 'Address' }), + location: Field.location({ label: 'Coordinates' }), + store_type: Field.select({ + options: [ + { label: 'Flagship', value: 'flagship', color: '#FFD700' }, + { label: 'Standard', value: 'standard', color: '#4169E1' }, + { label: 'Outlet', value: 'outlet', color: '#999999' }, + ], + }), + }, + + views: { + list: { + type: 'map', + columns: ['store_name', 'address'], // Info shown in popup + + map: { + locationField: 'location', // GPS coordinates + titleField: 'store_name', + colorField: 'store_type', // Marker color + }, + }, + }, +}); +``` + +--- + +## Form Views + +Three layout types for record detail pages: + +1. **Simple** - Single page with sections +2. **Tabbed** - Multiple tabs for grouped fields +3. **Wizard** - Step-by-step multi-page form + +--- + +## 1. Simple Form + +Single-page layout with collapsible sections. + +### Configuration + +```typescript +export const Contact = ObjectSchema.create({ + name: 'contact', + label: 'Contact', + + fields: { + // ... field definitions + }, + + views: { + form: { + type: 'simple', + sections: [ + { + label: 'Basic Information', + columns: 2, // 2-column layout + fields: ['first_name', 'last_name', 'email', 'phone'], + }, + { + label: 'Address', + columns: 2, + collapsible: true, + collapsed: false, + fields: ['street', 'city', 'state', 'postal_code', 'country'], + }, + { + label: 'Additional Details', + columns: 1, // Full-width fields + collapsible: true, + collapsed: true, // Collapsed by default + fields: ['notes', 'description'], + }, + ], + }, + }, +}); +``` + +### Section Configuration + +```typescript +{ + label: 'Section Title', // Optional header + columns: 2, // 1, 2, 3, or 4 columns + collapsible: true, // Can be collapsed + collapsed: false, // Initial state + fields: ['field1', 'field2'], // Fields to include +} +``` + +--- + +## 2. Tabbed Form + +Multi-tab layout for complex objects with many fields. + +### Configuration + +```typescript +export const Account = ObjectSchema.create({ + name: 'account', + label: 'Account', + + fields: { + // ... many fields + }, + + views: { + form: { + type: 'tabbed', + sections: [ + { + label: 'Overview', // Tab 1 + columns: 2, + fields: [ + 'account_number', + 'name', + 'type', + 'industry', + 'annual_revenue', + 'website', + ], + }, + { + label: 'Contact Information', // Tab 2 + columns: 2, + fields: [ + 'phone', + 'email', + 'billing_address', + 'shipping_address', + ], + }, + { + label: 'Description', // Tab 3 + columns: 1, + fields: ['description', 'notes'], + }, + ], + }, + }, +}); +``` + +--- + +## 3. Wizard Form + +Multi-step form for guided data entry. + +### Configuration + +```typescript +export const Lead = ObjectSchema.create({ + name: 'lead', + label: 'Lead', + + fields: { + // ... field definitions + }, + + views: { + form: { + type: 'wizard', + sections: [ + { + label: 'Step 1: Basic Info', // Wizard step 1 + fields: ['first_name', 'last_name', 'company', 'title'], + }, + { + label: 'Step 2: Contact Details', // Step 2 + fields: ['email', 'phone', 'address'], + }, + { + label: 'Step 3: Qualification', // Step 3 + fields: ['lead_source', 'industry', 'annual_revenue', 'status'], + }, + ], + }, + }, +}); +``` + +### Wizard Features + +- **Progress Indicator**: Shows current step +- **Navigation**: Previous/Next buttons +- **Validation**: Each step validated before proceeding +- **Summary**: Review all data before submit + +--- + +## Multiple Views + +Define multiple views for different use cases. + +### Example + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + + fields: { + // ... fields + }, + + views: { + // Default list view (Grid) + list: { + type: 'grid', + columns: ['name', 'account', 'amount', 'stage', 'close_date'], + sort: [{ field: 'close_date', order: 'asc' }], + }, + + // Default form view + form: { + type: 'tabbed', + sections: [ + { label: 'Details', fields: ['name', 'account', 'amount'] }, + { label: 'Timeline', fields: ['stage', 'close_date'] }, + ], + }, + + // Additional list views + listViews: { + // Kanban pipeline + pipeline: { + name: 'pipeline', + label: 'Sales Pipeline', + type: 'kanban', + columns: ['name', 'amount', 'close_date'], + kanban: { + groupByField: 'stage', + summarizeField: 'amount', + }, + }, + + // Calendar of close dates + timeline: { + name: 'timeline', + label: 'Timeline', + type: 'calendar', + columns: ['name', 'amount'], + calendar: { + startDateField: 'close_date', + titleField: 'name', + colorField: 'stage', + }, + }, + + // My opportunities + my_opportunities: { + name: 'my_opportunities', + label: 'My Opportunities', + type: 'grid', + columns: ['name', 'account', 'amount', 'stage'], + filter: [ + { field: 'owner', operator: '=', value: '$current_user' }, + ], + }, + }, + + // Additional form views + formViews: { + // Quick create form + quick_create: { + type: 'simple', + sections: [ + { + label: 'Essential Fields', + columns: 2, + fields: ['name', 'account', 'amount', 'close_date', 'stage'], + }, + ], + }, + }, + }, +}); +``` + +--- + +## Best Practices + +### List Views + +1. **Column Selection**: Show 4-7 columns for optimal readability +2. **Default Sort**: Always define a default sort order +3. **Filters**: Pre-filter common views (e.g., "My Records", "Active Only") +4. **Searchable**: Enable search on key text fields +5. **Named Views**: Create specific views for common use cases + +### Kanban + +1. **Group Field**: Use select fields with 3-7 options (too many = cluttered) +2. **Card Fields**: Show 3-5 key fields on cards +3. **Colors**: Define colors for select options +4. **Summarize**: Add monetary totals for sales/revenue tracking + +### Calendar + +1. **Date Fields**: Use datetime for multi-day events, date for single-day +2. **Color Coding**: Use select field with meaningful colors +3. **Title Field**: Choose concise, descriptive field +4. **Filters**: Allow filtering by type, owner, etc. + +### Gantt + +1. **Dependencies**: Use structured format (comma-separated IDs or JSON) +2. **Progress**: Percentage field (0-100) +3. **Sort**: Sort by start date for logical flow +4. **Granularity**: Choose appropriate zoom level (day/week/month) + +### Forms + +1. **Sections**: Group related fields logically +2. **Columns**: Use 2 columns for most sections, 1 for wide fields (textarea, rich text) +3. **Collapsible**: Make optional sections collapsible +4. **Tabs**: Use tabs when >15 fields +5. **Wizard**: Use for complex multi-step processes + +--- + +## Real-World Example + +Complete view configuration for CRM Opportunity: + +```typescript +export const Opportunity = ObjectSchema.create({ + name: 'opportunity', + label: 'Opportunity', + pluralLabel: 'Opportunities', + + fields: { + name: Field.text({ label: 'Name' }), + account: Field.lookup('account', { label: 'Account' }), + amount: Field.currency({ label: 'Amount' }), + stage: Field.select({ + label: 'Stage', + options: [ + { label: 'Prospecting', value: 'prospecting', color: '#FFA500' }, + { label: 'Qualification', value: 'qualification', color: '#FFD700' }, + { label: 'Proposal', value: 'proposal', color: '#4169E1' }, + { label: 'Closed Won', value: 'closed_won', color: '#00AA00' }, + { label: 'Closed Lost', value: 'closed_lost', color: '#DC143C' }, + ], + }), + probability: Field.percent({ label: 'Probability' }), + close_date: Field.date({ label: 'Close Date' }), + owner: Field.lookup('user', { label: 'Owner' }), + description: Field.textarea({ label: 'Description' }), + }, + + views: { + // Default grid + list: { + type: 'grid', + columns: ['name', 'account', 'amount', 'stage', 'close_date', 'owner'], + sort: [{ field: 'close_date', order: 'asc' }], + searchableFields: ['name', 'account'], + }, + + // Default form + form: { + type: 'simple', + sections: [ + { + label: 'Opportunity Information', + columns: 2, + fields: ['name', 'account', 'amount', 'close_date'], + }, + { + label: 'Stage & Forecast', + columns: 2, + fields: ['stage', 'probability', 'owner'], + }, + { + label: 'Description', + columns: 1, + fields: ['description'], + }, + ], + }, + + // Named views + listViews: { + pipeline: { + type: 'kanban', + columns: ['name', 'amount', 'close_date'], + kanban: { + groupByField: 'stage', + summarizeField: 'amount', + }, + filter: [ + { field: 'stage', operator: 'notIn', value: ['closed_won', 'closed_lost'] }, + ], + }, + + closing_soon: { + type: 'grid', + columns: ['name', 'account', 'amount', 'close_date', 'probability'], + filter: [ + { field: 'close_date', operator: '<=', value: '$30_days_from_now' }, + { field: 'stage', operator: '!=', value: 'closed_won' }, + { field: 'stage', operator: '!=', value: 'closed_lost' }, + ], + sort: [{ field: 'close_date', order: 'asc' }], + }, + }, + }, +}); +``` + +--- + +## Next Steps + +- [Field Types Guide](/docs/guides/field-types) +- [Workflows & Validation](/docs/guides/workflows-validation) +- [Dashboard Configuration](/docs/guides/dashboards) +- [CRM Example](/examples/crm) - See all view types in action From 7b8576e879e665d1df91ebefd25729407d04d002 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:28:38 +0000 Subject: [PATCH 6/6] Update documentation index pages with new guides and architecture Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- content/docs/index.cn.mdx | 45 ++++++++++++++++++++++++++------------- content/docs/index.mdx | 25 +++++++++++++++++----- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/content/docs/index.cn.mdx b/content/docs/index.cn.mdx index b3f1c82..e76466e 100644 --- a/content/docs/index.cn.mdx +++ b/content/docs/index.cn.mdx @@ -1,11 +1,11 @@ --- -title: 欢迎来到 ObjectStack -description: 后 SaaS 时代的元数据驱动协议 +title: 欢迎使用 ObjectStack +description: 后 SaaS 时代的元数据驱动协议。 --- import { Book, Compass, FileText, Layers } from 'lucide-react'; -**ObjectStack** 不仅仅是一个框架;它是构建企业软件的**协议**。 +**ObjectStack** 不仅仅是一个框架;它是一个用于构建企业软件的**协议**。 它将*业务意图*(用 JSON/YAML 定义)与*技术执行*(由内核处理)解耦。 本文档是 ObjectStack 协议的权威参考。 @@ -17,13 +17,13 @@ import { Book, Compass, FileText, Layers } from 'lucide-react'; icon={} title="快速开始" href="/docs/guides/getting-started" - description="5 分钟内构建你的第一个对象。学习 SDK 的基础知识。" + description="5 分钟内构建你的第一个对象。通过实际示例学习基础知识。" /> } title="概念" href="/docs/concepts/manifesto" - description="理解「意图优于实现」的理念和「本地优先」架构。" + description="理解"意图优于实现"和"本地优先"架构的理念。" /> } @@ -35,22 +35,37 @@ import { Book, Compass, FileText, Layers } from 'lucide-react'; icon={} title="协议参考" href="/docs/references/data/core/Object" - description="字典。每个 Schema、字段类型和配置选项的全面参考。" + description="字典。每个模式、字段类型和配置选项的全面参考。" /> -## "三位一体"架构 +## 快速链接 -ObjectStack 建立在三个协同工作的支柱之上: +### 基础指南 +- **[字段类型](/docs/guides/field-types)** - 30+ 种字段类型及示例(文本、数字、选择、查找、公式等) +- **[视图配置](/docs/guides/view-configuration)** - 网格、看板、日历、甘特图和表单布局 +- **[工作流与验证](/docs/guides/workflows-validation)** - 业务规则和自动化 +- **[项目结构](/docs/guides/project-structure)** - 组织代码的最佳实践 -| 支柱 | 协议 | 职责 | +### 示例 +- **[CRM 示例](/examples/crm)** - 全功能应用,包含 6 个对象、工作流、视图、仪表板 +- **[Todo 示例](/examples/todo)** - 快速入门最小化示例 + +## "五位一体"架构 + +ObjectStack 建立在五个协同工作的核心模块之上: + +| 模块 | 协议 | 职责 | | :--- | :--- | :--- | -| **数据层** | **[ObjectQL](/docs/specifications/data/architecture)** | 定义数据的形状(`Object`)以及如何访问它(`AST`)。不依赖于 SQL/NoSQL。 | +| **数据层** | **[ObjectQL](/docs/specifications/data/architecture)** | 定义数据的形状(`Object`、`Field`)以及如何访问它(`Query AST`)。与 SQL/NoSQL 无关。 | +| **UI 层** | **[ObjectUI](/docs/specifications/ui/sdui-protocol)** | 投影层。将用户界面定义为抽象的 JSON 布局(视图、仪表板、操作)。 | | **控制层** | **[ObjectOS](/docs/specifications/server/kernel-architecture)** | 内核。处理身份、安全、同步和自动化。 | -| **视图层** | **[ObjectUI](/docs/specifications/ui/sdui-protocol)** | 投影。将用户界面定义为抽象的 JSON 布局,实现服务器驱动 UI。 | +| **AI 层** | **AI 协议** | AI 代理定义、工具、知识库和模型配置。 | +| **API 层** | **API 协议** | 标准化的 REST/GraphQL 契约,带请求/响应封装。 | -## 这是为谁准备的? +## 适用对象 -* **平台架构师:** 想要构建可扩展的内部开发者平台(IDP)的人。 -* **协议实现者:** 想要为 ObjectQL 编写新驱动程序(例如,用于 FoundationDB)或为 ObjectUI 编写新渲染器(例如,用于 Flutter)的人。 -* **AI 代理开发者:** 需要一种确定性的、结构化的通用语言来让 AI 生成软件的人。 +* **平台架构师:** 想要构建可扩展的内部开发者平台(IDP)。 +* **协议实现者:** 想要为 ObjectQL 编写新的驱动(例如,用于 FoundationDB)或为 ObjectUI 编写新的渲染器(例如,用于 Flutter)。 +* **AI 代理开发者:** 需要一种确定性、结构化的通用语言来让 AI 生成软件。 +* **低代码构建者:** 想要一个强大的元数据驱动平台来快速应用开发。 diff --git a/content/docs/index.mdx b/content/docs/index.mdx index b7a3ccb..39f37b1 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -17,7 +17,7 @@ This documentation is the authoritative reference for the ObjectStack Protocol. icon={} title="Getting Started" href="/docs/guides/getting-started" - description="Build your first Object in 5 minutes. Learn the basics of the SDK." + description="Build your first Object in 5 minutes. Learn the basics with practical examples." /> } @@ -39,18 +39,33 @@ This documentation is the authoritative reference for the ObjectStack Protocol. /> +## Quick Links + +### Essential Guides +- **[Field Types](/docs/guides/field-types)** - 30+ field types with examples (text, number, select, lookup, formula, etc.) +- **[View Configuration](/docs/guides/view-configuration)** - Grid, Kanban, Calendar, Gantt, and Form layouts +- **[Workflows & Validation](/docs/guides/workflows-validation)** - Business rules and automation +- **[Project Structure](/docs/guides/project-structure)** - Best practices for organizing your code + +### Examples +- **[CRM Example](/examples/crm)** - Full-featured application with 6 objects, workflows, views, dashboards +- **[Todo Example](/examples/todo)** - Quick-start minimal example + ## The "Trinity" Architecture -ObjectStack is built on three pillars that work in unison: +ObjectStack is built on five core modules that work in unison: -| Pillar | Protocol | Responsibility | +| Module | Protocol | Responsibility | | :--- | :--- | :--- | -| **Data Layer** | **[ObjectQL](/docs/specifications/data/architecture)** | Defines the shape of data (`Object`) and how to access it (`AST`). Agnostic to SQL/NoSQL. | +| **Data Layer** | **[ObjectQL](/docs/specifications/data/architecture)** | Defines the shape of data (`Object`, `Field`) and how to access it (`Query AST`). Agnostic to SQL/NoSQL. | +| **UI Layer** | **[ObjectUI](/docs/specifications/ui/sdui-protocol)** | The Projection. Defines User Interfaces as abstract JSON layouts (Views, Dashboards, Actions). | | **Control Layer** | **[ObjectOS](/docs/specifications/server/kernel-architecture)** | The Kernel. Handles Identity, Security, Sync, and Automation. | -| **View Layer** | **[ObjectUI](/docs/specifications/ui/sdui-protocol)** | The Projection. Defines the User Interface as abstract JSON layouts, enabling Server-Driven UI. | +| **AI Layer** | **AI Protocol** | AI agent definitions, tools, knowledge bases, and model configurations. | +| **API Layer** | **API Protocol** | Standardized REST/GraphQL contracts with request/response envelopes. | ## For whom is this? * **Platform Architects:** Who want to build internal developer platforms (IDP) that scale. * **Protocol Implementers:** Who want to write a new Driver for ObjectQL (e.g., for FoundationDB) or a new Renderer for ObjectUI (e.g., for Flutter). * **AI Agent Developers:** Who need a deterministic, structured generic language for AI to generate software. +* **Low-Code Builders:** Who want a powerful metadata-driven platform for rapid application development.