Skip to main content
Hive uses Supabase for authentication, database storage, and file uploads. This guide walks through setting up a new Supabase project with the required schema and security policies.

Create a Supabase Project

  1. Go to supabase.com and sign in
  2. Click New Project
  3. Enter your project details:
    • Name: Hive (or your preferred name)
    • Database Password: Generate a secure password
    • Region: Choose the closest region to your users
  4. Click Create new project
Save your database password - you’ll need it for direct database access if required.

Database Schema

usuarios Table

The usuarios table stores user profiles and links to Supabase Auth users. Create it with the following schema:
CREATE TABLE usuarios (
  id SERIAL PRIMARY KEY,
  auth_user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
  nombre_usuario TEXT UNIQUE NOT NULL,
  nombre_completo TEXT,
  cedula TEXT UNIQUE,
  puesto TEXT,
  rol TEXT DEFAULT 'usuario',
  correo TEXT UNIQUE NOT NULL,
  foto_url TEXT,
  ultimo_acceso TIMESTAMPTZ,
  presence_state TEXT DEFAULT 'offline',
  last_manual_logout_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Index for faster lookups
CREATE INDEX idx_usuarios_auth_user_id ON usuarios(auth_user_id);
CREATE INDEX idx_usuarios_correo ON usuarios(correo);
CREATE INDEX idx_usuarios_nombre_usuario ON usuarios(nombre_usuario);
id
integer
required
Primary key for the user record
auth_user_id
uuid
Foreign key linking to Supabase Auth auth.users.id. This allows querying user profiles by authentication session.
nombre_usuario
string
required
Username for login. Must be unique across all users.
nombre_completo
string
Full name of the user (e.g., “Juan Pérez”)
cedula
string
National ID or employee ID number. Must be unique if provided.
puesto
string
Job title or position (e.g., “Desarrollador Senior”, “Gerente de Proyectos”)
rol
string
default:"usuario"
User role for access control. Valid values:
  • administrador or admin - Full system access
  • usuario - Standard user access
The /api/auth-sync function checks this field to authorize admin operations.
correo
string
required
Email address. Must match the email in Supabase Auth for authentication.
foto_url
string
Profile picture URL. Can reference Supabase Storage or external URLs.
presence_state
string
default:"offline"
Real-time presence status updated by /api/presence-ping. Values: online, offline
ultimo_acceso
timestamp
Last access timestamp, updated on login and presence pings

Row Level Security (RLS)

Enable RLS on the usuarios table to protect user data:
-- Enable RLS
ALTER TABLE usuarios ENABLE ROW LEVEL SECURITY;

-- Policy: Users can read all profiles (for team member lists)
CREATE POLICY "Users can view all profiles"
  ON usuarios
  FOR SELECT
  USING (true);

-- Policy: Users can update their own profile
CREATE POLICY "Users can update own profile"
  ON usuarios
  FOR UPDATE
  USING (auth.uid() = auth_user_id)
  WITH CHECK (auth.uid() = auth_user_id);

-- Policy: Service role can do anything (for serverless functions)
CREATE POLICY "Service role full access"
  ON usuarios
  FOR ALL
  USING (auth.role() = 'service_role')
  WITH CHECK (auth.role() = 'service_role');
RLS policies are critical for security. Never disable RLS on production tables without alternative security measures.

Policy Breakdown

Allows any authenticated user to read all user profiles. This is necessary for:
  • Displaying team member lists
  • Showing task assignees
  • User search and selection in the UI
If you need stricter privacy, modify this policy to filter by organization or team.
Users can only modify their own profile record (matched by auth_user_id). This prevents users from:
  • Changing other users’ roles
  • Modifying other users’ email addresses
  • Impersonating other users
The service role key bypasses RLS by default, but this policy makes it explicit. Serverless functions use the service role to:
  • Create new users during signup
  • Sync Auth changes to the usuarios table
  • Update presence status for all users

Authentication Setup

Enable Email Authentication

  1. Go to Authentication → Providers in your Supabase dashboard
  2. Enable Email provider
  3. Configure settings:
    • Enable email confirmations: Optional (recommended for production)
    • Enable email change confirmations: Recommended
    • Secure email change: Recommended

Email Templates

Customize email templates under Authentication → Email Templates:
  • Confirm signup: Sent when new users register
  • Magic Link: For passwordless login (if enabled)
  • Change Email Address: Confirmation for email changes
  • Reset Password: Password recovery emails
Customize the email templates with your brand colors and logo for a professional user experience.

Storage Setup

Profile Pictures Bucket

Create a storage bucket for user profile images:
  1. Go to Storage in your Supabase dashboard
  2. Click Create bucket
  3. Configure:
    • Name: profile-pics
    • Public: ✅ Enabled (for public profile image access)
    • File size limit: 2 MB (recommended)
    • Allowed MIME types: image/jpeg, image/png, image/webp, image/gif

Storage Policies

-- Allow authenticated users to upload their own profile picture
CREATE POLICY "Users can upload own profile picture"
  ON storage.objects
  FOR INSERT
  WITH CHECK (
    bucket_id = 'profile-pics' AND
    auth.role() = 'authenticated'
  );

-- Allow public read access to profile pictures
CREATE POLICY "Public profile pictures"
  ON storage.objects
  FOR SELECT
  USING (bucket_id = 'profile-pics');

-- Allow users to update/delete their own pictures
CREATE POLICY "Users can update own picture"
  ON storage.objects
  FOR UPDATE
  USING (
    bucket_id = 'profile-pics' AND
    auth.role() = 'authenticated'
  );

CREATE POLICY "Users can delete own picture"
  ON storage.objects
  FOR DELETE
  USING (
    bucket_id = 'profile-pics' AND
    auth.role() = 'authenticated'
  );
The application uses uploadProfileImage.js to handle file uploads to the profile-pics bucket. After upload, it updates usuarios.foto_url with the file path.

Additional Tables

Hive also requires these tables for full functionality:

proyectos

CREATE TABLE proyectos (
  id SERIAL PRIMARY KEY,
  nombre TEXT NOT NULL,
  descripcion TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

tareas

CREATE TABLE tareas (
  id SERIAL PRIMARY KEY,
  titulo TEXT NOT NULL,
  descripcion TEXT,
  proyecto_id INTEGER REFERENCES proyectos(id) ON DELETE CASCADE,
  proyecto TEXT,
  progreso INTEGER DEFAULT 0,
  fecha_vencimiento DATE,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

tarea_usuarios (Task Assignments)

CREATE TABLE tarea_usuarios (
  tarea_id INTEGER REFERENCES tareas(id) ON DELETE CASCADE,
  usuario_id INTEGER REFERENCES usuarios(id) ON DELETE CASCADE,
  assigned_at TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (tarea_id, usuario_id)
);

CREATE INDEX idx_tarea_usuarios_tarea ON tarea_usuarios(tarea_id);
CREATE INDEX idx_tarea_usuarios_usuario ON tarea_usuarios(usuario_id);

etiquetas (Tags)

CREATE TABLE etiquetas (
  id SERIAL PRIMARY KEY,
  nombre TEXT UNIQUE NOT NULL,
  color TEXT DEFAULT '#3B82F6',
  created_at TIMESTAMPTZ DEFAULT NOW()
);
Tags allow you to categorize and label tasks for better organization. Each tag has a name and color for visual identification.

tarea_etiquetas (Task Tags Junction)

CREATE TABLE tarea_etiquetas (
  tarea_id INTEGER REFERENCES tareas(id) ON DELETE CASCADE,
  etiqueta_id INTEGER REFERENCES etiquetas(id) ON DELETE CASCADE,
  PRIMARY KEY (tarea_id, etiqueta_id)
);

CREATE INDEX idx_tarea_etiquetas_tarea ON tarea_etiquetas(tarea_id);
CREATE INDEX idx_tarea_etiquetas_etiqueta ON tarea_etiquetas(etiqueta_id);
This junction table creates a many-to-many relationship between tasks and tags, allowing each task to have multiple tags.

usuarios_borrados (Deleted Users Archive)

CREATE TABLE usuarios_borrados (
  id SERIAL PRIMARY KEY,
  original_id INTEGER,
  auth_user_id UUID,
  nombre_usuario TEXT,
  nombre_completo TEXT,
  correo TEXT,
  deleted_at TIMESTAMPTZ DEFAULT NOW(),
  deleted_by INTEGER REFERENCES usuarios(id)
);
This table archives user data when users are deleted from the system, maintaining audit history and referential integrity.

Realtime Subscriptions

Enable realtime for live updates:
-- Enable realtime for all tables
ALTER PUBLICATION supabase_realtime ADD TABLE usuarios;
ALTER PUBLICATION supabase_realtime ADD TABLE tareas;
ALTER PUBLICATION supabase_realtime ADD TABLE tarea_usuarios;
ALTER PUBLICATION supabase_realtime ADD TABLE proyectos;
ALTER PUBLICATION supabase_realtime ADD TABLE etiquetas;
ALTER PUBLICATION supabase_realtime ADD TABLE tarea_etiquetas;
The application uses Supabase Realtime in app.realtime.js to subscribe to table changes and update the UI automatically.

Testing the Connection

After setup, test your Supabase connection:
// Open browser console on your deployed app
console.log(window.__supabaseClient);

// Test query
const { data, error } = await window.supabase
  .from('usuarios')
  .select('count', { count: 'exact', head: true });

if (error) {
  console.error('Connection failed:', error);
} else {
  console.log('✅ Connected to Supabase');
}

Troubleshooting

The usuarios table hasn’t been created yet.Solution: Run the SQL schema creation commands in the Supabase SQL Editor.
RLS is enabled but no policy allows the operation.Solution:
  • Check that RLS policies are created
  • Verify the user is authenticated (for policies requiring auth.uid())
  • Use the service role key for admin operations
Storage bucket or policies not configured.Solution:
  • Verify profile-pics bucket exists and is public
  • Check storage policies allow authenticated uploads
  • Ensure file size is under the bucket limit
SMTP not configured or confirmation emails disabled.Solution:
  • For development, disable email confirmations in Auth settings
  • For production, configure custom SMTP in Auth → Settings

Next Steps

Environment Variables

Configure environment variables for your deployment

Deployment

Deploy Hive to Vercel or other platforms

Build docs developers (and LLMs) love