Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nieto2020/portalhub/llms.txt

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

The appointments module (modules/citas/) lets clients and advisors collaborate on scheduling sessions. Every operation is gated by checkAuth(), and ownership checks ensure that a client can only act on their own appointments while an advisor can only act on appointments assigned to them. Creating a new appointment also triggers an automatic in-app notification to the assigned advisor.

Appointment State Machine

Each appointment (cita) moves through a well-defined lifecycle. The estado column is an ENUM with the following values:
StateMeaning
ProgramadaDefault state when the appointment is first created
ReprogramadaReserved ENUM value for a rescheduled appointment; defined in the database schema
CanceladaTerminal state set by cancelar.php; no further edits are allowed
A cancelled appointment is immutable — neither modificar.php nor cancelar.php will process a request for a cita already in the Cancelada state. Note that modificar.php updates only the fecha_hora column; it does not automatically transition estado to Reprogramada.

Creating an Appointment

Endpoint: POST modules/citas/crear.php Before inserting the new row, crear.php queries for any existing non-cancelled appointment held by the target advisor at the exact same fecha_hora. If a conflict exists, 409 Conflict is returned. On success, NotificationService::notify() is called to alert the advisor. Required fields:
FieldTypeDescription
id_clienteintID of the client requesting the appointment
id_asesorintID of the advisor to assign
fecha_horastringISO-8601 datetime (YYYY-MM-DD HH:MM:SS)
{
  "id_cliente": 12,
  "id_asesor": 5,
  "fecha_hora": "2025-08-20 10:00:00"
}
Conflict check (from crear.php):
$validar = $conexion->prepare("
    SELECT COUNT(*)
    FROM citas
    WHERE id_asesor = ?
      AND fecha_hora = ?
      AND estado != 'Cancelada'
");
$validar->execute([$id_asesor, $fecha_hora]);

if ($validar->fetchColumn() > 0) {
    sendResponse(409, "El asesor ya tiene una cita en ese horario");
}

Rescheduling an Appointment

Endpoint: POST modules/citas/modificar.php modificar.php updates the fecha_hora to a new value. The advisor conflict check is repeated (excluding the current id_cita), and ownership is enforced: clients may only reschedule their own appointments, and advisors may only reschedule appointments assigned to them. Required fields:
FieldTypeDescription
id_citaintPrimary key of the appointment to reschedule
fecha_horastringNew ISO-8601 datetime
{
  "id_cita": 88,
  "fecha_hora": "2025-08-21 14:00:00"
}
Attempting to reschedule a Cancelada appointment returns 400 Bad Request. Check the appointment’s current state before calling this endpoint.

Cancelling an Appointment

Endpoint: POST modules/citas/cancelar.php Sets estado = 'Cancelada' and records the reason in motivo_cancelacion. Both fields are required. Required fields:
FieldTypeDescription
id_citaintPrimary key of the appointment to cancel
motivo_cancelacionstringFree-text explanation for the cancellation
{
  "id_cita": 88,
  "motivo_cancelacion": "El cliente solicitó reprogramar para la semana siguiente."
}
$sql = "UPDATE citas
        SET estado = :estado,
            motivo_cancelacion = :motivo_cancelacion
        WHERE id_cita = :id_cita";

$stmt = $conexion->prepare($sql);
$stmt->bindParam(":estado", $estado, PDO::PARAM_STR);
$stmt->bindParam(":motivo_cancelacion", $motivo_cancelacion, PDO::PARAM_STR);
$stmt->bindParam(":id_cita", $id_cita, PDO::PARAM_INT);
$stmt->execute();

Listing Appointments

Endpoint: GET modules/citas/listar.php The result set is automatically scoped based on the session role:
RoleFilter Applied
ROL_CLIENTE (3)Only appointments where id_cliente = id_usuario
ROL_ASESOR (2)Only appointments where id_asesor = id_usuario
ROL_ADMIN (1)All appointments, unfiltered
Results are ordered by fecha_hora DESC. Response fields:
[
  {
    "id_cita": 88,
    "id_cliente": 12,
    "id_asesor": 5,
    "fecha_hora": "2025-08-21 14:00:00",
    "estado": "Programada",
    "motivo_cancelacion": null
  }
]
$sql = "SELECT id_cita, id_cliente, id_asesor, fecha_hora,
               estado, motivo_cancelacion
        FROM citas";

$params = [];

if ($rol === ROL_CLIENTE) {
    $sql .= " WHERE id_cliente = ?";
    $params[] = $id_usuario;
} elseif ($rol === ROL_ASESOR) {
    $sql .= " WHERE id_asesor = ?";
    $params[] = $id_usuario;
}

$sql .= " ORDER BY fecha_hora DESC";

Notifications on Appointment Creation

When a new appointment is saved successfully, crear.php uses NotificationService to push an in-app notification to the assigned advisor:
$notificador = new NotificationService($conexion);
$notificador->notify(
    $id_asesor,
    "Cita",
    "Se ha programado una nueva cita para el: $fecha_hora"
);
See the Notifications page for details on how NotificationService works and how notification events are consumed.

Build docs developers (and LLMs) love