damien-kaiser/taskloft

Taskloft — team task boards (owner / member / viewer), card history, my plate, overdue, blockers, AI checklists and summaries, usable from Claude and ChatGPT over MCP.

A remix template · 0 remixes · Remix damien-kaiser/taskloft

schema.sql

-- Created once by the remix, in the bucket it makes. Natural keys only: DataK3 has no sequences.
-- An older bucket gets the newer tables and columns from the app's additive migrations at start-up
-- (app/boards/infrastructure/repository.py, MIGRATIONS): never a rename, never a drop.
CREATE TABLE IF NOT EXISTS boards (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  owner_email TEXT NOT NULL,
  created_at TIMESTAMP
);
CREATE TABLE IF NOT EXISTS memberships (
  id TEXT PRIMARY KEY,            -- board_id + ':' + email
  board_id TEXT NOT NULL,
  email TEXT NOT NULL,
  role TEXT NOT NULL              -- member | viewer (the owner lives on boards.owner_email)
);
CREATE TABLE IF NOT EXISTS lists (
  id TEXT PRIMARY KEY,
  board_id TEXT NOT NULL,
  name TEXT NOT NULL,
  position BIGINT NOT NULL,
  is_done BOOLEAN                 -- cards here count as finished (never overdue, never "on my plate")
);
CREATE TABLE IF NOT EXISTS cards (
  id TEXT PRIMARY KEY,
  board_id TEXT NOT NULL,
  list_name TEXT NOT NULL,        -- the list's name, kept for readable SQL; list_id is the reference
  title TEXT NOT NULL,
  assignee TEXT,
  due_date DATE,
  updated_at TIMESTAMP,
  number BIGINT,                  -- "#12": claimed once in card_numbers
  list_id TEXT,
  description TEXT,
  labels TEXT,                    -- JSON array of short words
  position DOUBLE                 -- order inside its list (drag and drop drops between two cards)
);
CREATE TABLE IF NOT EXISTS card_numbers (
  number BIGINT PRIMARY KEY,      -- a CLAIM: plain INSERT, the loser of a race gets 23505 and retries
  card_id TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS card_blockers (
  id TEXT PRIMARY KEY,            -- card_id + '>' + blocked_by
  card_id TEXT NOT NULL,
  blocked_by TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS checklist_items (
  id TEXT PRIMARY KEY,
  card_id TEXT NOT NULL,
  text TEXT NOT NULL,
  done BOOLEAN,
  position BIGINT
);
CREATE TABLE IF NOT EXISTS activity (
  id TEXT PRIMARY KEY,
  board_id TEXT NOT NULL,
  card_id TEXT,
  actor TEXT NOT NULL,
  action TEXT NOT NULL,
  event_at TIMESTAMP,
  changes TEXT                    -- JSON {field: [before, after]}
);
CREATE TABLE IF NOT EXISTS card_vectors (
  card_id TEXT PRIMARY KEY,
  board_id TEXT NOT NULL,         -- KNN is filtered to the boards the person can see
  text_hash TEXT NOT NULL,        -- re-embedded only when the card's text changed
  embedding VECTOR(2048)          -- jina-embeddings-v4 through Dodil Models; cosine distance (<=>)
);
CREATE TABLE IF NOT EXISTS board_summaries (
  id TEXT PRIMARY KEY,            -- board_id + ':' + hash of the facts the summary was written from
  board_id TEXT NOT NULL,
  text TEXT NOT NULL,
  made_at TIMESTAMP
);