Skip to content

pxlauf/sparpal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sparpal Backend

Backend API para la aplicación móvil Sparpal de comparación de precios de supermercados alemanes.

🛠️ Stack Tecnológico

  • Node.js + Express.js
  • PostgreSQL como base de datos
  • Sequelize ORM para manejo de base de datos
  • JWT (jsonwebtoken) para autenticación
  • bcryptjs para hashing de contraseñas
  • dotenv para variables de entorno

📋 Características

  • ✅ Autenticación JWT con refresh tokens
  • ✅ CRUD completo para productos, precios y supermercados
  • ✅ Gestión de listas de compras
  • ✅ Sistema de suscripciones (free/premium)
  • ✅ CORS configurado para React Native (Expo)
  • ✅ Rate limiting y seguridad con Helmet
  • ✅ Manejo global de errores
  • ✅ Logging con Morgan
  • ✅ Migraciones y seeders con Sequelize CLI
  • Sistema de scraping para 5 supermercados alemanes
  • Job programado diario (06:00 AM UTC)
  • Fallback automático a datos mock
  • Panel de administración completo

🚀 Instalación y Configuración

1. Clonar el repositorio

git clone <repository-url>
cd sparpal-backend

2. Instalar dependencias

npm install

3. Configurar variables de entorno

cp .env.example .env

Edita el archivo .env con tus configuraciones:

# Database Configuration
DATABASE_URL=postgresql://username:password@localhost:5432/sparpal_db
DB_HOST=localhost
DB_PORT=5432
DB_NAME=sparpal_db
DB_USER=tu_usuario
DB_PASSWORD=tu_password

# JWT Configuration
JWT_SECRET=tu-super-secreto-jwt-key-cambiar-en-produccion
JWT_REFRESH_SECRET=tu-super-secreto-refresh-jwt-key-cambiar-en-produccion
JWT_EXPIRES_IN=24h
JWT_REFRESH_EXPIRES_IN=7d

# Server Configuration
NODE_ENV=development
PORT=3000

# CORS Configuration
CORS_ORIGIN=http://localhost:19000

# Logging
LOG_LEVEL=info

4. Configurar PostgreSQL

  1. Instalar PostgreSQL (si no está instalado)
  2. Crear la base de datos:
    createdb sparpal_db

5. Ejecutar migraciones y seeders

# Ejecutar migraciones (crear tablas)
npm run migrate

# Poblar con datos iniciales (opcional)
npm run seed

6. Iniciar el servidor

# Modo desarrollo
npm run dev

# Modo producción
npm start

El servidor estará ejecutándose en http://localhost:3000

📚 API Endpoints

🔐 Autenticación

POST /api/auth/signup

Registrar nuevo usuario.

Request Body:

{
  "email": "user@example.com",
  "password": "SecurePassword123",
  "name": "Juan Pérez"
}

Response:

{
  "message": "User created successfully",
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "name": "Juan Pérez",
    "created_at": "2024-01-01T00:00:00.000Z"
  },
  "token": "jwt-token",
  "refreshToken": "refresh-token"
}

POST /api/auth/login

Iniciar sesión.

Request Body:

{
  "email": "user@example.com",
  "password": "SecurePassword123"
}

POST /api/auth/refresh

Renovar token de acceso.

Request Body:

{
  "refreshToken": "refresh-token"
}

GET /api/auth/profile

Obtener perfil del usuario (requiere autenticación).

🏪 Supermercados (Públicos)

GET /api/supermarkets

Obtener todos los supermercados.

GET /api/supermarkets/:id

Obtener supermercado por ID.

🛍️ Productos (Públicos)

GET /api/products

Obtener productos con búsqueda opcional.

Query Parameters:

  • name - Buscar por nombre
  • category - Filtrar por categoría
  • limit - Límite de resultados (default: 50)
  • offset - Offset para paginación

GET /api/products/:id

Obtener producto por ID con precios.

💰 Precios (Públicos)

GET /api/prices

Obtener precios con filtros opcionales.

Query Parameters:

  • productId - Filtrar por producto
  • supermarketId - Filtrar por supermercado
  • limit - Límite de resultados
  • offset - Offset para paginación

