Documentation Index
Fetch the complete documentation index at: https://wiki.vivla.com/llms.txt
Use this file to discover all available pages before exploring further.
Servicios Compartidos
Ubicación: src/shared/services/
Los servicios encapsulan lógica de infraestructura y comunicación con sistemas externos. Todos son singletons o funciones puras sin estado de UI.
API Client
Archivo: api/client.ts
El cliente HTTP central de la aplicación, construido sobre Axios.
Configuración
| Parámetro | Valor | Descripción |
|---|
| Timeout | 30 segundos | Tiempo máximo por request |
| Token caching | 5 segundos | Evita lecturas repetidas al SecureStore |
| Retry | 3 intentos, 500ms delay | Vía axios-retry, solo para errores de red |
| Idioma | Query param automático | Inyecta el idioma actual del usuario |
| Guest mode | Soportado | Permite requests sin autenticación |
Interceptores
- Obtiene el access token (con cache de 5s) 2. Agrega header
Authorization: Bearer {token} 3.
Inyecta el idioma como query parameter 4. Si el token está expirado, intenta refresh antes de
enviar
- Retorna
response.data directamente 2. En caso de 401: intenta refresh del token 3. Encola
requests pendientes mientras se refresca el token 4. Reintenta requests encolados con el nuevo
token
Métodos disponibles
apiClient.get<T>(url, config?)
apiClient.post<T>(url, data?, config?)
apiClient.put<T>(url, data?, config?)
apiClient.patch<T>(url, data?, config?)
apiClient.delete<T>(url, config?)
apiClient.request<T>(config)
Nunca instancies un segundo cliente Axios. Usa siempre apiClient exportado desde este módulo
para garantizar la inyección de tokens y el manejo de refresh.
Error Handler
Archivo: api/errorHandler.ts
Clasifica y procesa errores de red para mostrar mensajes amigables al usuario e informar a Sentry.
Clasificación de errores
| Tipo | Condición | Acción |
|---|
| Timeout | ECONNABORTED o code === 'TIMEOUT' | Mensaje de timeout al usuario |
| DNS | ENOTFOUND | Mensaje de conexión |
| TLS | Error de certificado | Mensaje de seguridad |
| Cancelled | CancelledError o abort | Silenciado |
| Unknown | Cualquier otro | Mensaje genérico + reporte a Sentry |
Integración con Sentry
- Agrega breadcrumbs con detalles del request (URL, método, status)
- Reporta errores no cancelados como excepciones
- Incluye contexto extra: response body, headers relevantes
Mock Response Handler
Archivo: api/mockResponseHandler.ts
Este servicio solo está activo en modo desarrollo. En producción no se incluye en el bundle.
Proporciona respuestas simuladas para endpoints durante desarrollo local:
register — Simula registro de usuario
deleteAccount — Simula eliminación de cuenta
- Endpoints de booking — Simula flujos de reserva
Secure Storage
Archivo: storage/secureStorage.ts
Wrapper de expo-secure-store con retry y backoff exponencial.
Configuración de retry
| Parámetro | Valor |
|---|
| Máximo de intentos | 3 |
| Estrategia | Backoff exponencial |
| Primer retry | ~100ms |
Datos gestionados
Tokens de autenticación
- Access token - Refresh token - Token expiry timestamp
Datos de usuario
- Información del perfil serializada - Se almacena como JSON cifrado
Métodos
| Método | Descripción |
|---|
storeTokens(access, refresh, expiry) | Guarda los tres tokens de autenticación |
getTokens() | Recupera access + refresh + expiry |
getAccessToken() | Obtiene solo el access token |
getRefreshToken() | Obtiene solo el refresh token |
storeUserData(data) | Persiste datos del usuario |
getUserData() | Recupera datos del usuario |
clearAllAuthData() | Elimina todos los datos de autenticación |
isTokenExpired() | Verifica si el access token ha expirado |
Nunca almacenes tokens o datos sensibles en AsyncStorage. Usa siempre SecureStorage para
información de autenticación.
Upload Service
Archivo: uploadService.ts
Gestiona la subida de imágenes a S3 con compresión previa y tracking de progreso.
Flujo de upload
- Compresión de la imagen según parámetros configurados (quality, maxWidth, maxHeight)
- Obtención de una signed URL desde el backend
- Upload directo a S3 vía
PUT con la signed URL
- Tracking del progreso para actualizar la UI
Categorías de upload
| Categoría | Uso |
|---|
home-issues | Fotos de incidencias en la propiedad |
property-photos | Fotos de la propiedad para el listing |
profile-photos | Foto de perfil del usuario |
documents | Documentos adjuntos |
Linking Service
Archivo: linkingService.ts
Parser y router de deep links. Gestiona la navegación desde URLs externas hacia pantallas de la app.
Capacidades
- Soporta URL schemes nativos y links web (universal links)
- Crea links compartibles para diferentes entidades
- Mapea URLs entrantes a rutas de Expo Router
- Procesa deep links provenientes de push notifications
Tipos de link soportados
| Tipo | Descripción |
|---|
invite | Invitación a la plataforma |
booking | Enlace a una reserva específica |
booking-review | Enlace a review de una estancia |
property | Enlace a una propiedad |
custom | Links con rutas personalizadas |
El servicio tiene configuradas más de 20 rutas de pantalla. Cada ruta mapea un patrón de URL a una
pantalla específica de Expo Router.
Query Invalidation Service
Archivo: queryInvalidationService.ts
Centraliza la invalidación de caches de React Query para mantener la coherencia de datos entre módulos.
Métodos
| Método | Descripción |
|---|
invalidateAllStaysQueries() | Invalida todas las queries de estancias |
invalidateBookingQueries() | Invalida queries de reservas |
invalidatePropertyQueries() | Invalida queries de propiedades |
invalidateWalletBalanceQueries() | Invalida queries de balance del wallet |
forceRefreshStays() | Fuerza re-fetch de estancias |
forceRefreshAll() | Invalida y refresca todos los caches |
onPropertySelectionChange() | Limpia caches al cambiar de propiedad |
onBookingStateChange() | Invalida caches afectados por cambio de estado de booking |
clearAllUserData() | Limpia todos los caches del usuario (logout) |
Version Gate
Ubicación: services/versionGate/
Servicio que verifica la versión instalada de la app contra los valores min y current del backend, mostrando un modal bloqueante (actualización obligatoria) o un banner dismissible (actualización recomendada).
Archivos
| Archivo | Descripción |
|---|
types.ts | VersionInfo (respuesta API) y VersionCheckResult (estado) |
api.ts | fetchAppVersions() — raw axios GET, retry once, fail open |
useVersionCheck.ts | Hook principal: comparación semver, dismiss, deep link a store |
versionGateStore.ts | Zustand store que expone isActive para coordinar otros modales |
index.ts | Barrel exports |
API Call
GET {API_URL}/v1/app-versions?platform=ios|android
- Sin autenticación — usa
axios.get() directo, no el cliente centralizado
- Timeout: 5 segundos
- Retry: 1 reintento en caso de fallo
- Fail open: si ambos intentos fallan, el usuario pasa sin bloqueo
- Response format: soporta tanto
{ min, current } (filtrado) como { ios: {...}, android: {...} } (nested)
Comparación de versiones
Compara la versión instalada (Constants.expoConfig?.version) contra:
| Condición | Resultado | UI |
|---|
installed < min | update-required | Modal bloqueante (sin dismiss) |
installed < current | update-recommended | Banner dismissible |
installed >= current | up-to-date | Sin UI |
Coordinación con otros modales
El versionGateStore expone isActive: boolean que otros componentes pueden consultar para esperar a que el version gate se resuelva antes de mostrar sus propios modales. Por ejemplo, AutoShowReviewModal espera a que isActive sea false.
Store URLs
| Plataforma | URL |
|---|
| iOS | https://apps.apple.com/es/app/vivla/id6448851807 |
| Android | https://play.google.com/store/apps/details?id=com.vivla.app |
Analytics
| Evento | Trigger |
|---|
version_update_dismissed | Usuario toca “Maybe later” en el banner recomendado |
Onboarding Service
Archivo: onboardingService.ts
Wrapper del onboardingStore que expone métodos simples para gestionar el estado del onboarding.
Métodos
| Método | Descripción |
|---|
getOnboardingStatus() | Obtiene si el usuario ya vio el onboarding |
markOnboardingComplete() | Marca el onboarding como completado |
clearOnboardingStatus() | Resetea el estado (para testing/debug) |
markOnboardingUnseen() | Fuerza que el onboarding se muestre de nuevo |