Files
Enelix-EMS/tools/public-docs/README.md
T
2026-10-06 14:32:05 +00:00

191 lines
9.6 KiB
Markdown

# Public Enelix Documentation Publisher
## Context and decision
The license portal already serves public static files and exposes its effective
catalog at `GET /api/catalog`. Documentation is therefore built as static HTML;
the existing portal process, authentication, database and payment code are not
modified. Generic Utils runtime code is not coupled to the documentation service.
Source ownership:
- `docs/public/*.md` in Enelix-EMS: installation, operator guides, FAQ and pricing explanation.
- `docs/public/images/*.png`: explicitly reviewed real Symcon screenshots, allowlisted in `images.mjs`.
- Explicit README/interface allowlists in `config.mjs`: original EMS and Utils references.
- Backend catalog: every monetary value, product name, SKU, term and effective VAT rate.
- This directory: rendering, navigation, publication and tests.
The default source branch is `develop`, visibly identified as Testing. The
publisher reads separate shallow bare mirrors; it never changes existing
developer checkouts. All sources are pinned to the commits captured at the start
of a successful run. Neither unpublished worktrees nor internal handoffs, open
issues, credentials, operational notes or arbitrary new files are published.
Alternative considered: adding server-side documentation routes. Not selected:
the current static mount enables this rollout without a portal restart or a new
public service. A separately maintained copy of prices was rejected because it
would drift from checkout. The browser refreshes the same catalog endpoint every
30 seconds while visible, on reappearance and on manual refresh.
## Public routes
- `/docs/index.html`
- `/docs/erste-schritte.html`
- `/docs/installation.html`
- `/docs/manager.html`
- `/docs/verbraucher.html`
- `/docs/utils.html`
- `/docs/faq.html`
- `/docs/preise.html`
- `/docs/ems/*.html` and `/docs/utils/*.html`
- `/docs/manifest.json`: published source commits and file mappings.
- `/docs-status.json`: last attempted/successful synchronization, no internal errors.
The portal's anonymous login screen links to documentation, FAQ and prices.
Authenticated sidebar navigation additionally links to documentation and prices.
Within the EMS references, Manager remains a direct link; consumer modules and
technical interfaces are nested in native, keyboard-accessible disclosure groups.
The current page's group opens on the server, also without JavaScript. Search
expands matching groups and restores their previous state when cleared. All
page URLs remain unchanged; new references without a group stay accessible.
`assets/portal-links.css` contains only the added navigation styling.
`portal-navigation.patch` records the exact additive portal HTML change; check
it against the current portal before applying it and copy the stylesheet to
`public/docs-portal.css`. Never replace the full portal HTML from another checkout.
## Install and publish
Deploy the reviewed publisher files to `/home/agent/services/public-docs` as
the unprivileged `agent` user. Do not copy `node_modules`, state, preview, QA or
backups into a repository or the public directory. Install locked dependencies:
```sh
npm ci --ignore-scripts
npm test
```
For rendering/rollback checks without changing public pages:
```sh
node preview.mjs
node verify.mjs
node browser-test.mjs
```
Publication uses the existing public mount at
`/home/agent/services/license/public`. The portal container's UID must be able to
read generated directories and files. No credentials are included in the
publisher: Git uses the server's preconfigured access. Never put credentials in
repository URLs or public output.
Install the two supplied units through `systemctl --user link`, reload the user
manager, start `enelix-public-docs.service` once and enable
`enelix-public-docs.timer`. Only these user units are affected. The timer checks
Git five minutes after completion, with at most fifteen seconds of jitter.
The successful first run can take longer while fetching both repositories.
`DOCS_BRANCH` accepts `develop`, `beta` or `main`; reading a source branch does
not merge or modify it. `DOCS_PUBLIC_DIR` and `DOCS_STATE_DIR` support isolated
tests. Keep the chosen channel explicit in the service configuration.
## Git-only operation and historical bootstrap
The production service does not enable `DOCS_ALLOW_DRAFTS`. All approved guides
and screenshots must exist in the selected Git branch. A missing source aborts
publication and preserves the last good release; deployment copies cannot
silently replace deleted Git content.
The initial 2026-10-06 deployment used explicitly labelled drafts while Git
publication awaited authorization. Daniel approved commit and push on the same
day. The bootstrap fallback remains available only through the explicit
`DOCS_ALLOW_DRAFTS=true` setting, including isolated previews. It reads missing
sources from the deployment-only `guides/` directory and labels them as drafts.
Do not treat these bootstrap copies as a second long-term editing location.
When completing a bootstrap deployment, push the approved sources first, verify
that publication uses their Git commits, then install the production unit without
the draft setting and reload the user service manager.
## Security and resilience
Markdown is rendered with pinned Marked and sanitized with sanitize-html.
Raw HTML and remote images are disabled; link schemes and local mappings are
restricted. Relative links to unpublished files are plain text. The existing
portal CSP remains active; there is no inline JavaScript or browser-side Git
credential. Every page is readable without JavaScript except the live price
table, which shows an explicit notice and a catalog link in that case.
Only the exact local PNG paths in `images.mjs` render as screenshots. The
publisher reads binary files at the same EMS commit as the guides, checks regular
file type, PNG signature and dimensions, and publishes content-hashed filenames.
Image hashes, dimensions and source revisions are recorded in the manifest.
Missing or invalid images fail publication and preserve the last good release.
Draft bootstrap images follow the same explicit opt-in as the draft guides.
Screenshot refresh is intentionally reviewed, not a live camera into Symcon.
Capture through the local-only web console in a separate browser session, without
saving configuration or invoking regulation. Select useful crops, inspect them
for license codes, installation IDs, accounts and private plant details, then
replace the approved PNGs in Git and update the dated captions. Never publish
unreviewed captures automatically. Current screenshots show the demo object tree
and the manager basic settings in Symcon 8.0 on 2026-10-06. Test values are not
recommended installation settings; reference READMEs may evolve faster than the
dated screenshots.
Publication is a complete immutable release followed by an atomic `docs`
symlink switch. Failed fetches or rendering leave the previous release intact.
Public status reports failed or overdue checks. Stale prices are removed when
the catalog cannot be obtained or validated; no hardcoded fallback is used.
The sync lock prevents overlapping manual and timer runs. If the process is
forcibly terminated, inspect process state before removing its stale lock from
the publisher state directory. Generated releases are retained to permit
rollback; disk usage should be monitored and old releases pruned only after
checking that they are not current or needed for rollback.
## Verification and rollback
`npm test` covers relative and cross-repository links, HTML sanitization,
allowlist isolation, headings/tables, price validation, VAT and periods.
`node verify.mjs` validates all published links and deliberately exercises a
source failure against an isolated mirror, proving last-good preservation.
`node browser-test.mjs` checks desktop, 390px and 320px layouts, search, automatic
catalog refresh, newly returned products, VAT toggle, API failure/recovery and
JavaScript-free documentation. Mocks affect only a fresh browser context, never
the production catalog. Screenshots remain private in `qa/`.
`node verify.mjs live` and `node browser-test.mjs --live` perform anonymous checks
on the actual domain. The tests must not log in or mutate live application data.
For rollback, first stop and disable only the documentation timer. Restore the
previous documentation symlink atomically. For full removal, revert only the
added portal navigation and stylesheet link after checking for concurrent edits;
do not overwrite the portal with an older full backup if other edits occurred.
No database, Nginx or IP-Symcon rollback is required because those were unchanged.
## Initial deployment evidence
2026-10-06: 29 pages, 1,116 valid local links, 12 unit tests passed, isolated
failure recovery passed, desktop/mobile browser tests passed both in preview and
against the public domain. The initial sources were EMS
`58f91e431936fedca3e59178037b939f420ce3e3` and Utils
`82860c0eb938173841088f935a306729b6ce9a1c`. These are dated evidence, not permanent
source pins. The price API initially returned 15 products and was accessed
without login.
Portal navigation backup:
`/home/agent/services/public-docs/backups/2026-10-06T12-58-13-558Z/index.html`.
The backup is private and must never be copied into `public/`.
## Pull request summary
Add public documentation and FAQ from reviewed Git-backed sources, plus a live
backend-driven price table. Preserve existing portal authentication and data;
publish static releases atomically with a five-minute user timer. No schema or
module migration and no beta/main changes. Include the end-user introduction,
guided first steps, reviewed Symcon screenshots and grouped module navigation.
Production publication requires versioned guides and screenshots, without draft
fallback.