Skip to main content

Overview

Trazea uses Supabase as its backend platform, providing:
  • PostgreSQL database with 17 tables for inventory, solicitudes, guarantees, and more
  • Authentication with email/password and Google OAuth
  • Row Level Security (RLS) for multi-tenant access control
  • Storage for warranty photos and spare part images
  • Real-time subscriptions for notifications

Prerequisites

  • Supabase account (free tier available)
  • New Supabase project created
  • Project URL and anon key from project settings

Project Setup

1. Create Supabase Project

1

Create New Project

Go to Supabase Dashboard and click New Project
2

Configure Project

  • Name: Trazea (or your preferred name)
  • Database Password: Generate a strong password (save this securely)
  • Region: Choose closest to your users
  • Pricing Plan: Free tier is sufficient for development
3

Get API Credentials

Once created, navigate to Settings > API and copy:
  • Project URL: https://xxxxxxxxxxx.supabase.co
  • anon/public key: Your client-side API key

2. Configure Environment Variables

Add these credentials to your .env file:
.env
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key-here
See Environment Setup for full details.

Authentication Configuration

Trazea supports two authentication methods:

Email/Password Authentication

Enabled by default in Supabase. Configuration:
1

Navigate to Auth Settings

Authentication > Providers > Email
2

Enable Email Provider

Ensure Email is enabled (on by default)
3

Configure Email Settings

  • Confirm email: Recommended for production
  • Secure email change: Enabled (requires confirmation)
  • Secure password change: Enabled
4

Customize Email Templates (Optional)

Go to Authentication > Email Templates to customize:
  • Confirmation email
  • Password reset email
  • Magic link email

Google OAuth

Trazea supports Google OAuth for single sign-on:
1

Create Google OAuth App

  1. Go to Google Cloud Console
  2. Create new project or select existing
  3. Navigate to APIs & Services > Credentials
  4. Click Create Credentials > OAuth 2.0 Client ID
  5. Configure OAuth consent screen if prompted
2

Configure OAuth Client

  • Application type: Web application
  • Name: Trazea
  • Authorized redirect URIs: https://your-project.supabase.co/auth/v1/callback
Copy the Client ID and Client Secret
3

Enable in Supabase

  1. Go to Authentication > Providers > Google
  2. Enable the Google provider
  3. Paste Client ID and Client Secret
  4. Click Save
Users who sign in with Google OAuth will have their email automatically verified.

User Registration Flow

Trazea implements an approval-based registration system:
  1. User registers via email/password or Google OAuth
  2. User profile created in usuarios table with aprobado = false
  3. Admin receives notification via admin_notifications table
  4. Admin approves/rejects user in the admin panel
  5. User gains access once approved

User Profile Schema

The usuarios table stores user profiles with these key fields:
CREATE TABLE usuarios (
  id UUID PRIMARY KEY REFERENCES auth.users(id),
  email TEXT UNIQUE NOT NULL,
  nombre_completo TEXT,
  rol_id UUID REFERENCES roles(id),
  aprobado BOOLEAN DEFAULT false,
  aprobado_por UUID REFERENCES usuarios(id),
  fecha_aprobacion TIMESTAMP,
  razon_rechazo TEXT,
  created_at TIMESTAMP DEFAULT NOW()
);
aprobado
boolean
default:"false"
User approval status. Must be set to true by an admin before user can access the system.
aprobado_por
uuid
Admin user who approved/rejected the registration.
razon_rechazo
text
Reason for rejection (if applicable).

Row Level Security (RLS)

RLS is critical for Trazea’s multi-tenant security model. It ensures users can only access data for their assigned locations.
Never deploy to production without RLS enabled on all tables. This would allow any user to access all data.

Enable RLS on All Tables

