From cb564fb1709b0c7ba0fc811622ab1e5ff66447a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoni=20Nu=C3=B1ez=20Romeu?= Date: Thu, 16 Jul 2026 12:51:48 +0200 Subject: [PATCH] docs: add comprehensive parapharmacy and N8N documentation - Create docs/parapharmacy.md with full API, N8N, and setup documentation - Update README.md with parapharmacy system overview and links - Add project structure for parapharmacy-api and n8n - Update Docker setup section with all services - Add API endpoints for parapharmacy - Add N8N workflow automation section --- README.md | 141 +++++++++++++++--- docs/parapharmacy.md | 347 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 469 insertions(+), 19 deletions(-) create mode 100644 docs/parapharmacy.md diff --git a/README.md b/README.md index 3dcf358..d9069f0 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,11 @@ A web application to search for medicines from the official Spanish CIMA databas | App | Stack | |-----|-------| -| Backend | Node.js + Express, SQLite, Redis | +| Backend | Node.js + Express, SQLite/PostgreSQL, Redis | +| Parapharmacy API | Node.js + Express, MongoDB | | Frontend (Web) | React + Vite, Capacitor | | Frontend (Mobile) | Expo SDK 57 + React Native, Zustand, Axios + TanStack Query | +| Workflow Automation | N8N | | Build system | Turborepo | | Package manager | npm workspaces | @@ -50,10 +52,11 @@ This is a **Turborepo monorepo**. All applications live under `apps/`: FarmaFinder/ ├── package.json # Root: workspaces + turbo scripts ├── turbo.json # Turborepo task configuration -├── docker-compose.yml # Full stack: backend + frontend + Redis + Postgres +├── docker-compose.yml # Full stack: backend + frontend + Redis + Postgres + MongoDB + N8N +├── .env.example # Environment variables template │ ├── apps/ -│ ├── backend/ # Node.js + Express API +│ ├── backend/ # Node.js + Express API (medicines) │ │ ├── Dockerfile │ │ ├── server.js # Express server and API routes │ │ ├── cima-service.js # CIMA API integration with Redis cache @@ -62,6 +65,18 @@ FarmaFinder/ │ │ ├── create-admin.js # Admin user creation script │ │ └── package.json │ │ +│ ├── parapharmacy-api/ # Parapharmacy products API +│ │ ├── Dockerfile +│ │ ├── src/ +│ │ │ ├── server.js # Express + Swagger +│ │ │ ├── config.js # Configuration +│ │ │ ├── models/ +│ │ │ │ └── Product.js +│ │ │ └── routes/ +│ │ │ └── products.js +│ │ ├── README.md +│ │ └── package.json +│ │ │ ├── frontend/ # React + Vite (Desktop/PWA) │ │ ├── Dockerfile │ │ ├── nginx.conf # Nginx config for Docker @@ -79,7 +94,7 @@ FarmaFinder/ │ │ ├── store/ │ │ └── package.json │ │ -│ ├── scraper/ # Puppeteer scraper (standalone) +│ ├── scraper/ # Puppeteer scraper (legacy) │ │ └── package.json │ │ │ └── pip-platform/ # Python FastAPI platform (separate docker-compose) @@ -87,11 +102,29 @@ FarmaFinder/ │ ├── docker-compose.yml │ └── pyproject.toml │ +├── n8n/ # N8N workflow automation +│ ├── workflows/ # Workflow JSON files +│ │ ├── parapharmacy-scraper.json +│ │ └── parapharmacy-manual-scraper.json +│ └── README.md +│ ├── API/ # Shared API source files ├── scripts/ # Build/utility scripts └── docs/ # Documentation + └── parapharmacy.md # Parapharmacy system documentation ``` +## Features + +### Parapharmacy Search +- Scraping de múltiples tiendas españolas (Promofarma, Pharmarket, DocMorris, etc.) +- API REST dedicada con MongoDB +- Scraping automático cada 3 días via N8N +- Búsqueda full-text por nombre, marca y categoría +- [Documentación completa](docs/parapharmacy.md) + +--- + ## Quick Start ### Install dependencies @@ -141,34 +174,53 @@ npm test --workspace=farma-clic-frontend ## Docker Setup -Runs the full stack (backend, frontend, Redis, Postgres) with a single command. +Runs the full stack with a single command. ```bash -# Copy and configure environment (optional - defaults work for local dev) -cp apps/backend/.env.example apps/backend/.env +# Copy and configure environment +cp .env.example .env +# Edit .env with your settings (especially passwords) docker compose up --build ``` -App available at `http://localhost:4000` (frontend) and `http://localhost:3001` (backend API). +### Services + +| Service | URL | Description | +|---------|-----|-------------| +| Frontend | http://localhost:4000 | React web app | +| Backend API | http://localhost:3001 | Medicines API | +| Parapharmacy API | http://localhost:3002 | Parapharmacy products API | +| Swagger Docs | http://localhost:3002/api/docs | API documentation | +| N8N | http://localhost:5678 | Workflow automation | + +### First Run -**First run - create an admin user:** ```bash +# Create admin user for FarmaFinder docker compose exec backend node create-admin.js -# Default: admin / admin123 - change after first login -``` +# Default: admin / admin123 -**Seed sample pharmacies:** -```bash +# Seed sample pharmacies docker compose exec backend node seed.js ``` -**Stop:** +### N8N Setup + +N8N auto-creates an admin account on first start: +- **Email**: admin@farmafinder.com +- **Password**: change-me (configurable in `.env`) + +See [Parapharmacy Documentation](docs/parapharmacy.md) for details. + +### Stop + ```bash docker compose down ``` -Database is persisted in named Docker volumes (`backend_data`, `postgres_data`). To wipe: +### Reset Data + ```bash docker compose down -v ``` @@ -225,18 +277,26 @@ npm run dev ## API Endpoints -### Public -- `GET /api/medicines/search?q=` - Search medicines (CIMA API, cached in Redis) +### Medicines (Backend - Port 3001) + +**Public:** +- `GET /api/medicines/search?q=` - Search medicines (CIMA API) - `GET /api/medicines/:nregistro` - Medicine details - `GET /api/medicines/:nregistro/pharmacies` - Pharmacies selling a medicine - `GET /api/pharmacies` - All pharmacies -### Auth +**Parapharmacy Proxy:** +- `GET /api/products/parapharmacy/search?q=` - Search parapharmacy products +- `GET /api/products/parapharmacy/:id` - Parapharmacy product details +- `GET /api/products/parapharmacy/categories` - List categories +- `GET /api/products/parapharmacy/brands` - List brands + +**Auth:** - `POST /api/auth/login` - Login - `POST /api/auth/logout` - Logout - `GET /api/auth/check` - Check auth status -### Admin (requires authentication) +**Admin:** - `POST /api/admin/pharmacies` - Add pharmacy - `PUT /api/admin/pharmacies/:id` - Update pharmacy - `DELETE /api/admin/pharmacies/:id` - Delete pharmacy @@ -246,6 +306,23 @@ npm run dev - `PUT /api/admin/pharmacy-medicines/:id` - Update price/stock - `DELETE /api/admin/pharmacy-medicines/:id` - Remove link +### Parapharmacy API (Port 3002) + +- `GET /api/products/search?q=` - Search products (full-text) +- `GET /api/products/:id` - Product details +- `GET /api/products` - List products +- `POST /api/products` - Create product +- `POST /api/products/bulk` - Bulk upsert (for scrapers) +- `PUT /api/products/:id` - Update product +- `DELETE /api/products/:id` - Delete product +- `GET /api/products/categories` - List categories +- `GET /api/products/brands` - List brands +- `GET /api/sources` - Configured sources +- `GET /api/health` - Health check +- `GET /api/docs` - Swagger documentation + +See [Parapharmacy Documentation](docs/parapharmacy.md) for details. + ## Database Schema ### SQLite Tables @@ -320,6 +397,32 @@ const ENV = { }; ``` +## N8N Workflow Automation + +N8N handles automated scraping of parapharmacy products. + +### Access +- **URL**: http://localhost:5678 +- **Email**: admin@farmafinder.com +- **Password**: change-me (change in `.env`) + +### Workflows + +| Workflow | Trigger | Description | +|----------|---------|-------------| +| Parapharmacy Scraper | Every 3 days at 2am | Automatic scraping (inactive by default) | +| Parapharmacy Manual Scraper | POST `/webhook/scrape-parapharmacy` | On-demand scraping | + +### Manual Scraping + +```bash +curl -X POST http://localhost:5678/webhook/scrape-parapharmacy +``` + +See [N8N Documentation](n8n/README.md) for details. + +--- + ## Troubleshooting ### Redis Connection Issues diff --git a/docs/parapharmacy.md b/docs/parapharmacy.md new file mode 100644 index 0000000..1575791 --- /dev/null +++ b/docs/parapharmacy.md @@ -0,0 +1,347 @@ +# FarmaFinder Parapharmacy System + +Sistema completo de búsqueda de productos de parafarmacia mediante scraping de múltiples tiendas españolas. + +## Arquitectura + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ N8N Workflows │────▶│ Parapharmacy │────▶│ MongoDB │ +│ (Scraper) │ │ API (Express) │ │ │ +└─────────────────┘ └────────┬─────────┘ └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ FarmaFinder │ + │ Backend │ + └─────────────────┘ +``` + +## Componentes + +| Componente | Puerto | Descripción | +|------------|--------|-------------| +| Parapharmacy API | 3002 | API REST para productos de parafarmacia | +| MongoDB | 27017 | Base de datos de productos | +| N8N | 5678 | Automatización de workflows y scraping | + +--- + +## Parapharmacy API + +### Endpoints + +| Método | Ruta | Descripción | +|--------|------|-------------| +| GET | `/api/products/search?q=term` | Buscar productos (full-text) | +| GET | `/api/products/:id` | Detalle de producto | +| GET | `/api/products` | Listar productos (con filtros) | +| POST | `/api/products` | Crear producto | +| POST | `/api/products/bulk` | Crear/actualizar múltiples (para scraper) | +| PUT | `/api/products/:id` | Actualizar producto | +| DELETE | `/api/products/:id` | Eliminar producto | +| GET | `/api/products/categories` | Listar categorías | +| GET | `/api/products/brands` | Listar marcas | +| GET | `/api/sources` | Fuentes configuradas | +| GET | `/api/health` | Health check | +| GET | `/api/docs` | Swagger UI | + +### Ejemplo de Búsqueda + +```bash +# Buscar "capricare" +curl "http://localhost:3002/api/products/search?q=capricare" + +# Buscar con filtros +curl "http://localhost:3002/api/products/search?q=crema&category=dermocosmetica&brand=bioderma" +``` + +### Respuesta + +```json +{ + "results": [ + { + "_id": "...", + "name": "Capricare 1 Leche en polvo", + "brand": "Capricare", + "category": "Fórmulas lácteas", + "price": 12.99, + "original_price": 14.99, + "image_url": "https://...", + "source": "promofarma", + "source_url": "https://promofarma.com/..." + } + ], + "total": 5, + "page": 1, + "pages": 1 +} +``` + +### Schema MongoDB + +```javascript +{ + name: String, // Nombre del producto + brand: String, // Marca + category: String, // Categoría principal + subcategory: String, // Subcategoría + description: String, // Descripción + image_url: String, // URL de la imagen + source_url: String, // URL en la tienda original + price: Number, // Precio actual + original_price: Number, // Precio anterior (si hay descuento) + currency: String, // EUR por defecto + source: String, // 'promofarma', 'pharmarket', etc. + source_product_id: String, + available: Boolean, // Disponible actualmente + rating: Number, // Valoración (0-5) + review_count: Number, + scraped_at: Date, // Cuándo se scrappeó + created_at: Date, + updated_at: Date +} +``` + +--- + +## N8N Configuration + +### Cuenta de Administrador + +Al iniciar N8N por primera vez, se crea automáticamente una cuenta de administrador: + +| Campo | Valor | +|-------|-------| +| **Email** | admin@farmafinder.com | +| **Password** | change-me | + +> **IMPORTANTE**: Cambia la contraseña después del primer login. + +### Variables de Entorno (`.env`) + +```bash +# N8N Configuration +N8N_USER=admin +N8N_PASSWORD=change-me +N8N_EMAIL=admin@farmafinder.com + +# Parapharmacy API +PARAPHARMACY_API_URL=http://parapharmacy-api:3002 +MONGODB_URI=mongodb://mongodb:27017/parapharmacy +``` + +### Acceso a N8N + +- **URL**: http://localhost:5678 +- **Email**: admin@farmafinder.com +- **Password**: change-me + +--- + +## Workflows de Scraping + +### 1. Parapharmacy Scraper (Automático) + +- **Trigger**: Cada 3 días a las 2:00 AM +- **Estado**: Inactivo por defecto +- **Función**: Scraping automático de Promofarma + +**Para activar:** +1. Ir a http://localhost:5678/workflows +2. Abrir "Parapharmacy Scraper" +3. Hacer clic en "Active" toggle + +### 2. Parapharmacy Manual Scraper (Webhook) + +- **Trigger**: POST a `/webhook/scrape-parapharmacy` +- **Estado**: Activo por defecto +- **Función**: Scraping bajo demanda + +**Uso:** + +```bash +# Scraping con queries por defecto +curl -X POST http://localhost:5678/webhook/scrape-parapharmacy + +# Scraping con queries específicas +curl -X POST http://localhost:5678/webhook/scrape-parapharmacy \ + -H "Content-Type: application/json" \ + -d '{"queries": ["crema hidratante", "protector solar"]}' +``` + +--- + +## Fuentes de Scraping + +| Fuente | URL | Estado | +|--------|-----|--------| +| Promofarma | promofarma.com | ✅ Implementado | +| Pharmarket | pharmarket.es | 🔄 Pendiente | +| DocMorris | docmorris.es | 🔄 Pendiente | +| 1001Farma | 1001farma.net | 🔄 Pendiente | +| Primor | primor.eu | 🔄 Pendiente | +| MiFarma | mifarma.es | 🔄 Pendiente | + +--- + +## Integración con FarmaFinder Backend + +El backend principal proxies las peticiones a la API de parafarmacia: + +### Endpoints Proxy + +| Método | Ruta | Descripción | +|--------|------|-------------| +| GET | `/api/products/parapharmacy/search` | Buscar productos | +| GET | `/api/products/parapharmacy/:id` | Detalle de producto | +| GET | `/api/products/parapharmacy/categories` | Categorías | +| GET | `/api/products/parapharmacy/brands` | Marcas | + +### Ejemplo desde Frontend + +```javascript +// Buscar productos de parafarmacia +const response = await fetch('/api/products/parapharmacy/search?q=capricare'); +const data = await response.json(); +// data.results = [{ name: "Capricare...", price: 12.99, ... }] +``` + +--- + +## Docker Setup + +### Servicios + +```yaml +services: + parapharmacy-api: # Puerto 3002 + mongodb: # Puerto 27017 + n8n: # Puerto 5678 +``` + +### Iniciar + +```bash +# Todos los servicios +docker-compose up -d + +# Solo parafarmacia +docker-compose up -d parapharmacy-api mongodb n8n + +# Ver logs +docker-compose logs -f parapharmacy-api +docker-compose logs -f n8n +``` + +### Detener + +```bash +docker-compose down +``` + +### Limpiar datos + +```bash +# Eliminar volumes (borra datos) +docker-compose down -v +``` + +--- + +## Troubleshooting + +### N8N muestra página /setup + +Verifica que las variables de entorno estén configuradas: + +```bash +N8N_OWNER_EMAIL=admin@farmafinder.com +N8N_OWNER_PASSWORD=change-me +``` + +### Webhook no funciona + +1. Verifica que el workflow esté activo en N8N +2. Revisa el historial de ejecuciones: http://localhost:5678/executions +3. Revisa logs: `docker logs n8n` + +### Productos no se guardan + +1. Verifica que parapharmacy-api esté ejecutándose +2. Revisa logs: `docker logs parapharmacy-api` +3. Verifica que MongoDB esté conectado +4. Prueba el health check: `curl http://localhost:3002/api/health` + +### MongoDB no conecta + +```bash +# Verificar que MongoDB está corriendo +docker-compose ps mongodb + +# Ver logs +docker-compose logs mongodb + +# Reiniciar +docker-compose restart mongodb +``` + +### API devuelve error 500 + +```bash +# Ver logs de la API +docker-compose logs parapharmacy-api + +# Verificar conexión a MongoDB +docker-compose exec mongodb mongosh --eval "db.adminCommand('ping')" +``` + +--- + +## Desarrollo + +### Estructura de Archivos + +``` +apps/parapharmacy-api/ +├── src/ +│ ├── server.js # Express + Swagger +│ ├── config.js # Configuración +│ ├── models/ +│ │ └── Product.js # Schema MongoDB +│ └── routes/ +│ └── products.js # Endpoints +├── Dockerfile +├── package.json +└── README.md + +n8n/ +├── workflows/ +│ ├── parapharmacy-scraper.json +│ └── parapharmacy-manual-scraper.json +└── README.md +``` + +### Ejecutar en Desarrollo + +```bash +# API +cd apps/parapharmacy-api +npm run dev + +# MongoDB (necesario) +docker run -d -p 27017:27017 mongo:7 +``` + +### Tests + +```bash +cd apps/parapharmacy-api +npm test +``` + +### Swagger Docs + +Acceso a documentación interactiva: +http://localhost:3002/api/docs