ddsite Template Development Guide

AI-friendly guidelines for creating JSON Schema templates

Overview

ddsite uses JSON Schema to define page content. Each template renders the same JSON structure with different visual styles.

For AI: When generating content, output valid JSON that matches the schema below. The frontend will render it using the site's selected template.

Key Concepts

  • Site: A website belonging to a tenant, has one template
  • Page: Content stored as JSON (draft_json / published_json)
  • Template: React components that render JSON into HTML
  • Section: Reusable content blocks (hero, about, services, etc.)

Architecture

┌─────────────────────────────────────────────────────────┐
│                     ddsite Flow                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  User Input ──→ AI Generate ──→ JSON Schema ──→ DB     │
│       │              │              │            │      │
│  "我是美甲店"    Claude API    { hero: {...} }   pages  │
│                                                  table  │
│                                                         │
│  Template ←── JSON Data ←── API ←── Frontend Request   │
│     │              │                                    │
│  restaurant/   published_json                           │
│  hotel/                                                 │
│  salon/                                                 │
│                                                         │
└─────────────────────────────────────────────────────────┘

JSON Schema Structure

Every page follows this base structure:

{
  "meta": {
    "title": "頁面標題 - 用於 SEO",
    "description": "頁面描述 - 用於 SEO",
    "keywords": ["關鍵字1", "關鍵字2"]
  },
  "hero": {
    "title": "主標題",
    "subtitle": "副標題",
    "backgroundImage": "https://...",
    "ctaText": "立即預約",
    "ctaLink": "#contact"
  },
  "sections": [
    {
      "type": "about",
      "props": { ... }
    },
    {
      "type": "services",
      "props": { ... }
    }
  ],
  "footer": {
    "copyright": "© 2024 店名",
    "links": []
  }
}

Field Descriptions

Field Type Status Description
meta Object Optional SEO metadata
hero Object Required Hero section at top of page
sections Array Required Array of content sections
footer Object Optional Footer content

Component Types

Hero Component

{
  "hero": {
    "title": "string",           // Main heading
    "subtitle": "string",        // Subheading
    "backgroundImage": "string", // URL or gradient
    "backgroundOverlay": 0.5,    // 0-1 darkness
    "ctaText": "string",         // Button text
    "ctaLink": "string",         // Button link
    "alignment": "center"        // left | center | right
  }
}

Navigation Component

{
  "nav": {
    "logo": "string",            // Logo URL or text
    "links": [
      { "label": "首頁", "href": "/" },
      { "label": "服務", "href": "#services" },
      { "label": "聯絡", "href": "#contact" }
    ],
    "style": "fixed"             // fixed | static
  }
}

Section Types

About Section

{
  "type": "about",
  "props": {
    "title": "關於我們",
    "content": "店家介紹文字...",
    "image": "https://...",
    "imagePosition": "right"     // left | right
  }
}

Services Section

{
  "type": "services",
  "props": {
    "title": "服務項目",
    "subtitle": "我們提供以下專業服務",
    "items": [
      {
        "icon": "💅",            // Emoji or icon name
        "title": "美甲服務",
        "description": "專業美甲設計",
        "price": "NT$800 起",
        "image": "https://..."
      }
    ],
    "columns": 3                 // 2 | 3 | 4
  }
}

Gallery Section

{
  "type": "gallery",
  "props": {
    "title": "作品集",
    "images": [
      {
        "url": "https://...",
        "alt": "作品描述",
        "caption": "可選標題"
      }
    ],
    "layout": "grid"             // grid | masonry | carousel
  }
}

Testimonials Section

{
  "type": "testimonials",
  "props": {
    "title": "客戶評價",
    "items": [
      {
        "content": "服務很棒!",
        "author": "王小姐",
        "rating": 5,
        "avatar": "https://..."
      }
    ]
  }
}

Contact Section

{
  "type": "contact",
  "props": {
    "title": "聯絡我們",
    "phone": "02-1234-5678",
    "email": "info@example.com",
    "address": "台北市...",
    "hours": "週一至週五 10:00-20:00",
    "mapEmbed": "https://maps.google.com/...",
    "showForm": true,
    "formFields": ["name", "email", "phone", "message"]
  }
}

Features Section

{
  "type": "features",
  "props": {
    "title": "為什麼選擇我們",
    "items": [
      {
        "icon": "⭐",
        "title": "專業認證",
        "description": "10年以上經驗"
      }
    ]
  }
}

CTA Section

{
  "type": "cta",
  "props": {
    "title": "立即預約",
    "subtitle": "享受專屬優惠",
    "buttonText": "線上預約",
    "buttonLink": "#contact",
    "background": "gradient"     // gradient | image | solid
  }
}

Pricing Section

