Full rewrite of the docs site under app/[locale]/ with next-intl
in localePrefix:"always" mode. Every page now exists at both
/en/<path> and /es/<path>; the root / shows a meta-refresh + JS
redirect to /<defaultLocale>/ so GitHub Pages serves something
on the apex URL.
Highlights:
- 107 doc pages migrated to file-per-page JSON namespaces under
messages/en/ and messages/es/. Spanish content is fully
translated (no copy-of-English placeholders).
- New documentation for the Active Suppressions section in the
Settings tab and the per-event Dismiss dropdown in the Health
Monitor modal.
- New screenshots: dismiss-duration-dropdown.png and an updated
health-suppression-settings.png.
- Pagefind integrated for client-side search; index is built on
every CI deploy (not committed).
- RSS feeds: per-locale at /<locale>/rss.xml plus root /rss.xml
for backward compat.
- Removed the dead app/[locale]/guides/[slug]/ route — every
guide now has its own static page and no markdown source
remains.
- Fixed orphan link /guides/nvidia -> /guides/nvidia-manual in
docs/hardware/nvidia-host.
- Removed obsolete components (footer2, calendar, drawer).
Verified locally with `npm ci && npm run build`: 2804 files in
out/, 231 pages indexed by pagefind, root redirect intact, both
locale roots and the new Active Suppressions docs render OK.
- README: modernize visual layout (status badges row, tagline,
Ko-fi shields badge, expanded Contributing section). Update
web URLs to proxmenux.com/en for the new locale-prefixed site.
- CONTRIBUTING.md: add as the canonical contributor guide. Fix
the workflow section to branch from develop (not main), add
a dedicated "dialog vs whiptail" section, reorder so Script
Header comes first.
- deploy.yml: switch npm install -> npm ci so the build uses
the committed lockfile; fix cache-dependency-path to track
web/package-lock.json (was package.json); add scripts/** to
the path triggers so script edits redeploy the doc site.
- .gitignore: ignore the accidental root-level package.json /
package-lock.json (pagefind is declared in web/package.json)
and the regenerated build artifacts web/public/pagefind/ and
web/public/scripts/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Updated the Spanish roadmap document for ProxMenux, improving clarity and correcting phrasing throughout. Adjusted sections on version planning and contributions.
Pedro Rico, 19/05: after reinstalling the Monitor from GitHub a real
SSH/web login failure went unnotified. Root cause was the auth_fail
cooldown surviving across the service restart — install_proxmenux_beta
extracts the new AppImage but leaves the notification_last_sent SQLite
table intact (desirable: we don't want to lose legitimate cooldowns
on every update). On startup `_load_cooldowns_from_db()` then loaded
the stale auth_fail row from the previous run into the in-memory
cache, and `_passes_cooldown` blocked the new event.
This extends the existing reset-on-start mechanism (already in place
for update_summary, proxmenux_update, post_install_update, …) to also
clear auth_fail rows. A security-relevant event shouldn't be silenced
because the same source IP happened to fail to log in yesterday.
- Rename `_UPDATE_EVENT_TYPES_RESET_ON_START` → `_EVENT_TYPES_RESET_ON_START`
(the list no longer covers only update-status reports).
- Rename `_reset_update_cooldowns_on_start()` → `_reset_cooldowns_on_start()`
for the same reason.
- Add `'auth_fail'` to the curated list.
High-frequency sources (log_critical_*, disk SMART errors, …) are
deliberately NOT on this list — they keep their 24h cooldown across
restarts to prevent inbox floods if the user toggles the service.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the user reinstalls or restarts the Monitor (deploy of a new
beta AppImage), they expect to see a fresh "what's available now"
summary in Telegram/Gotify/etc. instead of silence — even if the
24h anti-spam cooldown for `update_summary` etc. hasn't expired yet.
Without this, the operator had to wait up to 24h after every
deploy before the next `update_summary`, `proxmenux_update`,
`post_install_update`, `pve_update`, `update_available`,
`nvidia_driver_update_available` or `secure_gateway_update_available`
notification fired. The 24h cooldown is the right default for steady
state (don't pester the user every poll cycle with the same "177
packages pending" reminder), but a service restart is an explicit
signal that the user wants a fresh status report.
- New _UPDATE_EVENT_TYPES_RESET_ON_START tuple lists the event types
to clear (everything in the "*_update*" + "update_*" family).
- New _reset_update_cooldowns_on_start() runs at start() right after
the running flag flips, before watchers/dispatcher come up.
- Patterns match both fingerprint shapes:
"<host>:<entity>:<event_type>:" trailing-colon form
"<host>:<entity>:<event_type>" no-suffix form (managed installs)
- In-memory `_cooldowns` cache is also pruned so the live dispatcher
picks up the reset immediately, without waiting for the next
`_load_cooldowns_from_db()` cycle.
Non-update cooldowns (auth_fail, log_critical_*, disk errors, …) are
preserved so a restart doesn't unleash a backlog of stale alerts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`_dispatch_to_channels` does NOT receive the NotificationEvent object —
only the rendered primitives (title, body, severity, event_type, …).
The Quiet Hours + Daily Digest merge introduced two references to
`event.severity` / `event` inside this function, which raised
`NameError: name 'event' is not defined` for every event passing
through dispatch.
The dispatch loop swallows the exception with a broad `except`, so the
visible symptom was "the Test button works but no real event ever
arrives" — both for community beta users (multiple reports on
Telegram, 9-18 May) and verified live on a test host (id 905 in
notification_history confirms the pipeline post-fix).
- _dispatch_to_channels: read `severity` / `event_type` directly
instead of `event.severity` / `event.event_type`.
- _should_buffer_for_digest: take (ch_name, severity, event_type)
primitives instead of a NotificationEvent.
- _buffer_digest_event: same — take (ch_name, event_type,
event_group, severity, title, body).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix webhook loopback detection and update handoff
Thanks for the thorough work here, jcastro — really appreciate the bug triage on top of the fix itself, it makes reviewing much easier.
The changes look good to me:
• _is_loopback_addr() is a clean solution. Using the stdlib ipaddress module and explicitly handling the IPv4-mapped IPv6 case (::ffff:127.0.0.1) is exactly what was needed after the dual-stack binding change. The docstring explaining why is a nice touch.
• The exec bash swap in menu is the right fix for #180. Replacing the shell before the installer overwrites /usr/local/bin/menu avoids the half-old/half-new parsing that was causing the syntax error on line 105. Good catch removing the now-unreachable return 0 too.
Validation looks solid (8/8 loopback cases, syntax checks on all scripts).
Merging into develop. Thanks again! 🙌