diff --git a/apps/site/app/blog/[[...slug]]/page.tsx b/apps/site/app/blog/[[...slug]]/page.tsx new file mode 100644 index 00000000..a05c8a7a --- /dev/null +++ b/apps/site/app/blog/[[...slug]]/page.tsx @@ -0,0 +1,237 @@ +import { blogSource } from '@/lib/source'; +import type { Metadata } from 'next'; +import { notFound } from 'next/navigation'; +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import { HomeLayout } from 'fumadocs-ui/home-layout'; +import { baseOptions } from '@/app/layout.config'; +import Link from 'next/link'; + +// Blog listing component +function BlogListing() { + const posts = blogSource.getPages(); + + return ( +
+
+

+ ObjectQL Blog +

+

+ Updates, tutorials, and insights about the standard protocol for AI software generation +

+
+ +
+ {posts + .sort((a, b) => { + const dateA = new Date(a.data.date || 0); + const dateB = new Date(b.data.date || 0); + return dateB.getTime() - dateA.getTime(); + }) + .map((post) => ( +
+ +
+ {post.data.date && ( + + )} + {post.data.authors && ( + by {post.data.authors.join(', ')} + )} +
+ +

+ {post.data.title} +

+ + {post.data.description && ( +

+ {post.data.description} +

+ )} + + {post.data.tags && post.data.tags.length > 0 && ( +
+ {post.data.tags.map((tag) => ( + + {tag} + + ))} +
+ )} + +
+ ))} +
+ + {posts.length === 0 && ( +
+

No blog posts yet. Check back soon!

+
+ )} +
+ ); +} + +// Blog post component +function BlogPost({ page }: { page: ReturnType }) { + if (!page) return null; + + const MDX = page.data.body; + + return ( +
+ + + + + Back to Blog + + +
+

+ {page.data.title} +

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

+ {page.data.description} +

