Skip to content

Workshop: Blog Platform (2 hours) ​

Build a complete blog platform with content management, user authentication, comments, and SEO optimization. This hands-on workshop demonstrates real-world application development with Orchestre.

Workshop Overview ​

Duration: 2 hours Difficulty: Intermediate Result: Production-ready blog platform

You'll build:

  • πŸ“ Rich text editor with markdown support
  • πŸ‘€ User authentication and profiles
  • πŸ’¬ Nested commenting system
  • πŸ” SEO optimization
  • πŸ“Š Analytics dashboard
  • πŸš€ Deployed to production

Prerequisites ​

  • Orchestre installed
  • Basic web development knowledge
  • 2 hours of focused time

Part 1: Project Setup (15 minutes) ​

Initialize the Blog ​

bash
/create techblog makerkit-nextjs
cd techblog

Initial Planning ​

bash
/orchestrate "Build a modern tech blog with:
- Markdown-based writing with live preview
- Categories and tags
- User profiles with author pages
- Comments with moderation
- SEO optimization for all pages
- RSS feed
- Search functionality"

Configure Environment ​

bash
# Copy environment template
cp .env.example .env.local

# Update with your values
# DATABASE_URL=your-database-url
# NEXTAUTH_SECRET=generate-secret-key

Part 2: Content Management (30 minutes) ​

Data Model ​

bash
/execute-task "Create blog data model with posts, categories, tags, and authors"

This creates:

prisma
model Post {
  id          String    @id @default(cuid())
  slug        String    @unique
  title       String
  excerpt     String?
  content     String    @db.Text
  published   Boolean   @default(false)
  publishedAt DateTime?
  authorId    String
  author      User      @relation(fields: [authorId], references: [id])
  category    Category? @relation(fields: [categoryId], references: [id])
  categoryId  String?
  tags        Tag[]
  comments    Comment[]
  views       Int       @default(0)
  readTime    Int?      // in minutes
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  
  @@index([slug])
  @@index([published, publishedAt])
  @@index([authorId])
}

model Category {
  id    String @id @default(cuid())
  name  String @unique
  slug  String @unique
  posts Post[]
}

model Tag {
  id    String @id @default(cuid())
  name  String @unique
  slug  String @unique
  posts Post[]
}

model Comment {
  id        String    @id @default(cuid())
  content   String
  postId    String
  post      Post      @relation(fields: [postId], references: [id])
  authorId  String
  author    User      @relation(fields: [authorId], references: [id])
  parentId  String?
  parent    Comment?  @relation("CommentReplies", fields: [parentId], references: [id])
  replies   Comment[] @relation("CommentReplies")
  createdAt DateTime  @default(now())
}

Rich Text Editor ​

bash
/execute-task "Create markdown editor with live preview and image upload"

Key features implemented:

  • Markdown toolbar
  • Live preview pane
  • Image drag-and-drop
  • Code syntax highlighting
  • Auto-save draft

Publishing Workflow ​

bash
/execute-task "Implement post publishing workflow with draft, scheduled, and published states"

Part 3: User Features (30 minutes) ​

Author Profiles ​

bash
/execute-task "Create author profile pages with bio, social links, and post list"

Comment System ​

bash
/execute-task "Create nested comment system with real-time updates"

Features:

  • Nested replies
  • Markdown support
  • Edit/delete own comments
  • Moderation queue
  • Real-time updates via WebSocket

User Dashboard ​

bash
/execute-task "Create author dashboard with post management and analytics"

Dashboard includes:

  • Post list with status
  • View statistics
  • Comment notifications
  • Draft management

Part 4: SEO & Performance (30 minutes) ​

SEO Optimization ​

bash
/execute-task "Implement comprehensive SEO with meta tags, schema.org, and sitemap"

Implementation includes:

typescript
// Dynamic meta tags
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)
  
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.featuredImage],
      type: 'article',
      publishedTime: post.publishedAt,
      authors: [post.author.name]
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.excerpt,
      images: [post.featuredImage]
    },
    alternates: {
      canonical: `/blog/${post.slug}`
    }
  }
}

// Schema.org structured data
const articleSchema = {
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
  headline: post.title,
  description: post.excerpt,
  image: post.featuredImage,
  datePublished: post.publishedAt,
  dateModified: post.updatedAt,
  author: {
    '@type': 'Person',
    name: post.author.name,
    url: `/authors/${post.author.username}`
  }
}

Performance Optimization ​

bash
/performance-check
/execute-task "Optimize images, implement lazy loading, and add caching"

Search Implementation ​

bash
/implement-search "Full-text search across posts with filters"

Part 5: Advanced Features (30 minutes) ​

RSS Feed ​

bash
/execute-task "Generate RSS feed for blog posts"

Analytics ​

bash
/execute-task "Add view tracking and reading time analytics"

Categories & Tags ​

bash
/execute-task "Build category and tag pages with post filtering"
bash
/execute-task "Implement related posts algorithm based on tags and content"

Part 6: Deployment (15 minutes) ​

Production Checklist ​

bash
/validate-implementation "blog platform production readiness"

Deploy ​

bash
/deploy-production

Post-Deployment ​

bash
# Verify deployment
/execute-task "Create post-deployment checklist and monitoring"