{
  "type": "pricing",
  "props": {
    "title": "價目表",
    "categories": [
      {
        "name": "基礎服務",
        "items": [
          { "name": "單色美甲", "price": "NT$500" },
          { "name": "漸層美甲", "price": "NT$800" }
        ]
      }
    ]
  }
}

FAQ Section

{
  "type": "faq",
  "props": {
    "title": "常見問題",
    "items": [
      {
        "question": "需要預約嗎?",
        "answer": "建議事先預約以確保服務時段。"
      }
    ]
  }
}

Creating a Template

File Structure

shared/templates/
├── base/                    # Base components (shared)
│   ├── Hero.tsx
│   ├── Section.tsx
│   └── Footer.tsx
├── restaurant/              # Restaurant template
│   ├── index.tsx           # Template entry
│   ├── styles.css
│   └── components/
│       ├── MenuSection.tsx
│       └── ReservationCTA.tsx
├── hotel/                   # Hotel template
│   ├── index.tsx
│   └── components/
│       ├── RoomCard.tsx
│       └── AmenitiesGrid.tsx
└── salon/                   # Salon template
    └── ...

Template Entry Point

// shared/templates/salon/index.tsx
import { PageSchema } from '@/types/schema';
import { Hero } from '../base/Hero';
import { SectionRenderer } from '../base/Section';

interface Props {
  data: PageSchema;
}

export default function SalonTemplate({ data }: Props) {
  return (
    <div className="salon-template">
      <Hero {...data.hero} theme="elegant" />

      {data.sections.map((section, i) => (
        <SectionRenderer
          key={i}
          section={section}
          theme="salon"
        />
      ))}

      <Footer {...data.footer} />
    </div>
  );
}

Template Registration

// shared/templates/index.ts
import RestaurantTemplate from './restaurant';
import HotelTemplate from './hotel';
import SalonTemplate from './salon';

export const templates = {
  restaurant: RestaurantTemplate,
  hotel: HotelTemplate,
  salon: SalonTemplate,
} as const;

export type TemplateName = keyof typeof templates;

Complete Examples

Nail Salon Page

{
  "meta": {
    "title": "粉紅指尖美甲工作室 | 專業美甲服務",
    "description": "台北最專業的美甲工作室,提供凝膠美甲、光療指甲等服務"
  },
  "hero": {
    "title": "粉紅指尖",
    "subtitle": "讓指尖綻放專屬於你的美麗",
    "backgroundImage": "https://images.unsplash.com/photo-nail-salon",
    "ctaText": "立即預約",
    "ctaLink": "#contact"
  },
  "sections": [
    {
      "type": "about",
      "props": {
        "title": "關於我們",
        "content": "粉紅指尖成立於2018年,我們相信每個人都值得擁有美麗的指尖...",
        "image": "https://...",
        "imagePosition": "right"
      }
    },
    {
      "type": "services",
      "props": {
        "title": "服務項目",
        "items": [
          {
            "icon": "💅",
            "title": "凝膠美甲",
            "description": "持久亮麗的凝膠指甲",
            "price": "NT$800 起"
          },
          {
            "icon": "✨",
            "title": "光療指甲",
            "description": "快速固化,自然光澤",
            "price": "NT$1,000 起"
          },
          {
            "icon": "💎",
            "title": "指甲彩繪",
            "description": "客製化藝術設計",
            "price": "NT$1,200 起"
          }
        ],
        "columns": 3
      }
    },
    {
      "type": "gallery",
      "props": {
        "title": "作品集",
        "images": [
          { "url": "https://...", "alt": "法式美甲" },
          { "url": "https://...", "alt": "漸層設計" },
          { "url": "https://...", "alt": "季節限定款" }
        ],
        "layout": "grid"
      }
    },
    {
      "type": "testimonials",
      "props": {
        "title": "客戶好評",
        "items": [
          {
            "content": "技術超棒,而且環境很舒適!",
            "author": "Amy",
            "rating": 5
          }
        ]
      }
    },
    {
      "type": "contact",
      "props": {
        "title": "預約諮詢",
        "phone": "02-2345-6789",
        "address": "台北市大安區...",
        "hours": "週二至週日 11:00-20:00",
        "showForm": true
      }
    }
  ],
  "footer": {
    "copyright": "© 2024 粉紅指尖美甲工作室"
  }
}

Hotel Page

