Documentation
Documentation site operations
Run the Astro site, maintain API and search content, export Markdown, configure assistant bindings, and understand the local Studio boundary.
Site architecture
packages/web is an Astro server-output application with the Cloudflare adapter. Documentation articles declare prerendering and become static HTML assets. Server routes handle Markdown export, documentation assistant requests, artifact viewing/raw content, and the production Studio fallback. This deployment is separate from the CAD/CAM sidecar.
The documentation site describes application behavior and supplies generated reference content. It does not inherit a visitor's projects, local application bearer token, provider credentials, or paired desktop connection. Its assistant uses documentation excerpts rather than silently operating the CAD/CAM workspace.
The local Studio is an additional Bun process because it uses bun:sqlite. Vite proxies its development API requests to loopback port 4396. A deployed Cloudflare Worker cannot open that local database; the production Studio API deliberately explains this with HTTP 503.
Local commands
bun run --filter @cadcamfun/web start
bun run --filter @cadcamfun/web dev
bun run --filter @cadcamfun/web studio
bun test packages/web/test
bun run --filter @cadcamfun/web typecheck
bun run --filter @cadcamfun/web build | Command | Process or output |
|---|---|
start | Astro development server only. Use the address printed in the terminal. |
dev | Studio Bun process plus Astro. Its launcher stops the child processes when the main development process exits. |
studio | Only the local Studio API on loopback port 4396. |
typecheck | TypeScript and content integrity checks configured in this workspace. |
build | Production Worker output and prerendered assets under packages/web/dist. |
Use Astro alone for article editing when Studio is unnecessary. Production compilation validates template generation and route output but does not call a real model backend, publish artifacts, or verify a deployed Cloudflare account.
Content and API generation
Articles live in src/pages/docs and share DocsLayout.astro. The sidebar in src/data/docsSidebar.ts is the documentation route inventory. docsIndex.ts adds per-route summaries and keywords for retrieval. A public page should have both a navigation entry and accurate retrieval copy; an unlinked article does not become discoverable merely because its file exists.
The API reference combines a generated contract snapshot with curated resource grouping in src/data/apiGroups.ts. src/lib/apiReference.ts selects every operation, resolves named schemas, and supplies the resource templates. The snapshot is generated from the composed application HttpApi using its installed Effect implementation.
bun run generate:api-reference
bun run check:api-reference
bun run check:docs-index
bun test test Regeneration writes the current schema contract; it does not write domain guidance or prove that a remote application is on the same version. Handwritten pages explain business validation, side effects, permissions, recovery, and implementation limits. Keep those explanations tied to the actual handlers and services.
Source-reading notes can be prepared under packages/web/.tmp/content. They are temporary editorial material, excluded from publication. Move finished explanations into article pages and update navigation/retrieval; do not use a temporary note as the only documentation for an operation.
Markdown export
GET /llm lists known documentation pages as Markdown links. With path, it fetches the corresponding rendered article and converts it to GitHub-flavored Markdown. Adding format=prompt wraps that content in an instruction prompt that includes its canonical source.
curl "$DOCS_ORIGIN/llm"
curl "$DOCS_ORIGIN/llm?path=/docs/cam"
curl "$DOCS_ORIGIN/llm?path=/docs/api/projects&format=prompt" The pipeline reads only the article marked data-llm-document. It removes excluded content, scripts, styles, SVG decoration, and buttons so navigation and copy controls do not become answer context. It converts code blocks, headings, tables, and links rather than maintain a second handwritten Markdown corpus.
Only known documentation paths are admitted. Unknown paths return 404. A page-loading failure returns 502; another conversion failure returns 500. The response is Markdown with permissive read CORS and a public five-minute cache policy with stale-while-revalidate. These exported public articles do not contain local project credentials.
On Cloudflare, the helper prefers the ASSETS binding for prerendered pages. This keeps the read within the Worker deployment. Development can fall back to live fetching when the existing asset build does not contain a page. A stale local dist tree and a current source tree can therefore be different inputs while editing.
Documentation assistant
POST /api/docs-assistant accepts conversation messages, an optional documentation path, and an optional backend session identifier. It keeps only user/assistant messages, trims each message to 1,200 characters, retains the most recent 12 valid messages, and requires a user question.
Retrieval first scores the current question and earlier user questions against titles, routes, keywords, and summaries. The current known page is retained. When a Workers AI binding is available, an optional tool-call planner can select relevant documentation routes; invalid selections or planner failures fall back to lexical retrieval.
Up to three pages are loaded. Each is condensed to a 5,000-character budget by retaining its introduction and matching sections. A long API resource page is therefore not automatically supplied in full to the model. Link the user to the relevant operation when the excerpt does not contain enough detail.
Loaded Markdown is cached separately for 30 minutes when the Worker cache is available. A source edit can require cache refresh in an already-running deployment. If no selected page can be loaded, the route returns 502. If no Workers AI binding or complete nikcli backend configuration exists, it returns 503 before generation.
A single assistant request may carry at most 12 conversation messages, and a question is limited to 1,200 characters (MAX_MESSAGES and MAX_QUESTION_CHARS in src/lib/docsAssistant.ts).
Models and rate limits
| Binding or setting | Role |
|---|---|
AI | Workers AI model execution for planning, answers, and optional richer guide rendering. |
DOCS_ASSISTANT_MODEL | Answer/planning model; defaults to @cf/meta/llama-3.1-8b-instruct-fast in the route. |
DOCS_ASSISTANT_ARTIFACT_MODEL | Guide rendering model; defaults to @cf/openai/gpt-oss-20b. |
SESSIONS | Optional KV namespace used for best-effort per-IP hourly counters. |
DOCS_ASSISTANT_RATE_LIMIT | Configured hourly cap; route fallback is 20. |
CADCAMFUN_DOCS_SERVER and CADCAMFUN_DOCS_TOKEN | Both are needed to select the alternative nikcli session backend. |
CADCAMFUN_DOCS_AGENT, CADCAMFUN_DOCS_DIRECTORY | Optional agent and directory for that remote backend. |
The nikcli path creates or reuses a remote session, subscribes to its stream before sending the message, and applies a 90-second turn timeout. This is documentation support on a configured backend; its token is separate from the CAD/CAM application's bridge or provider credentials.
The rate limiter requires the optional KV binding and a client IP header. Its read/increment/write sequence is best-effort rather than an atomic security quota, and KV failures are allowed through. Without the binding there is no enforced per-IP cap. Do not present it as a guaranteed allocation or rely on historical model pricing claims.
Local adapter configuration disables remote bindings. The model has no local implementation in this site. A normal local article preview can work while assistant requests return 503. Configure a reachable backend or validate model behavior in the intended deployment environment.
Generated guide artifacts
A request for a guide, checklist, reference, or similar reusable page can produce an artifact draft. With ARTIFACTS R2 storage, the helper normalizes it to an HTML document and writes content plus metadata. A normalized empty document or one larger than 256 KiB is not published.
The returned link carries a ?key= read capability. Anyone with that complete link can read the artifact. The bare identifier is not sufficient; there is no owner-account login gate for these anonymous guides. Treat the key as a share credential and avoid putting private project data into a publicly shared guide.
The viewer uses a private, non-cached shell and an iframe sandbox allowing scripts and popups without same-origin permission. The raw HTML route applies a content policy that allows inline scripts/styles and embedded data/blob images but blocks external network fetches and external font/style/script loads. Generated guides must be self-contained; their layout cannot depend on the site's current DOM or local storage.
The current publishing helper writes version 1 and a new random capability. The raw route can select a valid stored version with v; an invalid or out-of-range version falls back to the latest stored version. That retrieval support does not establish a public edit/version-management API.
ARTIFACT_PUBLIC_ORIGIN can select the canonical share-link origin for non-local deployments. Missing storage returns 503 on artifact access. Missing content returns 404, and a rejected read capability returns 401. Keep generated guide storage and public documentation assets separate.
Local Studio
Studio chooses CADCAMFUN_DB, then DATABASE_URL after stripping an initial file prefix, then the repository's data/cadcamfun.db. It only opens an existing file. This selection differs from the DB package CLI's process-relative default and the native desktop's application data directory.
Login checks an existing user's stored password with Bun's password verifier. It writes a seven-day session to the application Session table and sets an HTTP-only, SameSite=Lax cookie for the local Studio. No user-registration or initial-password bootstrap is implemented by that local server. A native local profile without a password does not acquire a Studio password automatically.
Authenticated overview queries count users, projects, drawings, and toolpaths across the selected installation, then return the eight most recently updated projects. It is a local installation overview rather than a per-project ownership-filtered dashboard. Use an appropriate local database and account; opening Studio is not a reason to point it at an unrelated user's file.
The production fallback under /studio/api/* is HTTP 503. Deploying the public docs does not upload SQLite contents or turn this local tool into a hosted database service.
Deployment
wrangler.toml declares the Worker entry, static asset directory, custom domains under cadcam.fun, Workers AI, session and assistant-rate-limit KV namespaces, and the R2 artifact bucket. Wrangler provisions dedicated resources and binds them to the deployment. Configure secrets through the target Cloudflare environment. A binding name in a TypeScript interface is not proof the resource exists in the account.
The deploy script builds Astro, writes dist/.assetsignore so the Worker entry is excluded from static assets, and invokes Wrangler deployment. Deployment is a publishing operation; normal documentation verification should use build and local checks without running it.
Before publishing, validate static routes and API snapshot freshness, confirm intended bindings, verify assistant failure behavior without its backend, and check artifact capability access if storage is enabled. After publishing, inspect the resulting deployment and configured backend rather than treat a local build as evidence of a live service.
Operational diagnosis
| Finding | Check |
|---|---|
| Assistant 400 | Valid JSON body and at least one non-empty user message after parsing/trimming. |
| Assistant 429 | The optional configured per-IP counter and current hourly bucket. |
| Assistant 502 | Whether the selected article paths can be loaded and converted in the deployment. |
| Assistant 503 | Workers AI binding or complete nikcli backend URL/token configuration. |
| Markdown 404 | The requested route must be in the navigation inventory, not an arbitrary URL. |
| Artifact 401 | Use the complete capability link including its key. |
| Studio 503 locally | The selected existing SQLite file and running Bun Studio API. |
| Studio 503 in production | Expected fallback behavior; the deployed Worker is not the local Bun process. |
Implementation sources: astro.config.mjs, wrangler.toml, script/dev.ts, script/deploy.ts, script/studio-server.ts, src/lib/docsMarkdown.ts, docsRetrieval.ts, nikcliDocsSession.ts, docsArtifact.ts, and the route handlers under src/pages.
Scripts of the docs package
| Script | Runs | Use it to |
|---|---|---|
dev | bun script/dev.ts | Start the site for local editing |
start | astro dev | Plain Astro dev server |
studio | bun script/studio-server.ts | Local Studio against CADCAMFUN_DB, DATABASE_URL or data/cadcamfun.db |
build / preview | astro build / astro preview | Produce and serve the production build |
deploy | bun script/deploy.ts | Publish to Cloudflare |
check:freshness | check:docs-index then check:api-reference | Fail when the search index or API reference is stale |
typecheck | bun check -p tsconfig.json, then check:freshness | Type errors plus both freshness checks |
generate:api-reference | script/generate-api-reference.mjs | Regenerate the reference after a contract change |
3D previews
| Prop | Type | Meaning |
|---|---|---|
title, caption | string | Heading and explanation under the canvas |
solids | array | box (size), extrude (profile, holes, height) or cylinder (radius, height), each with optional at, color, opacity |
paths | array | Polylines with points as [x, y, z], rapid (dashed) and color |
height | number | Canvas height in pixels |
animate | boolean | Draw paths progressively and show a replay button |
The component uses three.js with Z up, mounts only when scrolled into view and shows a text fallback without WebGL. Feed it real output, such as kernel moves, rather than hand-drawn coordinates.