From 93865a1b8c31d404561da88c4221de502da19d43 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:09:02 +0000 Subject: [PATCH 01/10] Initial plan From 650c6f2cd6fa2daeb508cc0f51609dfc4a653eb2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:15:21 +0000 Subject: [PATCH 02/10] Fix homepage font colors for better readability Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- apps/docs/app/[lang]/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/docs/app/[lang]/page.tsx b/apps/docs/app/[lang]/page.tsx index 48b42fa28..5e9ce3d09 100644 --- a/apps/docs/app/[lang]/page.tsx +++ b/apps/docs/app/[lang]/page.tsx @@ -27,10 +27,10 @@ export default async function HomePage({ {t.hero.title.line1}
{t.hero.title.line2} -

+

{t.hero.subtitle.line1}
- {t.hero.subtitle.line2} + {t.hero.subtitle.line2}

@@ -124,7 +124,7 @@ export default async function HomePage({ {/* Personas Section */}
-

+

{t.personas.heading}

@@ -166,7 +166,7 @@ function FeatureCard({ icon, title, description, href }: { icon: React.ReactNode

{title}

-

+

{description}

@@ -188,7 +188,7 @@ function PersonaCard({ icon, title, description, href, action }: { icon: React.R {icon}

{title}

-

+

{description}

From 8e71906f18dc4ba1f8167fd33d041c866486d4e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:17:25 +0000 Subject: [PATCH 03/10] Changes before error encountered Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- apps/docs/app/source.ts | 7 +- apps/docs/source.config.ts | 14 ++++ content/blog/welcome.mdx | 38 +++++++++ content/blog/zod-first-design.mdx | 128 ++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 content/blog/welcome.mdx create mode 100644 content/blog/zod-first-design.mdx diff --git a/apps/docs/app/source.ts b/apps/docs/app/source.ts index 82838edb5..ed823c2c8 100644 --- a/apps/docs/app/source.ts +++ b/apps/docs/app/source.ts @@ -1,4 +1,4 @@ -import { docs } from 'fumadocs-mdx:collections/server'; +import { docs, blog as blogCollection } from 'fumadocs-mdx:collections/server'; import { loader } from 'fumadocs-core/source'; import { i18n } from '@/lib/i18n'; @@ -7,3 +7,8 @@ export const source = loader({ i18n, source: (docs as any).toFumadocsSource(), }); + +export const blog = loader({ + baseUrl: '/blog', + source: (blogCollection as any).toFumadocsSource(), +}); diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index a4cae9999..95750ad40 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -1,7 +1,21 @@ import { defineDocs, defineConfig } from 'fumadocs-mdx/config'; +import { z } from 'zod'; export const docs = defineDocs({ dir: '../../content/docs', }) as any; +export const blog = defineDocs({ + dir: '../../content/blog', + docs: { + schema: (ctx) => { + return ctx.schema.extend({ + author: z.string().optional(), + date: z.string().date().or(z.date()).optional(), + tags: z.array(z.string()).optional(), + }); + }, + }, +}) as any; + export default defineConfig(); diff --git a/content/blog/welcome.mdx b/content/blog/welcome.mdx new file mode 100644 index 000000000..25bcaffe6 --- /dev/null +++ b/content/blog/welcome.mdx @@ -0,0 +1,38 @@ +--- +title: Welcome to ObjectStack Blog +description: Introducing the ObjectStack Protocol blog - your source for updates, insights, and best practices. +author: ObjectStack Team +date: 2024-01-15 +tags: [announcement, introduction] +--- + +# Welcome to ObjectStack Blog + +We're excited to launch the official ObjectStack Protocol blog! This is your go-to resource for: + +## What You'll Find Here + +- **Protocol Updates**: Stay informed about the latest changes and improvements to the ObjectStack Protocol +- **Technical Deep Dives**: Detailed explorations of protocol components and implementation strategies +- **Best Practices**: Learn how to effectively use ObjectStack in your projects +- **Community Highlights**: Showcasing amazing projects built with ObjectStack +- **AI Integration**: Tips for using ObjectStack with LLMs and AI-powered development + +## Why ObjectStack? + +The ObjectStack Protocol is designed to be the **universal language** for metadata-driven applications. Whether you're building: + +- Internal developer platforms (IDP) +- Low-code/no-code solutions +- AI-powered applications +- Multi-tenant SaaS platforms + +ObjectStack provides a **Zod-first**, **database-agnostic**, and **AI-native** foundation for your project. + +## Stay Connected + +Follow our blog for regular updates, tutorials, and insights from the ObjectStack community. We're just getting started! + +--- + +*Have questions or feedback? Join our [GitHub Discussions](https://github.com/objectstack-ai/spec/discussions) or open an [issue](https://github.com/objectstack-ai/spec/issues).* diff --git a/content/blog/zod-first-design.mdx b/content/blog/zod-first-design.mdx new file mode 100644 index 000000000..28f4d21ca --- /dev/null +++ b/content/blog/zod-first-design.mdx @@ -0,0 +1,128 @@ +--- +title: Understanding Zod-First Protocol Design +description: Learn why ObjectStack chose Zod as the foundation for protocol definitions and how it benefits your development workflow. +author: ObjectStack Team +date: 2024-01-18 +tags: [zod, typescript, protocol, technical] +--- + +# Understanding Zod-First Protocol Design + +One of the core principles of ObjectStack is **Zod-First** design. But what does that mean, and why is it important? + +## What is Zod? + +[Zod](https://zod.dev/) is a TypeScript-first schema declaration and validation library. It allows you to: + +- Define schemas with full TypeScript type inference +- Validate data at runtime +- Generate JSON Schema for documentation +- Create parsers and transformers + +## Why Zod-First? + +ObjectStack Protocol uses Zod as the single source of truth for all definitions. This approach provides several key benefits: + +### 1. Runtime Validation + +```typescript +import { ObjectProtocol } from '@objectstack/spec'; + +export const User = ObjectProtocol.define({ + name: 'user', + fields: { + email: Field.text({ required: true }), + age: Field.number({ min: 0, max: 150 }), + } +}); + +// Runtime validation happens automatically +``` + +### 2. Static Type Inference + +Because everything is defined in Zod, TypeScript can infer types directly from your schemas: + +```typescript +type UserType = z.infer; +// No need to maintain separate type definitions! +``` + +### 3. JSON Schema Generation + +Zod schemas can be automatically converted to JSON Schema, making them: +- **Documentable**: Auto-generate API documentation +- **Interoperable**: Work with any language/tool that supports JSON Schema +- **AI-Friendly**: LLMs can understand and work with JSON Schema + +### 4. Single Source of Truth + +With Zod-First design, you define your protocol once and get: +- Runtime validation ✅ +- TypeScript types ✅ +- JSON Schema ✅ +- IDE autocomplete ✅ +- Error messages ✅ + +## Real-World Example + +Here's how a complete Object definition looks: + +```typescript +import { z } from 'zod'; +import { ObjectProtocol, Field } from '@objectstack/spec'; + +export const ProjectTaskSchema = ObjectProtocol.define({ + name: 'project_task', + label: 'Project Task', + fields: { + title: Field.text({ + required: true, + maxLength: 255 + }), + status: Field.select({ + options: ['todo', 'in_progress', 'done'], + default: 'todo' + }), + assignee: Field.lookup({ + reference: 'user', + multiple: false + }), + due_date: Field.date({ required: false }), + priority: Field.number({ + min: 1, + max: 5, + default: 3 + }), + }, + enable: { + trackHistory: true, + apiEnabled: true, + } +}); + +// TypeScript type is automatically inferred +type ProjectTask = z.infer; +``` + +## Benefits for AI Development + +Zod-First design makes ObjectStack incredibly **AI-friendly**: + +1. **Deterministic Schema**: LLMs can reliably generate valid ObjectStack definitions +2. **JSON Schema Output**: AI agents can understand the structure through standardized JSON Schema +3. **Validation Feedback**: Runtime validation provides clear error messages for AI to learn from + +## Conclusion + +Zod-First protocol design is not just a technical choice—it's a philosophy that prioritizes: +- **Developer Experience**: Write once, use everywhere +- **Type Safety**: Catch errors at compile time and runtime +- **Interoperability**: Work with any tool that understands JSON Schema +- **AI Integration**: Enable seamless AI-powered development + +Ready to dive deeper? Check out our [Schema Definition Guide](/docs/specifications/data/schema-definition) for more details. + +--- + +*Questions? Join the discussion on [GitHub](https://github.com/objectstack-ai/spec/discussions).* From dee0344adddad3bc08cadb9d8fdc9af65452c908 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:43:13 +0000 Subject: [PATCH 04/10] Add blog section with fumadocs integration Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- .../docs/app/[lang]/blog/[[...slug]]/page.tsx | 186 ++++++++++++++++++ apps/docs/app/layout.config.tsx | 5 + apps/docs/source.config.ts | 16 +- 3 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 apps/docs/app/[lang]/blog/[[...slug]]/page.tsx diff --git a/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx b/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx new file mode 100644 index 000000000..206518aa3 --- /dev/null +++ b/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx @@ -0,0 +1,186 @@ +import { notFound } from 'next/navigation'; +import { blog } from '@/app/source'; +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/app/layout.config'; +import Link from 'next/link'; +import { ArrowLeft } from 'lucide-react'; + +export default async function BlogPage({ + params, +}: { + params: Promise<{ lang: string; slug?: string[] }>; +}) { + const { slug } = await params; + + // If no slug, show blog index + if (!slug || slug.length === 0) { + const posts = blog.getPages(); + + return ( + +
+
+

Blog

+

+ Insights, updates, and best practices from the ObjectStack team. +

+
+ +
+ {posts.map((post) => ( + +
+

+ {post.data.title} +

+ {post.data.description && ( +

+ {post.data.description} +

+ )} +
+ +
+ {post.data.date && ( + + )} + {post.data.author && ( + By {post.data.author} + )} +
+ + {post.data.tags && post.data.tags.length > 0 && ( +
+ {post.data.tags.map((tag: string) => ( + + {tag} + + ))} +
+ )} + + ))} +
+ + {posts.length === 0 && ( +
+

No blog posts yet. Check back soon!

+
+ )} +
+
+ ); + } + + // Show individual blog post + const page = blog.getPage(slug); + + if (!page) { + notFound(); + } + + const MDX = page.data.body; + + return ( + +
+ + + Back to Blog + + +
+
+

{page.data.title}

+ + {page.data.description && ( +

+ {page.data.description} +

+ )} + +
+ {page.data.date && ( + + )} + {page.data.author && ( + By {page.data.author} + )} +
+ + {page.data.tags && page.data.tags.length > 0 && ( +
+ {page.data.tags.map((tag: string) => ( + + {tag} + + ))} +
+ )} +
+ + +
+
+
+ ); +} + +export async function generateStaticParams() { + return blog.getPages().map((page) => ({ + slug: page.slugs, + })); +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ slug?: string[] }>; +}) { + const { slug } = await params; + + // If no slug, return default metadata for blog index + if (!slug || slug.length === 0) { + return { + title: 'Blog', + description: 'Insights, updates, and best practices from the ObjectStack team.', + }; + } + + const page = blog.getPage(slug); + + if (!page) { + notFound(); + } + + return { + title: page.data.title, + description: page.data.description, + }; +} diff --git a/apps/docs/app/layout.config.tsx b/apps/docs/app/layout.config.tsx index 424eaa4d0..231f6ca15 100644 --- a/apps/docs/app/layout.config.tsx +++ b/apps/docs/app/layout.config.tsx @@ -22,6 +22,11 @@ export const baseOptions: BaseLayoutProps = { url: '/docs/', active: 'nested-url', }, + { + text: 'Blog', + url: '/blog', + active: 'nested-url', + }, // { // text: 'Concepts', // url: '/docs/concepts/manifesto', diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index 95750ad40..892181cc7 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -1,4 +1,4 @@ -import { defineDocs, defineConfig } from 'fumadocs-mdx/config'; +import { defineDocs, defineConfig, frontmatterSchema } from 'fumadocs-mdx/config'; import { z } from 'zod'; export const docs = defineDocs({ @@ -7,15 +7,11 @@ export const docs = defineDocs({ export const blog = defineDocs({ dir: '../../content/blog', - docs: { - schema: (ctx) => { - return ctx.schema.extend({ - author: z.string().optional(), - date: z.string().date().or(z.date()).optional(), - tags: z.array(z.string()).optional(), - }); - }, - }, + schema: frontmatterSchema.extend({ + author: z.string().optional(), + date: z.string().or(z.date()).optional(), + tags: z.array(z.string()).optional(), + }), }) as any; export default defineConfig(); From e1063f6a4e22ad3f14627210c0b49f74b6b40f25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:45:39 +0000 Subject: [PATCH 05/10] Fix blog schema validation for date field Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- apps/docs/source.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index 892181cc7..2e705c2b1 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -9,7 +9,7 @@ export const blog = defineDocs({ dir: '../../content/blog', schema: frontmatterSchema.extend({ author: z.string().optional(), - date: z.string().or(z.date()).optional(), + date: z.string().date().optional(), tags: z.array(z.string()).optional(), }), }) as any; From 929b5b30bdd5e4ee970ace8a77767e6c6827a3da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 05:47:47 +0000 Subject: [PATCH 06/10] Apply consistent font color improvements to blog pages Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- apps/docs/app/[lang]/blog/[[...slug]]/page.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx b/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx index 206518aa3..bcea85046 100644 --- a/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/blog/[[...slug]]/page.tsx @@ -22,7 +22,7 @@ export default async function BlogPage({

Blog

-

+

Insights, updates, and best practices from the ObjectStack team.

@@ -39,13 +39,13 @@ export default async function BlogPage({ {post.data.title} {post.data.description && ( -

+

{post.data.description}

)}
-
+
{post.data.date && (