Hotfixes and CI/CD
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 3m51s

This commit is contained in:
Antoni Nuñez Romeu
2026-04-17 15:33:19 +02:00
parent b3f7d6bf98
commit 114fda056d
24 changed files with 2806 additions and 53 deletions

View File

@@ -0,0 +1,48 @@
-- ============================================================
-- Time Tracker App - Automatic Session Closure at Midnight
-- Run this SQL in your Supabase SQL Editor
-- ============================================================
-- Check if pg_cron extension is available
CREATE EXTENSION IF NOT EXISTS pg_cron;
-- Function to close active sessions at midnight
-- This will only close sessions that are currently running (end_time IS NULL)
-- and will preserve all session history
CREATE OR REPLACE FUNCTION close_active_sessions_at_midnight()
RETURNS void AS $$
DECLARE
closed_count INTEGER;
BEGIN
-- Update all active sessions (where end_time is NULL)
-- Set end_time to today at 00:00:00 (midnight)
-- This closes only currently active sessions, preserving all history
UPDATE timers
SET end_time = DATE_TRUNC('day', NOW()),
duration_ms = EXTRACT(EPOCH FROM (DATE_TRUNC('day', NOW()) - start_time)) * 1000
WHERE end_time IS NULL
AND start_time < DATE_TRUNC('day', NOW());
-- Get the count of closed sessions for the notice
GET DIAGNOSTICS closed_count = ROW_COUNT;
RAISE NOTICE 'Closed % active sessions at midnight (history preserved)', closed_count;
END;
$$ LANGUAGE plpgsql;
-- Schedule the function to run daily at midnight (00:00)
-- This will run in the timezone of your Supabase project
SELECT cron.schedule(
'close-active-sessions-at-midnight', -- job name
'0 0 * * *', -- cron expression (at 00:00 every day)
$$SELECT close_active_sessions_at_midnight()$$
);
-- To manually test the function, you can run:
-- SELECT close_active_sessions_at_midnight();
-- To view all cron jobs:
-- SELECT * FROM cron.job;
-- To unschedule this job:
-- SELECT cron.unschedule('close-active-sessions-at-midnight');

192
supabase/schema.sql Normal file
View File

@@ -0,0 +1,192 @@
-- ============================================================
-- Time Tracker App - Teams & Privileges Schema
-- Run this SQL in your Supabase SQL Editor
-- ============================================================
-- 1. Teams table
CREATE TABLE IF NOT EXISTS teams (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name TEXT NOT NULL,
description TEXT DEFAULT '',
created_at TIMESTAMPTZ DEFAULT now(),
created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL
);
-- 2. Team Members table (links users to teams with roles)
CREATE TABLE IF NOT EXISTS team_members (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
team_id UUID NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'manager', 'user')),
joined_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(team_id, user_id)
);
-- 3. User Profiles table (extends auth.users with global role)
CREATE TABLE IF NOT EXISTS user_profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
full_name TEXT DEFAULT '',
phone TEXT DEFAULT '',
company TEXT DEFAULT '',
avatar_url TEXT DEFAULT '',
global_role TEXT NOT NULL DEFAULT 'user' CHECK (global_role IN ('admin', 'manager', 'user')),
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- ============================================================
-- Indexes
-- ============================================================
CREATE INDEX IF NOT EXISTS idx_team_members_team_id ON team_members(team_id);
CREATE INDEX IF NOT EXISTS idx_team_members_user_id ON team_members(user_id);
CREATE INDEX IF NOT EXISTS idx_user_profiles_global_role ON user_profiles(global_role);
-- ============================================================
-- Row Level Security (RLS)
-- ============================================================
-- Teams: anyone authenticated can read; only admins can insert/update/delete
ALTER TABLE teams ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Teams are viewable by authenticated users"
ON teams FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Admins can insert teams"
ON teams FOR INSERT
TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role = 'admin'
)
);
CREATE POLICY "Admins can update teams"
ON teams FOR UPDATE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role = 'admin'
)
);
CREATE POLICY "Admins can delete teams"
ON teams FOR DELETE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role = 'admin'
)
);
-- Team Members: authenticated users can read; admins/managers can manage
ALTER TABLE team_members ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Team members are viewable by authenticated users"
ON team_members FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Admins can insert team members"
ON team_members FOR INSERT
TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role IN ('admin', 'manager')
)
);
CREATE POLICY "Admins can update team members"
ON team_members FOR UPDATE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role IN ('admin', 'manager')
)
);
CREATE POLICY "Admins can delete team members"
ON team_members FOR DELETE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role IN ('admin', 'manager')
)
);
-- User Profiles: users can read all profiles, update their own; admins can update any
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "User profiles are viewable by authenticated users"
ON user_profiles FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Users can update own profile"
ON user_profiles FOR UPDATE
TO authenticated
USING (auth.uid() = id);
CREATE POLICY "Admins can update any profile"
ON user_profiles FOR UPDATE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM user_profiles
WHERE id = auth.uid() AND global_role = 'admin'
)
);
CREATE POLICY "Users can insert own profile"
ON user_profiles FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = id);
-- ============================================================
-- Trigger: Auto-create user_profiles on signup
-- ============================================================
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.user_profiles (id, full_name, avatar_url)
VALUES (
NEW.id,
COALESCE(NEW.raw_user_meta_data->>'full_name', ''),
COALESCE(NEW.raw_user_meta_data->>'avatar_url', '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
-- ============================================================
-- Trigger: Auto-update updated_at on user_profiles
-- ============================================================
CREATE OR REPLACE FUNCTION public.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS update_user_profiles_updated_at ON user_profiles;
CREATE TRIGGER update_user_profiles_updated_at
BEFORE UPDATE ON user_profiles
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at();
-- ============================================================
-- Seed: Make the first user an admin (adjust the user_id as needed)
-- ============================================================
-- UPDATE user_profiles SET global_role = 'admin' WHERE id = 'YOUR_USER_ID_HERE';