Every clinic in XHealtXperience has its own isolated security configuration stored in a singleDocumentation 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.
tenant_settings row within the clinic’s tenant database. This means a policy change in one clinic never affects another. The TenantSetting model exposes these knobs to clinic administrators, while the application automatically reads them at runtime to enforce session expiry, lockout policies, and visitor check-in access.
The TenantSetting model
App\Models\TenantSetting is a standard Eloquent model that maps to the tenant_settings table inside the tenant database. The table always contains at most one row, accessed via TenantSetting::first() or TenantSetting::firstOrCreate([]).
Full schema
Thetenant_settings table is built up across several tenant migrations:
| Column | Type | Default | Description |
|---|---|---|---|
id | bigint | auto | Primary key |
inactivity_timeout_minutes | integer | 15 | Minutes of inactivity before automatic session logout |
max_login_attempts | unsignedTinyInteger | 3 | Failed login attempts allowed before account lockout |
monto_penalizacion_cancelacion | decimal(10,2) | 0.00 | Late-cancellation fee (< 24 h before appointment) |
contador_pacientes | unsignedInteger | 0 | Atomic counter for generating sequential patient codes |
visitor_checkin_token | string(64) | null | Token authorizing the public visitor check-in page |
Only
inactivity_timeout_minutes, max_login_attempts, and visitor_checkin_token are in the model’s $fillable array. monto_penalizacion_cancelacion and contador_pacientes are managed by the application and are not exposed through mass assignment.Configurable security settings
Inactivity timeout
inactivity_timeout_minutes controls how long an authenticated staff session may sit idle before the check_inactivity middleware automatically logs it out.
The CheckInactivity middleware reads this value on every authenticated request:
409 response with an X-Inertia-Location header pointing to the tenant login page, triggering a full page reload on the client without a broken UI state.
Login lockout
max_login_attempts sets the threshold of consecutive failed login attempts before a staff user account is locked. Once locked, the user cannot log in until an Administrador Clinica unlocks them manually via PATCH /{tenantId}/usuarios/{usuario}/desbloquear.
Visitor check-in token
Thevisitor_checkin_token is a 40-character random string that authorizes a public, unauthenticated check-in page. This page is designed for a reception-area tablet where patients can confirm their arrival without any staff member needing to hand over a logged-in device.
How it works
The token is embedded in the public check-in URL:VisitorCheckInController::verificarToken() compares the URL token against the stored value using hash_equals() (timing-safe comparison):
403. The three check-in sub-routes that use this protection are:
| Method | Path | Description |
|---|---|---|
GET | /{tenantId}/citas/checkin/visitante/{token} | Renders the check-in UI |
GET | /{tenantId}/citas/checkin/visitante/{token}/buscar | Searches today’s appointments |
POST | /{tenantId}/citas/checkin/visitante/{token}/citas/{cita} | Confirms patient check-in |
Generating a QR code
Oncevisitor_checkin_token is populated, the Administrador Clinica can generate a QR code pointing to the full check-in URL and display it at the reception desk. The frontend reads the token from the tenant_settings prop shared by Inertia.
Regenerating the token
Administrador Clinica. It replaces the stored token with a new 40-character random string using Str::random(40):
403. This is the intended revocation mechanism if a device is lost or stolen.
The contador_pacientes field
contador_pacientes is managed automatically by the application and should never be edited manually. It is an atomic incrementing counter used to generate unique sequential patient codes in the format {CODIGO_CLINICA}{counter_padded} (e.g. STL00001, STL00002). Editing this value directly would create duplicate or non-sequential patient codes.Updating security settings
The security settings form is available exclusively to users with theAdministrador Clinica role.
TenantSettingController::update() method validates the input and calls firstOrCreate([]) to ensure the settings row always exists before updating it:
Security settings fields
Number of minutes of inactivity before a logged-in staff session is automatically terminated and the user is redirected to the clinic login page.
- Minimum:
1 - Maximum:
1440(24 hours) - Default:
15 - Enforced by:
check_inactivitymiddleware on every authenticated tenant route
Maximum number of consecutive failed login attempts before a user account is locked. The lockout is lifted only by an
Administrador Clinica using the unlock route.- Minimum:
1 - Maximum:
10 - Default:
3
How settings reach the frontend
HandleInertiaRequests::share() reads TenantSetting::first() on every request made within an initialized tenant context and injects the result into the global Inertia props:
tenant_settings.inactivity_timeout_minutes and can use it to drive client-side idle timers, countdown banners, or QR code generation without any additional API requests.
The
visitor_checkin_token is also included in the shared props so the Administrador Clinica dashboard can display the current check-in URL and offer a one-click regeneration button without a separate fetch.