- move state collectors from lib/state.py to daemon/collectors/ (7
modules, registration side-effect; daemon/server.py imports the
package before the first populate())
- webui/api: new daemon_route() decorator factory in common.py
collapses the try/except daemon-proxy boilerplate in all 8
blueprints (rules/params/body/transform keep responses identical)
- firewall: interface-coverage invariant — config is the source of
truth for zone interfaces (absent key = empty, no hands-off
zones); pure validate_coverage() enforced at save (400) and apply
(409, force: true overrides), top-level `unmanaged` exemption
- lib: get_config() reads are now pure (no dir creation or writes);
new lib/bootstrap.py creates runtime dirs and persists the
one-shot nginx legacy migration at daemon start, after
system_import (lib.nginx.migrate_config_file)
- lib/common: compute_pending() apply-bookkeeping helper
- daemon: emit_and_refresh() handler helper; refresh_state(bump=) so
/status/refresh no longer bumps versions (poll/mutation only)
- acme: move --log last so acme.sh never treats a real arg as the
log-file argument
- docs: AGENTS.md, config.md, state-model.md, api.md updated;
HARDEN.md dropped (plan implemented); apply-confirm force wording
Tests: 917 passed; ruff check + format clean.
Add comprehensive docstrings to firewall, DHCP, proxy, wireguard, certs,
and logs API endpoints. Document parameters, return values, and error cases
for the documentation system.
- Add daemon/ module with aiohttp server, sync client, and handler registry
- Add daemon/handlers/ for privileged operations (acme, dnsmasq, firewall, logs, nginx, wireguard)
- Add system/acme-deploy.py, vacuum-walld sudoers and systemd service
- Update API routes to use daemon client instead of lib/ directly
- Update lib/, tests/, and webui/ for new architecture
- Update docs and deployment scripts
- wireguard: POST /peers with JSON encoding (was /add-peer)
- rules: delete by rule_id in URL path (was JSON body); pass rule objects with id from server; add hx-disable to initial render
- nat: port forward delete uses URL path params to match blueprint
- nat: masquerade toggle uses native hx-post/hx-vals (was inline fetch)
- app.js renderers updated to use URL path deletes for rules and forwards
- remove TODO.md