BudgetView uses PostgreSQL via Supabase as its primary database. The schema is designed around four core tables that handle user wallets, transactions, categories, and budgets. All tables enforce Row Level Security (RLS) to ensure users can only access their own data.
Stores user wallet accounts (e.g., Cash, Bank, Savings).
CREATE TABLE billeteras ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), nombre VARCHAR(13) NOT NULL, usuario_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now());CREATE INDEX idx_billeteras_usuario ON billeteras(usuario_id);
Records all income and expense transactions linked to wallets and categories.
CREATE TABLE transacciones ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), monto NUMERIC(12, 2) NOT NULL CHECK (monto > 0), tipo VARCHAR(10) NOT NULL CHECK (tipo IN ('ingreso', 'gasto')), descripcion TEXT, fecha_transaccion TIMESTAMPTZ NOT NULL DEFAULT now(), categoria_id UUID REFERENCES categorias(id) ON DELETE SET NULL, billetera_id UUID NOT NULL REFERENCES billeteras(id) ON DELETE CASCADE, usuario_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now());CREATE INDEX idx_transacciones_usuario ON transacciones(usuario_id);CREATE INDEX idx_transacciones_billetera ON transacciones(billetera_id);CREATE INDEX idx_transacciones_categoria ON transacciones(categoria_id);CREATE INDEX idx_transacciones_fecha ON transacciones(fecha_transaccion DESC);
CREATE TABLE categorias ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), nombre VARCHAR(13) NOT NULL, tipo VARCHAR(10) NOT NULL CHECK (tipo IN ('ingreso', 'gasto')), usuario_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now());CREATE INDEX idx_categorias_usuario ON categorias(usuario_id);CREATE INDEX idx_categorias_tipo ON categorias(tipo);
Tracks spending limits per category and time period.
CREATE TABLE presupuestos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), monto NUMERIC(12, 2) NOT NULL CHECK (monto > 0), periodo VARCHAR(7) NOT NULL, -- Format: YYYY-MM categoria_id UUID NOT NULL REFERENCES categorias(id) ON DELETE CASCADE, usuario_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), UNIQUE(categoria_id, periodo, usuario_id));CREATE INDEX idx_presupuestos_usuario ON presupuestos(usuario_id);CREATE INDEX idx_presupuestos_categoria ON presupuestos(categoria_id);CREATE INDEX idx_presupuestos_periodo ON presupuestos(periodo);
Columns:
Column
Type
Constraints
Description
id
UUID
PRIMARY KEY
Budget identifier
monto
NUMERIC(12,2)
NOT NULL, > 0
Budget limit in USD
periodo
VARCHAR(7)
NOT NULL
ISO period (e.g., “2024-01”)
categoria_id
UUID
FOREIGN KEY
Category being budgeted
usuario_id
UUID
FOREIGN KEY
Owner of the budget
Unique constraint:The UNIQUE(categoria_id, periodo, usuario_id) constraint ensures users can only have one budget per category per month.
Each table has policies that enforce user ownership:
-- Enable RLS on all tablesALTER TABLE billeteras ENABLE ROW LEVEL SECURITY;ALTER TABLE transacciones ENABLE ROW LEVEL SECURITY;ALTER TABLE categorias ENABLE ROW LEVEL SECURITY;ALTER TABLE presupuestos ENABLE ROW LEVEL SECURITY;-- Example policy: Users can only see their own walletsCREATE POLICY "Users can view own wallets" ON billeteras FOR SELECT USING (auth.uid() = usuario_id);CREATE POLICY "Users can insert own wallets" ON billeteras FOR INSERT WITH CHECK (auth.uid() = usuario_id);CREATE POLICY "Users can update own wallets" ON billeteras FOR UPDATE USING (auth.uid() = usuario_id);CREATE POLICY "Users can delete own wallets" ON billeteras FOR DELETE USING (auth.uid() = usuario_id);
Similar policies exist for transacciones, categorias, and presupuestos tables.