99 lines
4.3 KiB
MySQL
99 lines
4.3 KiB
MySQL
|
|
-- BlindMaster schema. Idempotent: CREATE … IF NOT EXISTS so it works on a
|
||
|
|
-- fresh DB and replays cleanly against an existing one.
|
||
|
|
|
||
|
|
-- ── Core auth ───────────────────────────────────────────────────────────────
|
||
|
|
CREATE TABLE IF NOT EXISTS users (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
name TEXT,
|
||
|
|
email TEXT NOT NULL UNIQUE,
|
||
|
|
password_hash_string TEXT NOT NULL,
|
||
|
|
verification_token TEXT,
|
||
|
|
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||
|
|
timezone TEXT DEFAULT 'America/Chicago',
|
||
|
|
apns_token TEXT,
|
||
|
|
fcm_token TEXT, -- legacy (FCM era), kept harmless
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
|
|
);
|
||
|
|
|
||
|
|
-- One active session token per user. Code does delete-then-insert on login,
|
||
|
|
-- so PK on user_id enforces it.
|
||
|
|
CREATE TABLE IF NOT EXISTS user_tokens (
|
||
|
|
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
token TEXT NOT NULL UNIQUE,
|
||
|
|
connected BOOLEAN NOT NULL DEFAULT FALSE,
|
||
|
|
socket TEXT
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||
|
|
email TEXT PRIMARY KEY,
|
||
|
|
token TEXT NOT NULL,
|
||
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS user_pending_emails (
|
||
|
|
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
pending_email TEXT NOT NULL,
|
||
|
|
token TEXT NOT NULL,
|
||
|
|
expires_at TIMESTAMPTZ NOT NULL
|
||
|
|
);
|
||
|
|
|
||
|
|
-- ── Hardware: hubs (devices) and their controlled blinds (peripherals) ──────
|
||
|
|
CREATE TABLE IF NOT EXISTS devices (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
device_name TEXT NOT NULL,
|
||
|
|
max_ports INTEGER NOT NULL DEFAULT 4,
|
||
|
|
battery_soc SMALLINT,
|
||
|
|
timezone TEXT,
|
||
|
|
UNIQUE (user_id, device_name)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- token UNIQUE so socket-auth can `select device_id … where token=$1` quickly.
|
||
|
|
CREATE TABLE IF NOT EXISTS device_tokens (
|
||
|
|
device_id INTEGER NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
|
||
|
|
token TEXT NOT NULL UNIQUE,
|
||
|
|
connected BOOLEAN NOT NULL DEFAULT FALSE,
|
||
|
|
socket TEXT
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS device_tokens_device_id_idx ON device_tokens(device_id);
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS peripherals (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
device_id INTEGER NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
|
||
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
peripheral_number INTEGER NOT NULL,
|
||
|
|
peripheral_name TEXT NOT NULL,
|
||
|
|
last_pos INTEGER,
|
||
|
|
last_set TIMESTAMPTZ,
|
||
|
|
calibrated BOOLEAN DEFAULT FALSE,
|
||
|
|
await_calib BOOLEAN DEFAULT FALSE,
|
||
|
|
UNIQUE (device_id, peripheral_number)
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS peripherals_user_id_idx ON peripherals(user_id);
|
||
|
|
|
||
|
|
-- ── Multi-blind groups (e.g. "all kitchen blinds") ──────────────────────────
|
||
|
|
CREATE TABLE IF NOT EXISTS groups (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
name TEXT NOT NULL,
|
||
|
|
timezone TEXT,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
UNIQUE (user_id, name)
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS group_peripherals (
|
||
|
|
group_id INTEGER NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||
|
|
peripheral_id INTEGER NOT NULL REFERENCES peripherals(id) ON DELETE CASCADE,
|
||
|
|
PRIMARY KEY (group_id, peripheral_id)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- ── Idempotent column additions for older DBs ───────────────────────────────
|
||
|
|
-- These mirror the runtime-bootstrap ALTERs the index.js used to do on every
|
||
|
|
-- startup. Safe on fresh DBs because the columns are already in CREATE TABLE.
|
||
|
|
ALTER TABLE users ADD COLUMN IF NOT EXISTS apns_token TEXT;
|
||
|
|
ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone TEXT DEFAULT 'America/Chicago';
|
||
|
|
ALTER TABLE devices ADD COLUMN IF NOT EXISTS battery_soc SMALLINT;
|
||
|
|
ALTER TABLE devices ADD COLUMN IF NOT EXISTS timezone TEXT;
|
||
|
|
ALTER TABLE groups ADD COLUMN IF NOT EXISTS timezone TEXT;
|