import os import sqlite3 from pathlib import Path DB_PATH = os.environ.get("DB_PATH", "/data/whattodo.db") SCHEMA_VERSION = 1 DEFAULT_CATEGORIES = [ ("Work", "#2563eb"), ("Life", "#16a34a"), ("Personal", "#9333ea"), ("YouTube", "#dc2626"), ] SCHEMA = """ CREATE TABLE IF NOT EXISTS meta ( key TEXT PRIMARY KEY, value TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS categories ( id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE COLLATE NOCASE, color TEXT NOT NULL DEFAULT '#6b7280', position INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY, title TEXT NOT NULL, notes TEXT NOT NULL DEFAULT '', category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL, priority INTEGER NOT NULL DEFAULT 0, due_date TEXT, tags TEXT NOT NULL DEFAULT '[]', recurrence TEXT NOT NULL DEFAULT 'none', recur_interval INTEGER NOT NULL DEFAULT 1, done INTEGER NOT NULL DEFAULT 0, done_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS subtasks ( id INTEGER PRIMARY KEY, task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, title TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0, position INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX IF NOT EXISTS idx_subtasks_task ON subtasks(task_id); """ def connect() -> sqlite3.Connection: # FastAPI may open a request's connection and run its endpoint on different threads; # each connection is still used by only one request at a time. conn = sqlite3.connect(DB_PATH, check_same_thread=False) conn.row_factory = sqlite3.Row conn.execute("PRAGMA foreign_keys = ON") return conn def init() -> None: Path(DB_PATH).parent.mkdir(parents=True, exist_ok=True) conn = connect() try: conn.execute("PRAGMA journal_mode = WAL") conn.executescript(SCHEMA) row = conn.execute("SELECT value FROM meta WHERE key = 'schema_version'").fetchone() if row is None: # Fresh database: seed default categories. with conn: for i, (name, color) in enumerate(DEFAULT_CATEGORIES): conn.execute( "INSERT INTO categories (name, color, position) VALUES (?, ?, ?)", (name, color, i), ) conn.execute( "INSERT INTO meta (key, value) VALUES ('schema_version', ?)", (str(SCHEMA_VERSION),), ) finally: conn.close()