Files
HeatGuard/internal/store/schema.sql
vikingowl 1c9db02334 feat: add web UI with full CRUD setup page
Add server-side rendered setup UI accessible via `heatwave web`.
The dashboard is now re-rendered per request and includes a nav bar
linking to the new /setup page. Setup provides full CRUD for profiles,
rooms, devices, occupants, AC units (with room assignment), scenario
toggles, and forecast fetching — all via POST/redirect/GET forms.

- Add ShowNav field to DashboardData for conditional nav bar
- Extract fetchForecastForProfile() for reuse by web handler
- Create setup.html.tmpl with Tailwind-styled entity sections
- Create web_handlers.go with 15 route handlers and flash cookies
- Switch web.go from pre-rendered to per-request dashboard rendering
- Graceful dashboard fallback when no forecast data exists
2026-02-09 10:39:00 +01:00

107 lines
4.0 KiB
SQL

CREATE TABLE IF NOT EXISTS profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
timezone TEXT NOT NULL DEFAULT 'Europe/Berlin',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS rooms (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_id INTEGER NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
name TEXT NOT NULL,
area_sqm REAL NOT NULL,
ceiling_height_m REAL NOT NULL DEFAULT 2.5,
floor INTEGER NOT NULL DEFAULT 0,
orientation TEXT NOT NULL DEFAULT 'N',
shading_type TEXT NOT NULL DEFAULT 'none',
shading_factor REAL NOT NULL DEFAULT 1.0,
ventilation TEXT NOT NULL DEFAULT 'natural',
ventilation_ach REAL NOT NULL DEFAULT 0.5,
window_fraction REAL NOT NULL DEFAULT 0.15,
shgc REAL NOT NULL DEFAULT 0.6,
insulation TEXT NOT NULL DEFAULT 'average',
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS occupants (
id INTEGER PRIMARY KEY AUTOINCREMENT,
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
count INTEGER NOT NULL DEFAULT 1,
activity_level TEXT NOT NULL DEFAULT 'sedentary',
vulnerable INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS devices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
name TEXT NOT NULL,
device_type TEXT NOT NULL,
watts_idle REAL NOT NULL DEFAULT 0,
watts_typical REAL NOT NULL DEFAULT 0,
watts_peak REAL NOT NULL DEFAULT 0,
duty_cycle REAL NOT NULL DEFAULT 1.0,
schedule TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS ac_units (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_id INTEGER NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
name TEXT NOT NULL,
ac_type TEXT NOT NULL DEFAULT 'portable',
capacity_btu REAL NOT NULL,
has_dehumidify INTEGER NOT NULL DEFAULT 0,
efficiency_eer REAL NOT NULL DEFAULT 10.0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS ac_room_assignments (
ac_id INTEGER NOT NULL REFERENCES ac_units(id) ON DELETE CASCADE,
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
PRIMARY KEY (ac_id, room_id)
);
CREATE TABLE IF NOT EXISTS forecasts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_id INTEGER NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
timestamp TEXT NOT NULL,
temperature_c REAL,
humidity_pct REAL,
wind_speed_ms REAL,
cloud_cover_pct REAL,
precipitation_mm REAL,
sunshine_min REAL,
pressure_hpa REAL,
dew_point_c REAL,
apparent_temp_c REAL,
condition TEXT,
source TEXT NOT NULL,
fetched_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(profile_id, timestamp, source)
);
CREATE TABLE IF NOT EXISTS warnings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_id INTEGER NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
warning_id TEXT NOT NULL UNIQUE,
event_type TEXT,
severity TEXT,
headline TEXT,
description TEXT,
instruction TEXT,
onset TEXT,
expires TEXT,
fetched_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS toggles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
profile_id INTEGER NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
name TEXT NOT NULL,
active INTEGER NOT NULL DEFAULT 0,
activated_at TEXT
);