Language / 语言: English · 中文
Manage AI-generated HTML documents the way you manage Markdown notes. Tree-based workspace · Sandboxed live preview · Hot-reload on file change · One-click sharing · Built-in AI authoring · MCP server for agents.
Web-Doc is a self-hosted single-binary application that lets you organize, edit, preview, and share single-page or multi-file HTML documents. Each document lives in its own folder on disk, can be edited via Monaco editor or generated by an LLM with streaming output, and is rendered inside a hardened sandboxed iframe.
- Tree workspace with folders and documents (create / rename / delete / move).
- Drag & drop for reordering siblings and moving items into/out of folders (powered by
dnd-kit). - Single-file documents: paste raw HTML or upload a
.htmlfile. - Multi-file documents: upload a
.zipcontainingindex.htmlplus assets (js/css/images/fonts/...). - Per-document file browser — switch between any file inside a document from the toolbar.
- Monaco code editor with three modes:
Preview·Split·Code.⌘S/Ctrl+Sto save. - Sandboxed iframe preview isolated under a dedicated
/d/{docId}/path with thesandboxattribute. - Live hot-reload: a filesystem watcher (
fsnotify) pushes changes over WebSocket so the preview refreshes automatically whenever any file under a document changes — including streaming writes from AI.
- Streaming generation compatible with the OpenAI Chat Completions protocol — works with OpenAI, DeepSeek, Kimi, Zhipu (GLM), Qwen, OpenRouter and any compatible gateway.
- Configure
Base URL,API Key,Model,System Prompt,Temperature,MaxTokensper user. - Two modes: Generate a new document or rewrite the current document.
- Streamed-to-disk: chunks are written to the document folder in real time and the preview refreshes throttled at ~300 ms.
- AI Chat panel for iterative conversations with the model while editing.
- Reusable prompt templates: create / update / delete personal prompt presets.
- AI-assisted reorganization of the document tree (
/api/nodes/reorder/batchis also exposed for manual batch moves).
- Generate a public share token for any document.
- Clean, distraction-free public preview at
/s/{shareToken}(no app chrome).
- Username / password registration + login with JWT.
- Per-user storage of AI settings, prompts, MCP tokens, and ownership of documents.
- Optional
WEBDOC_DISABLE_REGISTER=1to lock down the instance to existing users.
Web-Doc ships with a built-in Model Context Protocol endpoint, so agents can manage docs programmatically:
| Tool | Purpose |
|---|---|
list_documents |
List the full document tree (flat list with parentId/type). |
get_document |
Get metadata + file manifest of a doc. |
create_document |
Create a new doc or folder (optionally with initial HTML). |
delete_document |
Recursively delete a node. |
read_document_file |
Read any text file inside a doc (default index.html). |
upload_html |
Write/overwrite a single file inside a doc. |
upload_zip_base64 |
Replace the whole doc with a base64-encoded zip. |
The endpoint is JSON-RPC 2.0 over Streamable HTTP at POST /mcp, authenticated by Bearer tokens that users mint from the UI.
- Modern UI with TailwindCSS + shadcn/ui.
- Floating left-side drawer that auto-hides and expands on hover.
- Light, fast, responsive.
web-doc/
├── apps/
│ ├── api/ # Go backend (Gin) — REST + static + filewatch + MCP
│ │ ├── cmd/server/ # main entrypoint
│ │ └── internal/
│ │ ├── ai/ # OpenAI-compatible streaming client
│ │ ├── auth/ # JWT helpers
│ │ ├── config/ # env-driven configuration
│ │ ├── db/ # GORM + Postgres
│ │ ├── handler/ # HTTP handlers (REST, MCP, auth, AI reorder)
│ │ ├── model/ # GORM models + seed
│ │ ├── storage/ # filesystem abstraction (per-doc folder)
│ │ └── watcher/ # fsnotify → WebSocket hub
│ └── web/ # React 19 + Vite + TypeScript SPA
│ └── src/
│ ├── components/ # AIChatPanel, AISettingsDialog, DocTree, DocViewer, ...
│ ├── pages/ # HomePage, SharePage
│ └── store/ # Zustand stores (auth, docs, aiChat)
├── deploy/nginx/ # nginx config for production reverse-proxy
├── storage/docs/ # default document storage root (one folder per doc)
├── docker-compose.full.yml # Postgres + server + nginx
├── Dockerfile # multi-stage build (web + api → single image)
└── package.json # root workspace scripts (concurrently)
Requires Node ≥ 18 and Go ≥ 1.21, plus a running PostgreSQL instance.
# Install deps for the root and the web app
npm run install:all
# Set DB credentials (or rely on defaults: 127.0.0.1:5432 / webdoc / webdoc / webdoc)
export WEBDOC_PG_HOST=127.0.0.1
export WEBDOC_PG_USER=webdoc
export WEBDOC_PG_PASSWORD=webdoc
export WEBDOC_PG_DB=webdoc
# Start API (:8787) and Web (:5173) concurrently
npm run devThen open:
- App: http://localhost:5173
- Document static path:
http://localhost:8787/d/{docId}/index.html - Public share: http://localhost:5173/s/{shareToken}
npm run build # builds web → apps/web/dist, then api → dist/webdoc-server
WEBDOC_WEB_ROOT=$(pwd)/apps/web/dist npm startThe Go server will serve the SPA, the REST API, document static assets, and the MCP endpoint from a single port (default :8787).
docker compose -f docker-compose.full.yml up -dThis brings up:
postgres— PostgreSQL 16server— the Web-Doc Go server (built fromDockerfile, multi-stage)nginx— reverse proxy on:80(configure underdeploy/nginx/)
Document files persist in the docs named volume; the database persists in pgdata.
All configuration is done through environment variables.
| Variable | Default | Description |
|---|---|---|
WEBDOC_ADDR |
:8787 |
Listen address. |
WEBDOC_STORAGE |
../../storage/docs |
Root directory for document folders. |
WEBDOC_WEB_ROOT |
(empty) | If set, the server also serves the SPA from this path (with SPA fallback). |
WEBDOC_ORIGIN |
* |
CORS allow-list (comma-separated; * = allow all). |
WEBDOC_JWT_SECRET |
(insecure default) | Change in production. HMAC secret for JWT. |
WEBDOC_DISABLE_REGISTER |
(unset) | Set to 1 to disable the public registration endpoint. |
WEBDOC_DSN |
(unset) | Full Postgres DSN; if set, overrides the WEBDOC_PG_* variables. |
WEBDOC_PG_HOST |
127.0.0.1 |
Postgres host. |
WEBDOC_PG_PORT |
5432 |
Postgres port. |
WEBDOC_PG_USER |
webdoc |
Postgres user. |
WEBDOC_PG_PASSWORD |
webdoc |
Postgres password. |
WEBDOC_PG_DB |
webdoc |
Postgres database name. |
WEBDOC_PG_SSLMODE |
disable |
Postgres SSL mode. |
WEBDOC_PG_TZ |
UTC |
Postgres timezone. |
Per-document upload size is capped at 50 MB by default (see MaxUploadMB in config.go).
GET /api/auth/public-info— public site info (e.g. whether registration is open).POST /api/auth/register·POST /api/auth/loginGET /api/auth/me— current user (requiresAuthorization: Bearer <jwt>).
GET /api/nodes·POST /api/nodes·GET /api/nodes/:id·PATCH /api/nodes/:id·DELETE /api/nodes/:idPATCH /api/nodes/reorder/batch— drag/drop batch move.
POST /api/docs/:id/html— upload a single.html.POST /api/docs/:id/zip— upload a multi-file.zip.GET /api/docs/:id/file?path=...·POST /api/docs/:id/file— read/save a single file.
POST /api/docs/:id/share— mint a public share token.GET /api/shares/:token— resolve a share token (used by the public page).
GET /api/ai/settings·PATCH /api/ai/settingsPOST /api/ai/generate— streaming generate / rewrite.GET /api/ai/prompts·POST /api/ai/prompts·PATCH /api/ai/prompts/:id·DELETE /api/ai/prompts/:id
GET /api/mcp/tokens·POST /api/mcp/tokens·DELETE /api/mcp/tokens/:idPOST /mcp— JSON-RPC 2.0 endpoint (Bearer auth) for agents.
GET /d/:id/*path— document static assets (sandboxed origin path).GET /ws/docs/:id— WebSocket: pushes change events for live reload.GET /healthz— health check.
| Layer | Tech |
|---|---|
| Frontend | React 19 · Vite · TypeScript · TailwindCSS · shadcn/ui · Zustand · React Router · Monaco Editor · dnd-kit |
| Backend | Go · Gin · GORM · PostgreSQL · fsnotify · gorilla/websocket · JWT |
| Storage | Local filesystem (per-doc folder) + PostgreSQL (metadata, users, AI settings, prompts, MCP tokens) |
| Deploy | Single Go binary · Docker · Docker Compose · Nginx |
- iframe
sandboxattribute strongly isolates user-authored HTML/JS. - Document static assets are served under a dedicated
/d/prefix with directory listing disabled. - Path-traversal protection (
..and absolute paths are rejected on all read/write paths). - Zip-upload extension whitelist (html / js / css / png / jpg / svg / woff2 / ...).
- Per-document upload size limit (default 50 MB).
- JWT-based auth for all write operations; per-user data isolation.
- The default
WEBDOC_JWT_SECRETmust be overridden in any non-development deployment.
See repository for license information.