feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
"""Centralized configuration — two-layer system (ENV bootstrap + DB runtime).
|
|
|
|
|
|
|
|
|
|
On first start, ENV values seed the database.
|
|
|
|
|
After that, the database is the source of truth for all integration configs.
|
|
|
|
|
ENV is only needed for: DB connection, ADMIN_PASSWORD, JWT_SECRET.
|
|
|
|
|
"""
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import json
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
import logging
|
2026-03-02 01:48:51 +01:00
|
|
|
import os
|
|
|
|
|
from dataclasses import dataclass, field
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
from typing import Any, Dict, List
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class UnraidServer:
|
|
|
|
|
name: str
|
2026-03-02 23:25:57 +01:00
|
|
|
host: str = ""
|
|
|
|
|
mqtt_prefix: str = "" # MQTT topic prefix, e.g. "Adriahub" or "unraid-daddelolymp"
|
|
|
|
|
api_key: str = "" # Deprecated — kept for backward compat
|
|
|
|
|
port: int = 80 # Deprecated — kept for backward compat
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class Settings:
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
# --- Bootstrap (always from ENV) ---
|
2026-03-02 01:48:51 +01:00
|
|
|
db_host: str = "10.10.10.10"
|
|
|
|
|
db_port: int = 5433
|
|
|
|
|
db_name: str = "openclaw"
|
|
|
|
|
db_user: str = "sam"
|
|
|
|
|
db_password: str = "sam"
|
|
|
|
|
|
|
|
|
|
# --- Weather ---
|
|
|
|
|
weather_location: str = "Leverkusen"
|
|
|
|
|
weather_location_secondary: str = "Rab,Croatia"
|
2026-03-03 01:13:49 +01:00
|
|
|
weather_location_tertiary: str = "München"
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
weather_cache_ttl: int = 1800
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
# --- Home Assistant ---
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
ha_url: str = ""
|
2026-03-02 01:48:51 +01:00
|
|
|
ha_token: str = ""
|
|
|
|
|
ha_cache_ttl: int = 30
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
ha_enabled: bool = False
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
# --- Vikunja Tasks ---
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
vikunja_url: str = ""
|
2026-03-02 01:48:51 +01:00
|
|
|
vikunja_token: str = ""
|
|
|
|
|
vikunja_cache_ttl: int = 60
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
vikunja_enabled: bool = False
|
|
|
|
|
vikunja_private_projects: List[int] = field(default_factory=lambda: [3, 4])
|
|
|
|
|
vikunja_sams_projects: List[int] = field(default_factory=lambda: [2, 5])
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
# --- Unraid Servers ---
|
|
|
|
|
unraid_servers: List[UnraidServer] = field(default_factory=list)
|
|
|
|
|
unraid_cache_ttl: int = 15
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
unraid_enabled: bool = False
|
2026-03-02 01:48:51 +01:00
|
|
|
|
|
|
|
|
# --- News ---
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
news_cache_ttl: int = 300
|
2026-03-02 01:48:51 +01:00
|
|
|
news_max_age_hours: int = 48
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
news_enabled: bool = True
|
2026-03-02 01:48:51 +01:00
|
|
|
|
2026-03-02 10:13:50 +01:00
|
|
|
# --- MQTT ---
|
|
|
|
|
mqtt_host: str = ""
|
|
|
|
|
mqtt_port: int = 1883
|
|
|
|
|
mqtt_username: str = ""
|
|
|
|
|
mqtt_password: str = ""
|
|
|
|
|
mqtt_topics: List[str] = field(default_factory=lambda: ["#"])
|
|
|
|
|
mqtt_client_id: str = "daily-briefing"
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
mqtt_enabled: bool = False
|
2026-03-02 10:13:50 +01:00
|
|
|
|
2026-03-02 01:48:51 +01:00
|
|
|
# --- Server ---
|
|
|
|
|
host: str = "0.0.0.0"
|
|
|
|
|
port: int = 8080
|
|
|
|
|
debug: bool = False
|
|
|
|
|
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
# --- WebSocket ---
|
|
|
|
|
ws_interval: int = 15
|
|
|
|
|
|
2026-03-02 01:48:51 +01:00
|
|
|
@classmethod
|
|
|
|
|
def from_env(cls) -> "Settings":
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
"""Load bootstrap config from environment variables."""
|
2026-03-02 01:48:51 +01:00
|
|
|
s = cls()
|
|
|
|
|
s.db_host = os.getenv("DB_HOST", s.db_host)
|
|
|
|
|
s.db_port = int(os.getenv("DB_PORT", str(s.db_port)))
|
|
|
|
|
s.db_name = os.getenv("DB_NAME", s.db_name)
|
|
|
|
|
s.db_user = os.getenv("DB_USER", s.db_user)
|
|
|
|
|
s.db_password = os.getenv("DB_PASSWORD", s.db_password)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.debug = os.getenv("DEBUG", "").lower() in ("1", "true", "yes")
|
2026-03-02 01:48:51 +01:00
|
|
|
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
# Legacy ENV support — used for first-run seeding
|
2026-03-02 01:48:51 +01:00
|
|
|
s.weather_location = os.getenv("WEATHER_LOCATION", s.weather_location)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.weather_location_secondary = os.getenv("WEATHER_LOCATION_SECONDARY", s.weather_location_secondary)
|
2026-03-03 01:13:49 +01:00
|
|
|
s.weather_location_tertiary = os.getenv("WEATHER_LOCATION_TERTIARY", s.weather_location_tertiary)
|
2026-03-02 01:48:51 +01:00
|
|
|
s.ha_url = os.getenv("HA_URL", s.ha_url)
|
|
|
|
|
s.ha_token = os.getenv("HA_TOKEN", s.ha_token)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.ha_enabled = bool(s.ha_url)
|
2026-03-02 01:48:51 +01:00
|
|
|
s.vikunja_url = os.getenv("VIKUNJA_URL", s.vikunja_url)
|
|
|
|
|
s.vikunja_token = os.getenv("VIKUNJA_TOKEN", s.vikunja_token)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.vikunja_enabled = bool(s.vikunja_url)
|
2026-03-02 10:13:50 +01:00
|
|
|
s.mqtt_host = os.getenv("MQTT_HOST", s.mqtt_host)
|
|
|
|
|
s.mqtt_port = int(os.getenv("MQTT_PORT", str(s.mqtt_port)))
|
|
|
|
|
s.mqtt_username = os.getenv("MQTT_USERNAME", s.mqtt_username)
|
|
|
|
|
s.mqtt_password = os.getenv("MQTT_PASSWORD", s.mqtt_password)
|
|
|
|
|
s.mqtt_client_id = os.getenv("MQTT_CLIENT_ID", s.mqtt_client_id)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.mqtt_enabled = bool(s.mqtt_host)
|
2026-03-02 10:13:50 +01:00
|
|
|
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
# Parse MQTT_TOPICS
|
2026-03-02 10:13:50 +01:00
|
|
|
raw_topics = os.getenv("MQTT_TOPICS", "")
|
|
|
|
|
if raw_topics:
|
|
|
|
|
try:
|
|
|
|
|
s.mqtt_topics = json.loads(raw_topics)
|
|
|
|
|
except (json.JSONDecodeError, TypeError):
|
|
|
|
|
s.mqtt_topics = [t.strip() for t in raw_topics.split(",") if t.strip()]
|
|
|
|
|
|
2026-03-02 01:48:51 +01:00
|
|
|
# Parse UNRAID_SERVERS JSON
|
|
|
|
|
raw = os.getenv("UNRAID_SERVERS", "[]")
|
|
|
|
|
try:
|
|
|
|
|
servers_data = json.loads(raw)
|
|
|
|
|
s.unraid_servers = [
|
|
|
|
|
UnraidServer(
|
|
|
|
|
name=srv.get("name", f"Server {i+1}"),
|
|
|
|
|
host=srv.get("host", ""),
|
2026-03-02 23:25:57 +01:00
|
|
|
mqtt_prefix=srv.get("mqtt_prefix", ""),
|
2026-03-02 01:48:51 +01:00
|
|
|
api_key=srv.get("api_key", ""),
|
|
|
|
|
port=int(srv.get("port", 80)),
|
|
|
|
|
)
|
|
|
|
|
for i, srv in enumerate(servers_data)
|
2026-03-02 23:25:57 +01:00
|
|
|
if srv.get("name") or srv.get("host")
|
2026-03-02 01:48:51 +01:00
|
|
|
]
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
s.unraid_enabled = len(s.unraid_servers) > 0
|
2026-03-02 01:48:51 +01:00
|
|
|
except (json.JSONDecodeError, TypeError):
|
|
|
|
|
s.unraid_servers = []
|
|
|
|
|
|
|
|
|
|
return s
|
|
|
|
|
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
async def load_from_db(self) -> None:
|
|
|
|
|
"""Override fields with values from the database."""
|
|
|
|
|
try:
|
|
|
|
|
from server.services import settings_service
|
|
|
|
|
|
|
|
|
|
# Load integrations
|
|
|
|
|
integrations = await settings_service.get_integrations()
|
|
|
|
|
for integ in integrations:
|
|
|
|
|
cfg = integ.get("config", {})
|
|
|
|
|
enabled = integ.get("enabled", True)
|
|
|
|
|
itype = integ["type"]
|
|
|
|
|
|
|
|
|
|
if itype == "weather":
|
|
|
|
|
self.weather_location = cfg.get("location", self.weather_location)
|
|
|
|
|
self.weather_location_secondary = cfg.get("location_secondary", self.weather_location_secondary)
|
2026-03-03 01:13:49 +01:00
|
|
|
self.weather_location_tertiary = cfg.get("location_tertiary", self.weather_location_tertiary)
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
|
|
|
|
|
elif itype == "news":
|
|
|
|
|
self.news_max_age_hours = int(cfg.get("max_age_hours", self.news_max_age_hours))
|
|
|
|
|
self.news_enabled = enabled
|
|
|
|
|
|
|
|
|
|
elif itype == "ha":
|
|
|
|
|
self.ha_url = cfg.get("url", self.ha_url)
|
|
|
|
|
self.ha_token = cfg.get("token", self.ha_token)
|
|
|
|
|
self.ha_enabled = enabled
|
|
|
|
|
|
|
|
|
|
elif itype == "vikunja":
|
|
|
|
|
self.vikunja_url = cfg.get("url", self.vikunja_url)
|
|
|
|
|
self.vikunja_token = cfg.get("token", self.vikunja_token)
|
|
|
|
|
self.vikunja_private_projects = cfg.get("private_projects", self.vikunja_private_projects)
|
|
|
|
|
self.vikunja_sams_projects = cfg.get("sams_projects", self.vikunja_sams_projects)
|
|
|
|
|
self.vikunja_enabled = enabled
|
|
|
|
|
|
|
|
|
|
elif itype == "unraid":
|
|
|
|
|
servers = cfg.get("servers", [])
|
|
|
|
|
self.unraid_servers = [
|
|
|
|
|
UnraidServer(
|
|
|
|
|
name=s.get("name", ""),
|
|
|
|
|
host=s.get("host", ""),
|
2026-03-02 23:25:57 +01:00
|
|
|
mqtt_prefix=s.get("mqtt_prefix", ""),
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
api_key=s.get("api_key", ""),
|
|
|
|
|
port=int(s.get("port", 80)),
|
|
|
|
|
)
|
|
|
|
|
for s in servers
|
2026-03-02 23:25:57 +01:00
|
|
|
if s.get("name") or s.get("host")
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
]
|
|
|
|
|
self.unraid_enabled = enabled
|
|
|
|
|
|
|
|
|
|
elif itype == "mqtt":
|
|
|
|
|
self.mqtt_host = cfg.get("host", self.mqtt_host)
|
|
|
|
|
self.mqtt_port = int(cfg.get("port", self.mqtt_port))
|
|
|
|
|
self.mqtt_username = cfg.get("username", self.mqtt_username)
|
|
|
|
|
self.mqtt_password = cfg.get("password", self.mqtt_password)
|
|
|
|
|
self.mqtt_client_id = cfg.get("client_id", self.mqtt_client_id)
|
|
|
|
|
self.mqtt_topics = cfg.get("topics", self.mqtt_topics)
|
|
|
|
|
self.mqtt_enabled = enabled
|
|
|
|
|
|
|
|
|
|
# Load app_settings (cache TTLs, etc.)
|
|
|
|
|
all_settings = await settings_service.get_all_settings()
|
|
|
|
|
for key, data in all_settings.items():
|
|
|
|
|
val = data["value"]
|
|
|
|
|
if key == "weather_cache_ttl":
|
|
|
|
|
self.weather_cache_ttl = int(val)
|
|
|
|
|
elif key == "ha_cache_ttl":
|
|
|
|
|
self.ha_cache_ttl = int(val)
|
|
|
|
|
elif key == "vikunja_cache_ttl":
|
|
|
|
|
self.vikunja_cache_ttl = int(val)
|
|
|
|
|
elif key == "unraid_cache_ttl":
|
|
|
|
|
self.unraid_cache_ttl = int(val)
|
|
|
|
|
elif key == "news_cache_ttl":
|
|
|
|
|
self.news_cache_ttl = int(val)
|
|
|
|
|
elif key == "ws_interval":
|
|
|
|
|
self.ws_interval = int(val)
|
|
|
|
|
|
|
|
|
|
logger.info("Settings loaded from database (%d integrations)", len(integrations))
|
|
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.exception("Failed to load settings from DB — using ENV defaults")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- Module-level singleton ---
|
2026-03-02 01:48:51 +01:00
|
|
|
settings = Settings.from_env()
|
feat: add Admin Panel with JWT auth, DB settings, and integration management
Complete admin backend with login, where all integrations (weather, news,
Home Assistant, Vikunja, Unraid, MQTT) can be configured via web UI instead
of ENV variables. Two-layer config: ENV seeds DB on first start, then DB
is source of truth. Auto-migration system on startup.
Backend: db.py shared pool, auth.py JWT, settings_service CRUD, seed_service,
admin router (protected), test_connections per integration, config.py rewrite.
Frontend: react-router v6, login page, admin layout with sidebar, 8 settings
pages (General, Weather, News, HA, Vikunja, Unraid, MQTT, ChangePassword),
shared IntegrationForm + TestButton components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:30 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_settings() -> Settings:
|
|
|
|
|
"""Return the current settings. Used by all routers."""
|
|
|
|
|
return settings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def reload_settings() -> None:
|
|
|
|
|
"""Reload settings from DB. Called after admin changes."""
|
|
|
|
|
global settings
|
|
|
|
|
s = Settings.from_env()
|
|
|
|
|
await s.load_from_db()
|
|
|
|
|
settings = s
|
|
|
|
|
logger.info("Settings reloaded from database")
|