xtablo-source/supabase/migrations/20251115211024_create_tasks_table.sql
2025-11-15 22:58:18 +01:00

118 lines
4.6 KiB
SQL

-- Create task_status enum type
CREATE TYPE task_status AS ENUM ('todo', 'in_progress', 'in_review', 'done');
-- Create tasks table
CREATE TABLE IF NOT EXISTS "public"."tasks" (
"id" "text" DEFAULT "public"."generate_random_string"(24) NOT NULL,
"tablo_id" "text" NOT NULL,
"title" character varying(500) NOT NULL,
"description" "text",
"status" task_status DEFAULT 'todo' NOT NULL,
"assignee_id" "uuid",
"position" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
"updated_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT "tasks_pkey" PRIMARY KEY ("id"),
CONSTRAINT "tasks_tablo_id_fkey" FOREIGN KEY ("tablo_id") REFERENCES "public"."tablos"("id") ON DELETE CASCADE,
CONSTRAINT "tasks_assignee_id_fkey" FOREIGN KEY ("assignee_id") REFERENCES "auth"."users"("id") ON DELETE SET NULL
);
ALTER TABLE "public"."tasks" OWNER TO "postgres";
-- Add comments
COMMENT ON TABLE "public"."tasks" IS 'Kanban tasks for tablos';
COMMENT ON COLUMN "public"."tasks"."id" IS 'Primary key: random 24-character alphanumeric string';
COMMENT ON COLUMN "public"."tasks"."tablo_id" IS 'Foreign key to tablos table';
COMMENT ON COLUMN "public"."tasks"."title" IS 'Task title';
COMMENT ON COLUMN "public"."tasks"."description" IS 'Optional task description';
COMMENT ON COLUMN "public"."tasks"."status" IS 'Task status: todo, in_progress, in_review, or done';
COMMENT ON COLUMN "public"."tasks"."assignee_id" IS 'Optional user ID of task assignee';
COMMENT ON COLUMN "public"."tasks"."position" IS 'Position within the column for ordering';
COMMENT ON COLUMN "public"."tasks"."created_at" IS 'Timestamp when the task was created';
COMMENT ON COLUMN "public"."tasks"."updated_at" IS 'Timestamp when the task was last updated (auto-updated by trigger)';
-- Create indexes for better query performance
CREATE INDEX "tasks_tablo_id_idx" ON "public"."tasks" USING btree ("tablo_id");
CREATE INDEX "tasks_status_idx" ON "public"."tasks" USING btree ("status");
CREATE INDEX "tasks_assignee_id_idx" ON "public"."tasks" USING btree ("assignee_id");
CREATE INDEX "tasks_position_idx" ON "public"."tasks" USING btree ("tablo_id", "status", "position");
-- Create trigger to auto-update updated_at timestamp
CREATE TRIGGER "update_tasks_updated_at"
BEFORE UPDATE ON "public"."tasks"
FOR EACH ROW
EXECUTE FUNCTION "public"."update_updated_at_column"();
-- Enable Row Level Security
ALTER TABLE "public"."tasks" ENABLE ROW LEVEL SECURITY;
-- RLS Policies: Users can only access tasks from tablos they have access to
CREATE POLICY "Users can view tasks from their tablos"
ON "public"."tasks"
FOR SELECT
USING (
EXISTS (
SELECT 1 FROM "public"."tablo_access"
WHERE "tablo_access"."tablo_id" = "tasks"."tablo_id"
AND "tablo_access"."user_id" = auth.uid()
AND "tablo_access"."is_active" = true
)
);
CREATE POLICY "Users can create tasks in their tablos"
ON "public"."tasks"
FOR INSERT
WITH CHECK (
EXISTS (
SELECT 1 FROM "public"."tablo_access"
WHERE "tablo_access"."tablo_id" = "tasks"."tablo_id"
AND "tablo_access"."user_id" = auth.uid()
AND "tablo_access"."is_active" = true
)
);
CREATE POLICY "Users can update tasks in their tablos"
ON "public"."tasks"
FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM "public"."tablo_access"
WHERE "tablo_access"."tablo_id" = "tasks"."tablo_id"
AND "tablo_access"."user_id" = auth.uid()
AND "tablo_access"."is_active" = true
)
);
CREATE POLICY "Users can delete tasks in their tablos"
ON "public"."tasks"
FOR DELETE
USING (
EXISTS (
SELECT 1 FROM "public"."tablo_access"
WHERE "tablo_access"."tablo_id" = "tasks"."tablo_id"
AND "tablo_access"."user_id" = auth.uid()
AND "tablo_access"."is_active" = true
)
);
-- Create a view that includes assignee information
CREATE OR REPLACE VIEW "public"."tasks_with_assignee" WITH ("security_invoker"='true') AS
SELECT
t.id,
t.tablo_id,
t.title,
t.description,
t.status,
t.assignee_id,
t.position,
t.created_at,
t.updated_at,
p.name AS assignee_name,
p.avatar_url AS assignee_avatar
FROM "public"."tasks" t
LEFT JOIN "public"."profiles" p ON t.assignee_id = p.id;
ALTER TABLE "public"."tasks_with_assignee" OWNER TO "postgres";
COMMENT ON VIEW "public"."tasks_with_assignee" IS 'View that returns tasks with assignee information from profiles';