diff --git a/packages/shared-types/src/database.types.ts b/packages/shared-types/src/database.types.ts index c48c314..3ab03a5 100644 --- a/packages/shared-types/src/database.types.ts +++ b/packages/shared-types/src/database.types.ts @@ -78,6 +78,54 @@ export type Database = { }, ]; }; + client_invites: { + Row: { + created_at: string; + expires_at: string; + id: number; + invited_by: string; + invited_email: string; + invite_token: string; + is_pending: boolean; + tablo_id: string; + }; + Insert: { + created_at?: string; + expires_at?: string; + id?: number; + invited_by: string; + invited_email: string; + invite_token: string; + is_pending?: boolean; + tablo_id: string; + }; + Update: { + created_at?: string; + expires_at?: string; + id?: number; + invited_by?: string; + invited_email?: string; + invite_token?: string; + is_pending?: boolean; + tablo_id?: string; + }; + Relationships: [ + { + foreignKeyName: "client_invites_tablo_id_fkey"; + columns: ["tablo_id"]; + isOneToOne: false; + referencedRelation: "tablos"; + referencedColumns: ["id"]; + }, + { + foreignKeyName: "client_invites_invited_by_fkey"; + columns: ["invited_by"]; + isOneToOne: false; + referencedRelation: "profiles"; + referencedColumns: ["id"]; + }, + ]; + }; devis: { Row: { client_email: string; @@ -385,6 +433,7 @@ export type Database = { email: string | null; first_name: string | null; id: string; + is_client: boolean; is_temporary: boolean; last_name: string | null; last_signed_in: string | null; @@ -398,6 +447,7 @@ export type Database = { email?: string | null; first_name?: string | null; id: string; + is_client?: boolean; is_temporary?: boolean; last_name?: string | null; last_signed_in?: string | null; @@ -411,6 +461,7 @@ export type Database = { email?: string | null; first_name?: string | null; id?: string; + is_client?: boolean; is_temporary?: boolean; last_name?: string | null; last_signed_in?: string | null; diff --git a/supabase/migrations/20260415120000_add_client_invites.sql b/supabase/migrations/20260415120000_add_client_invites.sql new file mode 100644 index 0000000..7ee07fd --- /dev/null +++ b/supabase/migrations/20260415120000_add_client_invites.sql @@ -0,0 +1,40 @@ +-- Add is_client column to profiles +ALTER TABLE public.profiles + ADD COLUMN is_client boolean NOT NULL DEFAULT false; + +-- Create client_invites table +CREATE TABLE public.client_invites ( + id serial PRIMARY KEY, + tablo_id text NOT NULL REFERENCES public.tablos(id) ON DELETE CASCADE, + invited_email varchar(255) NOT NULL, + invited_by uuid NOT NULL REFERENCES public.profiles(id), + invite_token text NOT NULL, + expires_at timestamptz NOT NULL DEFAULT (now() + interval '30 days'), + is_pending boolean NOT NULL DEFAULT true, + created_at timestamptz NOT NULL DEFAULT now() +); + +-- Index for token lookups +CREATE UNIQUE INDEX idx_client_invites_token ON public.client_invites(invite_token); + +-- Index for listing invites by tablo +CREATE INDEX idx_client_invites_tablo ON public.client_invites(tablo_id, is_pending); + +-- RLS +ALTER TABLE public.client_invites ENABLE ROW LEVEL SECURITY; + +-- Admins can manage invites they created +CREATE POLICY "Admins can manage their client invites" + ON public.client_invites + FOR ALL + USING (invited_by = auth.uid()); + +-- Client users can read invites sent to their email +CREATE POLICY "Clients can read their own invites" + ON public.client_invites + FOR SELECT + USING ( + invited_email = ( + SELECT email FROM auth.users WHERE id = auth.uid() + ) + );