First cut
This commit is contained in:
144
README.md
144
README.md
@@ -1,2 +1,144 @@
|
||||
# dynamic-sites-simple
|
||||
# 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 (Telnyx) │ POST /api/edit │ /editor │
|
||||
└───────┬─────────┴────────┬─────────┴─────┬──────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ 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 volume
|
||||
│ site-context.json│
|
||||
└────────┬─────────┘
|
||||
│ reads with TTL cache
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Astro SSR │
|
||||
│ (port 4321) │
|
||||
│ Homepage + Editor│
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 22+
|
||||
- npm
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
See `.env.example` for all options.
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
# Site: http://localhost:4321
|
||||
# Orchestrator: http://localhost:3001/health
|
||||
```
|
||||
|
||||
## 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/ # Telnyx 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
|
||||
├── docker-compose.yml # Full stack (web + orchestrator)
|
||||
├── Dockerfile # SSR site image
|
||||
└── server/Dockerfile # Orchestrator image
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
- **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/`
|
||||
|
||||
Reference in New Issue
Block a user