docs: deployment scaffolding + logos + live cluster examples
Three additions to the docs site, all atomic to docs/: 1. Deployment configs (Dockerfile + Caddyfile + docker-compose.yml + .env.example + Makefile) mirroring bingham/cucx's pattern. The compose service uses caddy-docker-proxy labels with the operator's .mcp.l.supported.systems wildcard DNS pattern; suggested subdomain is mcaxl-docs.mcp.l.supported.systems. 2. Logo + favicon (forest-green palette matching the existing custom.css accent). Wordmark uses ui-monospace with currentColor so Starlight inverts on light/dark; icon-mark is a terminal chevron + three diminishing query-row lines (audit-by-query motif). 3. Live cluster examples in reference/tools.md for axl_version, axl_list_tables (route% pattern), and axl_describe_table (routepartition). Outputs sanitized per python.md PII rules (15.0.1.12900(234) → 15.0(1); cluster-fingerprinting build string removed). Build clean: 17 pages built, pagefind search index across all, favicon resolves to /favicon.svg, logo fingerprinted into _astro/. Not yet deployed — operator wires docker compose up when ready.
This commit is contained in:
parent
f060170e90
commit
314a80d6de
10
docs/.dockerignore
Normal file
10
docs/.dockerignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.astro
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
18
docs/.env.example
Normal file
18
docs/.env.example
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# mcaxl docs — local environment.
|
||||||
|
#
|
||||||
|
# Copy to .env and adjust. `.env` is gitignored.
|
||||||
|
|
||||||
|
# Distinguishes this compose project from others on the host.
|
||||||
|
COMPOSE_PROJECT=mcaxl-docs
|
||||||
|
|
||||||
|
# Public hostnames (resolved via the wildcard DNS for *.mcp.l.supported.systems
|
||||||
|
# that already points at the host's edge caddy-docker-proxy).
|
||||||
|
# DOMAIN → prod static build
|
||||||
|
# DEV_DOMAIN → dev server, hot-reload
|
||||||
|
DOMAIN=mcaxl-docs.mcp.l.supported.systems
|
||||||
|
DEV_DOMAIN=dev-mcaxl-docs.mcp.l.supported.systems
|
||||||
|
|
||||||
|
# Mode switch — drives which compose profile is active.
|
||||||
|
# dev → astro dev server + HMR (hot reload) at DEV_DOMAIN
|
||||||
|
# prod → static build served by in-container Caddy at DOMAIN
|
||||||
|
COMPOSE_PROFILES=dev
|
||||||
31
docs/Caddyfile
Normal file
31
docs/Caddyfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Internal Caddy used by the prod container to serve the static site.
|
||||||
|
# caddy-docker-proxy terminates TLS at the edge, forwards to :80 here.
|
||||||
|
|
||||||
|
:80 {
|
||||||
|
root * /srv
|
||||||
|
file_server
|
||||||
|
encode gzip zstd
|
||||||
|
|
||||||
|
# Long-cache everything Astro puts under /_astro/ (hashed filenames)
|
||||||
|
@immutable path /_astro/*
|
||||||
|
header @immutable Cache-Control "public, max-age=31536000, immutable"
|
||||||
|
|
||||||
|
# Short-cache HTML so content updates appear quickly after redeploy.
|
||||||
|
@html path_regexp htmlrx \.(html)?$
|
||||||
|
header @html Cache-Control "public, max-age=60, must-revalidate"
|
||||||
|
|
||||||
|
# Basic security headers
|
||||||
|
header {
|
||||||
|
X-Content-Type-Options nosniff
|
||||||
|
Referrer-Policy strict-origin-when-cross-origin
|
||||||
|
X-Frame-Options SAMEORIGIN
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
|
||||||
|
# Render 404 for missing pages
|
||||||
|
handle_errors {
|
||||||
|
@404 expression {http.error.status_code} == 404
|
||||||
|
rewrite @404 /404.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
}
|
||||||
62
docs/Dockerfile
Normal file
62
docs/Dockerfile
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# mcaxl docs — multi-stage build.
|
||||||
|
#
|
||||||
|
# Stages:
|
||||||
|
# deps — install node_modules once, cached by package.json
|
||||||
|
# dev — runs `astro dev` with the source bind-mounted (compose `dev` profile)
|
||||||
|
# build — produces the static site in /app/dist
|
||||||
|
# prod — serves /app/dist with Caddy (static file server, no Node runtime)
|
||||||
|
|
||||||
|
# ---------- Stage: deps --------------------------------------------------
|
||||||
|
FROM mirror.gcr.io/library/node:22-alpine AS deps
|
||||||
|
|
||||||
|
ENV ASTRO_TELEMETRY_DISABLED=1 \
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
RUN --mount=type=cache,target=/root/.npm \
|
||||||
|
npm install --no-audit --no-fund
|
||||||
|
|
||||||
|
# ---------- Stage: dev ---------------------------------------------------
|
||||||
|
FROM mirror.gcr.io/library/node:22-alpine AS dev
|
||||||
|
|
||||||
|
ENV ASTRO_TELEMETRY_DISABLED=1 \
|
||||||
|
NODE_ENV=development \
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 4321
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
|
|
||||||
|
# ---------- Stage: build -------------------------------------------------
|
||||||
|
FROM mirror.gcr.io/library/node:22-alpine AS build
|
||||||
|
|
||||||
|
ENV ASTRO_TELEMETRY_DISABLED=1 \
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# DOMAIN must be set at build time so Astro bakes the canonical site URL
|
||||||
|
# (sitemaps, og: tags, etc.) into the static output.
|
||||||
|
ARG DOMAIN
|
||||||
|
ENV DOMAIN=${DOMAIN}
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---------- Stage: prod --------------------------------------------------
|
||||||
|
# Static site served by Caddy. No Node in the final image.
|
||||||
|
FROM mirror.gcr.io/library/caddy:2-alpine AS prod
|
||||||
|
|
||||||
|
COPY --from=build /app/dist /srv
|
||||||
|
COPY Caddyfile /etc/caddy/Caddyfile
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
|
||||||
57
docs/Makefile
Normal file
57
docs/Makefile
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# mcaxl docs — compose wrapper.
|
||||||
|
#
|
||||||
|
# Mode (dev/prod) is driven by COMPOSE_PROFILES in .env. Flip it there.
|
||||||
|
# `docker compose` honors COMPOSE_PROJECT and COMPOSE_PROFILES automatically.
|
||||||
|
|
||||||
|
COMPOSE ?= docker compose
|
||||||
|
|
||||||
|
.PHONY: help up down restart logs shell ps build clean prod dev net pull-prod pull-dev
|
||||||
|
|
||||||
|
help: ## Show this help
|
||||||
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-10s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
up: ## Start the active profile (set COMPOSE_PROFILES in .env)
|
||||||
|
$(COMPOSE) up -d --build
|
||||||
|
|
||||||
|
dev: ## Start dev explicitly (hot reload at https://$${DEV_DOMAIN})
|
||||||
|
COMPOSE_PROFILES=dev $(COMPOSE) up -d --build
|
||||||
|
|
||||||
|
prod: ## Start prod explicitly (static site at https://$${DOMAIN})
|
||||||
|
COMPOSE_PROFILES=prod $(COMPOSE) up -d --build
|
||||||
|
|
||||||
|
down: ## Stop and remove all containers for this project
|
||||||
|
COMPOSE_PROFILES=dev $(COMPOSE) down
|
||||||
|
COMPOSE_PROFILES=prod $(COMPOSE) down
|
||||||
|
|
||||||
|
restart: ## Restart the active profile
|
||||||
|
$(COMPOSE) restart
|
||||||
|
|
||||||
|
logs: ## Tail logs for active services
|
||||||
|
$(COMPOSE) logs -f --tail=200
|
||||||
|
|
||||||
|
shell: ## Shell into the dev container
|
||||||
|
$(COMPOSE) exec docs-dev sh
|
||||||
|
|
||||||
|
ps: ## Show running containers for this project
|
||||||
|
$(COMPOSE) ps
|
||||||
|
|
||||||
|
build: ## Build images for both profiles
|
||||||
|
COMPOSE_PROFILES=dev,prod $(COMPOSE) build
|
||||||
|
|
||||||
|
clean: ## Remove containers, images, and volumes for this project
|
||||||
|
COMPOSE_PROFILES=dev,prod $(COMPOSE) down --rmi local -v
|
||||||
|
|
||||||
|
net: ## Create the external `caddy` network (one-time, host-wide)
|
||||||
|
docker network inspect caddy >/dev/null 2>&1 || docker network create caddy
|
||||||
|
|
||||||
|
pull-prod: ## Deploy: git pull, rebuild, and restart the prod container
|
||||||
|
git pull --ff-only
|
||||||
|
COMPOSE_PROFILES=prod $(COMPOSE) up -d --build docs-prod
|
||||||
|
@echo
|
||||||
|
@COMPOSE_PROFILES=prod $(COMPOSE) ps docs-prod
|
||||||
|
|
||||||
|
pull-dev: ## Deploy: git pull, rebuild, and restart the dev container
|
||||||
|
git pull --ff-only
|
||||||
|
COMPOSE_PROFILES=dev $(COMPOSE) up -d --build docs-dev
|
||||||
|
@echo
|
||||||
|
@COMPOSE_PROFILES=dev $(COMPOSE) ps docs-dev
|
||||||
@ -52,6 +52,7 @@ export default defineConfig({
|
|||||||
src: './src/assets/logo.svg',
|
src: './src/assets/logo.svg',
|
||||||
replacesTitle: false,
|
replacesTitle: false,
|
||||||
},
|
},
|
||||||
|
favicon: '/favicon.svg',
|
||||||
customCss: ['./src/styles/custom.css'],
|
customCss: ['./src/styles/custom.css'],
|
||||||
|
|
||||||
// Per-page action buttons: "Copy Markdown" + "View in Markdown"
|
// Per-page action buttons: "Copy Markdown" + "View in Markdown"
|
||||||
|
|||||||
71
docs/docker-compose.yml
Normal file
71
docs/docker-compose.yml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# mcaxl docs — dev/prod via compose profiles.
|
||||||
|
#
|
||||||
|
# Mode is driven by COMPOSE_PROFILES in .env:
|
||||||
|
# COMPOSE_PROFILES=dev → hot-reload astro dev server at https://${DEV_DOMAIN}
|
||||||
|
# COMPOSE_PROFILES=prod → static site via in-container Caddy at https://${DOMAIN}
|
||||||
|
#
|
||||||
|
# Both profiles sit behind the host's external caddy-docker-proxy on the
|
||||||
|
# `caddy` network. mcaxl is a public OSS project; no basic auth.
|
||||||
|
#
|
||||||
|
# Prerequisite: `docker network create caddy` (one-time, shared with the
|
||||||
|
# edge caddy-docker-proxy instance).
|
||||||
|
|
||||||
|
services:
|
||||||
|
docs-dev:
|
||||||
|
profiles: ["dev"]
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: dev
|
||||||
|
image: ${COMPOSE_PROJECT}-dev
|
||||||
|
container_name: ${COMPOSE_PROJECT}-dev
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
ASTRO_TELEMETRY_DISABLED: "1"
|
||||||
|
NODE_ENV: development
|
||||||
|
DOMAIN: ${DEV_DOMAIN} # Vite HMR binds wss://${DEV_DOMAIN}:443
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
- /app/.astro
|
||||||
|
networks:
|
||||||
|
- caddy
|
||||||
|
labels:
|
||||||
|
caddy: ${DEV_DOMAIN}
|
||||||
|
caddy.reverse_proxy: "{{upstreams 4321}}"
|
||||||
|
|
||||||
|
# ── HMR-through-Caddy streaming tweaks ──
|
||||||
|
# Vite HMR doesn't send app-level pings; Caddy closes idle WebSockets
|
||||||
|
# after ~10-15s without these. Refs in ~/.claude/CLAUDE.md.
|
||||||
|
caddy.reverse_proxy.flush_interval: "-1"
|
||||||
|
caddy.reverse_proxy.transport: "http"
|
||||||
|
caddy.reverse_proxy.transport.read_timeout: "0"
|
||||||
|
caddy.reverse_proxy.transport.write_timeout: "0"
|
||||||
|
caddy.reverse_proxy.transport.keepalive: "5m"
|
||||||
|
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
|
||||||
|
caddy.reverse_proxy.stream_timeout: "24h"
|
||||||
|
caddy.reverse_proxy.stream_close_delay: "5s"
|
||||||
|
|
||||||
|
caddy.encode: "gzip zstd"
|
||||||
|
|
||||||
|
docs-prod:
|
||||||
|
profiles: ["prod"]
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: prod
|
||||||
|
args:
|
||||||
|
DOMAIN: ${DOMAIN}
|
||||||
|
image: ${COMPOSE_PROJECT}-prod
|
||||||
|
container_name: ${COMPOSE_PROJECT}-prod
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- caddy
|
||||||
|
labels:
|
||||||
|
caddy: ${DOMAIN}
|
||||||
|
caddy.reverse_proxy: "{{upstreams 80}}"
|
||||||
|
caddy.encode: "gzip zstd"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
caddy:
|
||||||
|
external: true
|
||||||
8
docs/public/favicon.svg
Normal file
8
docs/public/favicon.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="mcaxl">
|
||||||
|
<rect x="1" y="1" width="30" height="30" rx="6" fill="#103e34"/>
|
||||||
|
<path d="M7 11 L12 16 L7 21" fill="none" stroke="#4f9a78" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<line x1="15" y1="13" x2="26" y2="13" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<line x1="15" y1="17" x2="22" y2="17" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round" opacity="0.75"/>
|
||||||
|
<line x1="15" y1="21" x2="24" y2="21" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round" opacity="0.55"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 659 B |
@ -1,6 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" aria-hidden="true">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 44" role="img" aria-label="mcaxl">
|
||||||
<rect x="2" y="2" width="36" height="36" rx="8" fill="#1f6f5c"/>
|
<!-- Icon mark: chevron prompt + stacked query rows (audit-by-query motif) -->
|
||||||
<path d="M10 12 L20 28 L30 12" stroke="#f3efe6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
<g transform="translate(4 6)">
|
||||||
<circle cx="20" cy="28" r="2.4" fill="#f3efe6"/>
|
<rect x="0" y="0" width="32" height="32" rx="6" fill="none" stroke="#2f7d5e" stroke-width="2"/>
|
||||||
|
<!-- Terminal chevron -->
|
||||||
|
<path d="M6 10 L11 16 L6 22" fill="none" stroke="#4f9a78" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<!-- Query rows (database lines) -->
|
||||||
|
<line x1="14" y1="13" x2="26" y2="13" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<line x1="14" y1="17" x2="22" y2="17" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round" opacity="0.75"/>
|
||||||
|
<line x1="14" y1="21" x2="24" y2="21" stroke="#a8cdb8" stroke-width="2" stroke-linecap="round" opacity="0.55"/>
|
||||||
|
</g>
|
||||||
|
<!-- Wordmark -->
|
||||||
|
<text x="46" y="29" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="20" font-weight="600" fill="currentColor" letter-spacing="0.5">mcaxl</text>
|
||||||
|
<text x="118" y="29" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="13" font-weight="400" fill="currentColor" opacity="0.55" letter-spacing="0.3">/ docs</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 1.3 KiB |
@ -26,6 +26,16 @@ change between cluster upgrades.
|
|||||||
|
|
||||||
**Returns:** `{ version: str, _cache: "hit" | "miss" }`
|
**Returns:** `{ version: str, _cache: "hit" | "miss" }`
|
||||||
|
|
||||||
|
**Live example** (against CUCM 15):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"componentVersion": {
|
||||||
|
"version": "15.0(1)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `axl_sql`
|
### `axl_sql`
|
||||||
|
|
||||||
Execute a `SELECT` (or `WITH` CTE) against the CUCM Informix data
|
Execute a `SELECT` (or `WITH` CTE) against the CUCM Informix data
|
||||||
@ -51,6 +61,24 @@ List Informix tables in the CUCM database.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `pattern` | `str \| None` | Optional LIKE pattern (`%` wildcards). e.g. `"route%"` finds `routelist`, `routegroup`, `routepartition`, `routefilter`. |
|
| `pattern` | `str \| None` | Optional LIKE pattern (`%` wildcards). e.g. `"route%"` finds `routelist`, `routegroup`, `routepartition`, `routefilter`. |
|
||||||
|
|
||||||
|
**Live example** (`pattern="route%"` against CUCM 15):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"table_count": 7,
|
||||||
|
"tables": [
|
||||||
|
"routefilter",
|
||||||
|
"routefiltercosroutingmap",
|
||||||
|
"routefiltermember",
|
||||||
|
"routegroup",
|
||||||
|
"routegroupdevicemap",
|
||||||
|
"routelist",
|
||||||
|
"routepartition"
|
||||||
|
],
|
||||||
|
"pattern": "route%"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `axl_describe_table`
|
### `axl_describe_table`
|
||||||
|
|
||||||
Describe an Informix table's columns: name, type, length, nullability.
|
Describe an Informix table's columns: name, type, length, nullability.
|
||||||
@ -63,6 +91,27 @@ table.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `table_name` | `str` | Exact Informix table name. |
|
| `table_name` | `str` | Exact Informix table name. |
|
||||||
|
|
||||||
|
**Live example** (`table_name="routepartition"` against CUCM 15):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"table": "routepartition",
|
||||||
|
"column_count": 11,
|
||||||
|
"columns": [
|
||||||
|
{ "name": "pkid", "type": "CHAR", "length": 36, "not_null": true },
|
||||||
|
{ "name": "name", "type": "VARCHAR", "length": 50, "not_null": true },
|
||||||
|
{ "name": "description", "type": "VARCHAR", "length": 200, "not_null": true },
|
||||||
|
{ "name": "fktimeschedule", "type": "CHAR", "length": 36, "not_null": false },
|
||||||
|
{ "name": "tktimezone", "type": "INTEGER", "length": 4, "not_null": true },
|
||||||
|
{ "name": "useoriginatingdevicetimezone", "type": "LVARCHAR", "length": 1, "not_null": true },
|
||||||
|
{ "name": "tkpartitionusage", "type": "INTEGER", "length": 4, "not_null": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(Trimmed: 4 internal-only columns omitted for clarity. The full
|
||||||
|
response includes 11 columns.)
|
||||||
|
|
||||||
### `cache_stats`
|
### `cache_stats`
|
||||||
|
|
||||||
Cache statistics: total entries, live entries, breakdown by method.
|
Cache statistics: total entries, live entries, breakdown by method.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user