For each table in your database:
ALTER TABLE usuarios ENABLE ROW LEVEL SECURITY;
ALTER TABLE localizacion ENABLE ROW LEVEL SECURITY;
ALTER TABLE inventario ENABLE ROW LEVEL SECURITY;
ALTER TABLE repuestos ENABLE ROW LEVEL SECURITY;
ALTER TABLE solicitudes ENABLE ROW LEVEL SECURITY;
ALTER TABLE garantias ENABLE ROW LEVEL SECURITY;
-- ... repeat for all 17 tables

Example RLS Policies

Here are example policies for key tables:
-- Users can view their own profile
CREATE POLICY "Users can view own profile"
ON usuarios FOR SELECT
USING (auth.uid() = id);

-- Admins can view all profiles
CREATE POLICY "Admins can view all profiles"
ON usuarios FOR SELECT
USING (
  EXISTS (
    SELECT 1 FROM usuarios u
    JOIN roles r ON u.rol_id = r.id
    WHERE u.id = auth.uid()
    AND r.permisos->>'admin' = 'true'
  )
);

-- Users can update their own profile
CREATE POLICY "Users can update own profile"
ON usuarios FOR UPDATE
USING (auth.uid() = id);

RLS Policy Patterns

Common patterns used across Trazea:
Most tables filter by usuarios_localizacion to ensure users only see data for their assigned locations:
localizacion_id IN (
  SELECT localizacion_id
  FROM usuarios_localizacion
  WHERE usuario_id = auth.uid()
)
Actions check role permissions stored in the permisos JSON field:
EXISTS (
  SELECT 1 FROM usuarios u
  JOIN roles r ON u.rol_id = r.id
  WHERE u.id = auth.uid()
  AND (r.permisos->>'action_name')::boolean = true
)
Some tables allow users to access their own records:
usuario_id = auth.uid()
-- or
created_by = auth.uid()
Admin users often bypass restrictions:
EXISTS (
  SELECT 1 FROM usuarios u
  JOIN roles r ON u.rol_id = r.id
  WHERE u.id = auth.uid()
  AND r.permisos->>'admin' = 'true'
)

Database Schema

Trazea uses 17 primary tables organized into these domains:

Core Tables

TablePurpose
usuariosUser profiles, approval status, roles
rolesRole definitions with JSON permissions
usuarios_localizacionUser-to-location assignments (many-to-many)
localizacionPhysical locations/warehouses
admin_notificationsAdmin alert subscriptions

Inventory Domain

TablePurpose
repuestosSpare parts catalog (reference, name, type, brand)
inventarioStock quantities by location
logs_inventarioAudit trail for all inventory changes
movimientos_tecnicosTechnician spare part movements (load/unload)

Solicitudes (Requests) Domain

TablePurpose
carrito_solicitudesShopping cart for multi-item requests
solicitudesTransfer requests between locations
detalles_solicitudesLine items with quantities requested/dispatched/received
trazabilidad_solicitudesComplete audit trail of status changes

Guarantees Domain

TablePurpose
garantiasWarranty claims with photos, km, failure reasons

Audit/Counting Domain

TablePurpose
registro_conteoPhysical inventory count sessions
detalles_conteoCount details (system qty vs physical qty)

Orders Domain

TablePurpose
scooter_typesCatalog of scooter models
order_followCustomer order tracking (levels 1-3)
For the complete schema with all columns and relationships, see the Database Model.

Storage Configuration

Trazea uses Supabase Storage for images:

Create Storage Buckets

1

Navigate to Storage

Storage > Buckets in Supabase dashboard
2

Create Buckets

Create these buckets:
  • repuestos-images: Spare part photos
  • garantias-images: Warranty claim evidence photos
  • avatares: User profile pictures (optional)
3

Configure Bucket Policies

For garantias-images and repuestos-images:
-- Allow authenticated users to upload
CREATE POLICY "Authenticated users can upload"
ON storage.objects FOR INSERT
WITH CHECK (
  bucket_id = 'garantias-images'
  AND auth.role() = 'authenticated'
);

