From 6b0627054e482144e3fdc82248b9ca951e8219cf Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:40:29 +0000 Subject: [PATCH] Add backend infrastructure --- src/integrations/supabase/types.ts | 133 +++++++++++++++- ...1_4e6b4b88-fb3e-4195-a832-a4d45168c5d9.sql | 147 ++++++++++++++++++ 2 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 supabase/migrations/20251020214011_4e6b4b88-fb3e-4195-a832-a4d45168c5d9.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 5997274..60b03f0 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -14,7 +14,138 @@ export type Database = { } public: { Tables: { - [_ in never]: never + audit_logs: { + Row: { + action: string + container_id: string | null + container_name: string | null + details: Json | null + id: string + timestamp: string | null + user_id: string | null + } + Insert: { + action: string + container_id?: string | null + container_name?: string | null + details?: Json | null + id?: string + timestamp?: string | null + user_id?: string | null + } + Update: { + action?: string + container_id?: string | null + container_name?: string | null + details?: Json | null + id?: string + timestamp?: string | null + user_id?: string | null + } + Relationships: [] + } + container_settings: { + Row: { + alert_on_stop: boolean | null + alerts_enabled: boolean | null + container_id: string + container_name: string + created_at: string | null + custom_webhook_url: string | null + debounce_interval: number | null + error_pattern: string | null + id: string + updated_at: string | null + user_id: string | null + } + Insert: { + alert_on_stop?: boolean | null + alerts_enabled?: boolean | null + container_id: string + container_name: string + created_at?: string | null + custom_webhook_url?: string | null + debounce_interval?: number | null + error_pattern?: string | null + id?: string + updated_at?: string | null + user_id?: string | null + } + Update: { + alert_on_stop?: boolean | null + alerts_enabled?: boolean | null + container_id?: string + container_name?: string + created_at?: string | null + custom_webhook_url?: string | null + debounce_interval?: number | null + error_pattern?: string | null + id?: string + updated_at?: string | null + user_id?: string | null + } + Relationships: [] + } + global_settings: { + Row: { + alert_debounce_sec: number | null + created_at: string | null + default_error_regex: string | null + discord_webhook_url: string | null + id: string + metrics_interval: number | null + theme: string | null + timezone: string | null + updated_at: string | null + user_id: string | null + } + Insert: { + alert_debounce_sec?: number | null + created_at?: string | null + default_error_regex?: string | null + discord_webhook_url?: string | null + id?: string + metrics_interval?: number | null + theme?: string | null + timezone?: string | null + updated_at?: string | null + user_id?: string | null + } + Update: { + alert_debounce_sec?: number | null + created_at?: string | null + default_error_regex?: string | null + discord_webhook_url?: string | null + id?: string + metrics_interval?: number | null + theme?: string | null + timezone?: string | null + updated_at?: string | null + user_id?: string | null + } + Relationships: [] + } + profiles: { + Row: { + created_at: string | null + id: string + updated_at: string | null + username: string + } + Insert: { + created_at?: string | null + id: string + updated_at?: string | null + username: string + } + Update: { + created_at?: string | null + id?: string + updated_at?: string | null + username?: string + } + Relationships: [] + } } Views: { [_ in never]: never diff --git a/supabase/migrations/20251020214011_4e6b4b88-fb3e-4195-a832-a4d45168c5d9.sql b/supabase/migrations/20251020214011_4e6b4b88-fb3e-4195-a832-a4d45168c5d9.sql new file mode 100644 index 0000000..91f3a65 --- /dev/null +++ b/supabase/migrations/20251020214011_4e6b4b88-fb3e-4195-a832-a4d45168c5d9.sql @@ -0,0 +1,147 @@ +-- Create profiles table for user data +CREATE TABLE public.profiles ( + id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, + username TEXT NOT NULL UNIQUE, + created_at TIMESTAMPTZ DEFAULT now(), + updated_at TIMESTAMPTZ DEFAULT now() +); + +-- Enable RLS +ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; + +-- Profiles policies +CREATE POLICY "Users can view their own profile" + ON public.profiles FOR SELECT + USING (auth.uid() = id); + +CREATE POLICY "Users can update their own profile" + ON public.profiles FOR UPDATE + USING (auth.uid() = id); + +-- Create global_settings table +CREATE TABLE public.global_settings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, + discord_webhook_url TEXT, + metrics_interval INTEGER DEFAULT 2000, + alert_debounce_sec INTEGER DEFAULT 30, + default_error_regex TEXT DEFAULT '(?i)(error|err|exception|traceback|crit(ical)?)', + theme TEXT DEFAULT 'dark', + timezone TEXT DEFAULT 'Europe/Copenhagen', + created_at TIMESTAMPTZ DEFAULT now(), + updated_at TIMESTAMPTZ DEFAULT now() +); + +ALTER TABLE public.global_settings ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "Users can view their own settings" + ON public.global_settings FOR SELECT + USING (auth.uid() = user_id); + +CREATE POLICY "Users can insert their own settings" + ON public.global_settings FOR INSERT + WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "Users can update their own settings" + ON public.global_settings FOR UPDATE + USING (auth.uid() = user_id); + +-- Create container_settings table +CREATE TABLE public.container_settings ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, + container_id TEXT NOT NULL, + container_name TEXT NOT NULL, + alerts_enabled BOOLEAN DEFAULT true, + alert_on_stop BOOLEAN DEFAULT true, + error_pattern TEXT DEFAULT '(?i)(error|err|exception|traceback|crit(ical)?)', + custom_webhook_url TEXT, + debounce_interval INTEGER DEFAULT 30, + created_at TIMESTAMPTZ DEFAULT now(), + updated_at TIMESTAMPTZ DEFAULT now(), + UNIQUE(user_id, container_id) +); + +ALTER TABLE public.container_settings ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "Users can view their own container settings" + ON public.container_settings FOR SELECT + USING (auth.uid() = user_id); + +CREATE POLICY "Users can insert their own container settings" + ON public.container_settings FOR INSERT + WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "Users can update their own container settings" + ON public.container_settings FOR UPDATE + USING (auth.uid() = user_id); + +CREATE POLICY "Users can delete their own container settings" + ON public.container_settings FOR DELETE + USING (auth.uid() = user_id); + +-- Create audit_logs table +CREATE TABLE public.audit_logs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, + action TEXT NOT NULL, + container_id TEXT, + container_name TEXT, + details JSONB, + timestamp TIMESTAMPTZ DEFAULT now() +); + +ALTER TABLE public.audit_logs ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "Users can view their own audit logs" + ON public.audit_logs FOR SELECT + USING (auth.uid() = user_id); + +CREATE POLICY "Users can insert their own audit logs" + ON public.audit_logs FOR INSERT + WITH CHECK (auth.uid() = user_id); + +-- Create function to update updated_at timestamp +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = now(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create triggers for updated_at +CREATE TRIGGER update_profiles_updated_at + BEFORE UPDATE ON public.profiles + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER update_global_settings_updated_at + BEFORE UPDATE ON public.global_settings + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER update_container_settings_updated_at + BEFORE UPDATE ON public.container_settings + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +-- Create function to auto-create profile on signup +CREATE OR REPLACE FUNCTION public.handle_new_user() +RETURNS TRIGGER AS $$ +BEGIN + INSERT INTO public.profiles (id, username) + VALUES ( + NEW.id, + COALESCE(NEW.raw_user_meta_data->>'username', split_part(NEW.email, '@', 1)) + ); + + -- Create default global settings + INSERT INTO public.global_settings (user_id) + VALUES (NEW.id); + + RETURN NEW; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Trigger to create profile on user signup +CREATE TRIGGER on_auth_user_created + AFTER INSERT ON auth.users + FOR EACH ROW EXECUTE FUNCTION public.handle_new_user(); \ No newline at end of file