Aquí tienes la documentación completa generada en formato `README.md` a partir de la arquitectura y el código de tu API. --- # Documentación de la API: Notas Encriptadas (E2EE) Esta API proporciona el backend para una aplicación de notas con sincronización **Offline-First** y **Cifrado de Extremo a Extremo (E2EE)**. Está construida sobre Node.js con Express y utiliza PostgreSQL (vía Sequelize) como base de datos. ## 🏗 Arquitectura y Flujo de Datos El sistema sigue un patrón estructurado en capas para separar responsabilidades: 1. **Punto de Entrada e Inicialización:** El archivo `app.js` inicializa Express, habilita CORS y permite payloads JSON de hasta 50MB. El archivo `initDB.js` se encarga de sincronizar los modelos con la base de datos PostgreSQL utilizando Sequelize. 2. **Enrutamiento Principal (`index.js`):** Todo el tráfico entra por `/api`. De ahí, el router principal distribuye las peticiones hacia `/auth` (autenticación), `/user` (datos del usuario) y `/` (sincronización). 3. **Controladores (`*Controller.js`):** Son la capa de seguridad y transporte. Validan que las peticiones vengan con un JWT válido en las cabeceras (Access Token), extraen el `userId` y envían los parámetros limpios a los servicios. 4. **Servicios (`*Service.js`):** Contienen toda la lógica de negocio profunda. Manejan la creación de tokens, el hasheo de contraseñas, las transacciones SQL y la lógica de resolución de conflictos durante la sincronización. 5. **Modelos (`.js`):** Definen las tablas y relaciones estructurales en la base de datos. --- ## 🗄 Modelos de Base de Datos y Relaciones El esquema de la base de datos se distribuye en cuatro entidades principales interconectadas: * **User (`User.js`):** Almacena el `email` y `password` (hasheado con bcrypt) del usuario. También guarda la `encrypted_master_key`, que es la llave maestra para desencriptar las notas, pero cifrada con la contraseña del usuario para asegurar el E2EE. Un usuario tiene muchas Notas, Categorías y RefreshTokens. * **Note (`Note.js`):** Guarda los datos cifrados de cada nota (`title`, `body`), su orden (`position`), versión en el servidor (`serverVersion`) y estados de borrado (`delete`, `permanentDelete`). * **Category (`Category.js`):** Guarda información visual (`colorValue`, `iconCodePoint`) y el nombre cifrado (`encrypted_name`) de las categorías. * **Relación Nota-Categoría:** Las Notas y las Categorías tienen una relación de *Muchos a Muchos* (M:N) a través de una tabla intermedia llamada `NoteCategories`. * **RefreshToken (`RefreshToken.js`):** Gestiona las sesiones multidispositivo. Guarda un token largo, seguro y único asociado al `deviceName` del usuario. Si el usuario se elimina, sus tokens se borran en cascada. --- ## 🚀 Endpoints de la API ### 1. Autenticación (`/api/auth`) Estos endpoints gestionan el registro, inicio de sesión y ciclo de vida de los tokens. El sistema usa un Access Token de corta duración (15 min) y un Refresh Token persistente en base de datos. * **Registro de Usuario** * **Ruta:** `POST /api/auth/register` * **Body:** `{ "email": "...", "password": "...", "encrypted_master_key": "...", "deviceName": "..." }` * **Descripción:** Comprueba que el usuario no exista, hashea su contraseña, crea la cuenta y automáticamente inicia sesión, devolviendo ambos tokens (Access y Refresh) y la llave maestra. * **Inicio de Sesión** * **Ruta:** `POST /api/auth/login` * **Body:** `{ "email": "...", "password": "...", "deviceName": "..." }` * **Descripción:** Verifica credenciales y crea una nueva sesión para el dispositivo (registrando un nuevo Refresh Token en DB). Retorna los tokens y la `encrypted_master_key`. * **Refrescar Token** * **Ruta:** `POST /api/auth/refresh` * **Body:** `{ "refresh_token": "..." }` * **Descripción:** Intercambia un Refresh Token válido por un nuevo Access Token limpio de 15 minutos. * **Cerrar Sesión Local** * **Ruta:** `POST /api/auth/logout` * **Body:** `{ "refresh_token": "..." }` * **Descripción:** Borra el Refresh Token proporcionado de la base de datos, revocando el acceso a ese dispositivo específico. * **Borrado Total de Cuenta (Danger Zone)** * **Ruta:** `DELETE /api/auth/delete-all-data` * **Headers:** `Authorization: Bearer ` * **Descripción:** Mediante una transacción de base de datos, borra irremediablemente todas las notas, categorías y sesiones (tokens) asociadas al usuario actual. * **Listar Dispositivos Activos** * **Ruta:** `GET /api/auth/getSessionsInfo` * **Headers:** `Authorization: Bearer ` * **Descripción:** Devuelve un listado de todos los dispositivos (`deviceName`), fechas de creación y los IDs de los Refresh Tokens asociados al usuario. ### 2. Estadísticas de Usuario (`/api/user`) * **Obtener Estadísticas** * **Ruta:** `GET /api/user/stats` * **Headers:** `Authorization: Bearer ` * **Descripción:** Descarga parcialmente las notas y categorías de la base de datos (solo los campos pesados como títulos y cuerpos) para calcular el peso en bytes (RAM-friendly) del almacenamiento en la nube del usuario. Devuelve totales formateados (KB/MB). ### 3. Sincronización Offline-First (`/api/sync`) Este endpoint único procesa de forma bidireccional los cambios ocurridos tanto en la app local como en la base de datos del servidor. * **Endpoint de Sincronización** * **Ruta:** `POST /api/sync` * **Headers:** `Authorization: Bearer ` * **Body:** ```json { "lastSyncAt": "ISO String", "changes": { "categories": [ ... ], "notes": [ ... ] } } ``` * **Descripción y Flujo de Resolución:** 1. Envuelve todo en una **Transacción SQL** para garantizar que o se guarda todo o no se guarda nada en caso de error. 2. Recorre las `categories` entrantes. Si el `id` no existe, lo crea. Si existe, compara la `serverVersion`. Si la versión enviada coincide con la del servidor, actualiza los datos e incrementa la versión en el servidor. Si el servidor tiene una versión superior (conflicto), ignora el cambio del cliente y anota el ID para mandárselo de vuelta. 3. Repite exactamente el mismo proceso de validación transaccional e inserción de datos para las `notes`, actualizando también la tabla intermedia de categorías mediante el array `categoryIds` entrante. 4. Consulta a la base de datos cualquier nota o categoría cuyo `updatedAt` sea mayor al `lastSyncAt` proporcionado por el cliente, además de sumar los registros que hayan sufrido un conflicto de versión en los pasos anteriores. 5. Devuelve al cliente un objeto estructurado con las notas y categorías actualizadas del servidor y el nuevo `serverTimestamp` (momento exacto en el que acabó la sincronización).