-- Allow public read access
CREATE POLICY "Public read access"
ON storage.objects FOR SELECT
USING (bucket_id = 'garantias-images');

CORS Configuration

Configure CORS to allow requests from your frontend domain:
1

Navigate to API Settings

Settings > API > CORS
2

Add Allowed Origins

Add your frontend domains:
http://localhost:5173
https://trazea.vercel.app
https://your-custom-domain.com
3

Save Changes

Click Save to apply CORS configuration
Do not use * (wildcard) for CORS in production. Always specify exact domains.

Real-Time Subscriptions

Trazea uses real-time subscriptions for notifications. Enable for these tables:
-- Enable realtime for notifications table
ALTER PUBLICATION supabase_realtime ADD TABLE notificaciones;

-- Enable for other tables as needed
ALTER PUBLICATION supabase_realtime ADD TABLE solicitudes;
ALTER PUBLICATION supabase_realtime ADD TABLE trazabilidad_solicitudes;
Subscriptions in code (example):
import { supabase } from '@/shared/api/supabase';

supabase
  .channel('notifications')
  .on(
    'postgres_changes',
    {
      event: 'INSERT',
      schema: 'public',
      table: 'notificaciones',
      filter: `usuario_id=eq.${userId}`,
    },
    (payload) => {
      // Handle new notification
      console.log('New notification:', payload.new);
    }
  )
  .subscribe();

Production Checklist

1

Authentication

✓ Email confirmation enabled for production✓ Google OAuth configured with correct redirect URIs✓ Email templates customized
2

Row Level Security

✓ RLS enabled on ALL tables✓ Policies tested for each user role✓ Admin users cannot bypass RLS without explicit policy
3

Storage

✓ Storage buckets created✓ Bucket policies configured✓ File size limits set (10 MB recommended)
4

CORS & Security

✓ CORS configured with exact domains (no wildcards)✓ Database password strong and stored securely✓ API keys rotated if exposed
5

Monitoring

✓ Database logs enabled✓ Alert rules configured for:
  • High CPU usage
  • Connection pool exhaustion
  • Storage quota warnings

Migration and Backups

Database Migrations

For schema changes, use Supabase CLI:
# Install Supabase CLI
npm install -g supabase

# Link to your project
supabase link --project-ref your-project-ref

# Create new migration
supabase migration new add_new_table

# Edit the migration file in supabase/migrations/
# Then push to database
supabase db push

Automated Backups

Supabase Pro and Team plans include:
  • Daily automated backups (retained for 7 days)
  • Point-in-time recovery (PITR) for accidental data loss
For Free tier:
  • Export database regularly: Database > Backups > Export
  • Store exports securely offsite

Troubleshooting

  1. Verify environment variables are correct
  2. Check that Supabase URL includes https:// protocol
  3. Ensure email provider is enabled in Supabase Auth settings
  4. For Google OAuth, verify redirect URI matches exactly
If users see “permission denied” errors:
  1. Check policy syntax in Database > Policies
  2. Test query in SQL Editor as that user: SET LOCAL ROLE authenticated; SET LOCAL request.jwt.claim.sub = 'user-uuid';
  3. Verify usuarios_localizacion assignments are correct
  4. Ensure user has aprobado = true in usuarios table
If seeing “CORS policy blocked” errors:
  1. Add your frontend domain to Settings > API > CORS
  2. Ensure protocol matches (http vs https)
  3. Remove trailing slashes from origins
  4. Wait ~1 minute for CORS changes to propagate
  1. Check bucket exists and is public/private as intended
  2. Verify storage policies allow the operation
  3. Ensure file size is under limit (default 50 MB)
  4. Check file type is allowed (configure in bucket settings)

Next Steps

Environment Setup

Configure environment variables for local and production

Deploy to Vercel

Deploy your Trazea instance to Vercel

Build docs developers (and LLMs) love