diff --git a/habitTrackerApp/DATABASE_SETUP.md b/habitTrackerApp/DATABASE_SETUP.md deleted file mode 100644 index f23231b..0000000 --- a/habitTrackerApp/DATABASE_SETUP.md +++ /dev/null @@ -1,118 +0,0 @@ -# Database Setup Instructions - -## 🗄️ Setting up the Database with Row Level Security - -### Step 1: Run the SQL Migration - -1. Go to your [Supabase Dashboard](https://supabase.com/dashboard) -2. Select your project -3. Navigate to **SQL Editor** -4. Copy the contents of `database/schema.sql` -5. Paste and run the SQL script - -This will create: -- ✅ **users** table with RLS enabled -- ✅ **habits** table with RLS enabled & enhanced constraints -- ✅ **habit_logs** table with RLS enabled & duplicate prevention -- ✅ All necessary RLS policies -- ✅ Performance indexes (including partial indexes) -- ✅ Auto-updating timestamps -- ✅ Auto user profile creation trigger -- ✅ **habit_stats** analytics view -- ✅ **get_habit_completion_rate()** function -- ✅ Data integrity constraints - -### Step 2: Verify RLS is Working - -After running the migration, you can verify RLS is working by: - -1. **Check Tables**: Go to Table Editor and confirm all tables exist -2. **Check RLS**: Each table should show "RLS enabled" -3. **Check Policies**: Go to Authentication → Policies to see all policies - -### Expected Tables: - -#### 🧑‍💼 **users** table -- `id` (UUID, references auth.users) -- `email` (TEXT, unique) -- `full_name` (TEXT, nullable) -- `avatar_url` (TEXT, nullable) -- `created_at` (TIMESTAMP) -- `updated_at` (TIMESTAMP) - -#### 📋 **habits** table -- `id` (UUID, primary key) -- `user_id` (UUID, references users) -- `title` (TEXT, required, trimmed) -- `description` (TEXT, nullable) -- `frequency` (daily/weekly/monthly, required) -- `target_count` (INTEGER, required, > 0) -- `color` (TEXT, hex color validation) -- `is_active` (BOOLEAN, required) -- `created_at` (TIMESTAMP, required) -- `updated_at` (TIMESTAMP, required) - -#### 📊 **habit_logs** table -- `id` (UUID, primary key) -- `habit_id` (UUID, references habits) -- `user_id` (UUID, references users) -- `completed_at` (TIMESTAMP, required) -- `notes` (TEXT, nullable) -- `created_at` (TIMESTAMP, required) -- **Constraint**: Prevents duplicate daily logs -- **Constraint**: Ensures habit belongs to user - -#### 📈 **habit_stats** view -- `habit_id` (UUID) -- `title` (TEXT) -- `user_id` (UUID) -- `frequency` (TEXT) -- `target_count` (INTEGER) -- `color` (TEXT) -- `is_active` (BOOLEAN) -- `total_completions` (INTEGER) -- `last_completed_at` (TIMESTAMP) -- `unique_completion_days` (INTEGER) -- `last_7_days` (INTEGER) -- `last_30_days` (INTEGER) -- `today_count` (INTEGER) - -### Step 3: Test the Setup - -After running the migration, test that everything works: - -```bash -# Start the development server -npm run dev -``` - -The app should now be able to connect to your Supabase database with full RLS protection! - -## 🔒 Row Level Security Policies Created - -### Users Table Policies: -- ✅ Users can view own profile -- ✅ Users can update own profile -- ✅ Users can insert own profile - -### Habits Table Policies: -- ✅ Users can view own habits -- ✅ Users can insert own habits -- ✅ Users can update own habits -- ✅ Users can delete own habits - -### Habit Logs Table Policies: -- ✅ Users can view own habit logs -- ✅ Users can insert own habit logs -- ✅ Users can update own habit logs -- ✅ Users can delete own habit logs - -## 🚀 Next Steps - -After the database is set up, you can proceed to: -1. Build authentication components -2. Create API routes -3. Add validation with Zod -4. Test the endpoints - -The database foundation with RLS is now complete! diff --git a/habitTrackerApp/database/schema.sql b/habitTrackerApp/database/schema.sql deleted file mode 100644 index 8890aae..0000000 --- a/habitTrackerApp/database/schema.sql +++ /dev/null @@ -1,247 +0,0 @@ --- =============================================== --- HABIT TRACKER DATABASE SCHEMA WITH RLS --- =============================================== - --- Enable necessary extensions -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - --- =============================================== --- USERS TABLE --- =============================================== - -CREATE TABLE IF NOT EXISTS public.users ( - id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY, - email TEXT UNIQUE NOT NULL, - full_name TEXT, - avatar_url TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); - -ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; - -CREATE POLICY "Users can view own profile" ON public.users - FOR SELECT USING (auth.uid() = id); - -CREATE POLICY "Users can update own profile" ON public.users - FOR UPDATE USING (auth.uid() = id); - -CREATE POLICY "Users can insert own profile" ON public.users - FOR INSERT WITH CHECK (auth.uid() = id); - --- =============================================== --- HABITS TABLE --- =============================================== - -CREATE TABLE IF NOT EXISTS public.habits ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - user_id UUID REFERENCES public.users(id) ON DELETE CASCADE NOT NULL, - title TEXT NOT NULL CHECK (length(trim(title)) > 0), - description TEXT, - frequency TEXT CHECK (frequency IN ('daily', 'weekly', 'monthly')) DEFAULT 'daily' NOT NULL, - target_count INTEGER DEFAULT 1 CHECK (target_count > 0) NOT NULL, - color TEXT DEFAULT '#3B82F6' CHECK (color ~ '^#[0-9A-Fa-f]{6}$'), - is_active BOOLEAN DEFAULT true NOT NULL, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL -); - -ALTER TABLE public.habits ENABLE ROW LEVEL SECURITY; - -CREATE POLICY "Users can view own habits" ON public.habits - FOR SELECT USING (auth.uid() = user_id); - -CREATE POLICY "Users can insert own habits" ON public.habits - FOR INSERT WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users can update own habits" ON public.habits - FOR UPDATE USING (auth.uid() = user_id); - -CREATE POLICY "Users can delete own habits" ON public.habits - FOR DELETE USING (auth.uid() = user_id); - --- =============================================== --- HABIT LOGS TABLE --- =============================================== - -CREATE TABLE IF NOT EXISTS public.habit_logs ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, - habit_id UUID REFERENCES public.habits(id) ON DELETE CASCADE NOT NULL, - user_id UUID REFERENCES public.users(id) ON DELETE CASCADE NOT NULL, - completed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, - notes TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, - -- Ensure habit belongs to user (data integrity) - CONSTRAINT habit_logs_user_habit_check - CHECK (user_id = (SELECT user_id FROM public.habits WHERE id = habit_id)) -); - --- Prevent duplicate completions on same day for same habit -CREATE UNIQUE INDEX idx_habit_logs_unique_daily ON public.habit_logs( - habit_id, - DATE(completed_at AT TIME ZONE 'UTC') -); - -ALTER TABLE public.habit_logs ENABLE ROW LEVEL SECURITY; - -CREATE POLICY "Users can view own habit logs" ON public.habit_logs - FOR SELECT USING (auth.uid() = user_id); - -CREATE POLICY "Users can insert own habit logs" ON public.habit_logs - FOR INSERT WITH CHECK (auth.uid() = user_id); - -CREATE POLICY "Users can update own habit logs" ON public.habit_logs - FOR UPDATE USING (auth.uid() = user_id); - -CREATE POLICY "Users can delete own habit logs" ON public.habit_logs - FOR DELETE USING (auth.uid() = user_id); - --- =============================================== --- INDEXES FOR PERFORMANCE --- =============================================== - --- Habits indexes -CREATE INDEX IF NOT EXISTS idx_habits_user_id ON public.habits(user_id); -CREATE INDEX IF NOT EXISTS idx_habits_user_active ON public.habits(user_id, is_active) - WHERE is_active = true; - --- Habit logs indexes -CREATE INDEX IF NOT EXISTS idx_habit_logs_user_id ON public.habit_logs(user_id); -CREATE INDEX IF NOT EXISTS idx_habit_logs_habit_id ON public.habit_logs(habit_id); -CREATE INDEX IF NOT EXISTS idx_habit_logs_completed_at ON public.habit_logs(completed_at DESC); - --- Composite index for common date range queries -CREATE INDEX IF NOT EXISTS idx_habit_logs_user_completed ON public.habit_logs( - user_id, - completed_at DESC -); - --- Composite index for habit-specific queries -CREATE INDEX IF NOT EXISTS idx_habit_logs_habit_completed ON public.habit_logs( - habit_id, - completed_at DESC -); - --- =============================================== --- FUNCTIONS AND TRIGGERS --- =============================================== - --- Update timestamp function -CREATE OR REPLACE FUNCTION public.handle_updated_at() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = NOW(); - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - --- Triggers for updated_at -CREATE TRIGGER set_updated_at_users - BEFORE UPDATE ON public.users - FOR EACH ROW - EXECUTE FUNCTION public.handle_updated_at(); - -CREATE TRIGGER set_updated_at_habits - BEFORE UPDATE ON public.habits - FOR EACH ROW - EXECUTE FUNCTION public.handle_updated_at(); - --- Auto-create user profile on signup -CREATE OR REPLACE FUNCTION public.handle_new_user() -RETURNS TRIGGER AS $$ -BEGIN - INSERT INTO public.users (id, email, full_name, avatar_url) - VALUES ( - NEW.id, - NEW.email, - NEW.raw_user_meta_data->>'full_name', - NEW.raw_user_meta_data->>'avatar_url' - ); - RETURN NEW; -END; -$$ LANGUAGE plpgsql SECURITY DEFINER; - -CREATE OR REPLACE TRIGGER on_auth_user_created - AFTER INSERT ON auth.users - FOR EACH ROW - EXECUTE FUNCTION public.handle_new_user(); - --- =============================================== --- HELPER FUNCTIONS --- =============================================== - --- Get habit completion rate for date range -CREATE OR REPLACE FUNCTION public.get_habit_completion_rate( - p_habit_id UUID, - p_start_date DATE, - p_end_date DATE -) -RETURNS DECIMAL AS $$ -DECLARE - v_frequency TEXT; - v_target_count INTEGER; - v_expected_completions INTEGER; - v_actual_completions INTEGER; -BEGIN - -- Get habit frequency and target - SELECT frequency, target_count INTO v_frequency, v_target_count - FROM public.habits - WHERE id = p_habit_id; - - -- Calculate expected completions based on frequency - v_expected_completions := CASE v_frequency - WHEN 'daily' THEN (p_end_date - p_start_date + 1) * v_target_count - WHEN 'weekly' THEN CEIL((p_end_date - p_start_date + 1) / 7.0) * v_target_count - WHEN 'monthly' THEN CEIL((p_end_date - p_start_date + 1) / 30.0) * v_target_count - END; - - -- Count actual completions - SELECT COUNT(*) INTO v_actual_completions - FROM public.habit_logs - WHERE habit_id = p_habit_id - AND DATE(completed_at) BETWEEN p_start_date AND p_end_date; - - -- Return completion rate - RETURN CASE - WHEN v_expected_completions = 0 THEN 0 - ELSE LEAST(v_actual_completions::DECIMAL / v_expected_completions * 100, 100) - END; -END; -$$ LANGUAGE plpgsql SECURITY DEFINER; - --- =============================================== --- VIEWS FOR ANALYTICS --- =============================================== - --- Improved habit stats view with flexible date ranges -CREATE OR REPLACE VIEW public.habit_stats AS -SELECT - h.id AS habit_id, - h.title, - h.user_id, - h.frequency, - h.target_count, - h.color, - h.is_active, - COUNT(hl.id) AS total_completions, - MAX(hl.completed_at) AS last_completed_at, - COUNT(DISTINCT DATE(hl.completed_at)) AS unique_completion_days, - COUNT(CASE WHEN hl.completed_at >= CURRENT_DATE - INTERVAL '7 days' THEN 1 END) AS last_7_days, - COUNT(CASE WHEN hl.completed_at >= CURRENT_DATE - INTERVAL '30 days' THEN 1 END) AS last_30_days, - COUNT(CASE WHEN DATE(hl.completed_at) = CURRENT_DATE THEN 1 END) AS today_count -FROM public.habits h -LEFT JOIN public.habit_logs hl ON h.id = hl.habit_id -GROUP BY h.id, h.title, h.user_id, h.frequency, h.target_count, h.color, h.is_active; - --- Enable RLS on view (queries run with user privileges) -ALTER VIEW public.habit_stats SET (security_invoker = true); - --- =============================================== --- GRANT PERMISSIONS --- =============================================== - --- Grant necessary permissions to authenticated users -GRANT USAGE ON SCHEMA public TO authenticated; -GRANT ALL ON ALL TABLES IN SCHEMA public TO authenticated; -GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO authenticated; -GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO authenticated; diff --git a/habitTrackerApp/package-lock.json b/habitTrackerApp/package-lock.json index d89c974..f4e53f2 100644 --- a/habitTrackerApp/package-lock.json +++ b/habitTrackerApp/package-lock.json @@ -9,14 +9,9 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@supabase/auth-helpers-nextjs": "^0.10.0", - "@supabase/auth-helpers-react": "^0.5.0", - "@supabase/ssr": "^0.7.0", - "@supabase/supabase-js": "^2.75.0", "next": "15.5.5", "react": "19.1.0", - "react-dom": "19.1.0", - "zod": "^4.1.12" + "react-dom": "19.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -985,129 +980,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@supabase/auth-helpers-nextjs": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.10.0.tgz", - "integrity": "sha512-2dfOGsM4yZt0oS4TPiE7bD4vf7EVz7NRz/IJrV6vLg0GP7sMUx8wndv2euLGq4BjN9lUCpu6DG/uCC8j+ylwPg==", - "deprecated": "This package is now deprecated - please use the @supabase/ssr package instead.", - "license": "MIT", - "dependencies": { - "@supabase/auth-helpers-shared": "0.7.0", - "set-cookie-parser": "^2.6.0" - }, - "peerDependencies": { - "@supabase/supabase-js": "^2.39.8" - } - }, - "node_modules/@supabase/auth-helpers-react": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-react/-/auth-helpers-react-0.5.0.tgz", - "integrity": "sha512-5QSaV2CGuhDhd7RlQCoviVEAYsP7XnrFMReOcBazDvVmqSIyjKcDwhLhWvnrxMOq5qjOaA44MHo7wXqDiF0puQ==", - "deprecated": "This package is now deprecated - please use the @supabase/ssr package instead.", - "license": "MIT", - "peerDependencies": { - "@supabase/supabase-js": "^2.39.8" - } - }, - "node_modules/@supabase/auth-helpers-shared": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.7.0.tgz", - "integrity": "sha512-FBFf2ei2R7QC+B/5wWkthMha8Ca2bWHAndN+syfuEUUfufv4mLcAgBCcgNg5nJR8L0gZfyuaxgubtOc9aW3Cpg==", - "deprecated": "This package is now deprecated - please use the @supabase/ssr package instead.", - "license": "MIT", - "dependencies": { - "jose": "^4.14.4" - }, - "peerDependencies": { - "@supabase/supabase-js": "^2.39.8" - } - }, - "node_modules/@supabase/auth-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.75.0.tgz", - "integrity": "sha512-J8TkeqCOMCV4KwGKVoxmEBuDdHRwoInML2vJilthOo7awVCro2SM+tOcpljORwuBQ1vHUtV62Leit+5wlxrNtw==", - "license": "MIT", - "dependencies": { - "@supabase/node-fetch": "2.6.15" - } - }, - "node_modules/@supabase/functions-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.75.0.tgz", - "integrity": "sha512-18yk07Moj/xtQ28zkqswxDavXC3vbOwt1hDuYM3/7xPnwwpKnsmPyZ7bQ5th4uqiJzQ135t74La9tuaxBR6e7w==", - "license": "MIT", - "dependencies": { - "@supabase/node-fetch": "2.6.15" - } - }, - "node_modules/@supabase/node-fetch": { - "version": "2.6.15", - "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", - "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/@supabase/postgrest-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.75.0.tgz", - "integrity": "sha512-YfBz4W/z7eYCFyuvHhfjOTTzRrQIvsMG2bVwJAKEVVUqGdzqfvyidXssLBG0Fqlql1zJFgtsPpK1n4meHrI7tg==", - "license": "MIT", - "dependencies": { - "@supabase/node-fetch": "2.6.15" - } - }, - "node_modules/@supabase/realtime-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.75.0.tgz", - "integrity": "sha512-B4Xxsf2NHd5cEnM6MGswOSPSsZKljkYXpvzKKmNxoUmNQOfB7D8HOa6NwHcUBSlxcjV+vIrYKcYXtavGJqeGrw==", - "license": "MIT", - "dependencies": { - "@supabase/node-fetch": "2.6.15", - "@types/phoenix": "^1.6.6", - "@types/ws": "^8.18.1", - "ws": "^8.18.2" - } - }, - "node_modules/@supabase/ssr": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.7.0.tgz", - "integrity": "sha512-G65t5EhLSJ5c8hTCcXifSL9Q/ZRXvqgXeNo+d3P56f4U1IxwTqjB64UfmfixvmMcjuxnq2yGqEWVJqUcO+AzAg==", - "license": "MIT", - "dependencies": { - "cookie": "^1.0.2" - }, - "peerDependencies": { - "@supabase/supabase-js": "^2.43.4" - } - }, - "node_modules/@supabase/storage-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.75.0.tgz", - "integrity": "sha512-wpJMYdfFDckDiHQaTpK+Ib14N/O2o0AAWWhguKvmmMurB6Unx17GGmYp5rrrqCTf8S1qq4IfIxTXxS4hzrUySg==", - "license": "MIT", - "dependencies": { - "@supabase/node-fetch": "2.6.15" - } - }, - "node_modules/@supabase/supabase-js": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.75.0.tgz", - "integrity": "sha512-8UN/vATSgS2JFuJlMVr51L3eUDz+j1m7Ww63wlvHLKULzCDaVWYzvacCjBTLW/lX/vedI2LBI4Vg+01G9ufsJQ==", - "license": "MIT", - "dependencies": { - "@supabase/auth-js": "2.75.0", - "@supabase/functions-js": "2.75.0", - "@supabase/node-fetch": "2.6.15", - "@supabase/postgrest-js": "2.75.0", - "@supabase/realtime-js": "2.75.0", - "@supabase/storage-js": "2.75.0" - } - }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -1429,17 +1301,12 @@ "version": "20.19.21", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.21.tgz", "integrity": "sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, - "node_modules/@types/phoenix": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", - "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==", - "license": "MIT" - }, "node_modules/@types/react": { "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", @@ -1460,15 +1327,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.46.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", @@ -2565,15 +2423,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4346,15 +4195,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5550,12 +5390,6 @@ "node": ">=10" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -6064,12 +5898,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -6230,6 +6058,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, "license": "MIT" }, "node_modules/unrs-resolver": { @@ -6308,22 +6137,6 @@ "punycode": "^2.1.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6439,27 +6252,6 @@ "node": ">=0.10.0" } }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -6482,15 +6274,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/habitTrackerApp/package.json b/habitTrackerApp/package.json index 2b03ab5..9572598 100644 --- a/habitTrackerApp/package.json +++ b/habitTrackerApp/package.json @@ -13,14 +13,9 @@ "author": "", "license": "ISC", "dependencies": { - "@supabase/auth-helpers-nextjs": "^0.10.0", - "@supabase/auth-helpers-react": "^0.5.0", - "@supabase/ssr": "^0.7.0", - "@supabase/supabase-js": "^2.75.0", "next": "15.5.5", "react": "19.1.0", - "react-dom": "19.1.0", - "zod": "^4.1.12" + "react-dom": "19.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/habitTrackerApp/src/app/calendar/page.tsx b/habitTrackerApp/src/app/calendar/page.tsx new file mode 100644 index 0000000..9ab6217 --- /dev/null +++ b/habitTrackerApp/src/app/calendar/page.tsx @@ -0,0 +1,19 @@ +import { Navbar } from '../components/navbar'; + +export default function Calendar() { + return ( +
+ +
+
+

