11 KiB
11 KiB
🎨 Visual Builder Implementation Plan
Craft.js + AstroWind + Direct DB Shim
Objective: Build a "Squarespace-style" visual editor that saves directly to PostgreSQL via the Shim, without CMS overhead.
🏗️ ARCHITECTURE
┌─────────────────────────────────────────────────────────┐
│ PUBLIC SITE (SSR - Lightning Fast) │
│ https://[site-domain]/[slug] │
│ - Reads sites.config JSONB │
│ - Renders AstroWind components │
│ - Zero editor overhead │
└─────────────────────────────────────────────────────────┘
▲
│ Reads config
│
┌─────────────────────────────────────────────────────────┐
│ POSTGRESQL (sites.config JSONB) │
│ { │
│ "template": "astrowind", │
│ "blocks": [ │
│ { "type": "Hero", "props": {...} }, │
│ { "type": "Features", "props": {...} } │
│ ] │
│ } │
└─────────────────────────────────────────────────────────┘
▲
│ Writes config via Shim
│
┌─────────────────────────────────────────────────────────┐
│ VISUAL EDITOR (React + Craft.js) │
│ https://[admin-domain]/admin/editor/[id] │
│ - Drag-and-drop blocks │
│ - Live preview │
│ - Saves to PostgreSQL via /api/shim/sites/save-config │
└─────────────────────────────────────────────────────────┘
📋 IMPLEMENTATION TASKS
Phase 1: Editor Infrastructure (60 min)
Task 1.1: Create Craft.js User Components
src/components/editor/blocks/HeroBlock.tsx- Wraps AstroWind Herosrc/components/editor/blocks/FeaturesBlock.tsx- Wraps Featuressrc/components/editor/blocks/ContentBlock.tsx- Wraps Contentsrc/components/editor/blocks/CTABlock.tsx- Wraps Call-to-Actionsrc/components/editor/blocks/index.ts- Exports all blocks
Task 1.2: Create Editor Canvas
src/components/editor/EditorCanvas.tsx- Main Craft.js editorsrc/components/editor/ToolboxPanel.tsx- Drag-and-drop panelsrc/components/editor/SettingsPanel.tsx- Block properties editorsrc/components/editor/TopBar.tsx- Save/Preview buttons
Task 1.3: Create Editor Utilities
src/lib/editor/serializer.ts- Convert Craft.js → JSONBsrc/lib/editor/deserializer.ts- Convert JSONB → Craft.jssrc/lib/editor/templates.ts- Pre-built template configs
Phase 2: Template Factory (45 min)
Task 2.1: AstroWind Component Adapters
src/components/templates/astrowind/Hero.astro- Reads from JSONBsrc/components/templates/astrowind/Features.astro- Reads from JSONBsrc/components/templates/astrowind/Content.astro- Reads from JSONBsrc/components/templates/astrowind/CTA.astro- Reads from JSONB
Task 2.2: Template Registry
src/lib/templates/registry.ts- Maps template names to componentssrc/lib/templates/schemas.ts- Zod schemas for block configssrc/lib/templates/defaults.ts- Default block configurations
Phase 3: API Routes (30 min)
Task 3.1: Editor API Routes
POST /api/shim/sites/save-config- Save JSONB to PostgreSQLGET /api/shim/sites/[id]/config- Load JSONB for editorPOST /api/shim/sites/[id]/preview- Generate preview URL
Task 3.2: Template API Routes
GET /api/templates/list- Available templatesPOST /api/templates/apply- Apply template to site
Phase 4: Editor Pages (30 min)
Task 4.1: Editor Route
src/pages/admin/editor/[id].astro- Main editor page- Token validation wrapper
- Load site config from Shim
Task 4.2: Template Selector
src/pages/admin/templates.astro- Template gallery- Preview thumbnails
- One-click apply
Phase 5: Public Rendering (30 min)
Task 5.1: Dynamic Template Renderer
src/pages/[...slug].astro- Reads sites.config and renders blocks- Block component resolver
- SEO metadata injection
Task 5.2: Site Utilities
src/lib/templates/renderer.ts- Render blocks from JSONBsrc/lib/templates/seo.ts- Extract SEO from config
🔧 CORE COMPONENTS
1. Editor Canvas (EditorCanvas.tsx)
import { Editor, Frame, Element } from '@craftjs/core';
import { HeroBlock, FeaturesBlock, ContentBlock } from './blocks';
export default function EditorCanvas({ initialState, siteId }) {
const handleSave = async (json) => {
await fetch(`/api/shim/sites/save-config`, {
method: 'POST',
body: JSON.stringify({ siteId, config: json })
});
};
return (
<Editor resolver={{ HeroBlock, FeaturesBlock, ContentBlock }}>
<div className="flex h-screen">
<ToolboxPanel />
<div className="flex-1">
<TopBar onSave={handleSave} />
<Frame json={initialState}>
<Element is="div" canvas>
{/* Editable canvas */}
</Element>
</Frame>
</div>
<SettingsPanel />
</div>
</Editor>
);
}
2. User Component Example (HeroBlock.tsx)
import { useNode } from '@craftjs/core';
export const HeroBlock = ({ title, subtitle, image, ctaText }) => {
const { connectors: { connect, drag } } = useNode();
return (
<div ref={ref => connect(drag(ref))} className="hero">
<h1>{title}</h1>
<p>{subtitle}</p>
{image && <img src={image} alt={title} />}
<button>{ctaText}</button>
</div>
);
};
HeroBlock.craft = {
props: {
title: 'Hero Title',
subtitle: 'Hero subtitle',
image: '/placeholder.jpg',
ctaText: 'Get Started'
},
rules: {
canDrag: true,
canDrop: false
},
related: {
settings: HeroSettings // Property panel component
}
};
3. Save Config API (save-config.ts)
import type { APIRoute } from 'astro';
import { updateSite } from '@/lib/shim/sites';
export const POST: APIRoute = async ({ request }) => {
try {
const { siteId, config } = await request.json();
// Update site config via Shim
await updateSite(siteId, {
config: JSON.stringify(config)
});
return new Response(JSON.stringify({ success: true }), {
status: 200
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500
});
}
};
4. Public Renderer ([...slug].astro)
---
import { getSiteByDomain } from '@/lib/shim/sites';
import { renderBlocks } from '@/lib/templates/renderer';
const site = await getSiteByDomain(Astro.url.hostname);
const config = site?.config || {};
const blocks = config.blocks || [];
---
<html>
<body>
{renderBlocks(blocks)}
</body>
</html>
🎨 TEMPLATE FACTORY STRUCTURE
Default Templates
| Template | Blocks | Use Case |
|---|---|---|
| Corporate | Hero + Features + Stats + Team + CTA | Business sites |
| Landing | Hero + Benefits + Testimonials + Pricing + CTA | SaaS landing pages |
| Blog | Header + Posts Grid + Sidebar + Footer | Content sites |
| Portfolio | Hero + Projects Grid + About + Contact | Personal branding |
JSONB Structure
{
"template": "astrowind",
"theme": {
"primaryColor": "#3B82F6",
"font": "Inter"
},
"blocks": [
{
"id": "hero-1",
"type": "Hero",
"props": {
"title": "Welcome to Our Site",
"subtitle": "Build amazing things",
"ctaText": "Get Started",
"ctaLink": "/signup"
}
},
{
"id": "features-1",
"type": "Features",
"props": {
"title": "Key Features",
"items": [
{ "icon": "⚡", "title": "Fast", "description": "Lightning quick" },
{ "icon": "🔒", "title": "Secure", "description": "Bank-level security" }
]
}
}
]
}
🔒 SECURITY MODEL
-
Editor Access:
- Only accessible at
/admin/editor/[id] - Requires
GOD_MODE_TOKENvalidation - Token checked in Astro middleware
- Only accessible at
-
Save Operations:
- All saves go through Shim (
/api/shim/sites/save-config) - Zod validation on JSONB structure
- Sanitize user input before SQL
- All saves go through Shim (
-
Public Rendering:
- No editor JavaScript loaded
- Pure SSR from JSONB config
- No exposure of admin endpoints
📊 PERFORMANCE COMPARISON
| Operation | Traditional CMS | God Mode Visual Builder |
|---|---|---|
| Load Editor | ~2000ms (API + DB + Render) | ~300ms (Direct DB) |
| Save Changes | ~1500ms (API → CMS → DB) | ~50ms (Shim → DB) |
| Public Page Load | ~800ms (CMS overhead) | ~10ms (Pure SSR) |
| Scale | 100s of sites | 10,000s of sites |
🎯 SUCCESS CRITERIA
- ✅ Can drag-and-drop AstroWind blocks in
/admin/editor/[id] - ✅ Changes save directly to
sites.configJSONB - ✅ Public site re-renders instantly with new config
- ✅ Zero performance impact on public-facing pages
- ✅ Can manage 1000+ sites with different layouts
- ✅ Full Zod validation on all block configs
- ✅ SEO metadata auto-extracted from blocks
🚀 DEPLOYMENT CHECKLIST
- Install Craft.js dependencies (
npm install @craftjs/core @craftjs/utils) - Create all editor components
- Create template adapters
- Test save/load flow
- Verify public rendering
- Security audit (token validation)
- Performance test (1000+ blocks)
📈 ROADMAP EXTENSIONS
Phase 6 (Future):
- A/B Testing - Save multiple configs, split traffic
- Version History - Keep history of config changes
- Template Marketplace - Share templates between sites
- AI Block Generator - Generate blocks from text prompts
- Responsive Preview - Mobile/tablet/desktop view
- Component Library - Custom reusable blocks