WIP: backend auth/chores/households work and frontend styling

This commit is contained in:
2026-07-15 21:20:57 -04:00
parent 08987d7c49
commit b4e47b652f
12 changed files with 1597 additions and 276 deletions
+72 -1
View File
@@ -1,10 +1,13 @@
{-# LANGUAGE OverloadedStrings #-}
{- | SQLite database support for Sis.
Opens (and creates if missing) a SQLite database with WAL journal
mode and foreign keys enabled.
mode and foreign keys enabled. Runs schema migrations on startup.
-}
module Sis.Database (
openDatabase,
runMigrations,
) where
import Database.SQLite.Simple qualified as SQL
@@ -22,4 +25,72 @@ openDatabase path = do
conn <- SQL.open path
SQL.execute_ conn "PRAGMA journal_mode=WAL"
SQL.execute_ conn "PRAGMA foreign_keys=ON"
runMigrations conn
pure conn
-- | Create all tables if they don't exist.
runMigrations :: SQL.Connection -> IO ()
runMigrations conn =
mapM_
(SQL.execute_ conn)
[ "CREATE TABLE IF NOT EXISTS users (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ display_name TEXT NOT NULL,\
\ email TEXT NOT NULL UNIQUE,\
\ password_hash TEXT NOT NULL,\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS sessions (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ token TEXT NOT NULL UNIQUE,\
\ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,\
\ expires_at TEXT NOT NULL,\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS households (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ name TEXT NOT NULL,\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS memberships (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,\
\ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,\
\ role TEXT NOT NULL CHECK (role IN ('owner', 'member')),\
\ UNIQUE (household_id, user_id))"
, "CREATE TABLE IF NOT EXISTS invites (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,\
\ code TEXT NOT NULL UNIQUE,\
\ email TEXT,\
\ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'revoked')),\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS chores (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ household_id INTEGER NOT NULL REFERENCES households(id) ON DELETE CASCADE,\
\ name TEXT NOT NULL,\
\ assignee_type TEXT NOT NULL DEFAULT 'anyone' CHECK (assignee_type IN ('user', 'anyone')),\
\ assignee_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,\
\ schedule_type TEXT NOT NULL CHECK (schedule_type IN ('one_off', 'recurring', 'sometime')),\
\ schedule_data TEXT NOT NULL,\
\ notify_on_due INTEGER NOT NULL DEFAULT 0,\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS occurrences (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ chore_id INTEGER NOT NULL REFERENCES chores(id) ON DELETE CASCADE,\
\ due_date TEXT NOT NULL,\
\ status TEXT NOT NULL DEFAULT 'due' CHECK (status IN ('due', 'overdue', 'completed', 'skipped')),\
\ UNIQUE (chore_id, due_date))"
, "CREATE TABLE IF NOT EXISTS activities (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ occurrence_id INTEGER NOT NULL REFERENCES occurrences(id) ON DELETE CASCADE,\
\ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,\
\ status TEXT NOT NULL CHECK (status IN ('completed', 'skipped')),\
\ note TEXT,\
\ notify_household INTEGER NOT NULL DEFAULT 0,\
\ recorded_at TEXT NOT NULL DEFAULT (datetime('now')))"
, "CREATE TABLE IF NOT EXISTS reset_tokens (\
\ id INTEGER PRIMARY KEY AUTOINCREMENT,\
\ user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,\
\ token TEXT NOT NULL UNIQUE,\
\ used INTEGER NOT NULL DEFAULT 0,\
\ expires_at TEXT NOT NULL,\
\ created_at TEXT NOT NULL DEFAULT (datetime('now')))"
]