This guide walks you through setting up Supabase for BotBrain. Supabase provides authentication, database storage, and file storage for the web dashboard.
- 1. Create a Supabase Project
- 2. Get Your API Keys
- 3. Create Database Tables
- 4. Set Up Row Level Security (RLS)
- 5. Configure Authentication
- 6. Set Up Storage (Optional)
- 7. Configure Environment Variables
- Go to supabase.com and sign up or log in
- Click New Project
- Fill in the project details:
- Name:
botbrain(or your preferred name) - Database Password: Generate a strong password and save it securely
- Region: Choose the closest region to your location
- Name:
- Click Create new project and wait for setup to complete (~2 minutes)
- In your Supabase dashboard, go to Project Settings (gear icon in sidebar)
- Click API in the left menu
- Copy these values:
- Project URL (
NEXT_PUBLIC_SUPABASE_URL) - anon/public key (
NEXT_PUBLIC_SUPABASE_ANON_KEY)
- Project URL (
Go to the SQL Editor in your Supabase dashboard and run the following SQL to create all required tables:
-- =============================================
-- BotBrain Database Schema
-- =============================================
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =============================================
-- Table: robots
-- Stores robot connection configurations
-- =============================================
CREATE TABLE IF NOT EXISTS public.robots (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
address TEXT NOT NULL,
type TEXT DEFAULT 'go2',
key TEXT,
is_favorite BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index for faster user queries
CREATE INDEX IF NOT EXISTS idx_robots_user_id ON public.robots(user_id);
-- =============================================
-- Table: user_profiles
-- Stores user preferences and settings
-- =============================================
CREATE TABLE IF NOT EXISTS public.user_profiles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL UNIQUE REFERENCES auth.users(id) ON DELETE CASCADE,
name TEXT,
avatar_url TEXT,
theme_color TEXT DEFAULT 'purple',
speed_mode TEXT DEFAULT 'normal',
connection_timeout INTEGER DEFAULT 30000,
audit_logging_enabled BOOLEAN DEFAULT TRUE,
hide_branding BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index for faster user queries
CREATE INDEX IF NOT EXISTS idx_user_profiles_user_id ON public.user_profiles(user_id);
-- =============================================
-- Table: audit_logs
-- Stores activity logs for tracking and debugging
-- =============================================
CREATE TABLE IF NOT EXISTS public.audit_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
robot_id UUID REFERENCES public.robots(id) ON DELETE SET NULL,
robot_name TEXT,
event_type TEXT NOT NULL,
event_action TEXT NOT NULL,
event_details JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes for faster queries
CREATE INDEX IF NOT EXISTS idx_audit_logs_user_id ON public.audit_logs(user_id);
CREATE INDEX IF NOT EXISTS idx_audit_logs_created_at ON public.audit_logs(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_logs_event_type ON public.audit_logs(event_type);
-- =============================================
-- Table: missions
-- Stores navigation mission definitions
-- =============================================
CREATE TABLE IF NOT EXISTS public.missions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
robot_id UUID REFERENCES public.robots(id) ON DELETE SET NULL,
name TEXT NOT NULL,
description TEXT,
map_name TEXT,
is_active BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index for faster user queries
CREATE INDEX IF NOT EXISTS idx_missions_user_id ON public.missions(user_id);
-- =============================================
-- Table: waypoints
-- Stores navigation waypoints for missions
-- =============================================
CREATE TABLE IF NOT EXISTS public.waypoints (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
mission_id UUID NOT NULL REFERENCES public.missions(id) ON DELETE CASCADE,
order_index INTEGER NOT NULL,
x DOUBLE PRECISION NOT NULL,
y DOUBLE PRECISION NOT NULL,
theta DOUBLE PRECISION NOT NULL DEFAULT 0,
is_reached BOOLEAN DEFAULT FALSE,
reached_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index for faster mission queries
CREATE INDEX IF NOT EXISTS idx_waypoints_mission_id ON public.waypoints(mission_id);
-- =============================================
-- Trigger: Auto-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';
-- Apply trigger to all tables with updated_at column
CREATE TRIGGER update_robots_updated_at
BEFORE UPDATE ON public.robots
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_user_profiles_updated_at
BEFORE UPDATE ON public.user_profiles
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_missions_updated_at
BEFORE UPDATE ON public.missions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_waypoints_updated_at
BEFORE UPDATE ON public.waypoints
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- =============================================
-- Function: Auto-create user profile on signup
-- =============================================
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.user_profiles (user_id, name)
VALUES (NEW.id, NEW.raw_user_meta_data->>'name');
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Trigger to create profile when user signs up
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();Row Level Security ensures users can only access their own data. Run this SQL:
-- =============================================
-- Row Level Security (RLS) Policies
-- =============================================
-- Enable RLS on all tables
ALTER TABLE public.robots ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.user_profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.audit_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.missions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.waypoints ENABLE ROW LEVEL SECURITY;
-- =============================================
-- Robots Policies
-- =============================================
CREATE POLICY "Users can view their own robots"
ON public.robots FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own robots"
ON public.robots FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update their own robots"
ON public.robots FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY "Users can delete their own robots"
ON public.robots FOR DELETE
USING (auth.uid() = user_id);
-- =============================================
-- User Profiles Policies
-- =============================================
CREATE POLICY "Users can view their own profile"
ON public.user_profiles FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own profile"
ON public.user_profiles FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update their own profile"
ON public.user_profiles FOR UPDATE
USING (auth.uid() = user_id);
-- =============================================
-- Audit Logs Policies
-- =============================================
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);
-- =============================================
-- Missions Policies
-- =============================================
CREATE POLICY "Users can view their own missions"
ON public.missions FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own missions"
ON public.missions FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update their own missions"
ON public.missions FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY "Users can delete their own missions"
ON public.missions FOR DELETE
USING (auth.uid() = user_id);
-- =============================================
-- Waypoints Policies
-- =============================================
CREATE POLICY "Users can view waypoints of their missions"
ON public.waypoints FOR SELECT
USING (EXISTS (
SELECT 1 FROM public.missions
WHERE missions.id = waypoints.mission_id
AND missions.user_id = auth.uid()
));
CREATE POLICY "Users can insert waypoints to their missions"
ON public.waypoints FOR INSERT
WITH CHECK (EXISTS (
SELECT 1 FROM public.missions
WHERE missions.id = waypoints.mission_id
AND missions.user_id = auth.uid()
));
CREATE POLICY "Users can update waypoints of their missions"
ON public.waypoints FOR UPDATE
USING (EXISTS (
SELECT 1 FROM public.missions
WHERE missions.id = waypoints.mission_id
AND missions.user_id = auth.uid()
));
CREATE POLICY "Users can delete waypoints of their missions"
ON public.waypoints FOR DELETE
USING (EXISTS (
SELECT 1 FROM public.missions
WHERE missions.id = waypoints.mission_id
AND missions.user_id = auth.uid()
));- In your Supabase dashboard, go to Authentication > Providers
- Ensure Email is enabled (it should be by default)
- Optionally configure:
- Confirm email: Disable for easier testing, enable for production
- Secure email change: Recommended to enable
Go to Authentication > Email Templates to customize:
- Confirmation email
- Password reset email
- Magic link email
If you want to support user avatar uploads:
- Go to Storage in your Supabase dashboard
- Click New bucket
- Create a bucket named
avatars - Set the bucket to Public (for avatar images)
- Run this SQL to set up storage policies:
-- =============================================
-- Storage Policies for Avatars
-- =============================================
-- Allow users to upload their own avatars
CREATE POLICY "Users can upload avatars"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
-- Allow users to update their own avatars
CREATE POLICY "Users can update their avatars"
ON storage.objects FOR UPDATE
USING (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
-- Allow users to delete their own avatars
CREATE POLICY "Users can delete their avatars"
ON storage.objects FOR DELETE
USING (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
-- Allow public read access to avatars
CREATE POLICY "Public can view avatars"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');-
Navigate to your BotBrain frontend directory:
cd frontend -
Copy the example environment file:
cp .env.example .env.local
-
Edit
.env.localand add your Supabase credentials:NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
-
Start the development server:
npm install npm run dev
-
Open http://localhost:3000 and create your first account!
| Table | Description |
|---|---|
robots |
Robot connection configurations (address, name, type) |
user_profiles |
User preferences (theme, avatar, settings) |
audit_logs |
Activity logging for debugging and compliance |
missions |
Navigation mission definitions |
waypoints |
Navigation waypoints within missions |
- Ensure RLS policies are created correctly
- Check that the user is authenticated before accessing data
- Verify the
handle_new_usertrigger is created - Check the Supabase logs for any trigger errors
- Ensure the
avatarsbucket exists and is public - Verify storage policies are in place
- Return to the main README for installation instructions
- See the BotBrain Workspace Guide for ROS2 setup