GET /api/prices/product/:productId

Obtener todos los precios de un producto específico.

💳 Suscripciones (Protegidas)

GET /api/subscriptions/me/subscription

Obtener suscripción actual del usuario.

POST /api/subscriptions/me/subscription

Crear o actualizar suscripción.

Request Body:

{
  "plan": "premium",
  "expires_at": "2024-12-31T23:59:59.000Z"
}

🛒 Listas de Compras (Protegidas)

GET /api/shopping-lists/me/shopping-lists

Obtener todas las listas de compras del usuario.

POST /api/shopping-lists/me/shopping-lists

Crear nueva lista de compras.

Request Body:

{
  "name": "Lista semanal"
}

GET /api/shopping-lists/me/shopping-lists/:id

Obtener lista específica.

PUT /api/shopping-lists/me/shopping-lists/:id

Actualizar lista.

DELETE /api/shopping-lists/me/shopping-lists/:id

Eliminar lista.

POST /api/shopping-lists/me/shopping-lists/:id/items

Agregar producto a lista.

Request Body:

{
  "product_id": "product-uuid",
  "quantity": 2,
  "notes": "Verde, sin daños"
}

PUT /api/shopping-lists/me/shopping-lists/items/:itemId

Actualizar item de lista.

DELETE /api/shopping-lists/me/shopping-lists/items/:itemId

Eliminar item de lista.

🏥 Sistema

GET /health

Health check del servidor.

Response:

{
  "status": "OK",
  "timestamp": "2024-01-01T00:00:00.000Z",
  "uptime": 3600,
  "environment": "development"
}

🧪 Testing

# Ejecutar tests
npm test

📁 Estructura del Proyecto

sparpal-backend/
├── src/
│   ├── config/
│   │   ├── database.js        # Configuración de base de datos
│   │   └── env.js            # Variables de entorno
│   ├── controllers/          # Lógica de negocio
│   │   ├── authController.js
│   │   ├── productController.js
│   │   ├── priceController.js
│   │   ├── supermarketController.js
│   │   ├── subscriptionController.js
│   │   └── shoppingListController.js
│   ├── middleware/
│   │   └── auth.js           # Middleware de autenticación JWT
│   ├── models/              # Modelos de Sequelize
│   │   ├── User.js
│   │   ├── Subscription.js
│   │   ├── Supermarket.js
│   │   ├── Product.js
│   │   ├── Price.js
│   │   ├── ShoppingList.js
│   │   ├── ShoppingListItem.js
│   │   └── index.js         # Configuración de modelos y relaciones
│   ├── routes/              # Rutas de Express
│   │   ├── auth.js
│   │   ├── products.js
│   │   ├── prices.js
│   │   ├── supermarkets.js
│   │   ├── subscriptions.js
│   │   └── shoppingLists.js
│   ├── app.js               # Configuración principal de Express
│   └── server.js            # Entry point del servidor
├── migrations/              # Migraciones de base de datos
├── seeders/                 # Datos iniciales
├── .env.example             # Ejemplo de variables de entorno
├── .gitignore
├── package.json
└── README.md

🔐 Seguridad

  • Rate Limiting: 100 requests por 15 minutos por IP
  • Helmet: Headers de seguridad HTTP
  • CORS: Configurado específicamente para React Native (Expo)
  • bcryptjs: Hash de contraseñas con salt rounds
  • JWT: Tokens con expiración configurada
  • Validación: Validación de entrada con express-validator

🚀 Scripts Disponibles

  • npm start - Iniciar servidor en producción
  • npm run dev - Iniciar servidor en desarrollo con nodemon
  • npm test - Ejecutar tests
  • npm run migrate - Ejecutar migraciones de base de datos
  • npm run migrate:undo - Revertir última migración
  • npm run seed - Ejecutar seeders
  • npm run seed:undo - Revertir seeders

📊 Base de Datos

Esquema Principal

users

  • id (UUID, PK)
  • email (STRING, UNIQUE)
  • password_hash (STRING)
  • name (STRING)
  • created_at, updated_at (TIMESTAMP)

