-- Additive remote-control storage; existing cases and time entries are untouched. CREATE TABLE IF NOT EXISTS remote_pins ( user_id INTEGER PRIMARY KEY REFERENCES users(user_id) ON DELETE CASCADE, pin_hash TEXT NOT NULL, generation INTEGER NOT NULL DEFAULT 1 ); CREATE TABLE IF NOT EXISTS remote_controls ( id UUID PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, code_lookup CHAR(64) UNIQUE NOT NULL, code_hash TEXT NOT NULL, revoked BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS remote_devices ( id UUID PRIMARY KEY, remote_id UUID NOT NULL REFERENCES remote_controls(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, token_hash CHAR(64) UNIQUE NOT NULL, expires_at TIMESTAMPTZ NOT NULL, unlocked_date DATE NOT NULL, pin_generation INTEGER NOT NULL, revoked BOOLEAN NOT NULL DEFAULT FALSE, last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS remote_devices_remote ON remote_devices(remote_id); CREATE TABLE IF NOT EXISTS remote_attempts ( bucket CHAR(64) PRIMARY KEY, next_allowed_at TIMESTAMPTZ NOT NULL ); CREATE TABLE IF NOT EXISTS remote_user_state ( user_id INTEGER PRIMARY KEY REFERENCES users(user_id) ON DELETE CASCADE, version BIGINT NOT NULL DEFAULT 0, active_case_id INTEGER REFERENCES sag_sager(id) ON DELETE SET NULL, follower_id UUID, follower_seen_at TIMESTAMPTZ, selection_seq BIGINT NOT NULL DEFAULT 0, selection_target UUID, selection_expires_at TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS remote_commands ( user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, request_id UUID NOT NULL, payload JSONB NOT NULL, result JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY(user_id, request_id) );