Publish the documentation site: docs.fluksio.com

A zensical site under docs/, served by a new `docs` compose service behind
Traefik, built with --strict in CI. Same pattern the sibling n3xd workspace
uses.

Getting started splits the way the landing page does — one path is
`pip install fluksio` and a training script, the other is a Docker stack and
an afternoon in the browser — because the two audiences will not spend the same
amount of time. Everything after that is shared: the concepts, the web
interface (app and portal), the CLI and the API, and a reference for node types,
payload types and configuration.

The three flow guides move here from the docs submodule rather than being
copied, so there is one version of them.

Styling mirrors DESIGN-GUIDELINES.md: the app's token palette remapped onto
Material's variables in both schemes, Inter, the 16px panel radius, and the one
terracotta accent spent on the facility lane of the audience split.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M7Xv3cJEW5c8AXxn2hoojV
This commit is contained in:
2026-08-22 05:55:34 +02:00
co-authored by Claude Opus 5
parent c3cbbbc962
commit d12c81c8a0
34 changed files with 4167 additions and 2 deletions
+19
View File
@@ -0,0 +1,19 @@
# ─── Fluksio docs site (zensical) ───
# Multi-stage: build the static documentation with zensical, serve it with Nginx.
# Routed to docs.${DOMAIN} by the `docs` service in compose.yml. The runtime
# image is just Nginx + static files (no Python), mirroring the SPA approach.
# ── Stage 1: Build the static site ───────────────────────────────
FROM python:3.13-slim AS docs-build
# Pin zensical so a rebuild is reproducible (it is only a build-time tool).
RUN pip install --no-cache-dir zensical==0.0.46
WORKDIR /docs
COPY zensical.toml ./
COPY docs/ ./docs/
RUN zensical build --clean
# ── Stage 2: Serve static files ──────────────────────────────────
FROM nginx:alpine
COPY docker/nginx.docs.conf /etc/nginx/conf.d/default.conf
COPY --from=docs-build /docs/site /usr/share/nginx/html
EXPOSE 80
+5
View File
@@ -137,6 +137,11 @@ services:
- VITE_API_URL=http://localhost:8000
- NODE_ENV=development
# Reachable at http://docs.${DOMAIN}, but a container rebuild per edit is a
# poor authoring loop — use `make docs-serve` for that.
docs:
restart: "no"
playwright:
build:
context: ..
+30
View File
@@ -188,6 +188,36 @@ services:
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.middlewares=https-redirect
# Static documentation site (zensical), served at docs.${DOMAIN}. Content and
# config live in ../docs/ and ../zensical.toml; `make docs-serve` previews it.
docs:
container_name: fluksio-docs
restart: always
security_opt:
- no-new-privileges:true
build:
context: ..
dockerfile: docker/Dockerfile.docs
expose:
- "80"
networks:
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- traefik.constraint-label=proxy
- traefik.http.services.${STACK_NAME?Variable not set}-docs.loadbalancer.server.port=80
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-http.rule=Host(`docs.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-http.entrypoints=http
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-http.middlewares=https-redirect
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-https.rule=Host(`docs.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-docs-https.tls.certresolver=le
# Docker never restarts a merely *unhealthy* container on its own; autoheal
# closes that gap for the services labeled autoheal=true.
#
+27
View File
@@ -0,0 +1,27 @@
# Static documentation site (zensical output). Clean-URL directories served from
# per-directory index.html, with a styled 404, gzip, and long-cached assets.
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml text/plain;
gzip_min_length 256;
location / {
try_files $uri $uri/ =404;
}
# Fingerprinted CSS/JS/images emitted under assets/ can be cached hard.
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}