Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Arthurr23/XHealtXperience/llms.txt

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

The Super Admin is a central user — they live in the central database, not inside any clinic’s tenant database. They are responsible for the full lifecycle of every clinic registered on the platform: onboarding new clinics, adjusting subscription limits, suspending inactive tenants, and provisioning initial staff accounts. All Super Admin functionality is available at the /panel-global path prefix and is protected by authentication, mandatory two-factor verification, and the Super Admin Spatie role.

Authentication and access

The Super Admin panel requires:
  1. Central authentication — the Super Admin logs in through the standard Laravel auth flow, which resolves against the central users table.
  2. Two-factor authentication (2FA) — the two_factor middleware enforces a verified 2FA challenge before any panel-global route is accessible. Attempting to access the dashboard before completing 2FA redirects to /two-factor/challenge.
  3. Role gate — the role:Super Admin middleware (Spatie Permission) ensures no clinic staff member can reach the central panel even if they somehow authenticate centrally.
Route::middleware(['auth', 'two_factor', 'role:Super Admin'])
    ->prefix('panel-global')
    ->group(function () {
        // All Super Admin routes
    });

Route reference

Dashboard

GET /panel-global/dashboard
Renders the main Super Admin dashboard (Dashboards/SuperAdminDashboard) with three data sets:
  • clinicas — all registered tenants with their core metadata.
  • administradores — empty array on initial load; populated by the administrators route.
  • metricas — aggregate counts: total_clinicas, clinicas_activas, clinicas_suspendidas.

Create a clinic

POST /panel-global/clinicas
Registers a new clinic as a tenant. See Create clinic flow and Request body below.

Toggle clinic status

PATCH /panel-global/clinicas/{tenantId}/estado
Toggles the clinic’s estado between activa and suspendida. No request body required — the controller reads the current value and flips it.

Update plan and account limit

PATCH /panel-global/clinicas/{tenantId}/limite
Updates a clinic’s subscription plan and account limit independently of the original defaults.
FieldRules
planrequired · one of basico, pro, premium, personalizado
limite_cuentasrequired · integer · 1–1000

Edit clinic (read)

GET /panel-global/clinicas/{tenantId}/edit
Returns a JSON object with the editable fields of the specified clinic: id, nombre_clinica, email_contacto, telefono_contacto, plan, limite_cuentas, estado, fecha_inicio_suscripcion. Used by the frontend modal to pre-populate the edit form.

Update clinic

PATCH /panel-global/clinicas/{tenantId}
Persists edits to an existing clinic’s profile.
FieldRules
nombre_clinicarequired · string · max 150
email_contactorequired · email · max 150
telefono_contactonullable · string · max 20
planrequired · one of basico, pro, premium, personalizado
limite_cuentasrequired · integer · 1–1000
fecha_inicio_suscripcionrequired · date

Delete clinic

DELETE /panel-global/clinicas/{tenantId}
Permanently removes the tenant record and drops the clinic’s dedicated database. This route is registered in routes/web.php and is protected by the same auth, two_factor, and role:Super Admin middleware stack as all other panel-global routes.

List clinic administrators

GET /panel-global/administradores
Iterates over every registered tenant, temporarily initializes each one’s database context, and collects all staff users with their assigned roles. Returns the same SuperAdminDashboard view with tab_inicial set to administradores. Each record includes tenant_id, nombre_clinica, estado_clinica, and the user’s Spatie role names.
This route initializes tenancy for each clinic in a loop and calls tenancy()->end() in a finally block after each iteration. Clinics whose databases are unavailable are skipped with a warning log entry — they do not abort the entire listing.

Show create-user form

GET /panel-global/clinicas/{tenantId}/usuarios/nuevo
Renders the SuperAdmin/CrearUsuarioClinica form pre-loaded with the clinic’s name and the list of available Spatie roles seeded in that tenant’s database. If the clinic has no roles yet (edge case for clinics created before the RoleSeeder fix), this route runs tenants:migrate and tenants:seed inline as a recovery mechanism.

Save new clinic user

