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 Sistema de Inventario Tecnológico is a two-process application: a stateless Express.js API on port 3001 and a Vite-served React SPA on port 5173. The browser communicates with the backend exclusively over HTTP, passing session state through an HTTP-only JWT cookie. All primary data lives in Firebase Firestore; a secondary MySQL database is used only for the password-recovery flow. Understanding this separation is the key to reasoning about how any given feature works end-to-end.

High-Level Architecture Diagram

Browser (React / Vite :5173)
       |
       | HTTP + Cookie (acceso_token)
       v
Express API (:3001)
├── /api/login, /api/logout, /api/me
├── /api/usuarios
├── /api/pc, /api/laptop, /api/equipos
├── /api/perifericos, /api/componentes
├── /api/ubicaciones, /api/region
├── /api/bitacora
├── /api/export
└── /api/recuperar-password, /api/restablecer-password
       |
       ├── Firebase Firestore (primary store)
       └── MySQL (password reset tokens only)

Backend

The backend is a single Node.js process running Express 5 with ES Modules. It is started via node index.js from the backend/ directory and listens on port 3001.

Middleware Stack

Middleware is applied in the following order to every incoming request:
  1. cookie-parser — deserializes the acceso_token HTTP-only cookie into req.cookies
  2. cors — enforces the allowed origin (http://localhost:5173), permits credentials, and exposes the Content-Disposition header so file-download responses work in the browser
  3. express.json() — parses application/json request bodies into req.body
  4. Request logger (inline middleware) — logs the method and URL for any request to /recuperar* or /restablecer* paths, aiding debugging of the email-based recovery flow
  5. verificarToken (per-router) — verifies the JWT from req.cookies.acceso_token using JWT_SECRET; absent or invalid tokens receive a 401 response before the route handler runs
  6. Role check middleware (per-route) — certain routes additionally assert the user’s rol claim from the JWT payload; unauthorized roles receive a 403 response

API Routers

All routers are mounted under the /api prefix. Each router module lives in backend/apis/.
Router moduleMounted pathsDescription
usuarios.js/api/login, /api/logout, /api/me, /api/usuariosAuthentication, session management, user CRUD
equipos.js/api/pc, /api/laptop, /api/equipos, /api/componentesPC and laptop registration, retrieval, updates, and component management
perifericos.js/api/perifericosMonitor, keyboard, mouse, switch, printer, and speaker CRUD
ubicacion.js/api/ubicaciones, /api/regionLocation hierarchy management (Region → Estado → Ciudad → Sede → Piso → Ala)
bitacora.js/api/bitacoraAudit log retrieval
exportacion.js/api/exportPDF and Excel inventory export
recuperarPassword.js/api/recuperar-password, /api/restablecer-passwordEmail-based password reset flow (uses MySQL for token storage)

Firebase Firestore (Primary Database)

Firestore is the system’s main data store. The backend uses firebase-admin (initialized in config/firebase.js with a service account) to interact with it. Every collection is accessed through the shared db instance exported from that module.

Collections

CollectionContents
equiposPC and laptop records, including embedded component sub-documents
perifericosStandalone peripheral records (Monitor, Teclado, Mouse, Switch, Impresora, Corneta)
ubicacionesSede-level location documents with Piso and Ala detail
regionesTop-level regional division records
estadosState-level subdivision records
ciudadesCity-level subdivision records
indicesSerial-number lookup index — one document per serial, enforces global uniqueness
bitacoraAudit log entries; each document records actor, resource, action type, and UTC timestamp
usuariosUser account documents storing name, email, hashed password, and role

Firestore Transaction Strategy

Any write that must touch multiple documents atomically runs inside db.runTransaction(). This is the mechanism behind two critical guarantees:
  1. Serial number uniqueness — when registering any asset (PC, laptop, or peripheral), the handler opens a transaction, reads the target document in the indices collection, aborts if a serial already exists, then writes the new asset document and the index entry in a single commit. No two concurrent requests can assign the same serial number.
  2. Consistent location and component updates — updates that affect a parent record and its related index or sub-collection documents (for example, changing a laptop’s motherboard while updating its location) are wrapped in the same transaction to prevent partial writes.
Firestore transactions are limited to a maximum of 500 document operations per commit. For bulk import scenarios, batch the imports into groups that stay well under this limit and issue separate transactions per group.

MySQL (Secondary Database)

MySQL is used only by the password-recovery flow in recuperarPassword.js. It is not involved in any inventory, location, or audit-log operations. The connection pool is initialized in config/bd.js using the mysql2 driver and the DB_HOST, DB_USER, DB_PASSWORD, and DB_NAME environment variables. The password-recovery flow works as follows:
  1. The user submits their email to POST /api/recuperar-password
  2. The backend generates a cryptographically random reset token (via Node’s built-in crypto module), stores it in the MySQL usuarios table alongside an expiry timestamp, and sends an email via Nodemailer containing a link to the frontend reset page
  3. The user clicks the link and submits a new password to POST /api/restablecer-password
  4. The backend validates the token against MySQL, hashes the new password with bcrypt, updates the user’s record in Firestore, and deletes the token from MySQL

Frontend

The frontend is a single-page application built with React 19 and bundled by Vite 8. It is served by the Vite dev server on port 5173 during development.

Routing

Client-side routing is handled by React Router v7 (react-router-dom). All routes except /login, /recuperar-password, and /nueva-password are wrapped in a RutaProtegida component that reads the auth context — if no authenticated user is present, it redirects to /login.
PathPage componentAccess
/loginLoginPublic
/recuperar-passwordRecuperarPasswordPublic
/nueva-passwordNuevaPasswordPublic (token-gated)
/dashboardDashboardProtected
/busquedaBusquedaProtected
/registroRegistroProtected
/registro-usuariosRegistroUsuariosProtected
/perfilPerfilProtected
/bitacoraBitacoraProtected
/ubicacionUbicacionProtected

Key Libraries

LibraryVersionRole
react / react-dom19Core UI rendering
react-router-dom7Declarative client-side routing
react-hook-form7Performant form state management
zod4Schema-based form validation via @hookform/resolvers
axios1.16HTTP client (all requests use withCredentials: true)
tailwindcss4Utility-first CSS framework, integrated via @tailwindcss/vite
shadcn / radix-uilatestAccessible, unstyled UI primitives (dialogs, dropdowns, tables)
lucide-reactlatestSVG icon library
react-hot-toast2Non-blocking toast notification system
recharts3Composable chart library used in the Dashboard
date-fns4Date formatting utilities
react-datepicker9Date picker component

Authentication Flow

The AuthProvider context (in controllers/AuthContext.jsx) is mounted at the root of the application. On mount, it calls GET /api/me to check whether a valid acceso_token cookie exists and hydrates the user state with the response. This check gates all protected routes and makes the current user’s role available throughout the component tree for conditional rendering.

Authentication Details

JWTs are signed with the JWT_SECRET environment variable using jsonwebtoken 9. The token is written as an HTTP-only cookie named acceso_token on a successful POST /api/login. Because the cookie is HTTP-only, it is invisible to JavaScript running in the browser, which protects it from XSS attacks. Every protected Express route passes the request through the verificarToken middleware first. The middleware reads req.cookies.acceso_token, verifies the signature, and attaches the decoded payload (including uid, correo, and rol) to req.usuario for downstream handlers to use. Logout is implemented by calling res.clearCookie("acceso_token") — no server-side token revocation is required.
The default cookie configuration does not set secure: true, which means the cookie will be transmitted over plain HTTP during local development. In a production deployment behind HTTPS, add secure: true and sameSite: "strict" to the res.cookie call in the login handler.

Build docs developers (and LLMs) love