Documentación técnica interna del backend: decisiones de arquitectura, bugs conocidos, problemas de entorno y su solución.
| Herramienta | Versión requerida | Notas |
|---|---|---|
| Node.js | v20.x LTS (recomendado v20.14.12) | Ver sección de problema crítico abajo |
| npm | v10.x | Incluido con Node 20 |
| Python | v3.x | Requerido por node-gyp para compilar sqlite3 |
IMPORTANTE: No usar Node.js v21, v22, v23 ni v24.
sqlite3requiere compilación nativa (node-gyp) y actualmente no tiene binarios precompilados (N-API) para versiones de Node superiores a la 20 LTS.
sqlite3 es una dependencia nativa que requiere compilación en C++ mediante node-gyp. Al correr npm install en Node.js v21+, el proceso falla con errores similares a:
prebuild-install warn install No prebuilt binaries found (target=undefined runtime=napi)
gyp ERR! find VS could not find a version of Visual Studio 2017 or newer to use
gyp ERR! not ok
El error tiene dos causas combinadas:
sqlite3 v5.1.7no publica binarios precompilados para Node v21+.node-gyp(necesario como fallback de compilación) requiere tener Windows SDK instalado junto a Visual Studio, que en muchos entornos de desarrollo no está completo.
Paso 1 — Instalar nvm-windows (gestor de versiones de Node):
winget install coreybutler.nvmforwindows --accept-source-agreements --accept-package-agreementsCerrar y reabrir la terminal después de instalar.
Paso 2 — Instalar y activar Node 20 LTS:
nvm install 20.14.12
nvm use 20.14.12
node --version # debe mostrar v20.14.12Paso 3 — Instalar dependencias:
cd Blog-Backend
npm installPaso 4 — Verificar que sqlite3 cargó correctamente:
node -e "require('sqlite3'); console.log('sqlite3 OK')"
# debe imprimir: sqlite3 OKSi por alguna razón debes quedar en Node v24, puedes intentar compilar sqlite3 instalando las herramientas de compilación de Windows:
# Como administrador:
npm install --global windows-build-tools
# O instalar Windows SDK manualmente desde:
# https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/Esta opción no es recomendada — es más frágil y lenta. Usa Node 20 LTS.
# 1. Clonar el repositorio
git clone https://github.com/Max1mus5/SIV-Source-Code-Project.git
cd SIV-Source-Code-Project/Blog-Backend
# 2. Verificar versión de Node (debe ser v20.x)
node --version
# 3. Instalar dependencias
npm install
# 4. Crear archivo .env en Blog-Backend/
cp .env.example .env # o crear manualmente (ver sección Variables de Entorno)
# 5. Iniciar en modo desarrollo
npm run devCrear el archivo Blog-Backend/.env con los siguientes valores:
# Puerto del servidor principal (API REST)
PORT=3000
# Puerto del servidor blockchain
BC_PORT=3001
# URL base del servidor (sin trailing slash)
baseURL=http://localhost
# Clave secreta para firmar JWT (usar string largo y aleatorio en producción)
JWT_SECRET=tu_clave_secreta_muy_larga_aqui
# Ruta del archivo de base de datos SQLite
DATABASE_URL=database.sqlite3
# Correo desde el que se envían los emails (Gmail recomendado)
SIV_EMAIL="tucorreo@gmail.com"
# App Password de Google (verificación en 2 pasos activa requerida)
# Generar en: https://myaccount.google.com/apppasswords
SIV_APP_PASSWORD="xxxx xxxx xxxx xxxx"Para el email: activa la verificación en dos pasos en tu cuenta de Google, luego genera una contraseña de aplicación en https://myaccount.google.com/apppasswords. Usa esa contraseña en
SIV_APP_PASSWORD, no tu contraseña real.
Con el servidor corriendo (npm run dev), verificar:
| Endpoint | URL | Resultado esperado |
|---|---|---|
| Estado API | GET http://localhost:3000/status |
{ status: "OK" } |
| Estado Blockchain | GET http://localhost:3001/status |
{ status: "OK" } |
| Docs Users | GET http://localhost:3000/user/docs |
JSON con documentación |
| Docs Posts | GET http://localhost:3000/post/docs |
JSON con documentación |
| Docs Blockchain | GET http://localhost:3001/blockchain/docs |
JSON con documentación |
El run_server.js levanta dos servidores Express simultáneamente:
Puerto 3000 → API Principal (user, post, comments, category, reaction, notifications)
Puerto 3001 → Blockchain (blockchain)
El servidor principal llama al servidor blockchain vía HTTP interno (axios) cada vez que se crea, actualiza o elimina un post.
startServices()
├── startServer() → Sync DB con Sequelize (alter:true), levanta puerto 3000
├── blockchainApp.listen → Levanta puerto 3001
└── mountBlockchain() → Reconstruye la blockchain desde los posts en DB
(cron semanal: domingos a medianoche)
| Módulo | Base path | Docs |
|---|---|---|
| Usuarios | /user |
/user/docs |
| Recuperar contraseña | /reset |
— |
| Posts | /post |
/post/docs |
| Comentarios | /comments |
— |
| Categorías | /category |
— |
| Reacciones | /reaction |
— |
| Notificaciones | /notifications |
/notifications/docs |
| Operación | Método | Ruta |
|---|---|---|
| Estado | GET | /status |
| Ver cadena completa | GET | /blockchain/blockchain |
| Validar cadena | GET | /blockchain/validate-blockchain |
| Crear transacción | POST | /blockchain/create-transaction |
| Minar bloque | POST | /blockchain/mine-block |
| Obtener por hash | GET | /blockchain/transaction/:hash |
| Actualizar transacción | PUT | /blockchain/update-transaction |
| Eliminar bloque | DELETE | /blockchain/block/:hash |
| Módulo | Estado | Notas |
|---|---|---|
| User (auth) | Completo | Login, registro, verificación email, recuperar contraseña |
| Posts | Completo | CRUD + integración blockchain |
| Comments | ~95% | Sin blockchain en comentarios, sin editar comentario |
| Reactions | Completo | Posts y comentarios |
| Category | Completo | CRUD + relación many-to-many con posts |
| Notifications | Corregido | Bug de import, campos y métodos faltantes resueltos |
| Blockchain | ~98% | Validación post-eliminación restaurada |
| Upload imágenes | Agregado | multer en /user/profile-image/:username y /post/upload-image/:postId |
Notificaciones (bug crítico resuelto):
notificationController.js: el import apuntaba anotificationUtils(no existía). Corregido anotifications.js.- Todos los campos del controller usaban los nombres del ORM (
userId,isRead,content) en vez del schema real (user_id,read,message). Corregidos. - Métodos
getAllNotificationsygetUnreadNotificationsno existían en utils. Implementados. - Método
markAsReaden controller tenía nombre distinto al que llamaba el router (markNotificationAsReadvsmarkAsRead). Unificado. - La ruta
/notificationsno estaba registrada enrun_server.js. Añadida.
Blockchain:
- Método
createTransactionestaba duplicado enblockchainServices.js. Eliminada la copia sin actualización de mapas. - Método
mineBlockestaba duplicado. Conservada la versión que actualizablockIndexMap. - Validación de cadena en
removeBlockByhash()estaba comentada. Restaurada con lógica de reorganización automática.
Imágenes:
- Instalado
multer. - Creado
connection/middlewares/uploadMiddleware.jscon storage separado para perfiles y posts. - Carpetas
public/uploads/profiles/ypublic/uploads/posts/creadas. run_server.jssirve/uploadscomo ruta estática.
- Cambiar
JWT_SECRETa un string de mínimo 64 caracteres aleatorios. - Configurar HTTPS (cadena SSL/TLS).
- Revisar la política de CORS (
origin: '*'es solo válido en desarrollo). - Agregar
helmetpara headers de seguridad:npm install helmet
const helmet = require('helmet'); app.use(helmet());
- Mover almacenamiento de imágenes a un servicio cloud (S3, Cloudinary) antes de deployment.
Todos los bugs críticos resueltos. El backend está listo para levantar y probar.
Lo que se hizo:
-
notificationController.js— import roto (notificationUtils→notifications.js) + campos incorrectos (userId/isRead/content→user_id/read/message) + métodos faltantes (getAllNotifications,getUnreadNotifications,getNotificationsByType) - Ruta
/notificationsno estaba registrada enrun_server.js— añadida -
blockchainServices.js— métodoscreateTransactionymineBlockestaban duplicados — eliminadas copias sinblockIndexMap -
blockchainServices.js— validación enremoveBlockByhash()estaba comentada — restaurada con reorganización automática -
blockchainServices.js—updateTransaction()llamabagetTransactionByHash()(async) sinawait— corregido -
blockchainServices.js— métodoremoveBlockByIndex()no existía pero el router lo llamaba — implementado -
blockchainRouter.js— routePUT /update-transactionno eraasyncaunque llama método async — corregido - Instalar
multer+ crearuploadMiddleware.js+ carpetaspublic/uploads/profiles/ypublic/uploads/posts/ -
PUT /user/profile-image/:username— endpoint upload de foto de perfil -
PUT /post/upload-image/:postId— endpoint upload de imagen de post (solo actualiza DB, no toca blockchain) -
run_server.jssirve/uploadscomo ruta estática -
start-dev.ps1— script para levantar el servidor con Node 20 desde cualquier terminal - Node.js v24 incompatible con
sqlite3— solución documentada (usar Node 20 LTS viafnm)
Cómo levantar el servidor:
# Opción A — desde terminal donde ya activaste fnm:
cd Blog-Backend
npm run dev
# Opción B — script autónomo:
cd Blog-Backend
powershell -ExecutionPolicy Bypass -File start-dev.ps1Construir el frontend desde cero con React + Vite.
-
npm create vite@latest Blog-Frontend -- --template react - Instalar dependencias:
axios,react-router-dom,jwt-decode,react-hook-form - Estructura de carpetas:
src/api/,src/components/,src/pages/,src/hooks/,src/context/,src/utils/ - Configurar variable de entorno
VITE_API_URL=http://localhost:3000
-
src/api/authService.js— funcioneslogin(),register(),verifyEmail(),recoverPassword(),resetPassword() -
src/context/AuthContext.jsx— estado global de sesión (user,token,isAuthenticated) -
src/utils/tokenManager.js— guardar/recuperar/validar JWT enlocalStorage -
src/api/axiosInstance.js— interceptor que inyectaAuthorization: Bearer <token>automáticamente -
src/pages/Login.jsx— formulario + llamada a API + redirect -
src/pages/Register.jsx— formulario con validación de password fuerte -
src/pages/VerifyEmail.jsx— recibe token de URL (/verify/:token) y llama al backend -
src/pages/RecoverPassword.jsx— solicitar reset por email -
src/pages/ResetPassword.jsx— nueva contraseña con token de URL -
src/components/ProtectedRoute.jsx— redirige a/loginsi no hay sesión
-
src/components/Navbar.jsx— logo, links (Feed, Perfil), botón Logout -
src/components/Layout.jsx— header + footer +<Outlet /> - Configurar React Router: rutas públicas (
/login,/register,/verify/:token,/recover,/reset/:token) y privadas (/feed,/post/:hash,/profile/:username,/create)
-
src/api/postService.js—getPosts(),getPostByHash(),createPost(),deletePost() -
src/components/PostCard.jsx— título, autor, fecha, preview de contenido, imagen, likes, nº comentarios -
src/pages/Feed.jsx— lista paginada de todos los posts -
src/pages/PostDetail.jsx— post completo + sección de comentarios
-
src/pages/CreatePost.jsx— formulario: título, contenido (textarea), categorías, imagen opcional - Mostrar spinner mientras se mina el bloque
- Redirect a feed tras creación exitosa
-
src/pages/Profile.jsx— info del usuario + sus posts - Edición de bio y username
- Upload de foto de perfil (usar
PUT /user/profile-image/:username)
Trabajo pendiente en backend mientras avanza el frontend.
- Comentarios — agregar endpoint
PUT /comments/:idpara editar comentario - Búsqueda de posts —
GET /post/search?q=con búsqueda por título/contenido (SequelizeOp.like) - Paginación en feed —
GET /post/my-feed?page=1&limit=10(actualmente devuelve todos sin paginar) - Security headers — instalar y configurar
helmet - Límite de tamaño body — agregar
express.json({ limit: '5mb' })enrun_server.js - Variables de entorno faltantes — documentar
baseURLen el.env.example(ahora mismo no se documenta y es crítica para los posts) - Tests unitarios básicos — instalar
jest+supertest, cubrir auth (register/login/verify) - Logging estructurado — reemplazar
console.log/errorconwinston - Crear
.env.examplepara que otros desarrolladores sepan qué variables configurar
- WebSockets con
socket.io— notificaciones en tiempo real - Dashboard de admin — listado de usuarios, gestión de roles, moderación de posts
- Sistema de favoritos funcional (el campo existe en el schema pero no hay endpoints)
- Refresh tokens (actualmente JWT expira en 4h sin renovación)
- Migrar almacenamiento de imágenes a Cloudinary o S3
- Docker + CI/CD pipeline
- Estrategia de pruning / archivado para la blockchain a escala