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.

Leo Counter enforces a simple two-role permission model: admin and member. The very first account created in a fresh installation automatically becomes the admin — there is no separate seeding step or environment variable required. All subsequent accounts are created by that admin from the user management panel, and they receive the member role by default. Every authenticated user, regardless of role, can view and update their own profile information and change their own password.

Roles

Admin

Full access to the application. Can manage all users (create, edit, delete, reset passwords), access the configuration panel, view soft-deleted records, and perform hard deletes.

Member

Access to all finance features (accounts, movements, budgets, reports). Can update their own profile and password. Cannot access user management or the configuration panel.
The roles are defined as a PHP backed enum with two cases:
// app/Domains/Usuario/Enums/Roles.php
enum Roles: string
{
    case ADMIN  = 'admin';
    case MEMBER = 'member';
}
The role column is stored in the users table with a default of member. The migration that adds it is:
// database/migrations/2026_01_04_023439_add_role_column_to_users_table.php
Schema::table('users', function (Blueprint $table) {
    $table->string('role')->default('member')->index();
});
The AdminMiddleware checks this column on every request to a protected route:
// app/Http/Middleware/AdminMiddleware.php
if (!$user || $user->role !== Roles::ADMIN->value) {
    abort(403, 'Acción no autorizada.');
}

User Fields

FieldTypeNotes
idUUIDPrimary key, non-incrementing
namestringDisplay name
emailstringUnique, used for login
passwordstringHashed with bcrypt (BCRYPT_ROUNDS=12)
rolestringadmin or member
email_verified_attimestampNullable
remember_tokenstringStandard Laravel remember-me token

First-Time Admin Setup

When there are no users in the database, Leo Counter’s RedirectIfUsersAreEmptyMiddleware intercepts every request to the login page and redirects to /register. After the first account is created, that route is locked by RedirectIfUserExistsMiddleware, which bounces any subsequent visit to /register back to the login page.
1

Clone and start the Docker stack

git clone https://github.com/juanVillamilEchavarria/Leo_Counter-app.git
cd Leo_Counter-app
cp .env.example .env
# Fill in DB_*, REVERB_*, and other required values, then:
docker compose up -d
2

Generate the application key

docker compose exec app php artisan key:generate
This writes APP_KEY into your .env file automatically.
3

Run migrations and seeders

docker compose exec app php artisan migrate --seed
The seeder populates lookup tables (frequencies, account types, movement types, categories, notification channels) but does not create any user.
4

Navigate to /register

Open http://localhost:8080/register in your browser. Because no users exist yet, the middleware redirects you here automatically from the home page.
5

Fill in the registration form

Enter a name, email address, and password. On submission, RegisteredUserController dispatches CreateTheAdminUserCommand, which creates the user with the admin role.
// app/Http/Controllers/Auth/RegisteredUserController.php
$this->commandBus->dispatch(new CreateTheAdminUserCommand(
    name:     $request->input('name'),
    email:    $request->input('email'),
    password: $request->input('password'),
));
6

Log in as admin

After registration you are redirected to /login. Sign in with the credentials you just created. You now have full admin access to Leo Counter.
Once the first user exists, any visit to /register is caught by RedirectIfUserExistsMiddleware and redirected to route('login'). There is no public self-registration for additional accounts — only the admin can create new users.

Admin: Managing Other Users

All user management routes are protected by both the auth middleware and AdminMiddleware. They are accessible under /usuarios.

Available Routes

MethodPathAction
GET/usuariosList all users
GET/usuarios/createShow create-user form
POST/usuariosCreate a new user
GET/usuarios/{usuario}/editShow edit form
PUT/usuarios/{usuario}Update name and email
DELETE/usuarios/{usuario}Delete a user
PUT/usuarios/{usuario}/passwordReset another user’s password

Creating a New User

  1. Navigate to Usuarios → Crear Usuario (/usuarios/create).
  2. Fill in Nombre, Email, and Contraseña.
  3. Click Guardar. The new account is created with the member role.

Resetting Another User’s Password

An admin can reset any user’s password without knowing the current one:
PUT /usuarios/{usuario}/password
This calls UsuarioController::changePassword(), which dispatches ChangeUserPasswordCommand with only id and newPassword — no current-password verification is required at the admin level.

Deleting a User

DELETE /usuarios/{usuario}
Dispatches DestroyUsuarioCommand. This is a hard delete on the users table — the record is permanently removed.
Deleting a user is irreversible. Any data owned exclusively by that user (e.g., budgets with user_id) will have their foreign key set to NULL (the presupuestos migration uses nullOnDelete()).

Self-Service: Profile and Password

Every authenticated user can manage their own account through the profile routes, which require auth but not AdminMiddleware.

Profile Routes

MethodPathRoute nameDescription
GET/profileprofile.indexView own profile
PUT/profileprofile.updateUpdate own name and email
GET/profile/passwordprofile.password.indexView password-change form
PUT/profile/passwordprofile.password.updateChange own password

Updating Profile Information

ProfileController::update() accepts name and email, then dispatches UpdatePublicDataCommand:
$this->commandBus->dispatch(new UpdatePublicDataCommand(
    id:    (string) auth()->id(),
    name:  $request->name,
    email: $request->email,
));

Changing Own Password

PasswordController::update() requires the current password for verification before applying the change, using ChangeOwnPasswordCommand:
$this->commandBus->dispatch(new ChangeOwnPasswordCommand(
    id:              (string) auth()->id(),
    currentPassword: $request->current_password,
    newPassword:     $request->password,
));
If a user forgets their current password, an admin can reset it for them via PUT /usuarios/{usuario}/password — which skips the current-password check.

Middleware Reference

Applied to the guest route group (login, forgot password, etc.). When User::exists() returns false, it redirects the visitor to /register instead of showing the login form. Once at least one user is registered, this middleware becomes a no-op.
Applied exclusively to GET /register and POST /register. When User::exists() returns true, it redirects the visitor to route('login'), making registration impossible for subsequent visitors.
Applied to the inner route group that contains /usuarios, /configuracion, and the soft-delete routes. Checks auth()->user()->role === 'admin'; aborts with HTTP 403 if the condition fails.

Build docs developers (and LLMs) love