+ )} + +
+ {page.data.date && ( + + )} + {page.data.authors && ( + by {page.data.authors.join(', ')} + )} +
+ + {page.data.tags && page.data.tags.length > 0 && ( +
+ {page.data.tags.map((tag) => ( + + {tag} + + ))} +
+ )} +
+ +
+ +
+ +
+ + + + + Back to Blog + +
+
+ ); +} + +export default async function BlogPage({ + params, +}: { + params: { slug?: string[] }; +}) { + // If no slug, show blog listing + if (!params.slug || params.slug.length === 0) { + return ( + +
+ +
+
+ ); + } + + // Otherwise, show individual blog post + const page = blogSource.getPage(params.slug); + if (!page) notFound(); + + return ( + +
+ +
+
+ ); +} + +export async function generateStaticParams() { + return blogSource.generateParams(); +} + +export function generateMetadata({ params }: { params: { slug?: string[] } }): Metadata { + // Default metadata for blog listing + if (!params.slug || params.slug.length === 0) { + return { + title: 'Blog', + description: 'Updates, tutorials, and insights about the standard protocol for AI software generation', + }; + } + + // Metadata for individual blog post + const page = blogSource.getPage(params.slug); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + }; +} diff --git a/apps/site/app/layout.config.tsx b/apps/site/app/layout.config.tsx index 7b97d640..affc833f 100644 --- a/apps/site/app/layout.config.tsx +++ b/apps/site/app/layout.config.tsx @@ -11,6 +11,11 @@ export const baseOptions: Omit = { url: '/docs', active: 'nested-url', }, + { + text: 'Blog', + url: '/blog', + active: 'nested-url', + }, ], githubUrl: 'https://github.com/objectstack-ai/objectql', // Enable sidebar search diff --git a/apps/site/content/blog/protocol-driven-architecture.mdx b/apps/site/content/blog/protocol-driven-architecture.mdx new file mode 100644 index 00000000..265096b9 --- /dev/null +++ b/apps/site/content/blog/protocol-driven-architecture.mdx @@ -0,0 +1,82 @@ +--- +title: Understanding ObjectQL's Protocol-Driven Architecture +description: A deep dive into how ObjectQL separates intent from implementation through its protocol-driven design. +date: 2026-01-19 +authors: + - ObjectQL Team +tags: + - architecture + - technical + - protocol +--- + +# Understanding ObjectQL's Protocol-Driven Architecture + +One of ObjectQL's core principles is being **Protocol-Driven, Not Code-Driven**. But what does this mean in practice? + +## The Problem with Traditional ORMs + +Traditional ORMs mix two concerns: + +1. **What** you want (the business logic) +2. **How** to achieve it (the implementation details) + +This creates several issues: + +- Tight coupling to specific databases +- Difficulty in testing and mocking +- Hard to optimize queries +- Challenging for AI to generate correctly + +## The ObjectQL Approach + +ObjectQL decouples these concerns through a three-layer architecture: + +### 1. The Intent Layer (YAML Schema) + +```yaml +name: project +fields: + name: + type: text + required: true + status: + type: select + options: [planning, active, completed] +``` + +This layer is **database-agnostic**. It describes what you want, not how to achieve it. + +### 2. The Compilation Layer + +The ObjectQL engine acts as a **compiler**, not a runtime wrapper: + +- Validates schema integrity +- Injects permission checks +- Optimizes query patterns +- Generates type definitions + +### 3. The Driver Layer + +Drivers translate the compiled AST into database-specific operations: + +- `@objectql/driver-sql` → PostgreSQL, MySQL +- `@objectql/driver-mongo` → MongoDB +- `@objectql/driver-sdk` → Remote HTTP APIs + +## Benefits for AI Code Generation + +This architecture makes ObjectQL ideal for AI-driven development: + +✅ **Hallucination-Free**: YAML schemas are validated before compilation +✅ **Type-Safe**: All operations are strongly typed +✅ **Testable**: Mock drivers for testing without a real database +✅ **Portable**: Change databases without rewriting business logic + +## Learn More + +Want to dive deeper? Check out: + +- [Architecture Specification](/docs/reference/spec/architecture) +- [Core Concepts](/docs/modeling/concepts) +- [Driver Development Guide](/docs/reference/api/drivers) diff --git a/apps/site/content/blog/welcome.mdx b/apps/site/content/blog/welcome.mdx new file mode 100644 index 00000000..2e809cef --- /dev/null +++ b/apps/site/content/blog/welcome.mdx @@ -0,0 +1,40 @@ +--- +title: Welcome to ObjectQL Blog +description: Introducing the ObjectQL blog - your source for updates, tutorials, and insights about the standard protocol for AI software generation. +date: 2026-01-20 +authors: + - ObjectQL Team +tags: + - announcement + - getting-started +--- + +# Welcome to the ObjectQL Blog + +We're excited to launch the ObjectQL blog! This is your go-to resource for: + +## What You'll Find Here + +- **Product Updates**: Stay informed about new features, improvements, and releases +- **Technical Deep Dives**: Learn about the architecture and design decisions behind ObjectQL +- **Best Practices**: Discover how to get the most out of ObjectQL in your projects +- **Community Stories**: Hear from developers building with ObjectQL + +## Why ObjectQL? + +ObjectQL represents a fundamental shift in how we approach software development. Instead of writing boilerplate code, you define **intent** through declarative schemas. The framework handles: + +- ✅ Type-safe database schemas +- ✅ Validated CRUD operations +- ✅ Permission enforcement +- ✅ API endpoint generation + +## Getting Started + +If you're new to ObjectQL, check out our [Getting Started Guide](/docs/getting-started) to begin your journey. + +## Stay Connected + +Follow our blog for regular updates, and don't hesitate to [contribute on GitHub](https://github.com/objectstack-ai/objectql) or join our community discussions. + +Happy coding! 🚀 diff --git a/apps/site/lib/source.ts b/apps/site/lib/source.ts index d786824d..911b8bba 100644 --- a/apps/site/lib/source.ts +++ b/apps/site/lib/source.ts @@ -1,4 +1,4 @@ -import { docs, meta } from '@/.source'; +import { docs, meta, blog } from '@/.source'; import { createMDXSource } from 'fumadocs-mdx'; import { loader } from 'fumadocs-core/source'; @@ -6,3 +6,8 @@ export const source = loader({ baseUrl: '/docs', source: createMDXSource(docs, meta), }); + +export const blogSource = loader({ + baseUrl: '/blog', + source: createMDXSource(blog, []), +}); diff --git a/apps/site/source.config.ts b/apps/site/source.config.ts index 0ed039e7..2606dc2c 100644 --- a/apps/site/source.config.ts +++ b/apps/site/source.config.ts @@ -1,4 +1,4 @@ -import { defineDocs, defineConfig } from 'fumadocs-mdx/config'; +import { defineDocs, defineConfig, defineCollections } from 'fumadocs-mdx/config'; import { rehypeCode } from 'fumadocs-core/mdx-plugins'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; @@ -10,6 +10,11 @@ export const { docs, meta } = defineDocs({ dir: 'content/docs', }); +export const blog = defineCollections({ + dir: 'content/blog', + type: 'doc', +}); + export default defineConfig({ mdxOptions: { remarkPlugins: [