diff --git a/backend/src/db.js b/backend/src/db.js index 9ea51551..faaf981d 100644 --- a/backend/src/db.js +++ b/backend/src/db.js @@ -81,7 +81,9 @@ export async function initDb() { await pool.query(` INSERT INTO app_settings (key, value) VALUES ('forecasting_url', ''), - ('forecasting_api_key', '') + ('forecasting_api_key', ''), + ('utilities_url', ''), + ('utilities_api_key', '') ON CONFLICT (key) DO NOTHING `) } diff --git a/backend/src/lib/utilities-client.js b/backend/src/lib/utilities-client.js index 961738d8..3357c528 100644 --- a/backend/src/lib/utilities-client.js +++ b/backend/src/lib/utilities-client.js @@ -1,11 +1,13 @@ // Client for the `utilities` app's internal API (meter readings, tariffs, energy costs). // Mirrors the existing forecasting integration pattern used in // routes/directors-forecast.js and routes/weekly-actual.js (X-API-Key header, -// base URL + key from env, throw on non-2xx). +// base URL + key from the app_settings table — set via Settings UI — with +// env vars as a fallback, throw on non-2xx). +import { getSetting } from '../db.js' async function utilFetch(path) { - const apiKey = process.env.UTILITIES_API_KEY - const baseUrl = process.env.UTILITIES_URL || 'http://10.10.10.127:3080' + const apiKey = await getSetting('utilities_api_key') || process.env.UTILITIES_API_KEY + const baseUrl = await getSetting('utilities_url') || process.env.UTILITIES_URL || 'http://10.10.10.127:3080' if (!apiKey) throw new Error('UTILITIES_API_KEY not configured') const res = await fetch(`${baseUrl}${path}`, { headers: { 'X-API-Key': apiKey }, diff --git a/backend/src/routes/settings.js b/backend/src/routes/settings.js index 07ade62f..f9eb670b 100644 --- a/backend/src/routes/settings.js +++ b/backend/src/routes/settings.js @@ -1,7 +1,7 @@ import { requireAuth } from '../auth.js' import { pool } from '../db.js' -const ALLOWED_KEYS = new Set(['forecasting_url', 'forecasting_api_key']) +const ALLOWED_KEYS = new Set(['forecasting_url', 'forecasting_api_key', 'utilities_url', 'utilities_api_key']) export async function settingsRoutes(fastify) { fastify.addHook('preHandler', requireAuth) diff --git a/frontend/src/pages/SettingsPage.tsx b/frontend/src/pages/SettingsPage.tsx index 1be31307..06e327bf 100644 --- a/frontend/src/pages/SettingsPage.tsx +++ b/frontend/src/pages/SettingsPage.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { Save } from 'lucide-react' import { getSettings, saveSettings, type AppSetting } from '../api' -const SETTING_LABELS: Record = { +const SETTING_LABELS: Record = { forecasting_api_key: { label: 'Forecasting API Key', hint: 'API key for the Forecasting app public API. Create one in Forecasting → Settings → API Keys.', @@ -11,6 +11,17 @@ const SETTING_LABELS: Record setValues(v => ({ ...v, [s.key]: e.target.value }))} className="setting-input" autoComplete="off"