diff --git a/docs/superpowers/specs/2026-07-06-farmafinder-mobile-design.md b/docs/superpowers/specs/2026-07-06-farmafinder-mobile-design.md new file mode 100644 index 0000000..790cf6a --- /dev/null +++ b/docs/superpowers/specs/2026-07-06-farmafinder-mobile-design.md @@ -0,0 +1,420 @@ +# FarmaFinder Mobile - Especificación de Diseño + +**Fecha**: 2026-07-06 +**Estado**: Aprobado +**Versión**: 1.0 + +--- + +## 1. Resumen + +Crear un segundo frontend en **React Native (Expo)** para FarmaFinder, manteniendo el frontend actual (React + Vite) para Desktop/PWA. El objetivo es lograr una experiencia móvil nativa que permita publicar en App Store y Google Play con mejor rendimiento, UX y mantenibilidad. + +--- + +## 2. Arquitectura + +### 2.1 Estructura del Proyecto + +``` +FarmaFinder/ +├── frontend/ ← React + Vite (Desktop/PWA, mantiene Capacitor) +├── frontend-mobile/ ← Expo + React Native (NUEVO) +│ ├── app/ ← Expo Router (file-based routing) +│ │ ├── _layout.tsx ← Layout raíz +│ │ ├── (tabs)/ ← Bottom tabs +│ │ │ ├── _layout.tsx ← Tab navigator +│ │ │ ├── index.tsx ← Home (búsqueda) +│ │ │ ├── map.tsx ← Mapa de farmacias +│ │ │ └── profile.tsx ← Perfil de usuario +│ │ ├── medicine/[id].tsx ← Detalle de medicamento +│ │ ├── pharmacy/[id].tsx ← Detalle de farmacia +│ │ └── auth/ ← Auth flow +│ ├── components/ ← Componentes React Native +│ ├── services/ ← Lógica de negocio y llamadas API +│ ├── hooks/ ← Custom hooks +│ ├── constants/ ← Colores, tipos, config +│ └── assets/ ← Imágenes, fuentes +├── backend/ ← API compartida (sin cambios) +└── package.json ← Scripts para ambos frontends +``` + +### 2.2 Stack Tecnológico + +| Componente | Tecnología | Justificación | +|------------|------------|---------------| +| Framework | Expo SDK 52+ | Setup rápido, OTA updates, fácil publicación | +| Routing | Expo Router v4 | File-based routing, similar a Next.js | +| Navegación | React Navigation | Bottom tabs + stack navigation | +| State | Zustand | Ligero, sin boilerplate, fácil de usar | +| HTTP Client | Axios | Interceptors, cancelación de requests | +| Cache | TanStack Query | Cache automático, optimistic updates | +| Mapas | react-native-maps | Google Maps provider nativo | +| Barcode | expo-camera | Escaneo de código de barras nativo | +| Storage | AsyncStorage + expo-secure-store | Datos offline + tokens seguros | +| Animaciones | React Native Reanimated 3 | Animaciones fluidas en 60fps | + +--- + +## 3. Estructura de Navegación + +### 3.1 Navegación Principal + +``` +Bottom Tabs +├── Home (🔍) → Búsqueda de medicamentos +├── Mapa (📍) → Mapa de farmacias +└── Perfil (👤) → Perfil de usuario + Admin +``` + +### 3.2 Navegación Detallada + +``` +Home Tab (Stack) +├── index.tsx ← Lista de resultados de búsqueda +└── medicine/[id].tsx ← Detalle de medicamento + +Mapa Tab (Stack) +├── map.tsx ← Mapa con marcadores de farmacias +└── pharmacy/[id].tsx ← Detalle de farmacia + +Perfil Tab (Stack) +├── profile.tsx ← Info de usuario + opciones +├── auth/login.tsx ← Login (si no autenticado) +├── auth/register.tsx ← Registro +└── admin/ ← Panel admin (solo si auth + admin) +``` + +### 3.3 Flujos de Navegación + +- **Auth Flow**: Si no hay token → redirigir a login +- **Admin Flow**: Si usuario es admin → mostrar acceso a admin +- **Deep Linking**: URLs como `farmafinder://medicine/123` abren pantalla específica + +--- + +## 4. Funcionalidades + +### 4.1 MVP (Paridad con Web) + +| Funcionalidad | Descripción | +|---------------|-------------| +| **Búsqueda** | Búsqueda en tiempo real de medicamentos vía API CIMA | +| **Resultados** | Lista de resultados con nombre, principio activo | +| **Detalle medicamento** | Precio, stock, farmacias que lo tienen | +| **Mapa farmacias** | Marcadores en mapa con ubicación | +| **Detalle farmacia** | Dirección, teléfono, medicamentos disponibles | +| **Auth** | Login/registro de usuarios | + +### 4.2 Extras Nativos (NUEVO) + +| Funcionalidad | Descripción | +|---------------|-------------| +| **Push Notifications** | Alertas de disponibilidad de medicamentos favoritos | +| **Escáner código barras** | Escanear medicamentos directamente con cámara | +| **Biometría** | Face ID / Touch ID para login rápido | +| **Deep Links** | Compartir medicamentos/farmacias via URL | +| **Offline Cache** | Medicamentos favoritos accesibles sin conexión | + +--- + +## 5. Integración con la API + +### 5.1 Cliente API + +```typescript +// frontend-mobile/services/api.ts +import axios from 'axios'; + +const API_BASE = __DEV__ + ? 'http://localhost:3001/api' + : 'https://tu-dominio.com/api'; + +export const api = axios.create({ + baseURL: API_BASE, + timeout: 10000, + headers: { 'Content-Type': 'application/json' } +}); + +// Request interceptor para auth token +api.interceptors.request.use((config) => { + const token = getToken(); + if (token) config.headers.Authorization = `Bearer ${token}`; + return config; +}); +``` + +### 5.2 Endpoints + +**Públicos:** +- `GET /api/medicines/search?q=` - Búsqueda de medicamentos +- `GET /api/medicines/:nregistro` - Detalle de medicamento +- `GET /api/medicines/:nregistro/pharmacies` - Farmacias con medicamento +- `GET /api/pharmacies` - Todas las farmacias + +**Autenticados:** +- `POST /api/auth/login` - Login +- `POST /api/auth/logout` - Logout +- `GET /api/auth/check` - Verificar auth + +**Admin:** +- CRUD de farmacias +- Búsqueda de medicamentos para admin +- Vincular medicamentos a farmacias + +### 5.3 Estrategia de Cache + +```typescript +// Con TanStack Query +const { data, isLoading } = useQuery({ + queryKey: ['medicines', searchQuery], + queryFn: () => searchMedicines(searchQuery), + staleTime: 5 * 60 * 1000, // 5 minutos + cacheTime: 30 * 60 * 1000, // 30 minutos +}); +``` + +**Persistencia offline:** +- AsyncStorage para datos no sensibles +- expo-secure-store para tokens y credenciales +- React Query persistor para cache de queries + +--- + +## 6. Diseño Visual + +### 6.1 Design Tokens + +```typescript +// frontend-mobile/constants/theme.ts +export const colors = { + // Primary + primary: '#007AFF', + primaryLight: '#4DA3FF', + + // Semantic + success: '#34C759', // Disponible + danger: '#FF3B30', // Sin stock + warning: '#FF9500', // Stock bajo + + // Neutral + background: '#F2F2F7', + card: '#FFFFFF', + border: '#E5E5EA', + + // Text + text: '#1C1C1E', + textSecondary: '#8E8E93', + textInverse: '#FFFFFF', +}; + +export const spacing = { + xs: 4, + sm: 8, + md: 16, + lg: 24, + xl: 32, +}; + +export const borderRadius = { + sm: 8, + md: 12, + lg: 16, +}; +``` + +### 6.2 Componentes Principales + +| Componente | Descripción | +|------------|-------------| +| **SearchBar** | Input con debounce (300ms) + dropdown de resultados | +| **MedicineCard** | Card con nombre, principio activo, precio, badge de stock | +| **PharmacyMarker** | Marcador personalizado en mapa con info window | +| **StockBadge** | Badge verde (disponible) / rojo (sin stock) | +| **LoadingSpinner** | Spinner nativo durante cargas | +| **ErrorToast** | Toast de error con retry | + +### 6.3 Patrones de Diseño + +- **Cards**: Sombra sutil, border-radius 12px +- **Tipografía**: Sistema nativo (SF Pro en iOS, Roboto en Android) +- **Espaciado**: Escala de 4px base (4, 8, 12, 16, 24, 32) +- **Animaciones**: Reanimated 3 para transiciones y gestos + +--- + +## 7. Extras Nativos (Detalles) + +### 7.1 Push Notifications + +```typescript +// Expo Notifications +import * as Notifications from 'expo-notifications'; + +// Registrar para notificaciones +const registerForPushNotifications = async () => { + const { status } = await Notifications.requestPermissionsAsync(); + if (status !== 'granted') return; + + const token = await Notifications.getExpoPushToken(); + return token.data; +}; + +// Escuchar notificaciones +Notifications.addNotificationReceivedListener((notification) => { + // Mostrar alerta de disponibilidad +}); +``` + +### 7.2 Escáner de Código de Barras + +```typescript +// expo-camera + barcode scanning +import { CameraView } from 'expo-camera'; + + { + // Buscar medicamento por código de barras + searchMedicineByBarcode(data.data); + }} +/> +``` + +### 7.3 Biometría + +```typescript +// expo-local-authentication +import * as LocalAuthentication from 'expo-local-authentication'; + +const authenticateWithBiometrics = async () => { + const hasHardware = await LocalAuthentication.hasHardwareAsync(); + const isEnrolled = await LocalAuthentication.isEnrolledAsync(); + + if (hasHardware && isEnrolled) { + return await LocalAuthentication.authenticateAsync(); + } + return false; +}; +``` + +--- + +## 8. Workflow de Desarrollo + +### 8.1 Scripts + +```json +{ + "scripts": { + "dev:mobile": "cd frontend-mobile && npx expo start", + "dev:mobile:android": "cd frontend-mobile && npx expo start --android", + "dev:mobile:ios": "cd frontend-mobile && npx expo start --ios", + "build:mobile:dev": "cd frontend-mobile && eas build --profile development", + "build:mobile:preview": "cd frontend-mobile && eas build --profile preview", + "build:mobile:prod": "cd frontend-mobile && eas build --profile production", + "submit:android": "cd frontend-mobile && eas submit --platform android", + "submit:ios": "cd frontend-mobile && eas submit --platform ios" + } +} +``` + +### 8.2 EAS Build Profiles + +```json +// frontend-mobile/eas.json +{ + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal" + }, + "production": {} + } +} +``` + +### 8.3 CI/CD + +- **Desarrollo**: Expo Go + hot reload +- **Testing**: EAS Build (preview) → APK/IPA para testing +- **Producción**: EAS Build (production) → Submit a tiendas +- **OTA Updates**: Expo Updates para fixes sin pasar por tienda + +--- + +## 9. Dependencias Principales + +```json +{ + "dependencies": { + "expo": "~52.0.0", + "expo-router": "~4.0.0", + "expo-camera": "~16.0.0", + "expo-notifications": "~0.29.0", + "expo-local-authentication": "~15.0.0", + "expo-secure-store": "~14.0.0", + "react-native": "0.76.0", + "react-native-maps": "1.18.0", + "react-native-reanimated": "~3.16.0", + "react-native-gesture-handler": "~2.20.0", + "@react-navigation/native": "^7.0.0", + "@react-navigation/bottom-tabs": "^7.0.0", + "zustand": "^5.0.0", + "axios": "^1.7.0", + "@tanstack/react-query": "^5.0.0", + "@react-native-async-storage/async-storage": "^2.0.0" + } +} +``` + +--- + +## 10. Criterios de Aceptación + +### MVP +- [ ] Búsqueda de medicamentos funcional +- [ ] Mapa con farmacias mostrando marcadores +- [ ] Detalle de medicamento con precio y stock +- [ ] Detalle de farmacia con ubicación +- [ ] Login/registro funcional +- [ ] Navegación entre pantallas fluida +- [ ] Build de desarrollo funcionando en Expo Go + +### Extras Nativos +- [ ] Push notifications configuradas +- [ ] Escáner de código de barras funcional +- [ ] Biometría para login rápido +- [ ] Deep links configurados +- [ ] Offline cache para favoritos + +### Publicación +- [ ] Build de producción optimizado +- [ ] App Store listing configurado +- [ ] Google Play listing configurado +- [ ] Screenshots y descripción preparados + +--- + +## 11. Riesgos y Mitigaciones + +| Riesgo | Mitigación | +|--------|------------| +| API del backend no preparada para móvil | Revisar endpoints, agregar si es necesario | +| Performance en dispositivos antiguos | Testing en dispositivos低端, optimizar renders | +| Diferencias iOS/Android | Usar componentes nativos, testing en ambas plataformas | +| Mantenimiento de dos frontends | Documentar bien, compartir types cuando sea posible | + +--- + +## 12. Próximos Pasos + +1. Crear estructura del proyecto Expo +2. Configurar routing con Expo Router +3. Implementar cliente API +4. Crear pantallas MVP +5. Implementar extras nativos +6. Testing y optimización +7. Build y publicación en tiendas