Lets plant have its own dedicated MQTT credentials instead of sharing
the single central mqtt integration with utilities/hvac, so its
dynsec client can be scoped to plant/# without touching other apps'
access. Generalizes the test-connection dispatch to match any
mqtt_* slug, not just the literal 'mqtt' one.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New /settings/api/mqtt-clients routes (list/create/revoke/delete) manage
per-consumer dynamic-security identities on the shared broker (LXC 104) —
name + topic scope + publish/subscribe flags in, generated username/password
out (shown once, never stored). Replaces manually running mosquitto_ctrl
over SSH by hand for every new device or app that needs broker access.
Implementation SSHs into the broker LXC and runs mosquitto_ctrl inside a
throwaway container on its Docker network (src/lib/ssh.js + mqtt-dynsec.js)
rather than reimplementing the dynamic-security plugin's JSON wire protocol
from scratch — reuses the exact commands verified by hand while wiring up
the water-softener and mqtt-inspector clients this session. Needs the
shared deploy SSH key mounted (Dockerfile/compose changes) and
MQTT_ADMIN_USER/PASS threaded in via stack-init.
mqtt_clients table is bookkeeping only (name/scope/active) — the broker's
own dynamic-security.json remains the source of truth for auth.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
schema.js already had an uncommitted mqtt entry (host/port config,
username/password secrets) from a prior session — commits it now, adds
the missing test-connection case (routes/integrations.js), and the mqtt
package dependency it needs. The existing generic integration card UI in
portal's AdminSettings.tsx needs no changes — it renders any schema
entry automatically. initDb() auto-seeds the 'mqtt' row on next restart,
so the "MQTT Broker" card will appear in Settings -> Integrations.
Also adds a .gitignore — node_modules was untracked in this repo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lets the Claude API key be managed once in Portal → Settings →
Integrations and shared across apps (forecasting, wages), instead of
each app storing its own copy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Registers hosted_tables in the integration schema with a single site_url config
field. On save, syncHostedTables() PATCHes auth to update restaurant_bookings
base_path and active state, so the portal app appears only when a URL is set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /settings/api/integrations/nextcloud/browse?path=<path>
Uses stored Nextcloud credentials to PROPFIND the given path and
returns a sorted list of subdirectories for the UI picker.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows a Nextcloud subdirectory to be specified as the target for
stack-level backups run by the management backup service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Repurpose the azure slot from Azure AD (tenant_id/client_id/client_secret)
to Azure Document Intelligence (endpoint/api_key), matching the kitchen
app's OCR credential fields. The kitchen can now delegate its OCR credentials
to the central settings service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After a successful PUT to /integrations/workforce or /integrations/smtp,
fire-and-forget POST to auth's /internal/cache-bust so credential changes
(including default location) propagate instantly without a container restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds bearer_token secret field — if configured, the auth service uses it
directly and skips the OAuth password grant entirely. Falls back to
email/password flow if no token is set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows other services (e.g. room-planner) to read shared config
stored in settings_db without cross-database queries. Auth via
SETTINGS_SECRET bearer token, same pattern as /internal/integration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Config object starts empty so the frontend had nothing to render for
plaintext fields (region, username etc). Now populates all schema-defined
fields with empty string when not yet saved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fastify API for storing third-party integration credentials (Newbook, Resos,
Nextcloud, Azure, SambaPOS) with AES-256-GCM encryption for sensitive fields.
Includes Newbook room sync endpoint and global_config store for shared app data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>