supermarkets

  • id (UUID, PK)
  • name (STRING, UNIQUE) - REWE, EDEKA, ALDI, LIDL, PENNY
  • city (STRING) - Berlin (MVP)
  • website_url (STRING)
  • created_at, updated_at (TIMESTAMP)

products

  • id (UUID, PK)
  • name (STRING)
  • category (STRING)
  • unit (ENUM: 'kg', 'L', 'unit', 'piece')
  • description (TEXT)
  • created_at, updated_at (TIMESTAMP)

prices

  • id (UUID, PK)
  • product_id (UUID, FK)
  • supermarket_id (UUID, FK)
  • price (DECIMAL(10,2))
  • price_per_unit (DECIMAL(10,2))
  • last_updated (TIMESTAMP)
  • source (ENUM: 'scraper', 'manual')
  • created_at, updated_at (TIMESTAMP)

subscriptions

  • id (UUID, PK)
  • user_id (UUID, FK)
  • plan (ENUM: 'free', 'premium')
  • started_at (TIMESTAMP)
  • expires_at (TIMESTAMP, NULL allowed)
  • created_at, updated_at (TIMESTAMP)

shopping_lists

  • id (UUID, PK)
  • user_id (UUID, FK)
  • name (STRING)
  • created_at, updated_at (TIMESTAMP)

shopping_list_items

  • id (UUID, PK)
  • shopping_list_id (UUID, FK)
  • product_id (UUID, FK)
  • quantity (INTEGER)
  • notes (TEXT)
  • created_at, updated_at (TIMESTAMP)

🌐 Variables de Entorno

Variable Descripción Default
DATABASE_URL URL de conexión completa a PostgreSQL -
DB_HOST Host de PostgreSQL localhost
DB_PORT Puerto de PostgreSQL 5432
DB_NAME Nombre de la base de datos sparpal_db
DB_USER Usuario de PostgreSQL -
DB_PASSWORD Password de PostgreSQL -
JWT_SECRET Secret para JWT tokens -
JWT_REFRESH_SECRET Secret para refresh tokens -
JWT_EXPIRES_IN Expiración de tokens 24h
JWT_REFRESH_EXPIRES_IN Expiración de refresh tokens 7d
NODE_ENV Entorno de ejecución development
PORT Puerto del servidor 3000
CORS_ORIGIN Origen permitido para CORS http://localhost:19000
LOG_LEVEL Nivel de logging info

🛠️ Desarrollo

Agregar nueva migración

npx sequelize-cli migration:generate --name nombre-de-la-migracion

Agregar nuevo seeder

npx sequelize-cli seed:generate --name nombre-del-seeder

Ejecutar migración específica

npx sequelize-cli db:migrate --env development

📝 Notas

  • Sistema de scraping implementado para REWE, EDEKA, ALDI, LIDL y PENNY
  • Datos mock realistas con precios alemanes actuales
  • Job diario automático a las 06:00 AM UTC
  • Fallback automático a datos mock si falla el scraper
  • CORS configurado para React Native (Expo) en http://localhost:19000
  • Sistema de logging básico implementado con Morgan
  • Error handling global implementado

🤖 Sistema de Scraping

El sistema incluye scrapers para 5 supermercados alemanes con:

Supermercados Soportados

  • REWE
  • EDEKA
  • ALDI
  • LIDL
  • PENNY

Productos Scraped (9 productos básicos)

  • Leche 1L, Pan, Huevos (6), Manzanas 1kg
  • Aceite, Sal, Azúcar 1kg, Pasta, Tomates (lata)

Características

  • ✅ 3 reintentos con 5s de delay
  • ✅ 3s de delay entre supermercados
  • ✅ Fallback automático a mock data
  • ✅ Logs completos en tabla scrape_logs
  • ✅ Trigger manual desde panel admin

Ver documentación completa en SCRAPING_README.md

🔄 Próximos Pasos

  • Reemplazar datos mock con scraping web real
  • Agregar tests unitarios e integración
  • Documentación OpenAPI/Swagger
  • Docker para deployment
  • Sistema de notificaciones push
  • Analytics y métricas
  • Cache con Redis para mejorar performance

About

Price comparison app for German supermarkets

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors