Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Danielings/Pasantia-Proyecto/llms.txt

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

The bitácora is the system’s immutable audit trail. Every significant state change — user logins, account creations, profile updates, role changes, password resets, and location soft-deletes — writes a structured document to the bitacora Firestore collection. These records are append-only: no endpoint exists to delete or overwrite them, making the bitácora a reliable compliance and debugging tool.
The bitácora is ideal for compliance audits. Filter entries by usuario or accion to reconstruct the sequence of changes made to any user account, location, or configuration object. Because each entry carries a server-side Firestore Timestamp, the order of events is always accurate regardless of client clock skew.

Document Structure

Each bitácora document contains the following fields:
FieldTypeDescription
usuariostringUsername of the person who performed the action
id_modificadostringFirestore document ID of the affected record
accionstringHuman-readable label for the event type
detallesstring[]Array of strings describing each individual change
fechaTimestampServer-side Firestore timestamp of the event
sedestringOffice (sede) of the actor at the time of the action

Events Captured

Login

Recorded when a user authenticates successfully. The detalles array typically contains a single entry confirming the session start.

User Creation

Recorded when an administrator creates a new user account. Lists the initial field values in detalles.

User Update

Recorded when any user profile field changes. The generarCambios() controller diffs the old and new values and populates detalles with one entry per changed field.

User Deletion

Recorded when a user account is deactivated or removed. Includes the affected username in detalles.

Location Soft-Delete

Recorded by PUT /api/ubicaciones/eliminadas/:id. Confirms which location was set to inactivo.

Password Reset

Recorded when an administrator resets another user’s password. The new password value is never logged — only the event itself.

The generarCambios() Controller

When a user profile is updated, the system calls generarCambios(oldData, newData) to produce the detalles array. The function iterates over every field in the new data object and compares it to the corresponding field in the old snapshot. For each field where the value has changed, it appends a descriptive string to the changes list:
// Example output from generarCambios()
[
  "Nombre actualizado: 'Carlos' → 'Carlos A.'",
  "Rol actualizado: 'Operador' → 'Administrador'",
  "Correo actualizado: 'carlos@empresa.com' → 'carlosA@empresa.com'"
]
This granular diffing means a single edit that touches three fields produces three entries in detalles, making it straightforward to see exactly what changed in any given event.

Retrieving the Audit Log

GET /api/bitacora Returns all bitácora entries ordered by fecha descending (most recent first).
This endpoint does not require authentication. The bitacora router exports a bare Express route with no verificarToken middleware. If your deployment requires restricting access to the audit log, you should add the middleware or move the endpoint behind an API gateway rule.
curl http://localhost:3001/api/bitacora
Sample response:
[
  {
    "id": "xK9mPqR2LzTvAoW4nBcY",
    "accion": "Actualizar usuario",
    "detalles": [
      "Rol actualizado: 'Operador' → 'Administrador'",
      "Sede actualizada: 'Torre Norte' → 'Torre Sur'"
    ],
    "fecha": "2024-11-03T14:32:17.000Z",
    "id_modificado": "uZ3fJkL8mXqR6pTvN1oW",
    "sede": "Torre Norte",
    "usuario": "admin.principal"
  },
  {
    "id": "pN7wBcY5kXmL2qRvA9zT",
    "accion": "Iniciar sesión",
    "detalles": [
      "El usuario admin.principal inició sesión correctamente."
    ],
    "fecha": "2024-11-03T14:30:05.000Z",
    "id_modificado": "uZ3fJkL8mXqR6pTvN1oW",
    "sede": "Torre Norte",
    "usuario": "admin.principal"
  },
  {
    "id": "mQ4hVzW8cTpLrN6xKoYb",
    "accion": "Eliminar ubicación",
    "detalles": [
      "Se inactivó la ubicación: Torre Vieja Piso 3"
    ],
    "fecha": "2024-11-02T09:15:44.000Z",
    "id_modificado": "capital-dc-caracas-torre-vieja-3",
    "sede": "Torre Norte",
    "usuario": "superadmin"
  }
]
The fecha field is converted from a Firestore Timestamp to an ISO 8601 string by the API handler before being sent in the response:
fecha: data.fecha ? data.fecha.toDate().toISOString() : null,
Fields that are missing from older documents fall back to safe defaults ("Sin acción", [], "N/A", "Desconocido") so the response shape is always consistent.

Writing to the Bitácora

Any backend module can write an audit entry by creating a document directly in the bitacora collection. The pattern used throughout the codebase is:
const bitacoraRef = db.collection("bitacora").doc();
await bitacoraRef.set({
  usuario:       req.user.username,
  id_modificado: affectedDocId,
  accion:        "Descripción de la acción",
  detalles:      listaCambios,   // string[]
  fecha:         FieldValue.serverTimestamp(),
  sede:          req.user.sede,
});
Using FieldValue.serverTimestamp() ensures the timestamp is set by Firestore’s servers, not the application server, which provides a consistent ordering guarantee for entries written within the same millisecond window.

Build docs developers (and LLMs) love