This guide will help you set up user-specific data isolation so that each user only sees their own portfolio and watchlist data.
- Supabase project with authentication enabled
- Access to Supabase SQL Editor
- Backend server running
- Go to your Supabase Dashboard
- Navigate to SQL Editor
- Copy and paste the following SQL script:
-- Migration to add user_id columns for user-specific data isolation
-- Run this in your Supabase SQL Editor
-- Add user_id column to stocks table
ALTER TABLE stocks
ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE;
-- Add user_id column to watchlists table
ALTER TABLE watchlists
ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE;
-- Create indexes for better performance
CREATE INDEX IF NOT EXISTS idx_stocks_user_id ON stocks(user_id);
CREATE INDEX IF NOT EXISTS idx_watchlists_user_id ON watchlists(user_id);
-- Add RLS (Row Level Security) policies
-- Enable RLS on both tables
ALTER TABLE stocks ENABLE ROW LEVEL SECURITY;
ALTER TABLE watchlists ENABLE ROW LEVEL SECURITY;
-- Create policy for stocks table - users can only see their own stocks
CREATE POLICY "Users can view own stocks" ON stocks
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own stocks" ON stocks
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own stocks" ON stocks
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own stocks" ON stocks
FOR DELETE USING (auth.uid() = user_id);
-- Create policy for watchlists table - users can only see their own watchlist items
CREATE POLICY "Users can view own watchlist" ON watchlists
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own watchlist items" ON watchlists
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own watchlist items" ON watchlists
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own watchlist items" ON watchlists
FOR DELETE USING (auth.uid() = user_id);- Click Run to execute the migration
Run this query to verify the changes:
-- Check if user_id columns were added
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'stocks' AND column_name = 'user_id';
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'watchlists' AND column_name = 'user_id';
-- Check if RLS is enabled
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE tablename IN ('stocks', 'watchlists');Make sure your backend has the required dependencies:
cd backend
npm install @supabase/supabase-jsEnsure your backend .env file has:
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_keyRestart your backend server to apply the changes:
npm run devThe frontend has been updated to use a centralized API service with authentication. Check that src/services/api.js exists and includes:
- Request interceptor for adding auth tokens
- Response interceptor for handling auth errors
- Automatic token refresh
- Create two different user accounts
- Log in with the first user and add some stocks
- Log out and log in with the second user
- Verify that the second user sees an empty portfolio/watchlist
- Go to your application homepage
- Create a new account with email/password
- Verify you can log in successfully
- User A: Add stocks to portfolio and watchlist
- User B: Create a different account and verify empty data
- User A: Log back in and verify data is still there
Test these endpoints with authentication:
# Get portfolio stocks (requires auth)
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:5000/api/stocks
# Get watchlist (requires auth)
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:5000/api/watchlist
# Add stock to portfolio (requires auth)
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Apple Inc","ticker":"AAPL","shares":10,"buy_price":150}' \
http://localhost:5000/api/stocksIssue: "No token provided" error Solution: Check that the frontend is properly sending auth headers
Issue: "Access denied" error Solution: Verify RLS policies are correctly set up
Issue: Users seeing each other's data
Solution: Check that user_id is being set correctly in database operations
-- Check current user's stocks
SELECT * FROM stocks WHERE user_id = auth.uid();
-- Check all stocks (admin only)
SELECT * FROM stocks;
-- Check RLS policies
SELECT schemaname, tablename, policyname, permissive, roles, cmd, qual
FROM pg_policies
WHERE tablename IN ('stocks', 'watchlists');- Database migration completed successfully
- RLS policies are active
- Backend authentication middleware is working
- Frontend API service includes auth tokens
- User registration and login works
- Data isolation between users is working
- All CRUD operations work with authentication
- Error handling for unauthorized access works
✅ Complete Data Isolation: Each user only sees their own data ✅ Security: Row Level Security prevents unauthorized access ✅ Scalability: System can handle multiple users efficiently ✅ Compliance: Meets data privacy requirements ✅ User Experience: Clean, personalized interface for each user
If you encounter any issues:
- Check the browser console for frontend errors
- Check the backend logs for API errors
- Verify Supabase authentication is working
- Test with a fresh user account
🎯 Result: Each user will now have their own isolated portfolio and watchlist data!