On this page
8. Backend & API
The API is a classic Express server. All routes are mounted in apps/api/src/index.ts.
8.1 Public Demo Endpoints (no auth, stateless mode compatible)#
| Method | Path | Limit | Purpose |
|---|---|---|---|
| GET | /health | — | Status check (db, LLM availability) |
| POST | /api/generate | 10/min/IP | Markdown → HTML (full pipeline) |
| POST | /api/validate | 10/min/IP | Validate MD without render |
| GET | /api/templates | — | List of starter templates |
| POST | /api/convert | 5/min/IP | DOCX/PDF/… → Markdown |
| POST | /api/convert/code-to-mermaid | 5/min/IP | ASCII → Mermaid DSL via LLM |
8.2 Auth Endpoints#
| Method | Path | Limit | Auth | Purpose |
|---|---|---|---|---|
| POST | /api/auth/register | 5/h/IP | no | Create account (argon2id) |
| POST | /api/auth/login | 10/15min/IP | no | Create session (connect.sid) |
| POST | /api/auth/logout | — | yes | Destroy session |
| GET | /api/auth/me | — | yes | Current user |
8.3 Protected Endpoints (all require auth + DB)#
Projects:
GET /api/projects— ListPOST /api/projects— New project (Limit: 10 per user)PATCH /api/projects/:id— Update (name, designPack, languages, projectType, docsConfig, componentVariants)DELETE /api/projects/:id,POST /api/projects/:id/duplicate
Pages (nested under projects):
GET /api/projects/:projectId/pages— ListGET /api/projects/:projectId/pages/manifest— Lightweight (for Sidebar)POST /api/projects/:projectId/pages— New pageGET/PATCH/DELETE /api/projects/:projectId/pages/:pageIdPOST .../duplicate,PATCH /api/projects/:projectId/pages/reorderPOST .../generate— the main action: renders the pagePOST .../export— multi-language static export for Deploy
Translations:
GET/POST/PATCH/DELETE /api/projects/:projectId/pages/:pageId/translations[/:lang]POST .../translate— Trigger LLM Translation
Media:
POST /api/projects/:projectId/media— Upload (multipart, max 100 Assets/Project)GET /api/projects/:projectId/media— ListPATCH/DELETE .../media/:assetIdPOST .../media/upload-url— Presigned R2-URL
Deploy & Domain:
POST /api/projects/:projectId/deploy— Cloudflare-Push (Cooldown: 60s)GET .../deployments[/:id]— List/DetailPOST .../deployments/:id/rollbackPOST/GET/DELETE .../domain— Custom Domain ManagementGET .../analytics?range=7d|30d|90d— Cloudflare-Zone-Stats
Public Media-Serving:
GET /api/media/:projectId/:filename— 100/min/IP (for Preview-Iframes + Deploys)
8.4 Auth-Flow in Detail#
- Session-Storage: in-memory
MemoryStorein stateless mode;connect-pg-simplewith thesessionstable ifDATABASE_URLis set - Cookie:
connect.sid(httpOnly, sameSite=lax, maxAge 7 days) - Password Hashing: argon2id, memoryCost 65536, timeCost 3, parallelism 1
- Middlewares:
requireAuth(401 if no session),optionalAuth(User if present, otherwise continue)
8.5 Services — the Pipeline Layer#
| Service | Purpose |
|---|---|
llm-client.ts | OpenAI-SDK to OpenRouter; capture'd Node-Native-Fetch (against JSDOM-Globals) |
llm-service.ts | Mapper-Prompt-Wrapper, Cache via mdHash in llm_cache table |
auto-detect-pipeline.ts | sanitize → sectionize → detect → extract → validate (Default for Landing-Pages) |
docs-pipeline.ts | Alternative path for layout: docs-pages (TOC, Sidebar, Article-Flow) |
deterministic-mapper.ts | LLM-Fallback if OPENROUTER_API_KEY is not set |
mermaid-ssr.ts | JSDOM-Pre-Render of Mermaid-Fences to inline SVG |
code-to-mermaid.ts | ASCII → Mermaid DSL (Sonnet 4.5) |
translation-engine.ts | Markdown-Translate (Gemini Flash) |
lang-detect.ts | Language-Auto-Detection (franc-min) |
deploy-engine.ts | Cloudflare-Pages-Integration |
media-storage.ts | Local FS / Cloudflare R2 with presigned-URLs |
media-cleanup.ts | Cron-Job for orphaned uploads |
custom-domain.ts | DNS-Validation + Zone-Sync |
analytics.ts | Cloudflare-Zone-Analytics-Pull |