feat: explore tab, React Query data layer, programs, sync, analytics, testing infrastructure

- Replace browse tab with Supabase-connected explore tab with filters
- Add React Query for data fetching with loading states
- Add 3 structured programs with weekly progression
- Add Supabase anonymous auth sync service
- Add PostHog analytics with screen tracking and events
- Add comprehensive test strategy (Vitest + Maestro E2E)
- Add RevenueCat subscription system with DEV simulation
- Add i18n translations for new screens (EN/FR/DE/ES)
- Add data deletion modal, sync consent modal
- Add assessment screen and program routes
- Add GitHub Actions CI workflow
- Update activity store with sync integration
This commit is contained in:
Millian Lamiaux
2026-03-24 12:04:48 +01:00
parent 8703c484e8
commit cd065d07c3
138 changed files with 26819 additions and 1043 deletions

View File

@@ -235,3 +235,77 @@ ON CONFLICT DO NOTHING;
-- SELECT id, email, 'admin'
-- FROM auth.users
-- WHERE email = 'your-email@example.com';
-- ============================================================
-- USER SYNC TABLES (Premium Feature - Anonymous Auth)
-- ============================================================
-- User profiles (created after opt-in to sync for personalization)
CREATE TABLE IF NOT EXISTS public.user_profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT,
name TEXT NOT NULL,
fitness_level TEXT NOT NULL,
goal TEXT NOT NULL,
weekly_frequency INTEGER NOT NULL,
barriers JSONB DEFAULT '[]',
is_anonymous BOOLEAN DEFAULT true,
sync_enabled BOOLEAN DEFAULT true,
subscription_plan TEXT DEFAULT 'premium-yearly',
onboarding_completed_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Workout sessions (synced history for personalization)
CREATE TABLE IF NOT EXISTS public.workout_sessions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
workout_id UUID NOT NULL REFERENCES public.workouts(id),
completed_at TIMESTAMP WITH TIME ZONE NOT NULL,
duration_seconds INTEGER,
calories_burned INTEGER,
feeling_rating INTEGER CHECK (feeling_rating BETWEEN 1 AND 5),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- User preferences for personalization
CREATE TABLE IF NOT EXISTS public.user_preferences (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
preferred_categories TEXT[] DEFAULT '{}',
preferred_trainers TEXT[] DEFAULT '{}',
preferred_durations INTEGER[] DEFAULT '{}',
difficulty_preference TEXT DEFAULT 'matched',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id)
);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_workout_sessions_user_id ON public.workout_sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_workout_sessions_completed_at ON public.workout_sessions(completed_at DESC);
CREATE INDEX IF NOT EXISTS idx_user_profiles_email ON public.user_profiles(email);
-- RLS Policies for user data protection
ALTER TABLE public.user_profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.workout_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.user_preferences ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users manage own profile"
ON public.user_profiles FOR ALL USING (id = auth.uid());
CREATE POLICY "Users manage own sessions"
ON public.workout_sessions FOR ALL USING (user_id = auth.uid());
CREATE POLICY "Users manage own preferences"
ON public.user_preferences FOR ALL USING (user_id = auth.uid());
-- Triggers for updated_at
CREATE TRIGGER update_user_profiles_updated_at
BEFORE UPDATE ON public.user_profiles
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
CREATE TRIGGER update_user_preferences_updated_at
BEFORE UPDATE ON public.user_preferences
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();