API RESTful para gestión y mejora de hábitos mediante gamificación con sistema de desafíos, misiones diarias, niveles dinámicos y rankings comunitarios.
Backend del proyecto DailyGrind desarrollado con Node.js, Express, TypeScript, MongoDB y JWT.
- Autenticación con JWT almacenado en cookies HttpOnly y refresh token automático.
- Autenticación alternativa con Firebase.
- Roles de usuario con acceso diferenciado entre administrador y usuario.
- Sistema de desafíos globales (creados por admin) y personales (creados por usuarios).
- Misiones diarias automáticas con 3 desafíos globales + 2 personales asignables.
- Sistema de niveles dinámico basado en puntos totales acumulados.
- Sistema de badges y logros con condiciones personalizables.
- Ranking global y por zonas geográficas con posicionamiento en tiempo real.
- Perfil de usuario con información pública/privada y estadísticas personales.
- Estadísticas detalladas de desafíos y misiones completadas.
- Historial de actividad de los últimos 30 días.
- Sistema de reroll limitado para misiones globales (máximo 3 por día).
- Gestión administrativa de usuarios, desafíos y estadísticas del sistema.
- Node.js 18+
- Express 4.18
- TypeScript 5.9
- MongoDB 8.18 (Mongoose)
- JWT (jsonwebtoken)
- bcrypt
- Firebase Admin
- class-validator y class-transformer
- cookie-parser
- CORS
- Nodemon
DailyGrind-Back/
├── src/
│ ├── config/
│ │ └── firebase.ts
│ ├── controllers/
│ │ ├── userController.ts
│ │ ├── challengeController.ts
│ │ ├── dailyQuestController.ts
│ │ ├── profileController.ts
│ │ └── rankingController.ts
│ ├── dto/
│ │ ├── userDto.ts
│ │ ├── challengeDto.ts
│ │ └── dailyQuestDto.ts
│ ├── middlewares/
│ │ ├── auth.ts
│ │ └── middleware.ts
│ ├── models/
│ │ ├── user.ts
│ │ ├── challenge.ts
│ │ ├── dailyQuest.ts
│ │ ├── badge.ts
│ │ └── userBadge.ts
│ ├── routes/
│ │ ├── userRoutes.ts
│ │ ├── challengeRoutes.ts
│ │ ├── dailyQuestRoutes.ts
│ │ ├── profileRoutes.ts
│ │ └── rankingRoutes.ts
│ ├── types/
│ │ └── type.ts
│ ├── utils/
│ │ └── levelSystem.ts
│ └── index.ts
├── .env.example
├── nodemon.json
├── tsconfig.json
├── package.json
└── README.md
- Autenticación: registro, login, logout y autenticación con Firebase.
- Usuarios: gestión de perfiles, estadísticas personales y activación/desactivación de cuentas.
- Desafíos: creación, actualización y eliminación de desafíos globales (admin) y personales (usuarios).
- Misiones Diarias: generación automática de misiones, asignación manual de desafíos personales, completación y skipeo.
- Niveles: sistema dinámico basado en fórmula matemática (50 * nivel^1.4) para puntos requeridos.
- Rankings: visualización global y por zona con paginación, búsqueda de posición personal.
- Perfil: gestión de información pública, estadísticas y actividad reciente.
- Badges: logros desdeñables con condiciones personalizables y estadísticas.
- Administración: gestión centralizada de usuarios, desafíos, estadísticas y sincronización de niveles.
Node.js18 o superiornpm9 o superiorMongoDB Atlasdisponible (instancia remota o local)Firebase Project(opcional, para autenticación alternativa)
Crear un archivo backend/.env tomando como base .envexample:
# Base de datos
MONGODB_URI=mongodb+srv://USER:PASSWORD@CLUSTER.mongodb.net/DATABASE_NAME?retryWrites=true&w=majority
# JWT
JWT_SECRET=tu_access_secret_muy_seguro
JWT_REFRESH_SECRET=tu_refresh_secret_muy_seguro
# Entorno
NODE_ENV=development
PORT=5000
# Firebase (opcional, solo si se usa autenticación con Firebase)
FIREBASE_PROJECT_ID=tu_proyecto_id
FIREBASE_PRIVATE_KEY=tu_clave_privada
FIREBASE_CLIENT_EMAIL=tu_email_cliente# 1. Clonar el repositorio
git clone https://github.com/DailyGrindd/DailyGrind-Back.git
cd DailyGrind-Back
# 2. Instalar dependencias
npm install
# 3. Configurar las variables de entorno
# Crear archivo .env basado en .env.example# Modo desarrollo (con hot reload gracias a nodemon)
npm run dev
## El servidor queda disponible en `http://localhost:5000/api`.
# Compilación a producción
npm run build
# Ejecutar versión compilada
npm start- El login se realiza contra
/api/users/login. - El registro se realiza contra
/api/users/register. - La sesión se mantiene mediante cookies HttpOnly (
accessTokenyrefreshToken). - Cuando el access token expira (15 minutos), el refresh token genera uno nuevo automáticamente.
- Los endpoints administrativos están restringidos al rol
Administrador.
Roles presentes en el modelo de datos:
Administrador- Acceso completo a gestión de usuarios, desafíos globales y estadísticas.Usuario- Acceso limitado a crear desafíos personales, participar en misiones y ver rankings.
El esquema de Mongoose modela las siguientes entidades principales:
userName- Nombre único del usuarioemail- Email único del usuariopassword- Contraseña hasheada con bcryptrole- Rol del usuario (Administrador o Usuario)level- Nivel actual (calculado dinámicamente)isActive- Estado de la cuentaprofile- Datos públicos: displayName, avatarUrl, isPublic, zonestats- Estadísticas: totalPoints, weeklyPoints, totalCompleted, currentStreaklastActive- Última actividad registrada
type- Tipo: "global" (admin) o "personal" (usuario)ownerUser- Referencia al usuario propietario (solo desafíos personales)title- Título del desafíodescription- Descripción detalladacategory- Categoría del desafío (ej: salud, productividad)difficulty- Dificultad (1-5)points- Puntos otorgados al completarloisActive- Estado del desafíotags- Etiquetas asociadasrequirements- Nivel mínimo y desafío prerequisitorules- maxPerDay, minUserLevelstats- Estadísticas: timesAssigned, timesCompleted, completionRate
userId- Referencia al usuariodate- Fecha de la misiónmissions- Array de misiones (slots 1-5) con estado, puntos y fecha completaciónrerollCount- Cantidad de rerolls utilizados en el día
name- Nombre del logrodescription- Descripción del logroiconUrl- URL del iconodifficulty- Dificultad del logroconditions- Condiciones para obtenerlo (tipo, categoría, umbral)
userId- Referencia al usuariobadgeId- Referencia al badgeearnedAt- Fecha de obtención del logro
POST /register- Registro de nuevo usuarioPOST /login- Login de usuarioPOST /logout- LogoutPOST /firebase-register- Registro con FirebasePOST /firebase-login- Login con Firebase
GET /- Listar usuarios (admin)GET /:email- Obtener usuario por email (admin)POST /- Crear usuario (admin)PUT /:email- Actualizar usuario (admin)PUT /:email/activate- Activar usuario (admin)PUT /:email/desactivate- Desactivar usuario (admin)GET /access/user- Obtener datos del usuario actual (autenticado)GET /level/info- Obtener información de nivel del usuario (autenticado)GET /level/ranking- Obtener ranking de nivelesGET /level/stats- Estadísticas de niveles (admin)
GET /- Listar todos los desafíos (público)GET /:id- Obtener desafío por ID (público)GET /stats- Estadísticas generales de desafíos (público)GET /random- Obtener desafíos aleatorios (público)GET /category/:category- Desafíos por categoría (público)POST /- Crear desafío (autenticado, permiso según tipo)PUT /:id- Actualizar desafío (autenticado, owner o admin)DELETE /:id- Eliminar desafío (autenticado, owner o admin)PATCH /:id/reactivate- Reactivar desafío (autenticado, owner o admin)PATCH /:id/assign- Incrementar estadística de asignación (autenticado)PATCH /:id/complete- Incrementar estadística de completación (autenticado)
GET /initialize- Inicializar/obtener misión diaria de hoy (autenticado)GET /my-daily- Obtener misiones de hoy (autenticado)GET /history- Historial de últimos 30 días (autenticado)GET /mission-state- Promedio de misiones por estado (admin)GET /mission-typestats- Estadísticas por tipo (admin)POST /assign-personal- Asignar desafío personal (autenticado)DELETE /unassign-personal/:slot- Desasignar desafío personal (autenticado)PATCH /reroll/:slot- Reroll de misión global (autenticado)PATCH /complete/:slot- Completar misión (autenticado)PATCH /skip/:slot- Skipear misión (autenticado)
GET /:email- Obtener perfil personal (autenticado)GET /public/:userName- Obtener perfil público (público)PUT /:email- Actualizar perfil (autenticado)GET /search/public- Buscar usuarios públicos (público)
GET /global- Ranking global con paginación (público)GET /global/:email- Posición y usuarios cercanos (público)GET /zone/:zone- Ranking por zona (público)GET /zone/:zone/:email- Posición en zona (público)