Complete Code Examples ​

1. Markdown Editor Component ​

typescript
// components/MarkdownEditor.tsx
'use client'

import { useState, useCallback } from 'react'
import dynamic from 'next/dynamic'
import { Button } from '@/components/ui/button'
import { ImageUpload } from './ImageUpload'

const MDEditor = dynamic(
  () => import('@uiw/react-md-editor').then(mod => mod.default),
  { ssr: false }
)

export function MarkdownEditor({ 
  initialValue = '', 
  onChange,
  onSave 
}) {
  const [content, setContent] = useState(initialValue)
  const [saving, setSaving] = useState(false)
  
  const handleImageUpload = useCallback(async (file: File) => {
    const formData = new FormData()
    formData.append('image', file)
    
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData
    })
    
    const { url } = await response.json()
    const imageMarkdown = `![${file.name}](${url})`
    
    setContent(prev => prev + '\n' + imageMarkdown + '\n')
  }, [])
  
  const handleSave = async () => {
    setSaving(true)
    await onSave(content)
    setSaving(false)
  }
  
  return (
    <div className="markdown-editor">
      <div className="toolbar">
        <ImageUpload onUpload={handleImageUpload} />
        <Button 
          onClick={handleSave} 
          disabled={saving}
        >
          {saving ? 'Saving...' : 'Save Draft'}
        </Button>
      </div>
      
      <MDEditor
        value={content}
        onChange={(val) => {
          setContent(val || '')
          onChange?.(val || '')
        }}
        preview="live"
        height={500}
      />
    </div>
  )
}

2. Comment System ​

typescript
// components/Comments.tsx
export function Comments({ postId }) {
  const [comments, setComments] = useState<Comment[]>([])
  const { user } = useAuth()
  
  // Real-time updates
  useEffect(() => {
    const ws = new WebSocket(process.env.NEXT_PUBLIC_WS_URL)
    
    ws.on(`comments:${postId}`, (comment) => {
      setComments(prev => [...prev, comment])
    })
    
    return () => ws.close()
  }, [postId])
  
  const handleSubmit = async (content: string, parentId?: string) => {
    const comment = await createComment({
      postId,
      content,
      parentId
    })
    
    // Optimistic update
    setComments(prev => [...prev, comment])
  }
  
  return (
    <div className="comments">
      <h3>Comments ({comments.length})</h3>
      
      {user && (
        <CommentForm onSubmit={handleSubmit} />
      )}
      
      <CommentList 
        comments={comments}
        onReply={handleSubmit}
      />
    </div>
  )
}

3. SEO Component ​

typescript
// components/SEO.tsx
export function BlogSEO({ post }: { post: Post }) {
  const structuredData = {
    '@context': 'https://schema.org',
    '@type': 'BlogPosting',
    headline: post.title,
    description: post.excerpt,
    image: post.featuredImage,
    datePublished: post.publishedAt,
    dateModified: post.updatedAt,
    author: {
      '@type': 'Person',
      name: post.author.name,
      url: `/authors/${post.author.username}`
    },
    publisher: {
      '@type': 'Organization',
      name: 'TechBlog',
      logo: {
        '@type': 'ImageObject',
        url: '/logo.png'
      }
    },
    mainEntityOfPage: {
      '@type': 'WebPage',
      '@id': `https://techblog.com/blog/${post.slug}`
    }
  }
  
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          __html: JSON.stringify(structuredData)
        }}
      />
    </>
  )
}

Testing Your Blog ​

Create Test Content ​

  1. Create Categories:

    • Technology
    • Tutorials
    • News
  2. Write Test Posts:

    • "Getting Started with Orchestre"
    • "Building Modern Web Apps"
    • "Performance Optimization Tips"
  3. Test Features:

    • [ ] Create and publish post
    • [ ] Upload images
    • [ ] Add comments
    • [ ] Search functionality
    • [ ] RSS feed
    • [ ] Author pages
    • [ ] Category filtering

Extending the Blog ​

Additional Features ​

bash
# Add newsletter
/execute-task "Add newsletter subscription with email campaigns"

# Add social sharing
/execute-task "Add social media sharing buttons with OpenGraph"

# Add code playground
/execute-task "Embed runnable code examples in posts"

# Add series
/execute-task "Create post series feature for multi-part tutorials"

Performance Metrics ​

Expected performance:

  • Lighthouse Score: 95+
  • First Contentful Paint: <1.5s
  • Time to Interactive: <3s
  • SEO Score: 100

Troubleshooting ​

Common Issues ​

  1. Build errors: Check environment variables
  2. Database connection: Verify DATABASE_URL
  3. Image uploads: Check storage permissions
  4. SEO not working: Verify production URL

What You've Built ​

βœ… Full-featured blog platform βœ… Rich content management βœ… User engagement features βœ… SEO optimized βœ… Production deployed

Next Steps ​

Your blog is ready! Consider:

  1. Customize Design: Update theme to match brand
  2. Add Features: Newsletter, podcasts, videos
  3. Monetization: Add subscriptions or ads
  4. Analytics: Integrate advanced analytics
  5. Content: Start writing great content!

Resources ​

Congratulations! You've built a production-ready blog platform in just 2 hours!

Built with ❀️ for the AI Coding community, by Praney Behl