Skip to main content

Overview

The transacciones table stores all financial transactions (income and expenses) linked to user wallets. Each transaction is categorized and includes amount, type, date, and optional description.

Table Schema

Columns

id
UUID
required
Primary key. Auto-generated unique identifier for the transaction.
monto
NUMERIC(12,2)
required
Transaction amount in USD. Stored with 2 decimal precision.
tipo
VARCHAR
required
Transaction type. Either "gasto" (expense) or "ingreso" (income).
descripcion
TEXT
Optional description or note about the transaction (max 280 characters in UI).
fecha_transaccion
TIMESTAMPTZ
required
Date and time when the transaction occurred.
categoria_id
UUID
required
Foreign key to categorias. Links the transaction to a category.
billetera_id
UUID
required
Foreign key to billeteras. Links the transaction to a wallet.
usuario_id
UUID
required
Foreign key to auth.users. Links the transaction to its owner.
created_at
TIMESTAMPTZ
Timestamp when the transaction was created. Auto-set by database.
updated_at
TIMESTAMPTZ
Timestamp when the transaction was last modified. Auto-updated.

Relationships

  • Many-to-One with billeteras: Each transaction belongs to one wallet
  • Many-to-One with categorias: Each transaction belongs to one category
  • Many-to-One with auth.users: Each transaction belongs to one user

Row Level Security (RLS)

The table enforces RLS policies:
CREATE POLICY "Users can view their own transactions"
  ON transacciones FOR SELECT
  USING (auth.uid() = usuario_id);

CREATE POLICY "Users can insert their own transactions"
  ON transacciones FOR INSERT
  WITH CHECK (auth.uid() = usuario_id);

CREATE POLICY "Users can update their own transactions"
  ON transacciones FOR UPDATE
  USING (auth.uid() = usuario_id);

CREATE POLICY "Users can delete their own transactions"
  ON transacciones FOR DELETE
  USING (auth.uid() = usuario_id);

Example Queries

Fetch Transactions with Category Info

const { data, error } = await supabase
  .from("transacciones")
  .select("id, monto, tipo, descripcion, fecha_transaccion, categoria_id, categorias(id, nombre, tipo)")
  .eq("billetera_id", walletId)
  .order("fecha_transaccion", { ascending: false });

Create a New Transaction

const { error } = await supabase
  .from("transacciones")
  .insert({
    monto: 50.00,
    tipo: "gasto",
    descripcion: "Grocery shopping",
    categoria_id: categoryId,
    usuario_id: user.id,
    billetera_id: walletId,
    fecha_transaccion: new Date().toISOString()
  });

Filter by Date Range

const { data } = await supabase
  .from("transacciones")
  .select("*")
  .gte("fecha_transaccion", startDate.toISOString())
  .lte("fecha_transaccion", endDate.toISOString())
  .order("fecha_transaccion", { ascending: false });

Calculate Wallet Balance

const { data: transactions } = await supabase
  .from("transacciones")
  .select("monto, tipo")
  .eq("billetera_id", walletId);

const balance = transactions.reduce((acc, tx) => {
  return tx.tipo === "ingreso" ? acc + tx.monto : acc - tx.monto;
}, 0);

Transaction Types

Represents money spent or outgoing transactions.
  • Decreases wallet balance
  • Linked to expense categories
  • Displayed with red color indicators
  • Used for budget tracking

Validation Rules

  • Amount: Must be greater than 0 (enforced in UI)
  • Type: Must be either "gasto" or "ingreso"
  • Category Match: Category type must match transaction type
  • Wallet Selection: Cannot create transactions in global wallet mode
  • Date: Cannot be in the future (recommended)

Indexes

CREATE INDEX idx_transacciones_usuario_id ON transacciones(usuario_id);
CREATE INDEX idx_transacciones_billetera_id ON transacciones(billetera_id);
CREATE INDEX idx_transacciones_categoria_id ON transacciones(categoria_id);
CREATE INDEX idx_transacciones_fecha ON transacciones(fecha_transaccion DESC);
CREATE INDEX idx_transacciones_tipo ON transacciones(tipo);

Wallets

Parent wallet for transactions

Categories

Transaction categories

Budgets

Budget tracking by category

Build docs developers (and LLMs) love