{
  "meta": {
    "title": "山水渡假飯店 | 宜蘭頂級住宿",
    "description": "座落於宜蘭山水之間的頂級渡假飯店"
  },
  "hero": {
    "title": "山水渡假飯店",
    "subtitle": "在自然中找到寧靜",
    "backgroundImage": "https://...",
    "backgroundOverlay": 0.4,
    "ctaText": "查看房型",
    "ctaLink": "#rooms"
  },
  "sections": [
    {
      "type": "about",
      "props": {
        "title": "關於山水",
        "content": "山水渡假飯店座落於宜蘭礁溪,擁有絕美山景與溫泉設施..."
      }
    },
    {
      "type": "rooms",
      "props": {
        "title": "精選房型",
        "items": [
          {
            "name": "山景雙人房",
            "description": "180度山景視野",
            "price": "NT$4,800/晚",
            "image": "https://...",
            "amenities": ["免費WiFi", "山景陽台", "迷你吧"]
          },
          {
            "name": "溫泉套房",
            "description": "私人湯屋",
            "price": "NT$6,800/晚",
            "image": "https://...",
            "amenities": ["私人溫泉", "King Size床", "客廳"]
          }
        ]
      }
    },
    {
      "type": "features",
      "props": {
        "title": "飯店設施",
        "items": [
          { "icon": "♨️", "title": "溫泉SPA", "description": "天然碳酸氫鈉泉" },
          { "icon": "🍽️", "title": "景觀餐廳", "description": "在地食材料理" },
          { "icon": "🏊", "title": "無邊際泳池", "description": "俯瞰蘭陽平原" }
        ]
      }
    },
    {
      "type": "contact",
      "props": {
        "title": "訂房資訊",
        "phone": "03-988-1234",
        "email": "booking@shanshui.com",
        "address": "宜蘭縣礁溪鄉...",
        "mapEmbed": "https://maps.google.com/..."
      }
    }
  ]
}

Real Estate Agent Page (個人品牌)

{
  "meta": {
    "title": "陳建宏 | 信義房屋資深經理 | 大安區房產專家",
    "description": "專注大安區房產20年,為您找到理想的家"
  },
  "hero": {
    "title": "陳建宏",
    "subtitle": "您的房產投資最佳夥伴",
    "backgroundImage": "https://images.unsplash.com/photo-1560518883-ce09059eeffa?w=1920",
    "backgroundOverlay": 0.5,
    "ctaText": "立即諮詢",
    "ctaLink": "#contact"
  },
  "sections": [
    {
      "type": "about",
      "props": {
        "title": "關於我",
        "content": "我是陳建宏,從事房地產業已超過20年。專注於台北市大安區、信義區的中高端住宅市場,累積成交超過500件案件,成交總額突破50億。我相信每一位客戶都值得最專業的服務,無論是首購族還是投資客,我都會以同樣的熱忱協助您找到最適合的房產。",
        "image": "https://images.unsplash.com/photo-1560250097-0b93528c311a?w=800",
        "imagePosition": "right"
      }
    },
    {
      "type": "features",
      "props": {
        "title": "我的優勢",
        "items": [
          {
            "icon": "🏆",
            "title": "20年經驗",
            "description": "深耕大安區房產市場,熟悉每一條街道"
          },
          {
            "icon": "📊",
            "title": "500+ 成交",
            "description": "豐富的談判經驗,為您爭取最佳價格"
          },
          {
            "icon": "🤝",
            "title": "誠信服務",
            "description": "透明公開,不隱瞞任何屋況資訊"
          },
          {
            "icon": "📱",
            "title": "全天候服務",
            "description": "隨時為您解答房產相關問題"
          }
        ]
      }
    },
    {
      "type": "services",
      "props": {
        "title": "服務項目",
        "items": [
          {
            "icon": "🏠",
            "title": "買屋服務",
            "description": "根據您的需求,精準配對理想物件,從看屋到交屋全程陪同",
            "image": "https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=600"
          },
          {
            "icon": "💰",
            "title": "賣屋服務",
            "description": "專業估價、精美攝影、多平台曝光,讓您的房產快速成交",
            "image": "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=600"
          },
          {
            "icon": "📈",
            "title": "投資諮詢",
            "description": "分析市場趨勢,提供置產規劃建議,最大化投資報酬",
            "image": "https://images.unsplash.com/photo-1551836022-d5d88e9218df?w=600"
          }
        ],
        "columns": 3
      }
    },
    {
      "type": "gallery",
      "props": {
        "title": "近期成交案例",
        "images": [
          {
            "url": "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=800",
            "alt": "大安區電梯大樓",
            "caption": "大安區|電梯3房|成交價 3,280萬"
          },
          {
            "url": "https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=800",
            "alt": "信義區豪宅",
            "caption": "信義區|景觀4房|成交價 6,800萬"
          },
          {
            "url": "https://images.unsplash.com/photo-1600585154526-990dced4db0d?w=800",
            "alt": "中正區公寓",
            "caption": "中正區|翻新2房|成交價 1,680萬"
          },
          {
            "url": "https://images.unsplash.com/photo-1600573472591-ee6c563aaec9?w=800",
            "alt": "松山區新成屋",
            "caption": "松山區|新成屋|成交價 4,200萬"
          }
        ],
        "layout": "grid"
      }
    },
    {
      "type": "testimonials",
      "props": {
        "title": "客戶見證",
        "items": [
          {
            "content": "建宏經理非常專業,幫我們找到了心目中理想的房子,整個過程都很順利。從看屋到簽約只花了一個月!",
            "author": "林先生 (首購族)",
            "rating": 5
          },
          {
            "content": "賣房的過程比我想像中快很多,建宏幫我把房子拍得很漂亮,兩週就有人出價,最後成交價還超過我的預期。",
            "author": "王太太 (屋主)",
            "rating": 5
          },
          {
            "content": "已經跟建宏經理合作買過三間房了,每次都很滿意。他對市場的判斷很準確,是我信任的房產顧問。",
            "author": "張董 (投資客)",
            "rating": 5
          }
        ]
      }
    },
    {
      "type": "cta",
      "props": {
        "title": "想買房或賣房?",
        "subtitle": "免費諮詢,沒有壓力",
        "buttonText": "LINE 我聊聊",
        "buttonLink": "https://line.me/ti/p/xxxxx",
        "background": "gradient"
      }
    },
    {
      "type": "contact",
      "props": {
        "title": "聯絡方式",
        "phone": "0912-345-678",
        "email": "chen.realtor@example.com",
        "address": "台北市大安區忠孝東路四段100號",
        "hours": "週一至週日 09:00-21:00",
        "showForm": true,
        "formFields": ["name", "phone", "message"],
        "socialLinks": [
          { "platform": "LINE", "url": "https://line.me/ti/p/xxxxx" },
          { "platform": "Facebook", "url": "https://facebook.com/chen.realtor" }
        ]
      }
    }
  ],
  "footer": {
    "copyright": "© 2024 陳建宏 | 信義房屋大安店",
    "links": [
      { "label": "隱私權政策", "href": "/privacy" }
    ]
  }
}

