-- Drop v1 EAV table (full replacement per spec section 12.3) DROP TABLE IF EXISTS "records" CASCADE; CREATE TYPE "public"."habit_difficulty" AS ENUM('easy', 'medium', 'hard');--> statement-breakpoint CREATE TYPE "public"."habit_frequency" AS ENUM('daily', 'weekly', 'custom');--> statement-breakpoint CREATE TYPE "public"."job_status" AS ENUM('pending', 'processing', 'completed', 'failed');--> statement-breakpoint CREATE TYPE "public"."project_status" AS ENUM('active', 'paused', 'completed', 'archived');--> statement-breakpoint CREATE TYPE "public"."section_kind" AS ENUM('section', 'milestone');--> statement-breakpoint CREATE TYPE "public"."section_status" AS ENUM('planned', 'in_progress', 'complete');--> statement-breakpoint CREATE TYPE "public"."tag_scope" AS ENUM('global', 'tasks', 'habits', 'projects', 'notes');--> statement-breakpoint CREATE TYPE "public"."task_priority" AS ENUM('low', 'medium', 'high', 'urgent');--> statement-breakpoint CREATE TYPE "public"."task_status" AS ENUM('todo', 'in_progress', 'done', 'cancelled');--> statement-breakpoint CREATE TABLE "activity_feed" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "actor" text NOT NULL, "action" text NOT NULL, "entity_type" text NOT NULL, "entity_id" uuid NOT NULL, "changes" jsonb, "workspace_id" uuid NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "domains" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "slug" text NOT NULL, "color" text, "icon" text, "parent_id" uuid, "sort_order" integer DEFAULT 0, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "domains_slug_unique" UNIQUE("slug") ); --> statement-breakpoint CREATE TABLE "habit_completions" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "habit_id" uuid NOT NULL, "date" timestamp with time zone NOT NULL, "value" integer DEFAULT 1, "mood" integer, "notes" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "habit_tags" ( "habit_id" uuid NOT NULL, "tag_id" uuid NOT NULL, CONSTRAINT "habit_tags_habit_id_tag_id_pk" PRIMARY KEY("habit_id","tag_id") ); --> statement-breakpoint CREATE TABLE "habits" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "description" text, "domain_id" uuid NOT NULL, "frequency" "habit_frequency" DEFAULT 'daily' NOT NULL, "difficulty" "habit_difficulty" DEFAULT 'medium' NOT NULL, "goal_per_period" integer DEFAULT 1, "unit" text, "reminder_time" time, "skip_days" integer[] DEFAULT '{}', "streak_count" integer DEFAULT 0, "best_streak" integer DEFAULT 0, "mood_tracking" boolean DEFAULT false, "active" boolean DEFAULT true, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "deleted_at" timestamp with time zone ); --> statement-breakpoint CREATE TABLE "jobs" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "type" text NOT NULL, "payload" jsonb DEFAULT '{}'::jsonb, "status" "job_status" DEFAULT 'pending' NOT NULL, "attempts" integer DEFAULT 0, "max_attempts" integer DEFAULT 3, "next_retry_at" timestamp with time zone, "last_error" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "note_entity_links" ( "note_id" uuid NOT NULL, "entity_type" text NOT NULL, "entity_id" uuid NOT NULL ); --> statement-breakpoint CREATE TABLE "note_links" ( "source_note_id" uuid NOT NULL, "target_note_id" uuid NOT NULL, CONSTRAINT "note_links_source_note_id_target_note_id_pk" PRIMARY KEY("source_note_id","target_note_id") ); --> statement-breakpoint CREATE TABLE "note_tags" ( "note_id" uuid NOT NULL, "tag_id" uuid NOT NULL, CONSTRAINT "note_tags_note_id_tag_id_pk" PRIMARY KEY("note_id","tag_id") ); --> statement-breakpoint CREATE TABLE "notes" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "title" text NOT NULL, "content" text, "domain_id" uuid NOT NULL, "is_pinned" boolean DEFAULT false, "is_archived" boolean DEFAULT false, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "deleted_at" timestamp with time zone ); --> statement-breakpoint CREATE TABLE "project_tags" ( "project_id" uuid NOT NULL, "tag_id" uuid NOT NULL, CONSTRAINT "project_tags_project_id_tag_id_pk" PRIMARY KEY("project_id","tag_id") ); --> statement-breakpoint CREATE TABLE "projects" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "description" text, "status" "project_status" DEFAULT 'active' NOT NULL, "domain_id" uuid NOT NULL, "color" text, "icon" text, "target_date" timestamp with time zone, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "deleted_at" timestamp with time zone ); --> statement-breakpoint CREATE TABLE "scheduled_jobs" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "entity_type" text NOT NULL, "entity_id" uuid NOT NULL, "recurrence_rule" text NOT NULL, "next_occurrence_at" timestamp with time zone NOT NULL, "last_spawned_at" timestamp with time zone, "created_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "sections" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "project_id" uuid NOT NULL, "kind" "section_kind" DEFAULT 'section' NOT NULL, "status" "section_status" DEFAULT 'planned' NOT NULL, "target_date" timestamp with time zone, "sort_order" integer DEFAULT 0, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "tags" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text NOT NULL, "color" text, "scope" "tag_scope" DEFAULT 'global' NOT NULL, "parent_id" uuid, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "task_dependencies" ( "task_id" uuid NOT NULL, "depends_on_task_id" uuid NOT NULL, CONSTRAINT "task_dependencies_task_id_depends_on_task_id_pk" PRIMARY KEY("task_id","depends_on_task_id") ); --> statement-breakpoint CREATE TABLE "task_tags" ( "task_id" uuid NOT NULL, "tag_id" uuid NOT NULL, CONSTRAINT "task_tags_task_id_tag_id_pk" PRIMARY KEY("task_id","tag_id") ); --> statement-breakpoint CREATE TABLE "tasks" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "title" text NOT NULL, "description" text, "status" "task_status" DEFAULT 'todo' NOT NULL, "priority" "task_priority" DEFAULT 'medium' NOT NULL, "domain_id" uuid NOT NULL, "project_id" uuid, "section_id" uuid, "parent_id" uuid, "due_date" timestamp with time zone, "completed_at" timestamp with time zone, "estimated_minutes" integer, "tracked_minutes" integer DEFAULT 0, "recurrence_rule" text, "order" integer DEFAULT 0, "custom_fields" jsonb DEFAULT '{}'::jsonb, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "deleted_at" timestamp with time zone ); --> statement-breakpoint CREATE TABLE "users" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "email" text NOT NULL, "name" text NOT NULL, "password_hash" text NOT NULL, "passkey_credential_id" text, "passkey_public_key" text, "passkey_counter" integer DEFAULT 0, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, CONSTRAINT "users_email_unique" UNIQUE("email") ); --> statement-breakpoint CREATE TABLE "webhooks" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "name" text, "url" text NOT NULL, "secret" text, "events" text[] DEFAULT '{}', "active" boolean DEFAULT true, "workspace_id" uuid NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint ALTER TABLE "activity_feed" ADD CONSTRAINT "activity_feed_workspace_id_domains_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "domains" ADD CONSTRAINT "domains_parent_id_domains_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."domains"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint ALTER TABLE "habit_completions" ADD CONSTRAINT "habit_completions_habit_id_habits_id_fk" FOREIGN KEY ("habit_id") REFERENCES "public"."habits"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "habit_tags" ADD CONSTRAINT "habit_tags_habit_id_habits_id_fk" FOREIGN KEY ("habit_id") REFERENCES "public"."habits"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "habit_tags" ADD CONSTRAINT "habit_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "habits" ADD CONSTRAINT "habits_domain_id_domains_id_fk" FOREIGN KEY ("domain_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "note_entity_links" ADD CONSTRAINT "note_entity_links_note_id_notes_id_fk" FOREIGN KEY ("note_id") REFERENCES "public"."notes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "note_links" ADD CONSTRAINT "note_links_source_note_id_notes_id_fk" FOREIGN KEY ("source_note_id") REFERENCES "public"."notes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "note_links" ADD CONSTRAINT "note_links_target_note_id_notes_id_fk" FOREIGN KEY ("target_note_id") REFERENCES "public"."notes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "note_tags" ADD CONSTRAINT "note_tags_note_id_notes_id_fk" FOREIGN KEY ("note_id") REFERENCES "public"."notes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "note_tags" ADD CONSTRAINT "note_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "notes" ADD CONSTRAINT "notes_domain_id_domains_id_fk" FOREIGN KEY ("domain_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "project_tags" ADD CONSTRAINT "project_tags_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "project_tags" ADD CONSTRAINT "project_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "projects" ADD CONSTRAINT "projects_domain_id_domains_id_fk" FOREIGN KEY ("domain_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "sections" ADD CONSTRAINT "sections_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "tags" ADD CONSTRAINT "tags_parent_id_tags_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."tags"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint ALTER TABLE "task_dependencies" ADD CONSTRAINT "task_dependencies_task_id_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "task_dependencies" ADD CONSTRAINT "task_dependencies_depends_on_task_id_tasks_id_fk" FOREIGN KEY ("depends_on_task_id") REFERENCES "public"."tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "task_tags" ADD CONSTRAINT "task_tags_task_id_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "task_tags" ADD CONSTRAINT "task_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "tasks" ADD CONSTRAINT "tasks_domain_id_domains_id_fk" FOREIGN KEY ("domain_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint ALTER TABLE "tasks" ADD CONSTRAINT "tasks_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint ALTER TABLE "tasks" ADD CONSTRAINT "tasks_section_id_sections_id_fk" FOREIGN KEY ("section_id") REFERENCES "public"."sections"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint ALTER TABLE "tasks" ADD CONSTRAINT "tasks_parent_id_tasks_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."tasks"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint ALTER TABLE "webhooks" ADD CONSTRAINT "webhooks_workspace_id_domains_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."domains"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint CREATE INDEX "activity_feed_workspace_id_idx" ON "activity_feed" USING btree ("workspace_id");--> statement-breakpoint CREATE INDEX "activity_feed_entity_idx" ON "activity_feed" USING btree ("entity_type","entity_id");--> statement-breakpoint CREATE INDEX "activity_feed_created_at_idx" ON "activity_feed" USING btree ("created_at");--> statement-breakpoint CREATE INDEX "activity_feed_actor_idx" ON "activity_feed" USING btree ("actor");--> statement-breakpoint CREATE INDEX "domains_parent_id_idx" ON "domains" USING btree ("parent_id");--> statement-breakpoint CREATE INDEX "domains_slug_idx" ON "domains" USING btree ("slug");--> statement-breakpoint CREATE INDEX "habit_completions_habit_id_idx" ON "habit_completions" USING btree ("habit_id");--> statement-breakpoint CREATE INDEX "habit_completions_date_idx" ON "habit_completions" USING btree ("habit_id","date");--> statement-breakpoint CREATE INDEX "habit_tags_tag_id_idx" ON "habit_tags" USING btree ("tag_id");--> statement-breakpoint CREATE INDEX "habits_domain_id_idx" ON "habits" USING btree ("domain_id");--> statement-breakpoint CREATE INDEX "habits_active_idx" ON "habits" USING btree ("active");--> statement-breakpoint CREATE INDEX "habits_deleted_at_idx" ON "habits" USING btree ("deleted_at");--> statement-breakpoint CREATE INDEX "jobs_status_idx" ON "jobs" USING btree ("status");--> statement-breakpoint CREATE INDEX "jobs_type_idx" ON "jobs" USING btree ("type");--> statement-breakpoint CREATE INDEX "jobs_next_retry_at_idx" ON "jobs" USING btree ("next_retry_at");--> statement-breakpoint CREATE INDEX "note_entity_links_entity_idx" ON "note_entity_links" USING btree ("entity_type","entity_id");--> statement-breakpoint CREATE INDEX "note_entity_links_note_id_idx" ON "note_entity_links" USING btree ("note_id");--> statement-breakpoint CREATE INDEX "note_links_target_note_id_idx" ON "note_links" USING btree ("target_note_id");--> statement-breakpoint CREATE INDEX "note_tags_tag_id_idx" ON "note_tags" USING btree ("tag_id");--> statement-breakpoint CREATE INDEX "notes_domain_id_idx" ON "notes" USING btree ("domain_id");--> statement-breakpoint CREATE INDEX "notes_is_pinned_idx" ON "notes" USING btree ("is_pinned");--> statement-breakpoint CREATE INDEX "notes_is_archived_idx" ON "notes" USING btree ("is_archived");--> statement-breakpoint CREATE INDEX "notes_deleted_at_idx" ON "notes" USING btree ("deleted_at");--> statement-breakpoint CREATE INDEX "project_tags_tag_id_idx" ON "project_tags" USING btree ("tag_id");--> statement-breakpoint CREATE INDEX "projects_domain_id_idx" ON "projects" USING btree ("domain_id");--> statement-breakpoint CREATE INDEX "projects_status_idx" ON "projects" USING btree ("status");--> statement-breakpoint CREATE INDEX "projects_deleted_at_idx" ON "projects" USING btree ("deleted_at");--> statement-breakpoint CREATE INDEX "scheduled_jobs_next_occurrence_idx" ON "scheduled_jobs" USING btree ("next_occurrence_at");--> statement-breakpoint CREATE INDEX "scheduled_jobs_entity_idx" ON "scheduled_jobs" USING btree ("entity_type","entity_id");--> statement-breakpoint CREATE INDEX "sections_project_id_idx" ON "sections" USING btree ("project_id");--> statement-breakpoint CREATE INDEX "sections_kind_idx" ON "sections" USING btree ("kind");--> statement-breakpoint CREATE INDEX "sections_sort_order_idx" ON "sections" USING btree ("project_id","sort_order");--> statement-breakpoint CREATE INDEX "tags_parent_id_idx" ON "tags" USING btree ("parent_id");--> statement-breakpoint CREATE INDEX "tags_scope_idx" ON "tags" USING btree ("scope");--> statement-breakpoint CREATE INDEX "task_dependencies_depends_on_idx" ON "task_dependencies" USING btree ("depends_on_task_id");--> statement-breakpoint CREATE INDEX "task_tags_tag_id_idx" ON "task_tags" USING btree ("tag_id");--> statement-breakpoint CREATE INDEX "tasks_domain_id_idx" ON "tasks" USING btree ("domain_id");--> statement-breakpoint CREATE INDEX "tasks_project_id_idx" ON "tasks" USING btree ("project_id");--> statement-breakpoint CREATE INDEX "tasks_section_id_idx" ON "tasks" USING btree ("section_id");--> statement-breakpoint CREATE INDEX "tasks_parent_id_idx" ON "tasks" USING btree ("parent_id");--> statement-breakpoint CREATE INDEX "tasks_status_idx" ON "tasks" USING btree ("status");--> statement-breakpoint CREATE INDEX "tasks_priority_idx" ON "tasks" USING btree ("priority");--> statement-breakpoint CREATE INDEX "tasks_due_date_idx" ON "tasks" USING btree ("due_date");--> statement-breakpoint CREATE INDEX "tasks_order_idx" ON "tasks" USING btree ("order");--> statement-breakpoint CREATE INDEX "tasks_deleted_at_idx" ON "tasks" USING btree ("deleted_at");--> statement-breakpoint CREATE INDEX "webhooks_workspace_id_idx" ON "webhooks" USING btree ("workspace_id");--> statement-breakpoint CREATE INDEX "webhooks_active_idx" ON "webhooks" USING btree ("active");