Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/juanVillamilEchavarria/Leo_Counter-app/llms.txt

Use this file to discover all available pages before exploring further.

Categories give every financial movement a semantic label that goes beyond the raw amount and date. When you record a grocery run you tag it as “Supermercado”; when a salary arrives you tag it as “Salario”. Leo Counter uses those tags to group and aggregate data across the KPI, trend, and distribution charts in the reports module, making it easy to see which spending areas consume the most budget each month.

The Category Model

Categories are stored in the categorias table and support soft deletes, so removed categories are preserved in the historical record and can be restored by an admin.
// database/migrations/2026_01_14_200821_create_categorias_table.php
$table->uuid('id')->primary();
$table->string('nombre');
$table->foreignId('tipo_movimiento_id')->constrained('tipo_movimientos')->onDelete('cascade');
$table->boolean('es_fijo')->default(false);
$table->text('descripcion')->nullable();
$table->boolean('is_system')->default(false);
$table->softDeletes();
// unique per (nombre, tipo_movimiento_id)
$table->unique(['nombre', 'tipo_movimiento_id']);
The unique constraint means you can have an income category and an expense category with the same name (e.g. “Transferencia” for both directions), but you cannot have two income categories called “Salario”.

Category Fields

nombre
string
required
The category label (max 255 characters). Must be unique within the same movement type.
tipo_movimiento_id
integer
required
Classifies the category as income (1) or expense (2). This value is validated against the tipo_movimientos table.
descripcion
string
Optional longer description of what belongs in this category (max 1,000 characters).
// app/Http/Requests/Categoria/StoreAndUpdateCategoriaRequest.php
return [
    'nombre'             => 'required|string|max:255',
    'tipo_movimiento_id' => [
        'required', 'integer', 'exists:tipo_movimientos,id',
        Rule::unique('categorias')
            ->where(fn ($q) => $q->where('nombre', $this->nombre))
            ->ignore($this->id)
    ],
    'descripcion'        => 'nullable|string|max:1000',
];

The es_fijo Flag

The es_fijo boolean marks a category as “fixed” — meaning it is associated with recurring obligations rather than one-off purchases. When you create a fixed movement (MovimientoFijo), best practice is to use a category where es_fijo = true so that the reports engine can filter by fixed-only categories if needed. You toggle es_fijo without editing the full category form:
PATCH /categorias/{categoria}/{attribute}/toggle
Where {attribute} is es_fijo. The ToggleCategoryCommand is dispatched and the flag is flipped atomically.
// app/Http/Controllers/Categoria/CategoriaController.php
public function toggleEsFijo(string $id, string $attribute)
{
    $this->dispatcher->dispatch(new ToggleCategoryCommand(id: $id, attribute: $attribute));
    Inertia::flash('success', 'Categoria actualizada con exito');
    return redirect()->route('categorias.index');
}
The es_fijo flag does not restrict which movements can use the category — it is a soft metadata tag. Any movement type can reference any category regardless of this flag.

System Categories

The is_system boolean marks categories that are seeded by the application itself and cannot be deleted through the UI. These exist to ensure baseline reporting always has valid data.

Category Routes

MethodURIAction
GET/categoriasList all categories
GET/categorias/createShow creation form
POST/categoriasStore a new category
GET/categorias/{id}/editShow edit form
PUT/categorias/{id}Update a category
DELETE/categorias/{id}Soft-delete a category
PATCH/categorias/{id}/{attribute}/toggleToggle es_fijo flag

How Categories Appear in Reports

The CategoryDistributionAssembler aggregates all movements in the selected period, groups them by category, and returns a FullCategoryDistributionDTO containing the total movement count across categories:
// app/Application/Reporte/Assemblers/Movimientos/CategoryDistributionAssembler.php
$categoryCollection = $results->get(MovimientoReportStatisticType::CATEGORY_DISTRIBUTION);
return new FullCategoryDistributionDTO(
    $categoryCollection,
    $categoryCollection->totalMovimientos()
);
The reports front-end renders this data as a pie chart that shows which categories represent the largest share of income or expenses in your selected period. You can further filter by specific categories using the filter sheet.

Soft Deletes and Restoration

Deleting a category is a soft delete — the record is flagged with a deleted_at timestamp and hidden from lists and forms, but never physically removed. Admins can restore or permanently hard-delete categories from:
GET    /configuracion/deleted/categorias
PUT    /configuracion/deleted/categorias/restore/{id}
DELETE /configuracion/deleted/categorias/hard-delete/{id}
Hard-deleting a category that has associated movements will leave those movements without a valid category reference. Always check for dependent records before performing a hard delete.

Best Practices: Suggested Household Category Structure

Categoryes_fijoTypical use
SalariotrueMonthly fixed salary
FreelancefalseVariable project payments
Transferencia recibidafalseOne-off bank transfers
ReembolsofalseExpense reimbursements
Categoryes_fijoTypical use
Vivienda (Arriendo/Hipoteca)trueMonthly housing cost
Servicios públicostrueUtilities billed monthly
SupermercadofalseWeekly grocery runs
TransportefalseFuel, public transit
SaludfalseMedical and pharmacy
EducacióntrueTuition or subscriptions
EntretenimientofalseDining out, streaming
SegurostrueInsurance premiums
Keep category names short and consistent. The reports pie chart displays the nombre field directly — long names can truncate in smaller chart views.

Build docs developers (and LLMs) love