From 5149ef184d132a711ba32f9823dbaeb0c6486518 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 18 Oct 2025 04:11:47 +0000 Subject: [PATCH] Add projects table migration with RLS and policies cgen-1889eb269a534dca875135ae45774c03 --- client/lib/error-utils.ts | 11 +++++ client/pages/ProjectsNew.tsx | 6 ++- .../migrations/20251018_projects_table.sql | 44 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 client/lib/error-utils.ts create mode 100644 supabase/migrations/20251018_projects_table.sql diff --git a/client/lib/error-utils.ts b/client/lib/error-utils.ts new file mode 100644 index 00000000..f44264eb --- /dev/null +++ b/client/lib/error-utils.ts @@ -0,0 +1,11 @@ +export function normalizeErrorMessage(err: any): string { + if (!err) return "Unknown error"; + if (typeof err === "string") return err; + const m = err?.message || err?.error_description || err?.error || err?.msg; + if (typeof m === "string" && m.trim()) return m; + try { + return JSON.stringify(err); + } catch { + return String(err); + } +} diff --git a/client/pages/ProjectsNew.tsx b/client/pages/ProjectsNew.tsx index 0a70fa69..9b7062e0 100644 --- a/client/pages/ProjectsNew.tsx +++ b/client/pages/ProjectsNew.tsx @@ -79,10 +79,12 @@ export default function ProjectsNew() { throw new Error("Project creation failed"); } } catch (err: any) { - console.error("Error creating project:", err); + const { normalizeErrorMessage } = await import("@/lib/error-utils"); + const msg = normalizeErrorMessage(err); + console.error("Error creating project:", msg, err); aethexToast.error({ title: "Failed to create project", - description: err?.message || "Please try again.", + description: msg, }); } finally { setIsSubmitting(false); diff --git a/supabase/migrations/20251018_projects_table.sql b/supabase/migrations/20251018_projects_table.sql new file mode 100644 index 00000000..e21ae6e0 --- /dev/null +++ b/supabase/migrations/20251018_projects_table.sql @@ -0,0 +1,44 @@ +-- Create projects table and RLS policies if missing +begin; + +create type if not exists project_status_enum as enum ('planning','in_progress','completed','on_hold'); + +create table if not exists public.projects ( + id uuid primary key default gen_random_uuid(), + user_id uuid not null references public.user_profiles(id) on delete cascade, + title text not null, + description text, + status project_status_enum default 'planning', + technologies text[], + github_url text, + demo_url text, + image_url text, + start_date date, + end_date date, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +alter table public.projects enable row level security; + +-- Simple policies +do $$ begin + create policy projects_select_all on public.projects for select to authenticated using (true); +exception when duplicate_object then null; end $$; + +do $$ begin + create policy projects_manage_own on public.projects for all to authenticated using (auth.uid() = user_id) with check (auth.uid() = user_id); +exception when duplicate_object then null; end $$; + +-- updated_at trigger +create or replace function public.set_updated_at() +returns trigger as $$ +begin + new.updated_at = now(); + return new; +end; $$ language plpgsql; + +drop trigger if exists set_projects_updated_at on public.projects; +create trigger set_projects_updated_at before update on public.projects for each row execute procedure public.set_updated_at(); + +commit;