Best Practices

For AI Content Generation

  • Always output valid JSON - use proper escaping for quotes
  • Keep text concise - hero subtitles under 50 characters
  • Use Traditional Chinese (繁體中文) for Taiwan market
  • Include realistic placeholder images from Unsplash
  • Add 3-6 sections for a complete page
  • Always include contact section with business hours

Image Guidelines

  • Hero images: 1920x1080 or 16:9 ratio
  • Gallery images: 800x600 or 4:3 ratio
  • Service icons: Use emoji or icon names
  • Use HTTPS URLs only

Section Order Recommendation

  1. Hero (required)
  2. About / Introduction
  3. Services / Products
  4. Gallery / Portfolio
  5. Testimonials / Reviews
  6. Pricing (if applicable)
  7. FAQ (optional)
  8. CTA (optional)
  9. Contact (required)
Avoid:
  • Duplicate section types (except gallery)
  • Empty arrays or null values
  • External scripts or iframes (except maps)
  • Hardcoded colors in content (use template theme)

API Reference

Get Page Data

GET /api/public/sites/{siteSlug}/pages/{pageSlug}

Response:
{
  "id": 1,
  "slug": "home",
  "title": "首頁",
  "publishedJson": { ... },
  "site": {
    "name": "店名",
    "slug": "site-slug",
    "template": "salon"
  }
}

Update Page (Admin)

PATCH /api/sites/{siteId}/pages/{pageId}
Authorization: Bearer {token}

Body:
{
  "draftJson": { ... }
}

Publish Page

POST /api/sites/{siteId}/pages/{pageId}/publish
Authorization: Bearer {token}

// Copies draftJson to publishedJson

AI Generate Content

POST /api/chatbot/generate
Authorization: Bearer {token}

Body:
{
  "siteId": 1,
  "prompt": "我是一間美甲店,叫做粉紅指尖,位於台北大安區..."
}

Response:
{
  "generatedJson": { ... },
  "previewUrl": "https://..."
}

TypeScript Type Definitions

// types/schema.ts

interface PageSchema {
  meta?: MetaData;
  hero: HeroSection;
  sections: Section[];
  footer?: FooterData;
}

interface MetaData {
  title: string;
  description?: string;
  keywords?: string[];
}

interface HeroSection {
  title: string;
  subtitle?: string;
  backgroundImage?: string;
  backgroundOverlay?: number;
  ctaText?: string;
  ctaLink?: string;
  alignment?: 'left' | 'center' | 'right';
}

interface Section {
  type: SectionType;
  props: Record<string, any>;
}

type SectionType =
  | 'about'
  | 'services'
  | 'gallery'
  | 'testimonials'
  | 'contact'
  | 'features'
  | 'cta'
  | 'pricing'
  | 'faq'
  | 'rooms'      // Hotel specific
  | 'menu';      // Restaurant specific

interface FooterData {
  copyright?: string;
  links?: { label: string; href: string }[];
  socials?: { platform: string; url: string }[];
}