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.
Integración con vivla-mobile
La app mobile de Vivla (vivla-mobile) consume endpoints específicos de este backend para ofrecer chat de soporte a los huéspedes. Estos endpoints están bajo /api/chat/mobile/ y manejan autenticación, tokens de Stream Chat y gestión de perfil.
El chat en vivla-mobile no usa el backend principal de Vivla. Todos los endpoints de chat se sirven desde este backend (Tools API).
Flujo de autenticación
┌─────────────┐ ┌───────────────┐ ┌──────────────┐
│ vivla-mobile │────▶│ Tools API │────▶│ Stream Chat │
│ │ │ /chat/mobile │ │ │
└─────────────┘ └───────────────┘ └──────────────┘
│ │
│ authToken + │ Genera
│ userId │ streamToken
│ │ (1h expiry)
▼ ▼
┌─────────────┐ ┌───────────────┐
│vivla-backend│ │ Supabase │
│ (auth orig.)│ │ (users DB) │
└─────────────┘ └───────────────┘
- La app mobile obtiene un
authToken del backend principal de Vivla
- Envía
authToken + userId al endpoint de login de Tools API
- Tools API valida el usuario y verifica que tenga acceso al chat (
chat_enabled)
- Si tiene acceso, genera un token de Stream Chat con expiración de 1 hora
- La app usa el
streamToken para conectarse directamente a Stream Chat
Endpoints
Login
POST /api/chat/mobile/auth/login
Autentica al usuario mobile y retorna un token de Stream Chat.
Request:
{
"authToken": "token-del-backend-principal",
"userId": "vivla-user-id"
}
Respuestas posibles:
Acceso completo
Sin acceso
Usuario no encontrado
{
"hasAccess": true,
"streamUserId": "stream-user-id",
"streamToken": "eyJ...",
"expiresAt": "2025-01-15T12:00:00Z",
"user": {
"id": "uuid",
"firstName": "Juan",
"lastName": "Pérez",
"email": "juan@example.com"
}
}
{
"hasAccess": false,
"reason": "NOT_ENABLED"
}
{
"hasAccess": false,
"reason": "NOT_FOUND"
}
Refresh token
POST /api/chat/mobile/auth/refresh
Renueva el token de Stream Chat. Debe llamarse antes de que expire (1 hora).
Request:
{
"authToken": "token-del-backend-principal",
"userId": "vivla-user-id"
}
Response:
{
"streamToken": "eyJ...",
"expiresAt": "2025-01-15T13:00:00Z",
"streamUserId": "stream-user-id"
}
Actualizar perfil
PATCH /api/chat/mobile/profile
Actualiza el perfil del usuario y sincroniza los cambios con Stream Chat (nombre y avatar).
Request:
{
"authToken": "token-del-backend-principal",
"userId": "vivla-user-id",
"firstName": "Juan",
"lastName": "Pérez"
}
Crear invitación
POST /api/chat/mobile/invitations
Crea una invitación a un canal de chat con un deep link para compartir.
Response:
{
"id": "uuid",
"streamChannelId": "channel-id",
"status": "pending",
"expiresAt": "2025-01-20T00:00:00Z",
"deepLink": "vivla://chat/invitation/token-uuid"
}
GET /api/chat/mobile/invitations/:token
Endpoint público (sin autenticación). Permite previsualizar un canal antes de aceptar la invitación.
Response:
{
"channel": {
"id": "uuid",
"name": "Canal de soporte",
"type": "support"
},
"inviter": {
"name": "Agente Vivla",
"avatar": "https://..."
}
}
Endpoints de Surveys (Mobile)
La app mobile también consume endpoints de encuestas bajo /api/surveys/mobile/. Estos endpoints usan el mismo MobileAuthGuard para POST y son públicos para GET.
Obtener encuesta activa
GET /api/surveys/mobile/:slug
Retorna la definición completa de la encuesta activa para el slug dado (ej: home-review). Público, sin autenticación. Soporta ?lang=es para resolución de i18n.
Guardar respuesta parcial
POST /api/surveys/mobile/:slug/responses
Guarda o actualiza una respuesta parcial. La app guarda localmente (MMKV) y sincroniza al backend por step y al salir.
Request:
{
"authToken": "token-del-backend-principal",
"userId": "vivla-user-id",
"survey_id": "uuid-de-la-version",
"scope_id": "home-id-o-booking-id",
"status": "in_progress",
"current_step": "step_2",
"current_question": "kitchen_rating",
"answers": {
"general_rating": { "value": 4 },
"kitchen_rating": { "value": 2 }
}
}
Completar encuesta
POST /api/surveys/mobile/:slug/responses/complete
Marca la encuesta como completada y otorga automáticamente reward points. Una vez completada, la respuesta es inmutable.
Reanudar respuesta
POST /api/surveys/mobile/:slug/responses/resume
Retorna la respuesta parcial existente. Es POST (no GET) porque el MobileAuthGuard necesita leer authToken y userId del body.
Response:
{
"id": "uuid",
"survey_id": "uuid",
"status": "in_progress",
"current_step": "step_2",
"current_question": "kitchen_rating",
"answers": { "...": "..." },
"updated_at": "2026-03-15T10:00:00Z"
}
Rewards
POST /api/surveys/mobile/rewards/me → Puntos, nivel y ciclo del usuario
POST /api/surveys/mobile/rewards/levels → Definiciones de niveles
POST /api/surveys/mobile/rewards/recommend → Toggle de recomendación
Consideraciones técnicas
- Los tokens de Stream Chat expiran en 1 hora. La app debe implementar auto-refresh.
- El
MobileAuthGuard valida authToken y userId en el body de cada request POST. Los endpoints GET de surveys mobile son públicos.
- Las actualizaciones de perfil se sincronizan bidireccionalmente con Stream Chat.
- Los deep links usan el formato
vivla://chat/invitation/{token} para abrir invitaciones directamente en la app.
- El endpoint de invitaciones (
GET /invitations/:token) es público para permitir previsualización sin autenticación.
- Las encuestas se envían como deep links generados desde el panel de administración.
- La persistencia parcial de respuestas sigue un flujo local-first: guarda en MMKV, sincroniza al backend por step, y al reabrir compara timestamps local vs backend (usa el más reciente).