Calendar

+
+

Habit Calendar

+

View your habit completion calendar and plan your schedule.

+ {/* Add your calendar functionality here */} +
+
+
+
+ ); +} diff --git a/habitTrackerApp/src/app/components/navbar.tsx b/habitTrackerApp/src/app/components/navbar.tsx index 3f27159..97adde1 100644 --- a/habitTrackerApp/src/app/components/navbar.tsx +++ b/habitTrackerApp/src/app/components/navbar.tsx @@ -2,30 +2,27 @@ import Link from "next/link"; import { FC } from "react"; -export interface NavbarProps { - url: string; - title: string; -} +export interface NavbarProps {} -export const Navbar: FC = ({ url, title }) => { +export const Navbar: FC = ({}) => { return ( diff --git a/habitTrackerApp/src/app/components/progress-tracker.tsx b/habitTrackerApp/src/app/components/progress-tracker.tsx deleted file mode 100644 index ad90d33..0000000 --- a/habitTrackerApp/src/app/components/progress-tracker.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react'; - -const ProgressTracker = () => { - const percentage = 100; - const completed = 10; - const inProgress = 0; - const pending = 0; - - return ( -
- {/* Title */} -

Progress Tracker

- - {/* Circular Progress */} -
- {/* Background Circle */} - - - {/* Progress Circle */} - - - - {/* Center Text */} -
- {percentage}% - Completed -
-
- - {/* Legend */} -
- {/* Completed */} -
-
- Completed -
- - {/* In Progress */} -
-
- In Progress -
- - {/* Pending */} -
-
- Pending -
-
-
- ); -}; - -export default ProgressTracker; diff --git a/habitTrackerApp/src/app/components/tasks-and-reminders.tsx b/habitTrackerApp/src/app/components/tasks-and-reminders.tsx deleted file mode 100644 index d492246..0000000 --- a/habitTrackerApp/src/app/components/tasks-and-reminders.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -const TasksAndReminders = () => { - return ( -
- {/* Tasks Completed Card */} -
-

Tasks completed

-
- - {/* Reminders Card */} -
-

Reminders

-
-
- ); -}; - -export default TasksAndReminders; diff --git a/habitTrackerApp/src/app/components/todo-list.tsx b/habitTrackerApp/src/app/components/todo-list.tsx deleted file mode 100644 index 85bfe8e..0000000 --- a/habitTrackerApp/src/app/components/todo-list.tsx +++ /dev/null @@ -1,13 +0,0 @@ - -const ToDoList = () => { - return ( -
- {/* To Do List Card */} -
-

To Do List

-
-
- ); -}; - -export default ToDoList; diff --git a/habitTrackerApp/src/app/components/weekly-streak.tsx b/habitTrackerApp/src/app/components/weekly-streak.tsx deleted file mode 100644 index 9acde85..0000000 --- a/habitTrackerApp/src/app/components/weekly-streak.tsx +++ /dev/null @@ -1,39 +0,0 @@ - -const WeeklyStreak = () => { - const days = [ - { label: 'M', completed: true }, - { label: 'T', completed: false }, - { label: 'W', completed: true }, - { label: 'TH', completed: true }, - { label: 'F', completed: true }, - { label: 'S', completed: false }, - { label: 'SU', completed: false } - ]; - - return ( -
- {/* Title */} -

Weekly streak

- - {/* Days Container */} -
- {days.map((day, index) => ( -
- {/* Day Pill */} -
- {/* Day Label */} - {day.label} -
- ))} -
-
- ); -}; - -export default WeeklyStreak; diff --git a/habitTrackerApp/src/app/components/welcome.tsx b/habitTrackerApp/src/app/components/welcome.tsx deleted file mode 100644 index 2e220bd..0000000 --- a/habitTrackerApp/src/app/components/welcome.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { FC } from "react"; - -export interface WelcomeProps { - userName?: string; - className?: string; -} - -export const Welcome: FC = ({ userName = "Jane", className = "" }) => { - return ( -
- {/* Welcome Message */} -

- Welcome in, {userName} -

- - {/* Buttons Container */} -
- {/* Add Task Button */} - - - {/* Journal Button */} - -
-
- ); -}; diff --git a/habitTrackerApp/src/app/dashboard/page.tsx b/habitTrackerApp/src/app/dashboard/page.tsx new file mode 100644 index 0000000..b5ebbdb --- /dev/null +++ b/habitTrackerApp/src/app/dashboard/page.tsx @@ -0,0 +1,28 @@ +import { Navbar } from '../components/navbar'; + +export default function Dashboard() { + return ( +
+ +
+
+

Dashboard

+
+
+

Habit Progress

+

Track your daily habits and see your progress over time.

+
+
+

Recent Activity

+

View your recent habit completions and journal entries.

+
+
+

Quick Stats

+

Get an overview of your habit tracking statistics.

+
+
+
+
+
+ ); +} diff --git a/habitTrackerApp/src/app/habits/page.tsx b/habitTrackerApp/src/app/habits/page.tsx new file mode 100644 index 0000000..09965fa --- /dev/null +++ b/habitTrackerApp/src/app/habits/page.tsx @@ -0,0 +1,19 @@ +import { Navbar } from '../components/navbar'; + +export default function Habits() { + return ( +
+ +
+
+

My Habits

+
+

Habit Tracker

+

Create, manage, and track your daily habits here.

+ {/* Add your habit tracking functionality here */} +
+
+
+
+ ); +} diff --git a/habitTrackerApp/src/app/journaling/page.tsx b/habitTrackerApp/src/app/journaling/page.tsx new file mode 100644 index 0000000..cfcff9a --- /dev/null +++ b/habitTrackerApp/src/app/journaling/page.tsx @@ -0,0 +1,19 @@ +import { Navbar } from '../components/navbar'; + +export default function Journaling() { + return ( +
+ +
+
+

Journaling

+
+

Daily Journal

+

Write about your daily experiences and reflect on your habits.

+ {/* Add your journaling functionality here */} +
+
+
+
+ ); +} diff --git a/habitTrackerApp/src/app/layout.tsx b/habitTrackerApp/src/app/layout.tsx index ec90dd5..196f58f 100644 --- a/habitTrackerApp/src/app/layout.tsx +++ b/habitTrackerApp/src/app/layout.tsx @@ -1,4 +1,3 @@ -import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import { Navbar } from "./components/navbar"; import "./globals.css"; @@ -26,16 +25,9 @@ export default function RootLayout({ }) { return ( - -
- -
- {children} -
-
+ + ) diff --git a/habitTrackerApp/src/app/page.tsx b/habitTrackerApp/src/app/page.tsx index ff944a8..c5a11f7 100644 --- a/habitTrackerApp/src/app/page.tsx +++ b/habitTrackerApp/src/app/page.tsx @@ -1,20 +1,17 @@ -import ProgressTracker from "./components/progress-tracker"; -import TasksAndReminders from "./components/tasks-and-reminders"; -import ToDoList from "./components/todo-list"; -import WeeklyStreak from "./components/weekly-streak"; -import { Welcome } from "./components/welcome"; +import Link from 'next/link'; export default function HomePage() { return ( -
- -
- -
-
- - - +
+
+

Habit Tracker

+

Build better habits, one day at a time

+ + Get Started +
); diff --git a/habitTrackerApp/src/app/types/types.ts b/habitTrackerApp/src/app/types/types.ts deleted file mode 100644 index 1f11b6a..0000000 --- a/habitTrackerApp/src/app/types/types.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface Users { - id: string - name: string - email: string - avatar_url?: string -} - -export interface Habits { - id: string - user_id: string - title: string - frequency: string - created_at: string -} - -export interface HabitProgress { - id: string - user_id: string - habit_id: string - date: string - completed: boolean - created_at: string -} \ No newline at end of file diff --git a/habitTrackerApp/src/lib/supabase-admin.ts b/habitTrackerApp/src/lib/supabase-admin.ts deleted file mode 100644 index 5da9bdd..0000000 --- a/habitTrackerApp/src/lib/supabase-admin.ts +++ /dev/null @@ -1,27 +0,0 @@ -/// - -import { createClient } from '@supabase/supabase-js' - -// Server-side only - ensure this runs in Node.js environment -if (typeof window !== 'undefined') { - throw new Error('supabase-admin should only be used on the server side') -} - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! -const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY! - -if (!supabaseUrl || !supabaseServiceKey) { - throw new Error('Missing Supabase environment variables') -} - -// Admin client for server-side operations (uses service role key) -export const supabaseAdmin = createClient( - supabaseUrl, - supabaseServiceKey, - { - auth: { - autoRefreshToken: false, - persistSession: false - } - } -) diff --git a/habitTrackerApp/src/types/app-types.ts b/habitTrackerApp/src/types/app-types.ts deleted file mode 100644 index 1f11b6a..0000000 --- a/habitTrackerApp/src/types/app-types.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface Users { - id: string - name: string - email: string - avatar_url?: string -} - -export interface Habits { - id: string - user_id: string - title: string - frequency: string - created_at: string -} - -export interface HabitProgress { - id: string - user_id: string - habit_id: string - date: string - completed: boolean - created_at: string -} \ No newline at end of file diff --git a/habitTrackerApp/src/types/database.ts b/habitTrackerApp/src/types/database.ts deleted file mode 100644 index e69de29..0000000 diff --git a/habitTrackerApp/tests/e2e/user-flows.test.ts b/habitTrackerApp/tests/e2e/user-flows.test.ts deleted file mode 100644 index 27ae1ee..0000000 --- a/habitTrackerApp/tests/e2e/user-flows.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// End-to-end tests for complete user flows -// Tests: registration → habit creation → daily tracking → streak building → leaderboard ranking \ No newline at end of file diff --git a/habitTrackerApp/tests/integration/auth.test.ts b/habitTrackerApp/tests/integration/auth.test.ts deleted file mode 100644 index c7b0ab0..0000000 --- a/habitTrackerApp/tests/integration/auth.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Integration tests for user authentication flows -// Tests: sign up, sign in, sign out, profile management \ No newline at end of file diff --git a/habitTrackerApp/tests/integration/badges.test.ts b/habitTrackerApp/tests/integration/badges.test.ts deleted file mode 100644 index 033b54f..0000000 --- a/habitTrackerApp/tests/integration/badges.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Integration tests for badge and milestone system -// Tests: earning badges, milestone achievements, badge display \ No newline at end of file diff --git a/habitTrackerApp/tests/integration/habits.test.ts b/habitTrackerApp/tests/integration/habits.test.ts deleted file mode 100644 index c8acf2e..0000000 --- a/habitTrackerApp/tests/integration/habits.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Integration tests for habit CRUD operations -// Tests: create, read, update, delete habits \ No newline at end of file diff --git a/habitTrackerApp/tests/integration/leaderboard.test.ts b/habitTrackerApp/tests/integration/leaderboard.test.ts deleted file mode 100644 index 0a1a5da..0000000 --- a/habitTrackerApp/tests/integration/leaderboard.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Integration tests for leaderboard functionality -// Tests: user ranking, streak comparisons, leaderboard data \ No newline at end of file diff --git a/habitTrackerApp/tests/integration/streaks.test.ts b/habitTrackerApp/tests/integration/streaks.test.ts deleted file mode 100644 index 2571555..0000000 --- a/habitTrackerApp/tests/integration/streaks.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Integration tests for streak tracking functionality -// Tests: marking habits complete, streak calculations, streak resets \ No newline at end of file diff --git a/habitTrackerApp/tests/mocks/index.ts b/habitTrackerApp/tests/mocks/index.ts deleted file mode 100644 index 1cb0308..0000000 --- a/habitTrackerApp/tests/mocks/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Mock implementations for external dependencies -// Includes: Supabase client mocks, notification service mocks, date/time utilities \ No newline at end of file diff --git a/habitTrackerApp/tests/setup/helpers.ts b/habitTrackerApp/tests/setup/helpers.ts deleted file mode 100644 index e9c5f3d..0000000 --- a/habitTrackerApp/tests/setup/helpers.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Test utilities and helper functions -// Includes: test data factories, common assertions, database seeders \ No newline at end of file diff --git a/habitTrackerApp/tests/unit/notifications.test.ts b/habitTrackerApp/tests/unit/notifications.test.ts deleted file mode 100644 index e9a5edd..0000000 --- a/habitTrackerApp/tests/unit/notifications.test.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Unit tests for notification system -// Tests: notification creation, scheduling, user preferences, delivery status \ No newline at end of file