251 lines
8.9 KiB
Markdown
251 lines
8.9 KiB
Markdown
|
|
# Site Operations
|
||
|
|
|
||
|
|
Operational guide for managing an htmx-ssr consumer site (L3 instance).
|
||
|
|
All recipes run from the **site root** — the directory that contains `site/`.
|
||
|
|
|
||
|
|
## Runtime boundary
|
||
|
|
|
||
|
|
The htmx-ssr binary separates what is compiled-in from what is read at runtime.
|
||
|
|
This determines whether a change requires a restart, a rebuild, or nothing.
|
||
|
|
|
||
|
|
| What you change | Binary effect | Action needed |
|
||
|
|
|------------------------------------------|---------------|---------------------------------------|
|
||
|
|
| Markdown content, NCL metadata | None | `just content` — no restart |
|
||
|
|
| JSON content indexes (`site/r/`) | None | Already written by `just content` |
|
||
|
|
| Knowledge graph (`content_graph.json`) | None | `just graph` — no restart |
|
||
|
|
| Static assets (CSS, images) | None | Copy to `site/public/` — no restart |
|
||
|
|
| Jinja templates (`.j2`) | None | `just templates` + server restart |
|
||
|
|
| FTL strings (`site/i18n/locales/`) | None | Server restart only |
|
||
|
|
| RBAC (`site/rbac.ncl`) | None | **Automatic hot-reload** — nothing |
|
||
|
|
| Routes or menus (`site/config/routes.ncl`) | **Baked** | Binary rebuild (see §Routes & menus) |
|
||
|
|
| New language (routes.ncl + site.ncl) | **Baked** | Binary rebuild (see §New language) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Update content — preview locally
|
||
|
|
|
||
|
|
Content = markdown posts, NCL metadata, and project/blog/recipe pages.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Edit markdown files:
|
||
|
|
# site/content/{type}/{lang}/{category}/{slug}/index.md
|
||
|
|
# site/content/{type}/{lang}/{category}/{slug}/index.ncl (metadata)
|
||
|
|
|
||
|
|
# Regenerate JSON indexes:
|
||
|
|
just content # all types, all langs
|
||
|
|
just content type=blog # single type
|
||
|
|
just content type=blog lang=en # single type + lang
|
||
|
|
just content type=blog lang=en category=rust # single category (uses --category)
|
||
|
|
|
||
|
|
# Watch mode (auto-regenerate on save):
|
||
|
|
just content-watch
|
||
|
|
just content-watch type=blog lang=en
|
||
|
|
|
||
|
|
# Start server and open browser:
|
||
|
|
just dev # http://localhost:3030
|
||
|
|
```
|
||
|
|
|
||
|
|
Changes in `site/content/` are served directly — no server restart.
|
||
|
|
The JSON indexes in `site/r/` are what the server reads; always run `just content` after editing NCL metadata or adding new files.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Update content including the knowledge graph
|
||
|
|
|
||
|
|
The knowledge graph connects posts to ontology nodes and to each other.
|
||
|
|
Requires `ONTOREF_NICKEL_IMPORT_PATH` and `CONTENT_GRAPH_IMPL_ONTOLOGY` in `.env`.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
just content # rebuild JSON indexes first
|
||
|
|
just graph # rebuild content_graph.json
|
||
|
|
just dev # preview
|
||
|
|
```
|
||
|
|
|
||
|
|
The graph is pre-built: `gen-content-graph --site .` writes `site/r/content_graph.json`.
|
||
|
|
The server reads it as a static file — no restart after regeneration.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Publish content to production (no binary rebuild)
|
||
|
|
|
||
|
|
Content changes do not need a new container image. Update the PV directly.
|
||
|
|
|
||
|
|
**Kubernetes / docker-compose (PVC):**
|
||
|
|
```sh
|
||
|
|
# Sync the JSON indexes to the running pod's PVC:
|
||
|
|
kubectl cp site/r/ <pod-name>:/var/www/site/r/
|
||
|
|
|
||
|
|
# Sync source content (if the server reads markdown directly):
|
||
|
|
kubectl cp site/content/ <pod-name>:/var/www/site/content/
|
||
|
|
|
||
|
|
# No rollout restart needed — server reads these on next request.
|
||
|
|
```
|
||
|
|
|
||
|
|
**Full PV resync (after template or FTL changes too):**
|
||
|
|
```sh
|
||
|
|
kubectl cp site/ <pod-name>:/var/www/site/
|
||
|
|
kubectl rollout restart deployment/<deployment-name>
|
||
|
|
```
|
||
|
|
|
||
|
|
**New container image (when binary was rebuilt):**
|
||
|
|
Run `just build-push-remote` from `website-htmx-rustelo/code/`.
|
||
|
|
This builds a new image via lian-build and pushes it to the registry.
|
||
|
|
Deployment manifests reference the new tag.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Update templates — preview locally and publish
|
||
|
|
|
||
|
|
Templates are Jinja2 (`.j2`) files loaded at server startup from `HTMX_TEMPLATE_PATH`.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Edit source templates in the L2 project:
|
||
|
|
# website-htmx-rustelo/code/crates/pages_htmx/templates/pages/{slug}.j2
|
||
|
|
# website-htmx-rustelo/code/crates/pages_htmx/templates/partials/{name}.j2
|
||
|
|
|
||
|
|
# Reassemble htmx-templates in the consumer site:
|
||
|
|
just templates # copies framework + project templates to htmx-templates/
|
||
|
|
|
||
|
|
# Restart server (templates loaded at startup):
|
||
|
|
just dev # kills old server, starts fresh
|
||
|
|
|
||
|
|
# Publish: sync htmx-templates to PV + rollout restart
|
||
|
|
kubectl cp htmx-templates/ <pod-name>:/var/www/htmx-templates/
|
||
|
|
kubectl rollout restart deployment/<deployment-name>
|
||
|
|
```
|
||
|
|
|
||
|
|
`just templates` runs `assemble-htmx-templates.nu` — it overlays framework defaults
|
||
|
|
with the L2 project's templates. Project templates always win over framework defaults.
|
||
|
|
|
||
|
|
If `just local-install` was run (binary rebuild), the installed share templates at
|
||
|
|
`~/.local/share/rustelo-htmx-server/htmx-templates/` are also updated. The site's
|
||
|
|
`htmx-templates/` directory takes precedence over the installed share.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Change menus or routes
|
||
|
|
|
||
|
|
Routes and menus are **compiled into the binary** from `site/config/routes.ncl` at
|
||
|
|
build time. Changing them requires rebuilding the binary.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# 1. Edit in the consumer site (jpl/site, etc.):
|
||
|
|
# site/site/config/routes.ncl — add/change URL paths and menu entries
|
||
|
|
# site/site/config/site.ncl — confirm language list is current
|
||
|
|
|
||
|
|
# 2. Copy to the L2 source project (website-htmx-rustelo/code):
|
||
|
|
# cp site/site/config/routes.ncl website-htmx-rustelo/code/site/config/routes.ncl
|
||
|
|
|
||
|
|
# 3. Rebuild the binary from website-htmx-rustelo/code:
|
||
|
|
cd /path/to/website-htmx-rustelo/code
|
||
|
|
just local-install # builds release binary + installs wrapper
|
||
|
|
|
||
|
|
# 4. Restart the consumer site server:
|
||
|
|
cd /path/to/jpl/site
|
||
|
|
just dev
|
||
|
|
```
|
||
|
|
|
||
|
|
`just local-install` takes ~2 min on first build, incremental afterward (sccache).
|
||
|
|
The new binary at `~/.local/libexec/rustelo-htmx-server` is picked up immediately
|
||
|
|
on next `just dev` — no path changes needed.
|
||
|
|
|
||
|
|
**Route component name convention:**
|
||
|
|
```
|
||
|
|
URL: /my-tool → Component: "MyToolPage"
|
||
|
|
URL: /lian-build → Component: "LianBuildPage"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Update FTL strings (i18n text)
|
||
|
|
|
||
|
|
FTL files are loaded at **server startup** from `site/i18n/locales/{lang}/`.
|
||
|
|
No rebuild needed; restart applies the changes.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Edit FTL files:
|
||
|
|
# site/i18n/locales/en/pages/{slug}.ftl
|
||
|
|
# site/i18n/locales/es/pages/{slug}.ftl
|
||
|
|
# site/i18n/locales/en/common.ftl (shared UI strings)
|
||
|
|
|
||
|
|
# Apply changes (restart server):
|
||
|
|
just dev # kills existing server, starts with fresh FTL
|
||
|
|
|
||
|
|
# Publish: sync i18n to PV + rollout restart
|
||
|
|
kubectl cp site/i18n/ <pod-name>:/var/www/site/i18n/
|
||
|
|
kubectl rollout restart deployment/<deployment-name>
|
||
|
|
```
|
||
|
|
|
||
|
|
FTL is fail-open: missing keys render as empty string, never crash.
|
||
|
|
Both languages (`en` and `es`) must be kept in sync — add every key to both.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. Add a new language
|
||
|
|
|
||
|
|
Adding a language requires both FTL files (runtime) and route paths (compile-time).
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Step 1 — Create FTL translations (runtime, no rebuild):
|
||
|
|
mkdir -p site/i18n/locales/{lang}/pages
|
||
|
|
cp site/i18n/locales/en/*.ftl site/i18n/locales/{lang}/
|
||
|
|
# Translate all strings in the copied files
|
||
|
|
|
||
|
|
# Step 2 — Register the language (requires rebuild):
|
||
|
|
# In site/config/site.ncl — add to the languages list
|
||
|
|
# In site/config/routes.ncl — add "{lang} = /{path}" to every route
|
||
|
|
|
||
|
|
# Step 3 — Rebuild binary:
|
||
|
|
cd /path/to/website-htmx-rustelo/code
|
||
|
|
just local-install
|
||
|
|
|
||
|
|
# Step 4 — Restart:
|
||
|
|
cd /path/to/consumer-site
|
||
|
|
just dev
|
||
|
|
```
|
||
|
|
|
||
|
|
If the new language shares URL paths with English (e.g., language detection via
|
||
|
|
`Accept-Language` header only), steps 2 and 3 may be skipped — only FTL is needed.
|
||
|
|
Verify with `just htmx-smoke` after starting the server.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Change RBAC permissions
|
||
|
|
|
||
|
|
RBAC is hot-reloaded automatically. The server watches `site/rbac.ncl` for changes
|
||
|
|
and applies them without restart.
|
||
|
|
|
||
|
|
```sh
|
||
|
|
# Edit:
|
||
|
|
# site/rbac.ncl — roles, groups, protected paths, anonymous deny paths
|
||
|
|
|
||
|
|
# No action needed — the running server picks up changes within ~1s.
|
||
|
|
# Confirm in server logs: "rbac hot-reload: N groups, M overrides"
|
||
|
|
```
|
||
|
|
|
||
|
|
If the server is not running, changes take effect on next `just dev`.
|
||
|
|
|
||
|
|
**For deployment**: sync `site/rbac.ncl` to the PVC — no rollout restart needed.
|
||
|
|
```sh
|
||
|
|
kubectl cp site/rbac.ncl <pod-name>:/var/www/site/rbac.ncl
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Quick reference
|
||
|
|
|
||
|
|
```sh
|
||
|
|
just dev # start local server
|
||
|
|
just content [type] [lang] # regenerate content indexes
|
||
|
|
just content-watch [type] [lang] # watch + auto-regenerate
|
||
|
|
just graph # rebuild content_graph.json
|
||
|
|
just templates # rebuild htmx-templates from source
|
||
|
|
just sync # templates + content (no graph)
|
||
|
|
just sync-full # templates + content + graph
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to rebuild the binary** (`just local-install` in `website-htmx-rustelo/code`):
|
||
|
|
- Routes or menu structure changed
|
||
|
|
- New language with distinct URL paths
|
||
|
|
- New page component type added
|