Supabase Database Design Patterns for Admin Dashboards
Building a robust admin dashboard requires careful database design. In this comprehensive guide, we'll explore proven database design patterns specifically tailored for Supabase-powered admin dashboards.
1. Core Table Design Patterns
User Management Tables
Start with a solid foundation for user management. Here's a recommended table structure:
-- Users table (extends Supabase auth.users)
CREATE TABLE public.profiles (
id UUID REFERENCES auth.users(id) PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
full_name TEXT,
avatar_url TEXT,
role TEXT DEFAULT 'user' CHECK (role IN ('admin', 'moderator', 'user')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- User roles and permissions
CREATE TABLE public.user_roles (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE,
role_name TEXT NOT NULL,
permissions JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);Audit Trail Pattern
Implement comprehensive audit trails for admin actions:
CREATE TABLE public.audit_logs ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES public.profiles(id), action TEXT NOT NULL, table_name TEXT NOT NULL, record_id UUID, old_values JSONB, new_values JSONB, ip_address INET, user_agent TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Index for performance CREATE INDEX idx_audit_logs_user_id ON public.audit_logs(user_id); CREATE INDEX idx_audit_logs_created_at ON public.audit_logs(created_at DESC); CREATE INDEX idx_audit_logs_table_name ON public.audit_logs(table_name);
2. Row Level Security (RLS) Patterns
Implement proper RLS policies for admin dashboard security:
-- Enable RLS on all tables
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.audit_logs ENABLE ROW LEVEL SECURITY;
-- Admin can see all profiles
CREATE POLICY "Admins can view all profiles" ON public.profiles
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.profiles
WHERE id = auth.uid() AND role = 'admin'
)
);
-- Users can only see their own profile
CREATE POLICY "Users can view own profile" ON public.profiles
FOR SELECT USING (auth.uid() = id);
-- Only admins can view audit logs
CREATE POLICY "Admins can view audit logs" ON public.audit_logs
FOR SELECT USING (
EXISTS (
SELECT 1 FROM public.profiles
WHERE id = auth.uid() AND role = 'admin'
)
);3. Performance Optimization Patterns
Strategic Indexing
Create indexes that match your admin dashboard queries:
-- Composite indexes for common queries CREATE INDEX idx_profiles_role_created ON public.profiles(role, created_at DESC); CREATE INDEX idx_audit_logs_user_action ON public.audit_logs(user_id, action, created_at DESC); -- Partial indexes for specific use cases CREATE INDEX idx_active_users ON public.profiles(created_at) WHERE role != 'inactive'; -- GIN indexes for JSONB columns CREATE INDEX idx_user_roles_permissions ON public.user_roles USING GIN (permissions);
Materialized Views for Analytics
Use materialized views for complex admin analytics:
-- Daily user activity summary CREATE MATERIALIZED VIEW public.daily_user_stats AS SELECT DATE(created_at) as date, COUNT(*) as new_users, COUNT(CASE WHEN role = 'admin' THEN 1 END) as new_admins, COUNT(CASE WHEN role = 'moderator' THEN 1 END) as new_moderators FROM public.profiles GROUP BY DATE(created_at) ORDER BY date DESC; -- Refresh function CREATE OR REPLACE FUNCTION refresh_daily_stats() RETURNS void AS $$ BEGIN REFRESH MATERIALIZED VIEW public.daily_user_stats; END; $$ LANGUAGE plpgsql;
4. Data Relationships and Foreign Keys
Design proper relationships between admin dashboard entities:
-- Organizations and departments
CREATE TABLE public.organizations (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
settings JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE public.departments (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
organization_id UUID REFERENCES public.organizations(id) ON DELETE CASCADE,
name TEXT NOT NULL,
manager_id UUID REFERENCES public.profiles(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- User-organization relationships
CREATE TABLE public.user_organizations (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE,
organization_id UUID REFERENCES public.organizations(id) ON DELETE CASCADE,
role TEXT DEFAULT 'member',
joined_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id, organization_id)
);5. Real-time Subscriptions for Admin Dashboards
Set up real-time subscriptions for live admin monitoring:
// Real-time user activity monitoring
const { data, error } = await supabase
.channel('user_activity')
.on('postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'audit_logs'
},
(payload) => {
console.log('New admin action:', payload.new);
updateAdminDashboard(payload.new);
}
)
.subscribe();
// Real-time user count updates
const { data: userCount } = await supabase
.channel('user_count')
.on('postgres_changes',
{
event: '*',
schema: 'public',
table: 'profiles'
},
() => {
fetchUserCount(); // Refresh user count
}
)
.subscribe();6. Database Functions for Complex Operations
Create PostgreSQL functions for complex admin operations:
-- Bulk user role update function
CREATE OR REPLACE FUNCTION update_user_roles(
user_ids UUID[],
new_role TEXT,
admin_id UUID
)
RETURNS JSONB AS $$
DECLARE
result JSONB;
updated_count INTEGER;
BEGIN
-- Update roles
UPDATE public.profiles
SET role = new_role, updated_at = NOW()
WHERE id = ANY(user_ids);
GET DIAGNOSTICS updated_count = ROW_COUNT;
-- Log the action
INSERT INTO public.audit_logs (user_id, action, table_name, new_values)
VALUES (admin_id, 'bulk_role_update', 'profiles',
jsonb_build_object('role', new_role, 'user_count', updated_count));
result := jsonb_build_object(
'success', true,
'updated_count', updated_count,
'new_role', new_role
);
RETURN result;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;7. Data Validation and Constraints
Implement robust data validation at the database level:
-- Email validation function
CREATE OR REPLACE FUNCTION is_valid_email(email TEXT)
RETURNS BOOLEAN AS $$
BEGIN
RETURN email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$';
END;
$$ LANGUAGE plpgsql;
-- Add email validation constraint
ALTER TABLE public.profiles
ADD CONSTRAINT valid_email CHECK (is_valid_email(email));
-- Role validation
ALTER TABLE public.profiles
ADD CONSTRAINT valid_role CHECK (role IN ('admin', 'moderator', 'user', 'inactive'));
-- JSONB validation for settings
ALTER TABLE public.organizations
ADD CONSTRAINT valid_settings CHECK (
jsonb_typeof(settings) = 'object'
);8. Backup and Recovery Strategies
Implement proper backup strategies for admin data:
-- Create backup tables for critical data CREATE TABLE public.profiles_backup (LIKE public.profiles INCLUDING ALL); -- Backup function CREATE OR REPLACE FUNCTION backup_profiles() RETURNS void AS $$ BEGIN TRUNCATE public.profiles_backup; INSERT INTO public.profiles_backup SELECT * FROM public.profiles; END; $$ LANGUAGE plpgsql; -- Automated backup trigger CREATE OR REPLACE FUNCTION trigger_backup() RETURNS TRIGGER AS $$ BEGIN PERFORM backup_profiles(); RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER backup_trigger AFTER INSERT OR UPDATE OR DELETE ON public.profiles FOR EACH STATEMENT EXECUTE FUNCTION trigger_backup();
Conclusion
Proper database design is crucial for admin dashboard success. By implementing these patterns, you'll create a robust, scalable, and secure foundation for your Supabase-powered admin dashboard.
Remember to always test your RLS policies, monitor query performance, and maintain proper indexes as your application grows. These patterns will serve as a solid foundation for building enterprise-grade admin dashboards.
Key Takeaways
- • Design tables with proper relationships and constraints
- • Implement comprehensive RLS policies for security
- • Use strategic indexing for optimal performance
- • Create materialized views for complex analytics
- • Set up real-time subscriptions for live monitoring
- • Implement proper audit trails and backup strategies