Files
FarmaFinder/README.md
T
2026-07-06 12:54:55 +02:00

619 lines
16 KiB
Markdown

# 💊 FarmaFinder
A web application to search for medicines from the official Spanish CIMA database and find which pharmacies sell them.
## ✨ Features
### Web App (Desktop/PWA)
- 🔍 **Real-time medicine search** from CIMA API (Agencia Española de Medicamentos)
- 💾 **Redis caching** for improved performance
- 📍 View pharmacies that sell a specific medicine
- 💰 See prices and stock availability
- 📱 Responsive design for mobile and desktop
- ⚙️ **Admin Panel** - Manage pharmacies and link medicines
- 🔐 **Secure authentication** - Login required to access admin features
- Add, edit, and delete pharmacies
- Search medicines from CIMA database
- Link medicines to pharmacies with prices and stock
### Mobile App (React Native)
- 📱 **Native iOS/Android** experience with Expo
- 🔍 **Medicine search** with real-time results
- 🗺️ **Interactive map** with pharmacy markers
- 📷 **Barcode scanner** for quick medicine lookup
- 🔔 **Push notifications** for availability alerts
- 🔐 **Biometric authentication** (Face ID / Touch ID)
- 💾 **Offline cache** for favorite medicines
## 🛠️ Tech Stack
### Backend
- **Runtime**: Node.js + Express
- **Database**: SQLite (for pharmacies and relationships)
- **Cache**: Redis
- **External API**: CIMA (Centro de Información online de Medicamentos de la AEMPS)
### Frontend (Web/PWA)
- **Framework**: React + Vite
- **Mobile wrapper**: Capacitor (for hybrid mobile builds)
### Frontend (Mobile - React Native)
- **Framework**: Expo SDK 57 + React Native
- **Navigation**: Expo Router v4
- **State**: Zustand
- **HTTP**: Axios + TanStack Query
- **Maps**: react-native-maps
- **Camera**: expo-camera (barcode scanning)
- **Auth**: expo-local-authentication (biometrics)
- **Notifications**: expo-notifications
- **Build**: EAS Build
## 📋 Prerequisites
- Node.js (v18 or higher)
- npm or yarn
- **Redis server** (v6.0 or higher)
## 🐳 Docker Setup (Recommended)
Runs the full stack (backend, frontend, Redis) with a single command.
**Prerequisites**: Docker and Docker Compose v2.
```bash
# Copy and configure environment (optional — defaults work for local dev)
cp backend/.env.example backend/.env
# Edit backend/.env to set SESSION_SECRET and any other vars
docker compose up --build
```
App available at `http://localhost:3000`.
**First run — create an admin user:**
```bash
docker compose exec backend node create-admin.js
# Default: admin / admin123 — change after first login
```
**Seed sample pharmacies:**
```bash
docker compose exec backend node seed.js
```
**Stop:**
```bash
docker compose down
```
Database is persisted in a named Docker volume (`backend_data`). To wipe it:
```bash
docker compose down -v
```
---
## 🚀 Manual Setup Instructions
### 1. Install Redis
**On Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install redis-server
sudo systemctl start redis-server
sudo systemctl enable redis-server
```
**On macOS (using Homebrew):**
```bash
brew install redis
brew services start redis
```
**On Windows:**
Download and install from: https://redis.io/download
**Using Docker:**
```bash
docker run -d -p 6379:6379 redis:alpine
```
Verify Redis is running:
```bash
redis-cli ping
# Should respond with: PONG
```
### 2. Install Application Dependencies
**Install backend dependencies:**
```bash
cd backend
npm install
```
**Install frontend dependencies:**
```bash
cd ../frontend
npm install
```
### 3. Configure Environment (Optional)
Create a `.env` file in the `backend` directory if you need custom Redis settings:
```env
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
SESSION_SECRET=your-secret-key-here
```
### 4. Initialize Database
**Seed the database with sample pharmacies:**
```bash
cd backend
npm run seed
```
**Create admin user:**
```bash
npm run create-admin
```
This creates a default admin user with:
- Username: `admin`
- Password: `admin123`
⚠️ **Important**: Change the default password after first login!
You can customize credentials using environment variables:
```bash
ADMIN_USERNAME=myadmin ADMIN_PASSWORD=mypassword npm run create-admin
```
### 5. Running the Application
**Start Redis** (if not running):
```bash
redis-server
```
**Start the backend server:**
```bash
cd backend
npm start
```
The backend will run on `http://localhost:3001`
**Start the frontend development server:**
```bash
cd frontend
npm run dev
```
The frontend will run on `http://localhost:3000`
**Open your browser** and navigate to `http://localhost:3000`
## 🎯 How to Use
### Public Search
1. Type the name of a medicine in the search bar
2. The app will search the CIMA database in real-time
3. Click on a medicine to see which pharmacies have it
4. View prices and stock availability
### Admin Panel
1. Click the "⚙️ Admin Panel" button
2. Login with your credentials (default: `admin` / `admin123`)
3. **Pharmacies Tab**: Add, edit, or delete pharmacies
4. **Medicines Tab**: Search medicines from the CIMA database
5. **Link Medicine Tab**: Associate medicines with pharmacies and set prices/stock
## 📁 Project Structure
```
FarmaFinder/
├── docker-compose.yml # Full stack: backend + frontend + Redis
├── backend/
│ ├── Dockerfile
│ ├── server.js # Express server and API routes
│ ├── cima-service.js # CIMA API integration with Redis cache
│ ├── redis-client.js # Redis connection configuration
│ ├── seed.js # Database seeding script
│ ├── create-admin.js # Admin user creation script
│ ├── .env.example # Environment variable template
│ └── package.json
├── frontend/ # React + Vite (Desktop/PWA)
│ ├── Dockerfile
│ ├── nginx.conf # Nginx config (Docker): serves SPA + proxies /api
│ ├── src/
│ │ ├── components/ # React components
│ │ │ ├── admin/ # Admin panel components
│ │ │ ├── PharmacyMap.jsx # Leaflet map (OpenStreetMap)
│ │ │ └── ...
│ │ ├── views/ # View components (Public/Admin)
│ │ ├── App.jsx # Main app component
│ │ └── main.jsx # Entry point
│ ├── index.html
│ └── package.json
├── frontend-mobile/ # Expo + React Native (iOS/Android)
│ ├── app/
│ │ ├── _layout.tsx # Root layout with providers
│ │ ├── (tabs)/ # Bottom tab navigation
│ │ │ ├── index.tsx # Home (medicine search)
│ │ │ ├── map.tsx # Pharmacy map
│ │ │ └── profile.tsx # User profile
│ │ ├── medicine/[id].tsx # Medicine detail
│ │ ├── pharmacy/[id].tsx # Pharmacy detail
│ │ ├── auth/ # Login/Register screens
│ │ └── scanner.tsx # Barcode scanner
│ ├── components/ # Reusable UI components
│ ├── services/ # API and business logic
│ ├── store/ # Zustand state management
│ ├── hooks/ # Custom React hooks
│ ├── constants/ # Theme and config
│ ├── types/ # TypeScript types
│ ├── eas.json # EAS Build configuration
│ └── package.json
├── android/ # Capacitor Android project
├── ios/ # Capacitor iOS project
└── README.md
```
## 🔌 API Endpoints
### Public API
- `GET /api/medicines/search?q=<query>` - Search medicines from CIMA API (cached in Redis)
- `GET /api/medicines/:nregistro` - Get medicine details from CIMA
- `GET /api/medicines/:nregistro/pharmacies` - Get pharmacies selling a medicine
- `GET /api/pharmacies` - Get all pharmacies
### Authentication API
- `POST /api/auth/login` - Login (requires username and password)
- `POST /api/auth/logout` - Logout
- `GET /api/auth/check` - Check authentication status
### Admin API (All require authentication)
- `POST /api/admin/pharmacies` - Add a new pharmacy
- `PUT /api/admin/pharmacies/:id` - Update a pharmacy
- `DELETE /api/admin/pharmacies/:id` - Delete a pharmacy
- `GET /api/admin/medicines?q=<query>` - Search medicines from CIMA (for admin)
- `GET /api/admin/pharmacies/:id/medicines` - Get medicines linked to a pharmacy
- `POST /api/admin/pharmacy-medicines` - Link medicine to pharmacy
- `PUT /api/admin/pharmacy-medicines/:id` - Update price/stock
- `DELETE /api/admin/pharmacy-medicines/:id` - Remove medicine from pharmacy
## 💾 Database Schema
### SQLite Tables
**pharmacies**
- `id`: Integer (Primary Key)
- `name`: Text (Pharmacy name)
- `address`: Text (Full address)
- `phone`: Text (Contact phone)
- `latitude`: Real (GPS coordinate)
- `longitude`: Real (GPS coordinate)
**pharmacy_medicines**
- `id`: Integer (Primary Key)
- `pharmacy_id`: Integer (Foreign Key → pharmacies.id)
- `medicine_nregistro`: Text (CIMA medicine registration number)
- `medicine_name`: Text (Cached medicine name)
- `price`: Real (Price in EUR)
- `stock`: Integer (Available units)
**users**
- `id`: Integer (Primary Key)
- `username`: Text (Unique)
- `password_hash`: Text (Bcrypt hashed)
- `created_at`: DateTime
### Redis Cache Structure
- `medicines:search:{query}` - Search results (TTL: 1 hour)
- `medicine:{nregistro}` - Medicine details (TTL: 24 hours)
## 🔧 Architecture Changes
### Migration from Local Database to CIMA API
The application now uses the **CIMA (Centro de Información online de Medicamentos)** API as the source of truth for medicine data, with Redis caching for performance:
**Benefits:**
- ✅ Always up-to-date medicine information
- ✅ Official data from Spanish health authorities
- ✅ Reduced database maintenance
- ✅ Fast responses thanks to Redis cache
- ✅ Fallback to stale cache if API is down
**Changes:**
- Medicines are no longer stored locally in SQLite
- Medicine searches query the CIMA API
- Results are cached in Redis for performance
- `pharmacy_medicines` now uses `medicine_nregistro` (CIMA registration number) instead of local `medicine_id`
## 📱 Mobile App Setup (React Native)
### Prerequisites
- Node.js (v18 or higher)
- npm or yarn
- **Expo CLI**: `npm install -g expo-cli`
- **EAS CLI**: `npm install -g eas-cli`
- **iOS**: Xcode (Mac only) + CocoaPods
- **Android**: Android Studio + Android SDK
### Quick Start
```bash
# Install all dependencies (backend + web + mobile)
npm run install:all
# Start mobile development server
npm run dev:mobile
# Scan QR code with Expo Go app (iOS/Android)
```
### Development Build
For native features (camera, biometrics, notifications), use a development build:
```bash
# Install EAS CLI
npm install -g eas-cli
# Login to Expo
eas login
# Create development build
eas build --profile development --platform ios
eas build --profile development --platform android
```
### Project Structure
```
frontend-mobile/
├── app/ # Expo Router screens
│ ├── (tabs)/ # Bottom tab navigation
│ ├── auth/ # Login/Register
│ ├── medicine/ # Medicine detail
│ ├── pharmacy/ # Pharmacy detail
│ └── scanner.tsx # Barcode scanner
├── components/ # Reusable UI components
├── services/ # API and business logic
├── store/ # Zustand state management
├── hooks/ # Custom React hooks
├── constants/ # Theme and config
└── types/ # TypeScript types
```
### Native Features
| Feature | Implementation |
|---------|---------------|
| Barcode Scanner | `expo-camera` with `CameraView` |
| Push Notifications | `expo-notifications` |
| Biometrics | `expo-local-authentication` |
| Maps | `react-native-maps` |
| Secure Storage | `expo-secure-store` |
### EAS Build Profiles
| Profile | Platform | Build Type | Use Case |
|---------|----------|------------|----------|
| `development` | iOS | Simulator | Local testing on Mac |
| `development` | Android | APK | Local testing on device |
| `preview` | Android | APK | Internal testing & sharing |
| `production` | Android | AAB | Google Play Store submission |
**Note:** iOS builds require Apple Developer account ($99/year) and are configured separately.
### Environment Configuration
The mobile app uses the same backend API as the web app. Configure the API URL in:
```typescript
// frontend-mobile/constants/config.ts
const ENV = {
development: {
API_BASE_URL: 'http://localhost:3001/api',
},
production: {
API_BASE_URL: 'https://your-production-api.com/api',
},
};
```
## 🚀 Production Deployment (Mobile)
### Distribution Flow
```
Development → EAS Build → App Store / Google Play → User Device
```
The mobile app is a **native application** that runs directly on the device. No Docker or server needed - users download it from the app stores.
### Step 1: Setup Expo Account
```bash
# Install EAS CLI
npm install -g eas-cli
# Create account at https://expo.dev
# Login
eas login
```
### Step 2: Initialize EAS Project
```bash
cd frontend-mobile
eas init
```
This generates a `projectId` - add it to `app.json`:
```json
"extra": {
"eas": {
"projectId": "your-project-id"
}
}
```
### Step 3: Configure Credentials
**Android (Google Play):**
1. Create developer account ($25 one-time fee)
2. Create project in Google Cloud Console
3. Enable Play Developer API
4. Download `google-service-account.json`
5. Place in `frontend-mobile/` directory
**iOS (App Store):**
1. Join Apple Developer Program ($99/year)
2. Create App ID in Apple Developer portal
3. Generate certificates and provisioning profiles
4. Update `eas.json` with your credentials
### Step 4: Build for Production
```bash
# Android (Google Play)
eas build --profile production --platform android
# iOS (App Store)
eas build --profile production --platform ios
```
### Step 5: Submit to Stores
```bash
# Submit to Google Play
eas submit --profile production --platform android
# Submit to App Store
eas submit --profile production --platform ios
```
### OTA Updates (Without App Store Review)
Push updates directly to users without going through store review:
```bash
# Install expo-updates
npx expo install expo-updates
# Send update
eas update --branch production --message "Fix: improved search"
```
### Useful Commands
| Command | Description |
|---------|-------------|
| `eas build:list` | View previous builds |
| `eas build:cancel <id>` | Cancel a build |
| `eas submit:list` | View previous submissions |
| `eas update` | Send OTA update |
## 🐛 Troubleshooting
### Redis Connection Issues
If you see "Redis Client Error":
```bash
# Check if Redis is running
redis-cli ping
# Start Redis if needed
redis-server
```
### CIMA API Timeout
If medicine searches are slow or failing:
- Check your internet connection
- The CIMA API may be temporarily unavailable
- The app will use cached data if available
### Database Issues
Reset the database:
```bash
cd backend
rm database.sqlite
npm run seed
npm run create-admin
```
## 📝 Development
### Backend
**Start with auto-reload:**
```bash
cd backend
npm run dev
```
### Frontend (Web/PWA)
**Start development server:**
```bash
cd frontend
npm run dev
```
### Frontend (Mobile - React Native)
**Install all dependencies:**
```bash
npm run install:all
```
**Start Expo dev server:**
```bash
npm run dev:mobile
```
**Start for specific platform:**
```bash
npm run dev:mobile:android # Android emulator
npm run dev:mobile:ios # iOS simulator
```
**Build with EAS:**
```bash
npm run build:mobile # Production build
```
**Submit to stores:**
```bash
npm run submit:android # Google Play
npm run submit:ios # App Store
```
### Clear Redis cache
```bash
redis-cli FLUSHALL
```
## 🌐 External Resources
- **CIMA API**: https://cima.aemps.es/
- **Redis Documentation**: https://redis.io/documentation
- **React Documentation**: https://react.dev
- **Express Documentation**: https://expressjs.com
## 📄 License
ISC