POST /panel-global/clinicas/{tenantId}/usuarios
Creates a staff user directly inside the specified clinic’s tenant database. The new user receives a random 32-character password and an activation email with a password-reset link (activation=1 parameter). Roles are assigned using Spatie’s assignRole().
FieldRules
namerequired · string · max 255
emailrequired · email · max 255 · unique within the tenant
rolerequired · string · must be an existing Spatie role in the tenant DB

Create clinic flow

1

Submit the registration form

The Super Admin fills in the clinic’s details on the dashboard and submits POST /panel-global/clinicas. Laravel validates the request against the rules in SuperAdminController::store().
2

Validate the tenant ID

The id field is validated as alpha_dash, unique against the tenants table, and not in the reserved list. The value is lowercased before storage.
3

Create the Tenant record

Tenant::create() writes a new row to the central tenants table with estado set to activa. A corresponding row is created in the domains table linking the domain slug to the new tenant.
$tenant = Tenant::create([
    'id'                       => $tenantId,
    'nombre_clinica'           => $validated['nombre_clinica'],
    'email_contacto'           => $validated['email_contacto'],
    'telefono_contacto'        => $validated['telefono_contacto'],
    'plan'                     => $plan,
    'limite_cuentas'           => $validated['limite_cuentas'],
    'estado'                   => 'activa',
    'fecha_inicio_suscripcion' => $validated['fecha_inicio_suscripcion'],
]);

$tenant->domains()->create(['domain' => $tenantId]);
4

Provision the tenant database

Artisan::call('tenants:migrate', ['--tenants' => [$tenant->id]]) creates the clinic’s dedicated database file and runs all migrations from database/migrations/tenant/.
5

Seed roles

Artisan::call('tenants:seed', ['--tenants' => [$tenant->id], '--class' => 'Database\\Seeders\\RoleSeeder']) seeds the standard Spatie roles (Doctor, Recepcion, Administrador Clinica, Auditor, etc.) into the new tenant’s database.
6

Redirect with confirmation

On success, the controller redirects to superadmin.dashboard with a flash message confirming the clinic and roles were created. If the migrate/seed step throws, a warning message is shown but the clinic record is preserved — the Super Admin can retry seeding manually.

Create clinic request body

The id field becomes the permanent URL prefix for the clinic (/{id}/dashboard). It cannot be changed after creation. Choose a short, URL-safe slug.
id
string
required
Unique tenant identifier. Used as the URL path prefix for all clinic routes (e.g. clinica-norte/{tenantId}/dashboard).
  • Format: alpha_dash (letters, numbers, hyphens, underscores)
  • Max length: 50 characters
  • Must be unique across all tenants
  • Cannot be any of the reserved IDs: panel-global, login, logout, register, api
nombre_clinica
string
required
Full display name of the clinic, shown throughout the application UI.
  • Max length: 150 characters
email_contacto
string
required
Primary contact / billing email address for this clinic.
  • Must be a valid email address
  • Max length: 150 characters
telefono_contacto
string
Optional contact phone number.
  • Max length: 20 characters
plan
string
required
Subscription plan that determines the default account limit. One of:
  • basico — default limit: 5 accounts
  • pro — default limit: 20 accounts
  • premium — default limit: 50 accounts
  • personalizado — starting limit: 5 (operator configures manually)
limite_cuentas
integer
required
Maximum number of staff user accounts the clinic may create. Pre-filled by the frontend based on the selected plan, but always editable.
  • Minimum: 1
  • Maximum: 200 (at creation; updatable to 1000 via PATCH /limite)
fecha_inicio_suscripcion
date
required
Subscription start date in YYYY-MM-DD format. Used for billing and reporting purposes.

Reserved tenant IDs

The following strings are forbidden as tenant IDs because they match central route prefixes. Submitting any of them returns a 422 Unprocessable Entity validation error:
Reserved IDConflicts with
panel-globalSuper Admin dashboard prefix
loginCentral login route
logoutCentral logout route
registerCentral registration route
apiAPI route group prefix
// SuperAdminController.php
private const IDS_RESERVADOS = ['panel-global', 'login', 'logout', 'register', 'api'];

// Applied in validation:
Rule::notIn(self::IDS_RESERVADOS),

Build docs developers (and LLMs) love