Files
dynamic-sites-simple/README.md
khalid@traclabs.com fdf6124fa1 Add tailwind and shadcn
2026-04-23 07:41:37 -05:00

8.6 KiB

Dynamic Sites

An LLM-powered website editing framework. Edit your site via SMS, a web API, or a visual editor — all driven by natural language.

Architecture

┌─────────────────────────────────────────────────┐
│                  Channels                       │
│   SMS (Vonage)  │  POST /api/edit  │  /editor   │
└───────┬─────────┴────────┬─────────┴─────┬──────┘
        │                  │               │
        ▼                  ▼               ▼
┌─────────────────────────────────────────────────┐
│         Single Container (entrypoint.sh)         │
│                                                  │
│  ┌────────────────────────────────────────────┐  │
│  │  Orchestrator (Express, port 3001)         │  │
│  │                                            │  │
│  │  Webhook ──► Idempotency ──► Rate Limit    │  │
│  │                                            │  │
│  │  ┌──────────────────────────────────────┐  │  │
│  │  │  In-Process FIFO Queue (concurrency 1) │  │
│  │  │  propose: route ► LLM ► proposal     │  │  │
│  │  │  apply:   validate ► writeContentFile│  │  │
│  │  └──────────────────────────────────────┘  │  │
│  │                                            │  │
│  │  SQLite: idempotency, proposals, rate      │  │
│  │          limits, audit log                 │  │
│  └──────────────────┬─────────────────────────┘  │
│                     │ writes canonical JSON       │
│                     ▼                             │
│           ┌──────────────────┐                    │
│           │  content/ (JSON) │  shared filesystem │
│           │  site-context.json│                   │
│           └────────┬─────────┘                    │
│                    │ reads with TTL cache          │
│                    ▼                              │
│  ┌────────────────────────────────────────────┐  │
│  │  Astro SSR (port 4321)                     │  │
│  │  Homepage + Editor                         │  │
│  └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘

Quick Start

Prerequisites

  • Node.js 22+
  • npm
  • A Vonage API account with a Messages API-enabled application

Local Development

# Clone and install
npm install

# Start the Astro dev server (port 4321)
npm run dev

# In another terminal, start the orchestrator (port 3001)
npm run dev:server

# Visit http://localhost:4321 — the demo site renders from fixtures
# Visit http://localhost:4321/editor — log in with API_EDIT_SECRET

Environment Variables

Copy .env.example to .env and set at minimum:

  • API_EDIT_SECRET — shared secret for API auth and editor login
  • OLLAMA_API_KEY — required for LLM-powered edits
  • VONAGE_API_KEY — your Vonage API key (from Dashboard)
  • VONAGE_API_SECRET — your Vonage API secret (from Dashboard)
  • VONAGE_APPLICATION_ID — your Vonage application ID
  • VONAGE_PRIVATE_KEY_PATH — path to the private.key file on disk, or set VONAGE_PRIVATE_KEY to the base64-encoded PEM content
  • VONAGE_API_SIGNATURE_SECRET — webhook signature secret (from Dashboard → API Settings)

See .env.example for all options.

Vonage Setup

  1. Create a Vonage application in the Dashboard with Messages capability enabled.
  2. Set the inbound message webhook URL to https://dynamicsites.kadil.dev/webhooks/inbound (POST).
  3. Set the status webhook URL to https://dynamicsites.kadil.dev/webhooks/status (POST).
  4. Under API Settings, ensure Messages API is set as the default for SMS.
  5. Copy the generated private.key to the project root (or base64-encode it for VONAGE_PRIVATE_KEY).
  6. Note your signature secret from Dashboard → API Settings for webhook verification.

Docker

docker compose build
docker compose up -d
# Site:         http://localhost:4321
# Orchestrator: http://localhost:3001/health

Both the Astro SSR site and the orchestrator run in a single container, sharing the same content/ directory. The entrypoint script starts both processes and seeds content from the image into the volume on first deploy.

Project Structure

├── content/                  # Canonical JSON content (the "database")
│   ├── sections/             # One JSON file per site section
│   ├── events.json           # Upcoming events
│   └── .backups/             # Pre-apply backups (auto-managed)
├── config/
│   └── sms-sites.json        # SMS routing allowlist
├── site-context.json         # Brand tone, style, LLM prompt context
├── shared/                   # Zod schemas + canonical JSON (workspace pkg)
│   └── src/
│       ├── schemas/index.ts  # All Zod schemas (the contract)
│       ├── canonical-json.ts # Sorted-key JSON serialization
│       └── repo-validation.ts# Path → schema mapping
├── server/                   # Orchestrator (workspace pkg)
│   └── src/
│       ├── index.ts          # Entrypoint + graceful shutdown
│       ├── app.ts            # Express app factory
│       ├── db.ts             # SQLite (idempotency, proposals, audit)
│       ├── logger.ts         # Structured logging (pino)
│       ├── queue/            # FIFO queue + job processor
│       ├── routes/           # API edit, SMS webhook, health
│       ├── llm/              # Ollama client with retry/validation
│       ├── sms/              # Vonage parse, reply, templates
│       └── io/               # Filesystem writer (atomic, with backup)
├── src/                      # Astro SSR site
│   ├── pages/
│   │   ├── index.astro       # Homepage (renders from content/)
│   │   └── editor.astro      # Editor (auth-gated React island)
│   ├── lib/
│   │   ├── site-bundle.ts    # Content parser + validator
│   │   └── site-data.ts      # Disk reader with TTL cache
│   ├── layouts/
│   │   └── BaseLayout.astro
│   └── components/
│       ├── sections/         # Astro section components
│       └── editor/           # React editor island
├── scripts/                  # CLI tools
├── Dockerfile                # Combined image (Astro SSR + orchestrator)
├── docker-compose.yml        # Full stack (single service)
└── entrypoint.sh             # Starts both processes + seeds content

Edit Flow

  1. User sends a natural language message (SMS, HTTP, or editor)
  2. Route: LLM determines which content file to edit
  3. Propose: LLM generates new JSON + plain-language summary
  4. Confirm: User replies YES/NO (SMS) or clicks confirm (editor/HTTP)
  5. Apply: Validated JSON is written to disk via atomic write
  6. Live: Astro SSR picks up the change on next request (TTL cache)

Key Design Decisions

  • Single container: Both Astro SSR and the orchestrator run in one container, sharing the filesystem for content reads and writes
  • No Redis, no BullMQ: Simple in-process FIFO queue with concurrency 1
  • No git: Content persistence is filesystem-only
  • SQLite for everything: Idempotency, proposals, rate limits, audit log
  • Zod is the contract: Schemas drive validation at every boundary
  • Atomic writes: temp file + rename prevents partial writes
  • Pre-write backups: Last 20 versions per file under content/.backups/

Shadcn Blocks

  • Pre-built shadcn blocks can be found by running npx shadcn@latest search @shadcnblocks