Make the docs state things rather than argue them
Docs / docs (push) Successful in 37s
Playwright Tests / test-playwright (1, 2) (push) Failing after 1m35s
Playwright Tests / test-playwright (2, 2) (push) Failing after 17s
pre-commit / pre-commit (push) Failing after 2m8s
Test Backend / test-backend (push) Failing after 2m48s
Compose Smoke Test / test-compose (push) Failing after 13s
Playwright Tests / merge-reports (push) Failing after 2m25s
Docs / docs (push) Successful in 37s
Playwright Tests / test-playwright (1, 2) (push) Failing after 1m35s
Playwright Tests / test-playwright (2, 2) (push) Failing after 17s
pre-commit / pre-commit (push) Failing after 2m8s
Test Backend / test-backend (push) Failing after 2m48s
Compose Smoke Test / test-compose (push) Failing after 13s
Playwright Tests / merge-reports (push) Failing after 2m25s
The site read as a design journal: rationale paragraphs, hedges
("deliberately", "on purpose", "genuinely"), meta-commentary about the docs
themselves, and one em-dash every ten lines carrying an aside.
Roughly twenty rationale blocks are gone or reduced to what a reader needs
in order to use the thing. Em-dashes go from 507 to 135, and what is left is
structural rather than prose: list and definition separators, table cells,
and four inside code blocks that quote what the CLI actually prints.
Also: api.example.com becomes api.fluksio.com (the emails stay, since
bootstrap.py really defaults to admin@example.com and RFC 2606 reserves it);
the mqtt table gains the two settings it had drifted behind on and inject's
wording matches the engine; llms.txt lists the two connector pages that were
in the nav but not in it; and the two device/device_policy notes now agree.
Builds clean under `zensical build --strict`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
@@ -20,7 +20,7 @@ in this interface a lot, so it is worth learning it properly.
|
||||
└── workers on other boxes (optional)
|
||||
```
|
||||
|
||||
One engine holds every flow. Nothing here is a plugin you install separately —
|
||||
One engine holds every flow. Nothing here is a plugin you install separately:
|
||||
the broker client, the time-series writer, the dashboards and the alerting are
|
||||
all part of the same process, editing the same graph.
|
||||
|
||||
@@ -28,7 +28,7 @@ all part of the same process, editing the same graph.
|
||||
|
||||
- Docker and Compose v2 on the host
|
||||
- The address you will type into a browser. On a home network that is the
|
||||
server's own address — `192.168.1.50` — and nothing else is needed. A
|
||||
server's own address, `192.168.1.50`, and nothing else is needed. A
|
||||
hostname is optional, and covered below
|
||||
- Optionally: an MQTT broker and an InfluxDB you already run. If not, the stack
|
||||
can start both for you
|
||||
@@ -53,15 +53,15 @@ $EDITOR .env # FIRST_SUPERUSER, ENVIRONMENT=production
|
||||
| `FIRST_SUPERUSER_PASSWORD` | leave it as `changethis` and one is generated for you |
|
||||
| `ENVIRONMENT` | `production` closes the interactive API schema; `local` leaves it open |
|
||||
|
||||
Everything the instance owns — the database, your flows, secrets,
|
||||
artifacts, the packages your node code imports — is on one Docker volume.
|
||||
Everything the instance owns (the database, your flows, secrets, artifacts,
|
||||
the packages your node code imports) is on one Docker volume.
|
||||
Backing that volume up is backing up the instance.
|
||||
|
||||
??? note "Even smaller: no Docker at all"
|
||||
|
||||
`pip install fluksio && fluksio serve` gives you the same engine with no
|
||||
containers, keeping its data in `~/.fluksio`. What it does not give you is
|
||||
the web interface, which the SPA container serves — so you would drive it
|
||||
the web interface, which the SPA container serves, so you would drive it
|
||||
from the API, or [pair it with a portal](../interface/portal.md) that
|
||||
serves the dashboard for you. Good for a Raspberry Pi that only runs flows;
|
||||
less good as your main instance.
|
||||
@@ -82,7 +82,7 @@ APP_PORT=8080 docker compose -p fluksio-app --env-file .env \
|
||||
-f docker/compose.yml -f docker/compose.lan.yml up -d --build
|
||||
```
|
||||
|
||||
Open `http://192.168.1.50:8080`. That one address is the whole application —
|
||||
Open `http://192.168.1.50:8080`. That one address is the whole application:
|
||||
the interface, the API under `/api`, and the websocket that puts live values on
|
||||
the canvas.
|
||||
|
||||
@@ -96,13 +96,13 @@ maintaining: the browser is talking to one origin.
|
||||
|
||||
A published port is plain HTTP with no certificate. Between your own
|
||||
machines that is fine, and it is not something to forward from a router. To
|
||||
reach the house from outside, put a reverse proxy with TLS in front of it —
|
||||
reach the house from outside, put a reverse proxy with TLS in front of it,
|
||||
or [pair it with a portal](../interface/portal.md), which needs no inbound
|
||||
route at all.
|
||||
|
||||
### With a hostname, behind a reverse proxy
|
||||
|
||||
If you have DNS — or want certificates — set `DOMAIN` and run `make up`
|
||||
If you have DNS, or want certificates, set `DOMAIN` and run `make up`
|
||||
instead. The interface is then served on `app.${DOMAIN}` and the API on
|
||||
`api.${DOMAIN}`, and nothing is published on a host port.
|
||||
|
||||
@@ -113,7 +113,7 @@ attach it to the `proxy` network and forward `app.${DOMAIN}` →
|
||||
|
||||
!!! tip "Developing on the same machine"
|
||||
|
||||
`make dev-lan` is the same idea for the integrated dev stack — the app on
|
||||
`make dev-lan` is the same idea for the integrated dev stack: the app on
|
||||
`http://<host-ip>:8080`, `APP_PORT` to move it. `make dev` rebuilds without
|
||||
the published port, so re-run `make dev-lan` after one.
|
||||
|
||||
@@ -128,9 +128,8 @@ Go to **Flows → New flow** and call it `house`. You land on the canvas.
|
||||
|
||||
A flow is a set of nodes that talk to each other through **named messages**.
|
||||
You do not draw wires: a node says which messages it needs and which it
|
||||
produces, and the canvas draws the graph that follows from those names. That
|
||||
sounds like a small difference and turns out to be a large one — renaming is
|
||||
safe, fan-in is free, and two flows can share a value by naming it.
|
||||
produces, and the canvas draws the graph that follows. Renaming is safe, fan-in
|
||||
is free, and two flows share a value by naming it.
|
||||
|
||||
### Read a sensor
|
||||
|
||||
@@ -150,8 +149,8 @@ broker sends one. Click the wire to see the last payload and its history.
|
||||
|
||||
### Do something with it
|
||||
|
||||
Add a **Function** node. This is a Python node — the code editor opens in its
|
||||
panel:
|
||||
Add a **Function** node. This is a Python node, and the code editor opens in
|
||||
its panel:
|
||||
|
||||
```python
|
||||
def process(living_temperature, comfortable=21.0):
|
||||
@@ -160,7 +159,7 @@ def process(living_temperature, comfortable=21.0):
|
||||
```
|
||||
|
||||
Declare `living_temperature` as an input (type `float`) and `heat_wanted` as an
|
||||
output (type `bool`). `comfortable` is not a port — it is a **setting**,
|
||||
output (type `bool`). `comfortable` is not a port but a **setting**,
|
||||
because it is a constant of this node rather than something the graph carries.
|
||||
It shows up as a field in the node's Settings section.
|
||||
|
||||
@@ -178,8 +177,8 @@ Publish the flow. You have a thermostat.
|
||||
!!! warning "Test before it touches a relay"
|
||||
|
||||
A flow can be **paused** (it holds messages instead of running them) and
|
||||
**stepped** (release exactly one). Together with the run button — which
|
||||
injects a value by hand — that is how you convince yourself the logic is
|
||||
**stepped** (release exactly one). Together with the run button, which
|
||||
injects a value by hand, that is how you convince yourself the logic is
|
||||
right before the contactor finds out. Both live on the dock at the bottom
|
||||
of the canvas.
|
||||
|
||||
@@ -212,11 +211,10 @@ point.
|
||||
Note the token. Credentials never sit in a flow: `{"$secret": "influx-token"}`
|
||||
is a reference into an encrypted store, and the editor renders those fields as
|
||||
a secret picker. Add the actual value once under **Secrets**. Flows are a git
|
||||
repository you might well push somewhere — this is what keeps a password out of
|
||||
it.
|
||||
repository you might well push somewhere, so this keeps a password out of it.
|
||||
|
||||
Reading back is the same node with `queries` instead of `writes`, or — for
|
||||
anything a chart asks for — a pair of small Python nodes on either side that
|
||||
Reading back is the same node with `queries` instead of `writes`, or, for
|
||||
anything a chart asks for, a pair of small Python nodes on either side that
|
||||
build a Flux query and shape its rows. That indirection is deliberate: the
|
||||
database node holds the connection and nothing else, so a dashboard widget
|
||||
never learns which database answered it.
|
||||
@@ -231,7 +229,7 @@ Widgets are typed the same way ports are: a switch binds to a `bool`, a gauge
|
||||
to a number, an agenda to a `list`. Bind it wrong and the editor says so rather
|
||||
than drawing nothing.
|
||||
|
||||
Controls work in the other direction — a switch on a dashboard publishes the
|
||||
Controls work in the other direction: a switch on a dashboard publishes the
|
||||
message it is bound to, exactly as a node would. The canvas draws it as a
|
||||
labelled endpoint feeding the nodes that read it, so a value never appears from
|
||||
nowhere.
|
||||
@@ -247,7 +245,7 @@ lives on a different network, or something needs hardware the engine's host
|
||||
does not have.
|
||||
|
||||
The unit of distribution is the **worker**. It runs the code of nodes you mark
|
||||
for it, and it dials *out* to the engine — so the Pi in the shed does not need
|
||||
for it, and it dials *out* to the engine, so the Pi in the shed does not need
|
||||
an inbound route, and the engine does not need to reach it.
|
||||
|
||||
On the engine, mint a token:
|
||||
@@ -276,7 +274,7 @@ flow before the hardware arrives.
|
||||
!!! note "What a worker is not"
|
||||
|
||||
It is not a second engine. Subscriptions, schedules, webhooks and the
|
||||
dashboards all stay in one process — that is what keeps a value having one
|
||||
dashboards all stay in one process, which keeps a value having one
|
||||
definition. A worker executes node bodies, nothing else. Scaling *the
|
||||
engine* to several processes is not supported: run one.
|
||||
|
||||
@@ -291,9 +289,9 @@ What you probably want on day one is everything, to ntfy:
|
||||
- add an ntfy channel with your server and topic
|
||||
- add a rule with no events ticked, which means *all of them*
|
||||
|
||||
The engine deduplicates aggressively — the same node failing every second is
|
||||
one alert, not thirty-six thousand — and caps the total at ten an hour however
|
||||
bad it gets. See [Secrets, modules and alerts](../interface/operations.md).
|
||||
The engine deduplicates aggressively, so the same node failing every second is
|
||||
one alert rather than thirty-six thousand, and caps the total at ten an hour
|
||||
however bad it gets. See [Secrets, modules and alerts](../interface/operations.md).
|
||||
|
||||
## Keep it alive
|
||||
|
||||
|
||||
Reference in New Issue
Block a user