diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index d57bd90..2d612e2 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -405,6 +405,111 @@ export type Database = { }, ] } + fee_schedule_items: { + Row: { + active: boolean + amount: number + billable: boolean + category: string + created_at: string + created_by: string | null + description: string | null + id: string + name: string + sort_order: number + updated_at: string + } + Insert: { + active?: boolean + amount?: number + billable?: boolean + category: string + created_at?: string + created_by?: string | null + description?: string | null + id?: string + name: string + sort_order?: number + updated_at?: string + } + Update: { + active?: boolean + amount?: number + billable?: boolean + category?: string + created_at?: string + created_by?: string | null + description?: string | null + id?: string + name?: string + sort_order?: number + updated_at?: string + } + Relationships: [] + } + firm_settings: { + Row: { + address_line1: string | null + address_line2: string | null + city: string | null + company_name: string | null + contact_email: string | null + contact_phone: string | null + country: string | null + created_at: string + default_tax_rate: number | null + footer_note: string | null + id: string + invoice_prefix: string | null + logo_storage_path: string | null + postal_code: string | null + state: string | null + updated_at: string + updated_by: string | null + website: string | null + } + Insert: { + address_line1?: string | null + address_line2?: string | null + city?: string | null + company_name?: string | null + contact_email?: string | null + contact_phone?: string | null + country?: string | null + created_at?: string + default_tax_rate?: number | null + footer_note?: string | null + id?: string + invoice_prefix?: string | null + logo_storage_path?: string | null + postal_code?: string | null + state?: string | null + updated_at?: string + updated_by?: string | null + website?: string | null + } + Update: { + address_line1?: string | null + address_line2?: string | null + city?: string | null + company_name?: string | null + contact_email?: string | null + contact_phone?: string | null + country?: string | null + created_at?: string + default_tax_rate?: number | null + footer_note?: string | null + id?: string + invoice_prefix?: string | null + logo_storage_path?: string | null + postal_code?: string | null + state?: string | null + updated_at?: string + updated_by?: string | null + website?: string | null + } + Relationships: [] + } homeowners: { Row: { address: string | null diff --git a/supabase/migrations/20260417005108_8d3570de-850d-4daf-a166-562c441db8d9.sql b/supabase/migrations/20260417005108_8d3570de-850d-4daf-a166-562c441db8d9.sql new file mode 100644 index 0000000..617bd4e --- /dev/null +++ b/supabase/migrations/20260417005108_8d3570de-850d-4daf-a166-562c441db8d9.sql @@ -0,0 +1,100 @@ +-- 1. Firm settings (single-row table keyed by a fixed id) +CREATE TABLE IF NOT EXISTS public.firm_settings ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + company_name text, + contact_email text, + contact_phone text, + website text, + address_line1 text, + address_line2 text, + city text, + state text, + postal_code text, + country text, + logo_storage_path text, + invoice_prefix text, + default_tax_rate numeric, + footer_note text, + updated_by uuid, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +ALTER TABLE public.firm_settings ENABLE ROW LEVEL SECURITY; + +CREATE POLICY firm_settings_select_auth ON public.firm_settings + FOR SELECT TO authenticated USING (true); + +CREATE POLICY firm_settings_insert_admin ON public.firm_settings + FOR INSERT TO authenticated + WITH CHECK (public.is_admin(auth.uid())); + +CREATE POLICY firm_settings_update_admin ON public.firm_settings + FOR UPDATE TO authenticated + USING (public.is_admin(auth.uid())); + +CREATE POLICY firm_settings_delete_admin ON public.firm_settings + FOR DELETE TO authenticated + USING (public.is_admin(auth.uid())); + +CREATE TRIGGER firm_settings_set_updated_at + BEFORE UPDATE ON public.firm_settings + FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); + +-- 2. Fee schedule items +CREATE TABLE IF NOT EXISTS public.fee_schedule_items ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + name text NOT NULL, + description text, + category text NOT NULL CHECK (category IN ('time','expense')), + amount numeric NOT NULL DEFAULT 0, + billable boolean NOT NULL DEFAULT true, + active boolean NOT NULL DEFAULT true, + sort_order int NOT NULL DEFAULT 0, + created_by uuid, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); +CREATE INDEX IF NOT EXISTS idx_fee_schedule_items_category ON public.fee_schedule_items(category); + +ALTER TABLE public.fee_schedule_items ENABLE ROW LEVEL SECURITY; + +CREATE POLICY fee_schedule_items_select_auth ON public.fee_schedule_items + FOR SELECT TO authenticated USING (true); + +CREATE POLICY fee_schedule_items_insert_admin ON public.fee_schedule_items + FOR INSERT TO authenticated + WITH CHECK (public.is_admin(auth.uid())); + +CREATE POLICY fee_schedule_items_update_admin ON public.fee_schedule_items + FOR UPDATE TO authenticated + USING (public.is_admin(auth.uid())); + +CREATE POLICY fee_schedule_items_delete_admin ON public.fee_schedule_items + FOR DELETE TO authenticated + USING (public.is_admin(auth.uid())); + +CREATE TRIGGER fee_schedule_items_set_updated_at + BEFORE UPDATE ON public.fee_schedule_items + FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); + +-- 3. Public logos bucket +INSERT INTO storage.buckets (id, name, public) +VALUES ('firm-logos', 'firm-logos', true) +ON CONFLICT (id) DO NOTHING; + +CREATE POLICY firm_logos_select_public ON storage.objects + FOR SELECT TO public + USING (bucket_id = 'firm-logos'); + +CREATE POLICY firm_logos_insert_auth ON storage.objects + FOR INSERT TO authenticated + WITH CHECK (bucket_id = 'firm-logos'); + +CREATE POLICY firm_logos_update_admin ON storage.objects + FOR UPDATE TO authenticated + USING (bucket_id = 'firm-logos' AND public.is_admin(auth.uid())); + +CREATE POLICY firm_logos_delete_admin ON storage.objects + FOR DELETE TO authenticated + USING (bucket_id = 'firm-logos' AND public.is_admin(auth.uid())); \ No newline at end of file