619 lines
16 KiB
Markdown
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
|
|
|