Add self-hosted kids calendar app
Express + SQLite (node:sqlite, no native build step) family calendar: parent accounts with household invites, per-child calendars with save/duplicate/print, a token-gated read-only kiosk view for tablets, and polling to keep parent and kiosk views in sync. Defaults to port 3007.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
CREATE TABLE IF NOT EXISTS households (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS parents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,
|
||||
email TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
||||
password_hash TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_parents_household ON parents(household_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS household_invites (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
created_by_parent_id INTEGER NOT NULL REFERENCES parents(id) ON DELETE CASCADE,
|
||||
expires_at TEXT NOT NULL,
|
||||
used_at TEXT,
|
||||
used_by_parent_id INTEGER REFERENCES parents(id),
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_invites_household ON household_invites(household_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS children (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
kiosk_token TEXT NOT NULL UNIQUE,
|
||||
active_calendar_id INTEGER REFERENCES calendars(id) ON DELETE SET NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_children_household ON children(household_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS calendars (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
child_id INTEGER NOT NULL REFERENCES children(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
week_start_date TEXT,
|
||||
show_weekend INTEGER NOT NULL DEFAULT 0,
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_calendars_child ON calendars(child_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS calendar_blocks (
|
||||
calendar_id INTEGER NOT NULL REFERENCES calendars(id) ON DELETE CASCADE,
|
||||
block_key TEXT NOT NULL CHECK (block_key IN ('morning','school','after','evening')),
|
||||
label TEXT NOT NULL,
|
||||
PRIMARY KEY (calendar_id, block_key)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS calendar_tasks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
calendar_id INTEGER NOT NULL REFERENCES calendars(id) ON DELETE CASCADE,
|
||||
day_of_week TEXT NOT NULL CHECK (day_of_week IN
|
||||
('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday')),
|
||||
block_key TEXT NOT NULL CHECK (block_key IN ('morning','school','after','evening')),
|
||||
text TEXT NOT NULL,
|
||||
done INTEGER NOT NULL DEFAULT 0,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_calendar ON calendar_tasks(calendar_id, day_of_week, block_key);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
sid TEXT PRIMARY KEY,
|
||||
sess TEXT NOT NULL,
|
||||
expires_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at);
|
||||
Reference in New Issue
Block a user