This is a Next.js project bootstrapped with create-next-app.
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.
This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.
Además de las variables NEXT_PUBLIC_FIREBASE_* para el cliente, los endpoints de IA
requieren credenciales de servidor:
# API de OpenAI (requerida para /api/categorizar, /api/voz/transcribir y /api/voz/parsear)
OPENAI_API_KEY=sk-...
# Credenciales de Firebase Admin SDK (para verificar el ID token en los endpoints).
# Exporta el JSON completo del service account como una sola línea.
# Obtenlo desde Firebase Console → Project settings → Service accounts → Generate new private key.
FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account","project_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n","client_email":"..."}Alternativamente, en entornos Google Cloud (Cloud Run / Functions) puedes omitir
FIREBASE_SERVICE_ACCOUNT_JSON y dejar que el SDK use las credenciales por defecto
de la aplicación (ADC).
Nunca commitees .env.local ni el JSON del service account. Están listados en .gitignore.
La app ofrece creación de tareas por voz en modo híbrido:
- Si el navegador soporta Web Speech API (Chrome, Edge, Safari reciente), la transcripción ocurre totalmente en el dispositivo (sin coste).
- Si no está disponible o falla, se graba audio con
MediaRecordery se envía a/api/voz/transcribirque usa OpenAI Whisper en el servidor. - El texto resultante se envía a
/api/voz/parsear, donde GPT-4o-mini extrae un JSON estructurado{ titulo, fechaLimite, carpeta }. Si esta llamada falla, el cliente degrada a un parser local basado en expresiones regulares (100% offline).
Nota sobre zonas horarias: el parseo de expresiones relativas ("el viernes", "mañana", etc.) usa
Europe/Madridcomo zona horaria de referencia (constanteZONA_HORARIA_USUARIOen app/api/voz/parsear/route.ts). El servidor pre-calcula el calendario de los próximos 14 días en esa zona y lo inyecta en el prompt, para evitar errores aritméticos del modelo. Si en el futuro se publica la app para usuarios fuera de España, la zona horaria debería enviarse desde el cliente según la ubicación del dispositivo (Intl.DateTimeFormat().resolvedOptions().timeZone).
Todos los endpoints bajo /api/ requieren un Firebase ID token en el header
Authorization: Bearer <token> y aplican rate limiting por usuario:
| Endpoint | Modelo | Límite por usuario |
|---|---|---|
/api/voz/transcribir |
whisper-1 |
30 req / hora |
/api/voz/parsear |
gpt-4o-mini |
100 req / hora |
/api/categorizar |
gpt-4o-mini |
100 req / hora |
El rate limiter actual es en memoria (lib/rate-limit.ts). Si se escala a
múltiples instancias (p. ej. Vercel con varias regiones o Lambda), hay que
migrar a un store compartido (Upstash Redis, Vercel KV, etc.) para que el
límite sea efectivo globalmente.
-
Firestore rules (
firestore.rules): cada usuario solo puede leer/escribir sus propios documentos entareas,completadas,carpetasyusuarios. Las reglas también validan tipos y tamaños máximos para mitigar abuso del almacenamiento. Despliega las reglas con:firebase deploy --only firestore:rules
-
Verificación de ID token (
lib/auth-server.ts): todos los endpoints de IA validan el token mediante Firebase Admin SDK. -
Rate limiting (
lib/rate-limit.ts): por uid, ventana móvil de 1 hora. -
Validación de inputs: tamaño máximo de audio (1 MB), tipos MIME permitidos, longitud máxima de texto (2000 chars) y de carpetas (60 chars).
- Tiers:
freeypremium. El documentosuscripciones/{uid}guarda el estado (gestionado por el webhook de RevenueCat en/api/revenuecat/webhook). El usuario solo tiene permiso de lectura sobre el suyo. - Cuotas mensuales persistentes: la colección
cuotas_uso/{uid}_{YYYYMM}almacena el consumo de IA del mes. Los endpoints de IA consumen cuota transaccionalmente (lib/cuotas.ts). Límites por tier enLIMITES_TIERy hard cap global enHARD_CAP. - Respuestas 402 / 403: al exceder la cuota del tier se devuelve 402
(indicando
upgradeDisponible) y al exceder el hard cap se devuelve 403 con la cuenta efectivamente bloqueada hasta fin de mes. - Paywall:
components/Paywall.tsxse muestra automáticamente al recibir un 402 víalib/paywall-bus.ts. El componente<RequierePremium>envuelve funcionalidad premium en cliente.
components/PerfilUsuario.tsx(modal accesible desde la barra de navegación): editar nombre, ver miembro desde, ver uso del mes, exportar datos, cerrar sesión y eliminar cuenta (doble confirmación con reauth)./api/cuenta/exportar(GET): descarga un JSON con todo el perfil, tareas, completadas, carpetas, suscripción y cuotas del usuario./api/cuenta/eliminar(POST): borra en cascada todas las colecciones del usuario y llamaauth.deleteUser(). Requiere un ID token conauth_timereciente (Firebase reauthentication).- Páginas legales estáticas: /privacidad y /terminos, accesibles sin autenticar.
- FCM:
lib/notificaciones.ts(cliente) +public/firebase-messaging-sw.js(SW web) + cron horario/api/cron/recordatoriosdeclarado envercel.json. NecesitaCRON_SECRETyNEXT_PUBLIC_FCM_VAPID_KEY. Ver docs/publicacion/notificaciones.md. - Widgets iOS/Android: el endpoint
/api/widgets/tareas-proximasdevuelve hasta 5 tareas próximas para ser consumido por un Widget Extension (WidgetKit) o un AppWidget Glance. Esqueletos Swift/Kotlin en docs/publicacion/widgets.md. - Analytics: Firebase Analytics + PostHog unificados en
lib/analytics.ts. Se inicializan desdeapp/layout.tsxy se auto-deshabilitan si no hay claves configuradas. - Onboarding:
components/Onboarding.tsxmuestra un tutorial de 4 slides en el primer login (persistido enlocalStorage).
Firebase App Check está integrado tanto en cliente (lib/firebase.ts con
reCAPTCHA v3 en web) como en servidor (lib/auth-server.ts →
verificarAppCheck). Controla la aplicación con la variable de entorno
APPCHECK_ENFORCE:
- Sin configurar o
APPCHECK_ENFORCE=0: modo monitor, registra en consola los tokens inválidos pero no bloquea la petición. APPCHECK_ENFORCE=1: modo enforce, rechaza peticiones sin token o con token inválido con401.
Ver guía completa en docs/publicacion/app-check.md.
Documentación detallada en docs/publicacion/:
- capacitor.md: comandos
cap:add:ios,cap:add:android, permisos, plugins y assets. - iap-productos.md: creación de
productos
premium_monthly(2,99€) ypremium_yearly(24,99€) con trial de 7 días en App Store Connect, Google Play Console y RevenueCat. - envio.md: checklist pre-envío, metadata y proceso de revisión Apple/Google.
- app-check.md: configuración de reCAPTCHA v3 (web), App Attest (iOS) y Play Integrity (Android).
- notificaciones.md: setup de FCM en web y móvil.
- widgets.md: widgets de pantalla de inicio con las próximas tareas.
Esta es una PWA servida desde Next.js empaquetada como app nativa con Capacitor:
- Privacy policy: obligatoria en ambas tiendas. Debe mencionar explícitamente
que:
- Se usa OpenAI para transcribir audio y categorizar tareas cuando el usuario invoca la función de voz.
- El audio se envía cifrado (HTTPS) al servidor, se procesa en OpenAI y no se almacena tras la transcripción.
- Los datos de tareas se guardan en Firebase Firestore y solo son accesibles por el usuario autenticado.
- Descripciones de permisos: si empaquetas con Capacitor, configura
NSMicrophoneUsageDescriptionenInfo.plist(iOS) y la razón de uso del permisoRECORD_AUDIOpara Google Play. - Data safety (Google Play) y App Privacy (App Store): declara que la app recolecta identificadores (Firebase UID), contenido de usuario (tareas) y audio (de forma transitoria para transcribirlo).
- Revisar que
firestore.rulesestá desplegado con las nuevas reglas antes de lanzar la app.
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.