/* # OKR Management System - Database Schema 1. New Tables - `users` - System users (owner/pm/member roles) - `projects` - Project entities with health status - `project_members` - Many-to-many relationship for project membership - `objectives` - Period-based objectives (O in OKR) - `krs` - Key Results with flexible periods - `checkins` - Daily progress updates - `meetings` - Meeting records with summaries - `metrics` - Configurable metrics library - `templates` - KR templates library 2. Security - RLS disabled for all tables (no-auth system requirement) - All tables accessible without authentication 3. Notes - All timestamps use timestamptz for timezone support - Status fields use text with CHECK constraints - JSON fields used for flexible template items */ -- Users table CREATE TABLE IF NOT EXISTS users ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, role text NOT NULL CHECK (role IN ('owner', 'pm', 'member')), avatar_url text, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now() ); -- Projects table CREATE TABLE IF NOT EXISTS projects ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, description text, owner_id uuid REFERENCES users(id) ON DELETE SET NULL, pm_id uuid REFERENCES users(id) ON DELETE SET NULL, project_type text DEFAULT 'general', status text NOT NULL DEFAULT 'green' CHECK (status IN ('green', 'yellow', 'red')), created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now() ); -- Project members junction table CREATE TABLE IF NOT EXISTS project_members ( project_id uuid REFERENCES projects(id) ON DELETE CASCADE, user_id uuid REFERENCES users(id) ON DELETE CASCADE, PRIMARY KEY (project_id, user_id) ); -- Objectives table (period-based goals) CREATE TABLE IF NOT EXISTS objectives ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE, title text NOT NULL, description text, period_start date NOT NULL, period_end date NOT NULL, created_by uuid REFERENCES users(id) ON DELETE SET NULL, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now(), CONSTRAINT valid_period CHECK (period_end >= period_start) ); -- Key Results table CREATE TABLE IF NOT EXISTS krs ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE, objective_id uuid REFERENCES objectives(id) ON DELETE SET NULL, period_type text NOT NULL DEFAULT 'custom' CHECK (period_type IN ('custom', '3d', '1w', '2w', 'monthly')), period_name text, period_start date NOT NULL, period_end date NOT NULL, title text NOT NULL, metric_name text NOT NULL, unit text NOT NULL, direction text NOT NULL DEFAULT 'increase' CHECK (direction IN ('increase', 'decrease')), target_value numeric NOT NULL CHECK (target_value > 0), current_value numeric NOT NULL DEFAULT 0, owner_user_id uuid REFERENCES users(id) ON DELETE SET NULL, confidence integer NOT NULL DEFAULT 80 CHECK (confidence >= 0 AND confidence <= 100), status text NOT NULL DEFAULT 'green' CHECK (status IN ('green', 'yellow', 'red')), reason_code text CHECK (reason_code IS NULL OR reason_code IN ('RESOURCE', 'DEPENDENCY', 'DECISION', 'SCOPE', 'EXECUTION', 'OTHER')), note text, need_owner_help boolean NOT NULL DEFAULT false, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now(), CONSTRAINT valid_kr_period CHECK (period_end >= period_start) ); -- Checkins table CREATE TABLE IF NOT EXISTS checkins ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), kr_id uuid NOT NULL REFERENCES krs(id) ON DELETE CASCADE, project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE, user_id uuid REFERENCES users(id) ON DELETE SET NULL, date date NOT NULL DEFAULT CURRENT_DATE, current_value numeric NOT NULL, delta_value numeric, confidence integer NOT NULL CHECK (confidence >= 0 AND confidence <= 100), status_snapshot text NOT NULL CHECK (status_snapshot IN ('green', 'yellow', 'red')), reason_code text CHECK (reason_code IS NULL OR reason_code IN ('RESOURCE', 'DEPENDENCY', 'DECISION', 'SCOPE', 'EXECUTION', 'OTHER')), note text, created_at timestamptz DEFAULT now() ); -- Meetings table CREATE TABLE IF NOT EXISTS meetings ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE, period_start date NOT NULL, period_end date NOT NULL, summary text NOT NULL, decisions text, risks text, next_period_commitments text, created_by uuid REFERENCES users(id) ON DELETE SET NULL, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now() ); -- Metrics library table CREATE TABLE IF NOT EXISTS metrics ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, unit text NOT NULL, direction text NOT NULL DEFAULT 'increase' CHECK (direction IN ('increase', 'decrease')), category text, is_active boolean NOT NULL DEFAULT true, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now() ); -- Templates library table CREATE TABLE IF NOT EXISTS templates ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, description text, project_type text, tags jsonb DEFAULT '[]'::jsonb, items jsonb NOT NULL DEFAULT '[]'::jsonb, is_active boolean NOT NULL DEFAULT true, created_at timestamptz DEFAULT now(), updated_at timestamptz DEFAULT now() ); -- Create indexes for better query performance CREATE INDEX IF NOT EXISTS idx_projects_owner ON projects(owner_id); CREATE INDEX IF NOT EXISTS idx_projects_pm ON projects(pm_id); CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status); CREATE INDEX IF NOT EXISTS idx_objectives_project ON objectives(project_id); CREATE INDEX IF NOT EXISTS idx_objectives_period ON objectives(period_start, period_end); CREATE INDEX IF NOT EXISTS idx_krs_project ON krs(project_id); CREATE INDEX IF NOT EXISTS idx_krs_objective ON krs(objective_id); CREATE INDEX IF NOT EXISTS idx_krs_owner ON krs(owner_user_id); CREATE INDEX IF NOT EXISTS idx_krs_status ON krs(status); CREATE INDEX IF NOT EXISTS idx_krs_period ON krs(period_start, period_end); CREATE INDEX IF NOT EXISTS idx_checkins_kr ON checkins(kr_id); CREATE INDEX IF NOT EXISTS idx_checkins_date ON checkins(date); CREATE INDEX IF NOT EXISTS idx_meetings_project ON meetings(project_id); CREATE INDEX IF NOT EXISTS idx_metrics_active ON metrics(is_active); CREATE INDEX IF NOT EXISTS idx_templates_active ON templates(is_active);