Documentos + Homepage rediseñada
Build & Push Docker Images / test-backend (push) Successful in 24s
Build & Push Docker Images / test-frontend (push) Successful in 23s
Build & Push Docker Images / build-backend (push) Successful in 2m22s
Build & Push Docker Images / build-frontend (push) Successful in 57s
Build & Push Docker Images / test-backend (push) Successful in 24s
Build & Push Docker Images / test-frontend (push) Successful in 23s
Build & Push Docker Images / build-backend (push) Successful in 2m22s
Build & Push Docker Images / build-frontend (push) Successful in 57s
This commit is contained in:
@@ -0,0 +1,709 @@
|
||||
# Memoria tecnica FarmaFinder
|
||||
|
||||
## 1. Resumen ejecutivo
|
||||
|
||||
FarmaFinder es una aplicacion web/PWA para buscar medicamentos en la base oficial de CIMA (AEMPS), localizar farmacias que los comercializan y administrar el catalogo de farmacias y sus relaciones con medicamentos. La aplicacion tambien incluye perfil de usuario con ubicacion guardada, geocodificacion, ordenacion por distancia, estados de apertura de farmacias, notificaciones push para medicamentos y un panel de administracion para altas/bajas/importacion de farmacias.
|
||||
|
||||
La base funcional actual esta repartida en cuatro capas principales:
|
||||
|
||||
- `frontend/`: interfaz React + Vite, tambien preparada para PWA y empaquetado Capacitor.
|
||||
- `backend/`: API Express con sesion, autenticacion, persistencia SQLite/PG y notificaciones push.
|
||||
- `API/`: helpers de importacion y normalizacion de farmacias desde fuentes externas.
|
||||
- `android/` e `ios/`: shells nativos generados por Capacitor.
|
||||
|
||||
## 2. Stack tecnologico
|
||||
|
||||
### Frontend
|
||||
|
||||
- React 18
|
||||
- Vite 5
|
||||
- Leaflet + React Leaflet para el mapa
|
||||
- Vitest + Testing Library + JSDOM para tests de UI
|
||||
- PWA con `vite-plugin-pwa`
|
||||
- Capacitor 6 para envoltorio nativo
|
||||
|
||||
### Backend
|
||||
|
||||
- Node.js en modo ESM
|
||||
- Express 4
|
||||
- SQLite como almacenamiento base local
|
||||
- PostgreSQL opcional para usuarios y sesiones cuando `PG_URL` esta definido
|
||||
- Redis para cache de CIMA
|
||||
- `express-session` para sesion de usuario
|
||||
- `bcrypt` para hash de contrasenas
|
||||
- `web-push` para notificaciones push web
|
||||
- `express-rate-limit` para proteccion de endpoints sensibles
|
||||
|
||||
### Integraciones externas
|
||||
|
||||
- CIMA API de la AEMPS para busqueda y detalle de medicamentos
|
||||
- Nominatim / OpenStreetMap para geocodificacion
|
||||
- OpenStreetMap Overpass u otras fuentes JSON para importacion de farmacias
|
||||
- Webhooks externos tipo n8n para importacion de farmacias
|
||||
|
||||
## 3. Estructura del repositorio
|
||||
|
||||
- `frontend/`: SPA principal
|
||||
- `backend/`: API principal y scripts de mantenimiento
|
||||
- `API/`: libreria de importacion de farmacias desde fuentes externas
|
||||
- `scraper/`: utilidades de scraping con Puppeteer
|
||||
- `android/` y `ios/`: proyectos nativos Capacitor
|
||||
- `docker-compose.yml`: entorno completo con backend, frontend, Redis y PostgreSQL
|
||||
|
||||
## 4. Arquitectura funcional
|
||||
|
||||
### Flujo publico
|
||||
|
||||
1. El usuario escribe un medicamento en el buscador.
|
||||
2. El frontend llama a `GET /api/medicines/search`.
|
||||
3. El backend consulta CIMA, filtra resultados y los cachea en Redis.
|
||||
4. Al seleccionar un medicamento, el frontend llama a `GET /api/medicines/:id/pharmacies`.
|
||||
5. El backend devuelve farmacias enlazadas en SQLite/PG con precio, stock, coordenadas y horario.
|
||||
6. La UI permite ordenar por distancia si el usuario tiene ubicacion guardada o concede geolocalizacion.
|
||||
|
||||
### Flujo de administracion
|
||||
|
||||
1. Un admin inicia sesion.
|
||||
2. El panel permite gestionar farmacias, buscar medicamentos en CIMA e importar farmacias externas.
|
||||
3. El admin enlaza medicamentos a farmacias con precio y stock.
|
||||
4. Al crear un nuevo enlace de farmacia-medicamento, el backend dispara notificaciones push a usuarios suscritos.
|
||||
|
||||
### Flujo de perfil y ubicacion
|
||||
|
||||
1. Un usuario autenticado puede editar su perfil.
|
||||
2. Puede guardar direccion y coordenadas manualmente.
|
||||
3. Tambien puede geocodificar su direccion via Nominatim o usar la geolocalizacion del navegador.
|
||||
4. Esa ubicacion se usa en el ordenamiento por distancia en la vista publica.
|
||||
|
||||
## 5. Frontend
|
||||
|
||||
### Punto de entrada
|
||||
|
||||
- `frontend/src/main.jsx` monta `<App />` en `#root`.
|
||||
- Se inicializa el shell nativo con `initNativeShell()`.
|
||||
|
||||
### Componente raiz
|
||||
|
||||
`frontend/src/App.jsx` controla tres vistas:
|
||||
|
||||
- `public`
|
||||
- `admin`
|
||||
- `profile`
|
||||
|
||||
Tambien gestiona:
|
||||
|
||||
- comprobacion de sesion con `GET /api/auth/check`
|
||||
- apertura/cierre del modal de login
|
||||
- cierre de sesion con `POST /api/auth/logout`
|
||||
- panel de notificaciones guardadas
|
||||
|
||||
### Vistas principales
|
||||
|
||||
#### PublicView
|
||||
|
||||
`frontend/src/views/PublicView.jsx`
|
||||
|
||||
Responsabilidades:
|
||||
|
||||
- busqueda de medicamentos con debounce
|
||||
- consulta de farmacias asociadas al medicamento
|
||||
- mapa de farmacias
|
||||
- lista de farmacias con precio, stock, horario y notificaciones
|
||||
- ordenacion por distancia usando ubicacion guardada o geolocalizacion del navegador
|
||||
|
||||
Caracteristicas clave:
|
||||
|
||||
- Si el usuario tiene coordenadas en el perfil, se priorizan sobre la geolocalizacion del navegador.
|
||||
- La lista y el mapa usan la misma ordenacion.
|
||||
- Si no hay coordenadas o el navegador falla, se muestra un mensaje de error contextual.
|
||||
|
||||
#### AdminView
|
||||
|
||||
`frontend/src/views/AdminView.jsx`
|
||||
|
||||
Responsabilidades:
|
||||
|
||||
- autenticar acceso al panel
|
||||
- mostrar tabs de:
|
||||
- farmacias
|
||||
- medicamentos
|
||||
- enlace farmacia-medicamento
|
||||
- logout de admin
|
||||
|
||||
#### ProfileView
|
||||
|
||||
`frontend/src/views/ProfileView.jsx`
|
||||
|
||||
Responsabilidades:
|
||||
|
||||
- editar direccion y coordenadas del usuario
|
||||
- geocodificar la direccion con `/api/geocode`
|
||||
- obtener ubicacion actual del dispositivo
|
||||
- abrir la vista de notificaciones guardadas
|
||||
- cerrar sesion
|
||||
|
||||
## 6. Componentes de UI
|
||||
|
||||
### Busqueda y resultados
|
||||
|
||||
- `frontend/src/components/SearchBar.jsx`
|
||||
- `frontend/src/components/MedicineResults.jsx`
|
||||
- `frontend/src/components/PharmacyList.jsx`
|
||||
- `frontend/src/components/PharmacyMap.jsx`
|
||||
|
||||
#### MedicineResults
|
||||
|
||||
- Lista resultados de CIMA.
|
||||
- Cada card incluye boton de notificaciones para ese medicamento.
|
||||
- Al pulsar la card se abre el detalle de farmacias asociadas.
|
||||
|
||||
#### PharmacyList
|
||||
|
||||
- Muestra farmacias enlazadas al medicamento.
|
||||
- Incluye:
|
||||
- distancia al usuario si existe ubicacion
|
||||
- estado de apertura calculado a partir de `opening_hours`
|
||||
- direccion
|
||||
- telefono
|
||||
- precio
|
||||
- stock
|
||||
- boton de notificacion por farmacia cuando el stock esta agotado
|
||||
|
||||
#### PharmacyMap
|
||||
|
||||
- Muestra farmacias sobre Leaflet.
|
||||
- Usa coordenadas de cada farmacia para ubicarlas en el mapa.
|
||||
|
||||
### Admin components
|
||||
|
||||
- `frontend/src/components/admin/PharmacyManagement.jsx`
|
||||
- `frontend/src/components/admin/MedicineManagement.jsx`
|
||||
- `frontend/src/components/admin/PharmacyMedicineLink.jsx`
|
||||
- `frontend/src/components/admin/LoginForm.jsx`
|
||||
|
||||
#### PharmacyManagement
|
||||
|
||||
- Lista farmacias existentes.
|
||||
- Permite crear, editar y borrar farmacias.
|
||||
- Integra importacion por:
|
||||
- webhook externo
|
||||
- OpenStreetMap / Overpass
|
||||
- URL de open data JSON/GeoJSON
|
||||
- Permite filtrar farmacias por radio geografico.
|
||||
- Permite geocodificar una ciudad para obtener lat/lon/radio de trabajo.
|
||||
- Gestiona horario semanal estructurado.
|
||||
|
||||
#### MedicineManagement
|
||||
|
||||
- Busca medicamentos en CIMA desde el panel admin.
|
||||
- Solo sirve para exploracion y seleccion previa al enlace.
|
||||
|
||||
#### PharmacyMedicineLink
|
||||
|
||||
- Permite seleccionar farmacia y medicamento.
|
||||
- Crea o actualiza el enlace con precio y stock.
|
||||
- Permite editar y eliminar relaciones ya existentes.
|
||||
|
||||
## 7. Utilidades de frontend
|
||||
|
||||
### Geolocalizacion
|
||||
|
||||
`frontend/src/utils/geo.js`
|
||||
|
||||
- `haversineKm()`: calcula distancia entre dos puntos GPS.
|
||||
- `getUserPosition()`: obtiene ubicacion del navegador con validaciones de contexto seguro.
|
||||
- `formatDistance()`: da formato a metros/kilometros.
|
||||
|
||||
### Horarios
|
||||
|
||||
`frontend/src/utils/hours.js`
|
||||
|
||||
- `getOpenStatus()`: interpreta el horario semanal y devuelve un estado legible.
|
||||
- Soporta:
|
||||
- abierto
|
||||
- cerrado
|
||||
- abre a una hora concreta
|
||||
- abre el siguiente dia habil
|
||||
- El formato almacenado es JSON con claves `sun`, `mon`, `tue`, `wed`, `thu`, `fri`, `sat`.
|
||||
|
||||
### Notificaciones
|
||||
|
||||
`frontend/src/utils/notifications.js`
|
||||
|
||||
- comprueba soporte de Push API y Service Worker
|
||||
- obtiene la VAPID public key del backend
|
||||
- registra suscripciones push del navegador
|
||||
- guarda una huella local en `localStorage`
|
||||
- permite suscripcion global por medicamento o por medicamento + farmacia
|
||||
|
||||
### Service worker
|
||||
|
||||
`frontend/src/sw.js`
|
||||
|
||||
- precache de assets PWA
|
||||
- muestra notificaciones al recibir eventos `push`
|
||||
- navega a la URL asociada al click en la notificacion
|
||||
|
||||
## 8. Backend
|
||||
|
||||
### Arranque
|
||||
|
||||
`backend/server.js` es el nucleo de la API. Expone:
|
||||
|
||||
- la aplicacion Express
|
||||
- `initDatabase()`
|
||||
- la conexion `db`
|
||||
|
||||
Si `NODE_ENV !== test`, inicializa DB y levanta el servidor en `PORT` o `3001`.
|
||||
|
||||
### Configuracion basica
|
||||
|
||||
- CORS con credenciales
|
||||
- `express.json()`
|
||||
- session middleware
|
||||
- rate limiting en:
|
||||
- busqueda
|
||||
- login
|
||||
- registro
|
||||
- geocoding
|
||||
|
||||
### Persistencia
|
||||
|
||||
#### SQLite
|
||||
|
||||
Se usa como base local principal:
|
||||
|
||||
- farmacias
|
||||
- relaciones farmacia-medicamento
|
||||
- subscripciones push
|
||||
- fallback de usuarios cuando no hay PostgreSQL
|
||||
|
||||
#### PostgreSQL opcional
|
||||
|
||||
Si existe `PG_URL`, la tabla `users` y el store de sesiones se montan sobre PostgreSQL.
|
||||
|
||||
Esto genera una arquitectura mixta:
|
||||
|
||||
- SQLite para catalogo/relaciones
|
||||
- PostgreSQL para usuarios y sesiones, si se configura
|
||||
|
||||
### Capa de sesion
|
||||
|
||||
- `express-session`
|
||||
- store SQLite o PostgreSQL segun entorno
|
||||
- cookie httpOnly con maxAge de 24h
|
||||
- `trust proxy` configurable con `TRUST_PROXY`
|
||||
|
||||
## 9. Modelo de datos
|
||||
|
||||
### `pharmacies`
|
||||
|
||||
Campos:
|
||||
|
||||
- `id`
|
||||
- `name`
|
||||
- `address`
|
||||
- `phone`
|
||||
- `latitude`
|
||||
- `longitude`
|
||||
- `opening_hours`
|
||||
|
||||
### `pharmacy_medicines`
|
||||
|
||||
Relacion farmacia-medicamento.
|
||||
|
||||
Campos:
|
||||
|
||||
- `id`
|
||||
- `pharmacy_id`
|
||||
- `medicine_nregistro`
|
||||
- `medicine_name`
|
||||
- `price`
|
||||
- `stock`
|
||||
|
||||
Restriccion:
|
||||
|
||||
- `UNIQUE(pharmacy_id, medicine_nregistro)`
|
||||
|
||||
### `users`
|
||||
|
||||
Campos actuales:
|
||||
|
||||
- `id`
|
||||
- `username`
|
||||
- `password_hash`
|
||||
- `is_admin`
|
||||
- `address`
|
||||
- `latitude`
|
||||
- `longitude`
|
||||
- `created_at`
|
||||
|
||||
### `push_subscriptions`
|
||||
|
||||
Subscripciones push globales por medicamento.
|
||||
|
||||
Campos:
|
||||
|
||||
- `id`
|
||||
- `medicine_nregistro`
|
||||
- `medicine_name`
|
||||
- `endpoint`
|
||||
- `p256dh`
|
||||
- `auth`
|
||||
- `user_id`
|
||||
- `created_at`
|
||||
|
||||
### `push_subscriptions_pharmacy`
|
||||
|
||||
Subscripciones push por medicamento y farmacia.
|
||||
|
||||
Campos:
|
||||
|
||||
- `id`
|
||||
- `medicine_nregistro`
|
||||
- `medicine_name`
|
||||
- `pharmacy_id`
|
||||
- `endpoint`
|
||||
- `p256dh`
|
||||
- `auth`
|
||||
- `user_id`
|
||||
- `created_at`
|
||||
|
||||
## 10. API backend
|
||||
|
||||
### Medicamentos
|
||||
|
||||
- `GET /api/medicines/search?q=...`
|
||||
- busca en CIMA con cache Redis
|
||||
- devuelve una lista normalizada
|
||||
- `GET /api/medicines/:medicineId`
|
||||
- devuelve detalle de un medicamento por `nregistro`
|
||||
- `GET /api/medicines/:medicineId/pharmacies`
|
||||
- devuelve farmacias que tienen ese medicamento
|
||||
|
||||
### Farmacias
|
||||
|
||||
- `GET /api/pharmacies`
|
||||
- lista completa de farmacias
|
||||
|
||||
### Autenticacion
|
||||
|
||||
- `POST /api/auth/login`
|
||||
- `POST /api/auth/register`
|
||||
- `POST /api/auth/logout`
|
||||
- `GET /api/auth/check`
|
||||
|
||||
### Perfil
|
||||
|
||||
- `GET /api/users/me`
|
||||
- `PUT /api/users/me`
|
||||
|
||||
### Geocoding
|
||||
|
||||
- `GET /api/geocode?q=...`
|
||||
- autenticado
|
||||
- usa Nominatim
|
||||
- devuelve lat/lon y texto de resultado
|
||||
- `GET /api/admin/geocode?q=...`
|
||||
- solo admin
|
||||
- ademas calcula radio sugerido
|
||||
|
||||
### Admin: farmacias
|
||||
|
||||
- `POST /api/admin/pharmacies`
|
||||
- `PUT /api/admin/pharmacies/:id`
|
||||
- `DELETE /api/admin/pharmacies/:id`
|
||||
- `POST /api/admin/pharmacies/import-webhook`
|
||||
- `POST /api/admin/pharmacies/import-external`
|
||||
|
||||
### Admin: medicamentos y relaciones
|
||||
|
||||
- `GET /api/admin/medicines`
|
||||
- `GET /api/admin/pharmacies/:pharmacyId/medicines`
|
||||
- `POST /api/admin/pharmacy-medicines`
|
||||
- `PUT /api/admin/pharmacy-medicines/:id`
|
||||
- `DELETE /api/admin/pharmacy-medicines/:id`
|
||||
|
||||
### Notificaciones
|
||||
|
||||
- `GET /api/notifications/vapid-public-key`
|
||||
- `POST /api/notifications/subscribe`
|
||||
- `DELETE /api/notifications/unsubscribe`
|
||||
- `GET /api/notifications/mine`
|
||||
- `DELETE /api/notifications/mine`
|
||||
|
||||
## 11. Capa de importacion externa
|
||||
|
||||
La carpeta `API/` no expone un servidor HTTP propio, sino funciones reutilizables para importar farmacias desde distintas fuentes.
|
||||
|
||||
### `API/index.js`
|
||||
|
||||
- `fetchPharmaciesExternal(opts)`
|
||||
- `source = 'osm'`
|
||||
- `source = 'openData'`
|
||||
- decide el extractor adecuado segun la fuente
|
||||
|
||||
### `API/normalize.js`
|
||||
|
||||
- `buildAddressFromOsmTags()`
|
||||
- `osmElementToPharmacy()`
|
||||
- normaliza nodos Overpass a un formato comun de farmacia
|
||||
- parsea horarios OSM si existen
|
||||
|
||||
### `API/opening-hours-osm.js`
|
||||
|
||||
- parser de un subconjunto de `opening_hours`
|
||||
- soporta:
|
||||
- `24/7`
|
||||
- rangos semanales
|
||||
- dias multiples
|
||||
- `off` / `closed`
|
||||
- franjas partidas resumidas
|
||||
|
||||
### `backend/farmacias-webhook-import.js`
|
||||
|
||||
- importa datos desde un webhook HTTP
|
||||
- normaliza campos en espanol o ingles
|
||||
- acepta ubicacion en distintas variantes
|
||||
- extrae horarios si vienen en formato OSM
|
||||
- inserta o salta duplicados con estadisticas
|
||||
|
||||
## 12. CIMA y cache
|
||||
|
||||
`backend/cima-service.js` implementa la integracion con CIMA.
|
||||
|
||||
### Busqueda
|
||||
|
||||
- consulta `https://cima.aemps.es/cima/rest/medicamentos`
|
||||
- usa el parametro `nombre`
|
||||
- normaliza el resultado a campos internos:
|
||||
- `id`
|
||||
- `nregistro`
|
||||
- `name`
|
||||
- `active_ingredient`
|
||||
- `dosage`
|
||||
- `form`
|
||||
- `formSimplified`
|
||||
- `laboratory`
|
||||
- `prescription`
|
||||
- `commercialized`
|
||||
- `generic`
|
||||
- `photos`
|
||||
- `docs`
|
||||
|
||||
### Detalle
|
||||
|
||||
- consulta `GET /medicamento/:nregistro`
|
||||
- cachea por mas tiempo que la busqueda
|
||||
|
||||
### Cache
|
||||
|
||||
- Redis guarda resultados de busqueda y detalle
|
||||
- si CIMA falla, se intenta devolver cache obsoleto si existe
|
||||
|
||||
## 13. Notificaciones push
|
||||
|
||||
### Estado actual
|
||||
|
||||
La app ya soporta notificaciones push web completas.
|
||||
|
||||
### Backend
|
||||
|
||||
- usa VAPID si `VAPID_PUBLIC_KEY` y `VAPID_PRIVATE_KEY` existen
|
||||
- si faltan, push queda desactivado con respuesta `503`
|
||||
- al crear una relacion nueva farmacia-medicamento, se ejecuta `sendPushForMedicine()`
|
||||
- se deduplican endpoints para evitar notificacion doble global + farmacia
|
||||
- si el endpoint devuelve `404` o `410`, la suscripcion se limpia
|
||||
|
||||
### Frontend
|
||||
|
||||
- permite suscripcion global por medicamento
|
||||
- permite suscripcion por medicamento + farmacia
|
||||
- el icono de campana refleja el estado local
|
||||
- la vista `Saved notifications` permite ver y borrar suscripciones guardadas del usuario
|
||||
|
||||
## 14. PWA y capa nativa
|
||||
|
||||
### PWA
|
||||
|
||||
- existe `frontend/src/sw.js`
|
||||
- hay assets publicos de icono
|
||||
- la app esta pensada para funcionar como PWA instalable
|
||||
|
||||
### Capacitor
|
||||
|
||||
- `capacitor.config.json`
|
||||
- `android/`
|
||||
- `ios/`
|
||||
|
||||
El proyecto esta preparado para empaquetarse como app nativa. La documentacion de `NATIVE.md` indica que no hay una base de codigo separada para Android e iOS; la UI real vive en `frontend/`.
|
||||
|
||||
## 15. Scripts y comandos
|
||||
|
||||
### Raiz
|
||||
|
||||
- `npm run dev`: backend + frontend en paralelo
|
||||
- `npm run start`: backend + preview frontend
|
||||
- `npm run install:all`: instala dependencias raiz, backend y frontend
|
||||
- `npm run build:web`: build de frontend
|
||||
- `npm run cap:sync`: build web + sync Capacitor
|
||||
|
||||
### Backend
|
||||
|
||||
- `npm start`
|
||||
- `npm run dev`
|
||||
- `npm run seed`
|
||||
- `npm run create-admin`
|
||||
- `npm run migrate`
|
||||
- `npm run import-farmacias`
|
||||
- `npm test`
|
||||
|
||||
### Frontend
|
||||
|
||||
- `npm run dev`
|
||||
- `npm run build`
|
||||
- `npm run preview`
|
||||
- `npm run test`
|
||||
|
||||
## 16. Docker
|
||||
|
||||
`docker-compose.yml` levanta:
|
||||
|
||||
- `redis`
|
||||
- `postgres`
|
||||
- `backend`
|
||||
- `frontend`
|
||||
|
||||
Puertos:
|
||||
|
||||
- frontend: `3000`
|
||||
- backend: `3001`
|
||||
|
||||
Persistencia:
|
||||
|
||||
- `backend_data` para la DB SQLite del backend
|
||||
- `postgres_data` para PostgreSQL
|
||||
|
||||
## 17. Variables de entorno
|
||||
|
||||
### Backend
|
||||
|
||||
- `PORT`
|
||||
- `SESSION_SECRET`
|
||||
- `CORS_ORIGIN`
|
||||
- `FARMACIAS_WEBHOOK_URL`
|
||||
- `REDIS_HOST`
|
||||
- `REDIS_PORT`
|
||||
- `REDIS_PASSWORD`
|
||||
- `DATABASE_PATH`
|
||||
- `PG_URL`
|
||||
- `TRUST_PROXY`
|
||||
- `VAPID_PUBLIC_KEY`
|
||||
- `VAPID_PRIVATE_KEY`
|
||||
- `VAPID_SUBJECT`
|
||||
- `NODE_ENV`
|
||||
|
||||
### App
|
||||
|
||||
- en produccion, el frontend debe poder resolver la URL del backend segun despliegue
|
||||
- en native shell, el manual `NATIVE.md` indica que conviene usar URL absoluta o servir el PWA desplegado
|
||||
|
||||
## 18. Seeds, migraciones y administracion
|
||||
|
||||
### `backend/seed.js`
|
||||
|
||||
- crea tablas basicas
|
||||
- inserta farmacias y medicamentos de ejemplo
|
||||
- genera relaciones ficticias usando `EXAMPLE_...`
|
||||
- actualmente es util para demos, no como dato real
|
||||
|
||||
### `backend/create-admin.js`
|
||||
|
||||
- crea usuario admin en SQLite o PostgreSQL segun `PG_URL`
|
||||
- por defecto:
|
||||
- usuario: `admin`
|
||||
- password: `admin123`
|
||||
|
||||
### `backend/migrate.js`
|
||||
|
||||
- migracion para el cambio historico de `medicine_id` a `medicine_nregistro`
|
||||
- la tabla `medicines` antigua se conserva como referencia si existe
|
||||
|
||||
## 19. Tests
|
||||
|
||||
### Backend
|
||||
|
||||
- `backend/__tests__/server.test.js`
|
||||
- valida busqueda vacia
|
||||
- valida login incorrecto
|
||||
- valida proteccion de rutas admin
|
||||
- valida creacion de farmacia autenticado
|
||||
- `backend/__tests__/opening-hours-osm.test.js`
|
||||
- cubre parser de horarios OSM
|
||||
|
||||
### Frontend
|
||||
|
||||
- existe configuracion de Vitest
|
||||
- hay `frontend/src/App.test.jsx`
|
||||
- la cobertura visible en el repo parece enfocada a smoke tests y utilidades
|
||||
|
||||
## 20. Observaciones tecnicas y limites actuales
|
||||
|
||||
1. El backend mezcla SQLite y PostgreSQL segun entorno. Esto funciona, pero introduce dos rutas de persistencia para usuarios y sesiones.
|
||||
2. Los medicamentos no se guardan localmente como catalogo propio; se consumen desde CIMA en tiempo real y se cachean en Redis.
|
||||
3. Los enlaces farmacia-medicamento dependen de `nregistro` de CIMA, no de un ID interno de medicamentos.
|
||||
4. Las notificaciones push son web push; en shells nativos siguen la logica del navegador/PWA, no una integracion FCM/APNs independiente.
|
||||
5. La importacion de farmacias depende de la calidad de la fuente externa y de la normalizacion de campos.
|
||||
6. El seed actual contiene datos de ejemplo y relaciones ficticias; no representa datos de produccion.
|
||||
|
||||
## 21. Conclusiones
|
||||
|
||||
El estado actual de FarmaFinder es el de una plataforma funcional orientada a consulta y administracion de farmacias y medicamentos, con un backend ya bastante consolidado: autentica usuarios, controla roles, persiste relaciones, geocodifica, importa fuentes externas, cachea CIMA y dispara push notifications. La parte de frontend acompana ese backend con un flujo publico de busqueda, un perfil con ubicacion y un panel admin operativo.
|
||||
|
||||
Si quieres, el siguiente paso puede ser convertir esta memoria en una version formal de entrega, con estilo academico o empresarial, o bien en un documento mas tecnico con diagramas de arquitectura y secuencia.
|
||||
|
||||
## 22. Next steps propuestos
|
||||
|
||||
El siguiente paso funcional natural para FarmaFinder seria incorporar el escaneo de la TSI, de forma que el usuario pueda identificar rapidamente su perfil asistencial y, a partir de ahi, cruzar su necesidad con el stock real disponible en farmacias.
|
||||
|
||||
### Objetivo
|
||||
|
||||
- Capturar la informacion de la tarjeta sanitaria individual mediante escaneo.
|
||||
- Asociar esa informacion al perfil del usuario de manera segura.
|
||||
- Recuperar o inferir los medicamentos relevantes para el usuario.
|
||||
- Contrastar esos medicamentos con el stock de farmacias cercanas.
|
||||
- Permitir actuar si no hay stock disponible, por ejemplo:
|
||||
- reservar una farmacia concreta
|
||||
- generar una solicitud de pedido
|
||||
- iniciar un flujo de aviso o sustitucion
|
||||
|
||||
### Flujo funcional propuesto
|
||||
|
||||
1. El usuario abre el escaner de TSI desde la app.
|
||||
2. La app lee la tarjeta y extrae los identificadores necesarios.
|
||||
3. El backend valida la informacion y la vincula al usuario autenticado.
|
||||
4. Se obtiene la lista de medicamentos asociados o derivados del contexto del usuario.
|
||||
5. El sistema cruza esa lista con:
|
||||
- farmacias cercanas
|
||||
- stock disponible
|
||||
- precio
|
||||
- horario
|
||||
6. Si no existe stock suficiente, la app muestra alternativas y acciones posibles.
|
||||
|
||||
### Consideraciones tecnicas
|
||||
|
||||
- Esta funcionalidad requiere definir el formato exacto de lectura de la TSI y las fuentes de datos sanitarias a consultar.
|
||||
- Debe tratarse como una funcionalidad sensible, con control de acceso estricto y minimizacion de datos.
|
||||
- El escaneo deberia integrarse con el mismo modelo de ubicacion, autenticacion y notificaciones que ya existe.
|
||||
- La logica de contraste stock/medicamento encaja bien con el modelo actual de `pharmacy_medicines`, pero probablemente exigiria ampliar la capa de negocio para soportar reservas, pedidos o estados intermedios.
|
||||
|
||||
### Riesgos y dependencias
|
||||
|
||||
- Dependencia de la integracion real con sistemas sanitarios externos.
|
||||
- Posible necesidad de cumplimiento legal adicional por el tipo de dato tratado.
|
||||
- Definicion de si el sistema solo informa de disponibilidad o si tambien permite operar pedidos/reservas.
|
||||
- Necesidad de auditar trazabilidad, consentimiento y control de uso de datos.
|
||||
|
||||
### Resultado esperado
|
||||
|
||||
Esta ampliacion convertiria FarmaFinder de un buscador de disponibilidad a un asistente operativo de acceso al medicamento, capaz de ayudar al usuario a pasar de la consulta del stock a la accion cuando no exista disponibilidad inmediata.
|
||||
Reference in New Issue
Block a user