Skip to content

Cuentas y acceso ​

Desde el 14 de octubre de 2026, todas las rutas de la aplicación exigen una sesión. Siguen públicas la portada (/, /en, /pt), esta documentación, los avisos legales (/privacidad, /terminos) y la página de roles. No hay contraseñas: la cuenta se crea sola la primera vez que una persona entra.

Cómo se entra ​

Una sola pantalla, /login:

  1. Escribes tu correo. Enviamos un código de 6 dígitos y un enlace en el mismo mensaje; cualquiera de los dos sirve y ambos caducan a los 5 minutos. La respuesta es idéntica exista o no la cuenta.
  2. Escribes el código (o abres el enlace). Si el correo no tenía cuenta, se crea en ese momento. Tres intentos fallidos invalidan el código; pides otro.

El acceso es solo por correo (código o enlace), enviado desde acceso@futuros.xyz a través de AgentMail. No hay inicio de sesión con Google: el botón y el vínculo en /cuenta están apagados salvo que quien despliega los active (VITE_AUTH_GOOGLE=1 más credenciales de Google).

Tras entrar vuelves a la página que pedías (?next=), validada como ruta propia del sitio; cualquier otro valor te lleva a /atlas.

Primer inicio ​

Un paso, opcional: nombre visible, idioma, y una nota de qué guardamos y cómo pedir borrado. Se puede omitir y no vuelve a aparecer en ese dispositivo.

Qué guardamos ​

DatoDóndePara qué
Correo, nombre visible, idioma, foto de perfil (solo si se activa Google)Neon Postgres, AWS São Paulo (sa-east-1)Identificarte y enviarte el código
Sesiones activas (navegador, IP, fecha)Misma baseCerrarlas; caducan a los 30 días sin actividad
Códigos y tokens de enlaceMisma base, como hash, un solo usoVerificar el acceso
Eventos de acceso (inicio, cierre, códigos fallidos, límites) con la IP en hashMisma baseSeguridad; se conservan 12 meses
Preferencias, elementos guardados (lista de seguimiento, vistas, bandejas de comparación, portafolios) y actos cívicos (posiciones, enmiendas, comentarios, respuestas de consenso, votos a pilotos)Misma baseQue te sigan entre dispositivos y la participación identificada
auth_login, auth_signup, auth_onboarding, preferences_migrated, saved_item_created, civic_action, account_export_requested, account_deletedPostHogMedir el funnel; sin correo

Lo que no guardamos: contraseñas (no existen), el correo en logs ni en analítica, el código en claro.

El detalle legal está en el aviso de privacidad (§2, §5, §8, §9).

Tu espacio de trabajo ​

Con la sesión abierta, tus preferencias, elementos guardados y actos cívicos viven en tu cuenta y te siguen entre dispositivos:

QuéDónde
Idioma, tour, modelo de chat, ajustes de interfaz, aviso de instalaciónuser_preference (lista cerrada de claves; cada valor se valida y se reescribe en el servidor)
Lista de seguimiento de /mercados, vistas de /explorar, bandejas de comparación de pilotos y personas, portafolios de pilotossaved_item (hasta 200 por tipo)
Posiciones y enmiendas de propuestas, respuestas de /consenso, comentarios, votos a pilotoscivic_action (ver Participación identificada)

Migración única de lo que ya tenías en el navegador. La primera cuenta que inicia sesión en un navegador sube lo que había en localStorage (lista de seguimiento, vistas, bandejas, portafolios y preferencias) y después lo retira o lo renombra a <clave>.migrated. Siempre es "insertar si no existe": un dispositivo nuevo, vacío o desactualizado nunca pisa lo que la cuenta ya tiene. Una segunda cuenta en el mismo navegador no hereda nada. Las claves rechazadas por el servidor (valores alterados o demasiado grandes) se descartan; un fallo transitorio de red la reintenta en el siguiente arranque. Los votos, enmiendas y respuestas anónimas de antes no se pueden atribuir y no se migran; las claves con correos en claro (futuros_comments_v1, futuros_comment_gate_v1) se borran. Siguen locales, a propósito: el idioma, el modelo de chat y las marcas del tour como caché de arranque (se leen antes de que cargue la sesión), la retroalimentación del chat y las colas de demostración.

Sesiones, exportación y eliminación ​

Todo vive en /cuenta; desde cualquier página, el avatar de la cabecera abre el menú con Tu cuenta y Cerrar sesión (en pantallas estrechas, arriba del menú ≡).

Sesiones. La página lista cada navegador con sesión abierta (navegador y sistema inferidos del User-Agent, última actividad). Cada sesión se cierra por separado; Cerrar sesión en todos los dispositivos borra todas las filas de session del usuario, incluida la actual. Las sesiones duran 30 días y se renuevan con el uso. Si quien despliega activa Google, se vincula y desvincula desde la misma página (la entrada por código sigue disponible).

Exportación. Pedir exportación (POST /api/account/export) construye un archivo JSON con perfil, conversaciones y mensajes (con sus citas tal como se mostraron), preferencias, elementos guardados, actos cívicos y eventos de auditoría, y envía al correo de la cuenta un enlace firmado válido 24 horas. Para descargarlo hacen falta las dos cosas: el enlace sin alterar y la sesión abierta de la misma cuenta para la que se emitió (con otra cuenta, o sin sesión, no se entrega nada). Si el archivo supera 4 MB se divide en partes (la primera con todo salvo las conversaciones; las siguientes, conversaciones completas) y el correo trae un enlace por parte. Una exportación por hora por persona.

Eliminación. Eliminar mi cuenta (POST /api/account/delete) exige escribir el correo de la cuenta (sin distinguir mayúsculas ni espacios). Si eres la única persona propietaria de una organización que tiene más integrantes, la operación se rechaza (409) hasta que transfieras la propiedad. Al confirmar:

MomentoQué pasa
Inmediatodeleted_at queda fijado; se cierran todas las sesiones; las claves de API se desactivan y los tokens de embed se revocan; cualquier intento de iniciar sesión se rechaza; el evento account_deleted se registra en analítica con un seudónimo, nunca con el correo.
7 días después (cron diario /api/account-purge, protegido con CRON_SECRET)Se borran perfil, sesiones, cuenta de Google vinculada, preferencias, actos cívicos, conversaciones privadas con sus mensajes y elementos guardados privados. Conversaciones y elementos compartidos con una organización quedan en ella con dueño vacío ("ex integrante"). Los eventos de auditoría quedan con actor vacío y el identificador sustituido por un hash.

El mismo cron borra los eventos de auditoría de más de 12 meses. No hay "deshacer": durante los 7 días la cuenta está cerrada, no suspendida. Los recibos del fideicomiso de datos no se borran (son el registro de procedencia de la propia persona, ya seudónimo).

Organizaciones ​

Una organización reúne a un equipo: comparte conversaciones y elementos guardados entre sus integrantes. Se gestiona en /cuenta/organizacion; el selector de la cabecera (o la hoja del menú ≡ en pantallas estrechas) define el espacio activo, y Personal es el espacio sin organización.

RolPuede
PropietarioTodo: cambiar roles, transferir la propiedad, eliminar la organización, además de lo del administrador.
AdministradorEditar nombre e identificador, invitar, cancelar invitaciones, quitar a integrantes (no a administradores ni propietarios) y editar o borrar lo compartido, incluido lo de ex integrantes.
IntegranteVer lo compartido, crear lo propio y compartirlo.
  • Crear. Cualquier persona; queda como propietaria. El identificador (la parte de URL) se puede cambiar una sola vez. Tope: 5 organizaciones creadas por persona y día, y 20 por cuenta.
  • Invitar. Propietario o administrador escribe un correo y un rol (administrador o integrante). La invitación llega por correo (en el idioma de la persona invitada si ya tiene cuenta, o en el de quien invita) con un enlace a /invite/<id>, vence a los 7 días y solo la puede aceptar la cuenta con ese mismo correo. Máximo 50 pendientes por organización y, para frenar abusos, 20 invitaciones por hora por persona y 30 por hora por organización. Si el correo no se puede enviar, la invitación se cancela y se avisa.
  • Compartir. Cada conversación o elemento guardado es privado hasta que su autor lo comparte con la organización activa (interruptor en /cuenta/organizacion, o en la barra lateral de /chat para conversaciones). Solo se puede compartir con una organización a la que perteneces. Autor, propietario y administradores pueden editarlo o borrarlo; el resto solo lo ve.
  • Salir o ser quitado. Lo que compartiste se queda en la organización, sin dueño, y se muestra como de un ex integrante; lo privado sigue siendo tuyo. La última persona propietaria no puede salir ni cambiar su rol: primero transfiere la propiedad (esa regla se aplica dentro de una única sentencia SQL, así que dos propietarios que salen a la vez no pueden dejar la organización sin dueño).
  • Eliminar la organización (solo propietario, escribiendo su identificador). Se borran la organización, sus integrantes e invitaciones. Las conversaciones y elementos que compartió cada integrante vuelven a ser privados de su autor; los de ex integrantes se borran con la organización. No se puede deshacer.
  • Auditoría. Creación, cambios, invitaciones (creación, cancelación, aceptación), cambios de rol, transferencias, salidas y expulsiones quedan en el registro de auditoría, sin correos.

Claves de API y tokens de embed ​

Fuera del navegador no hay cookie, así que se usan credenciales que emites tú:

  • Claves de API (ft_live_<48 hex>, /cuenta/claves): para la API pública /api/v1/* (y /data.json, /feeds/*), el servidor MCP /api/mcp y el chat por API /api/chat. Se muestran una sola vez y se guardan con hash. Tope de 600 solicitudes por minuto por clave (cobrado en cada solicitud) y 500 mensajes de chat por día por cuenta. El chat por clave se guarda en tu historial en una conversación titulada por el cliente o "API". Máximo 20 claves activas. Guía: API pública, MCP.
  • Tokens de embed (ft_embed_…, /cuenta/embeds): para los iframes /embed/stat, /embed/chart y /embed/board en sitios ajenos. Eliges las rutas permitidas y el vencimiento (365 días por defecto, máximo 730); abren solo esas rutas y los archivos de datos que esos widgets leen. Máximo 25 activos. Guía: Embeds.

Revocar una clave o un token surte efecto en menos de un minuto. Si eliminas tu cuenta, tus claves se desactivan y tus tokens se revocan al instante.

El muro de acceso (para operadores) ​

La frontera de seguridad es el Routing Middleware de Vercel (middleware.ts, lógica en server/auth/wall.ts), no la interfaz. Para cada petición fuera de la lista pública:

  • Lee la cookie de sesión y la valida con una llamada interna a /api/auth/get-session del mismo despliegue. Un resultado positivo se recuerda 60 s en memoria (clave: hash del token); uno negativo nunca.
  • Sin sesión válida: una navegación de documento recibe 302 /login?next=<ruta>; cualquier fetch, API, embed o MCP recibe 401 {"error":"auth_required"} con WWW-Authenticate: Bearer.
  • Si la validación falla por error (tiempo de espera de 3 s, 500, JSON inválido), cierra: 302/401 y una línea [auth] en los logs. Nunca abre el paso ni devuelve un 500.
  • Credenciales de máquina: las claves de API (Authorization: Bearer ft_live_… o X-Api-Key) se aceptan en /api/v1/*, /data.json, /feeds/*, /api/mcp y /api/chat; los tokens de embed (?et= o X-Embed-Token) en /embed/* y en los archivos de datos que esos widgets leen. Una credencial en la superficie equivocada se rechaza sin consulta. El muro las verifica con una llamada interna a /api/machine-verify del mismo despliegue (origen de plataforma, nunca el Host de la petición), guarda el veredicto positivo 60 s y no guarda nunca uno negativo. El tope por clave se cobra en cada solicitud, también con veredicto guardado. Si la verificación no es posible (sin secreto interno, base de datos caída), cierra: 503 con Retry-After, nunca un paso.
  • /api/machine-verify está en la lista pública solo para que el muro pueda llamarlo; la propia función responde 401 a cualquier petición que no traiga AUTH_INTERNAL_SECRET (comparación en tiempo constante). No usa la cabecera de exención del observador de scraping, que es derivable cuando SCRAPE_INTERNAL_TOKEN no está definido.

Lista pública exacta: /, /en, /pt, /login, /invite/*, /privacidad, /terminos, /roles*, /api/auth/*, /api/health, /manifest.webmanifest, /sw.js, /robots.txt, /sitemap*.xml, /favicon*, /assets/*, /fonts/*, /og/*, /.well-known/*, /icons/*, el deck inversor (/deck, /deck.html, /api/deck-access, /api/deck-slide), el salto de outreach /o/* (/api/o), y los endpoints que traen su propio secreto: /api/alerts-digest (cron), /api/access-webhook (Stripe), /api/questions y /api/chat-turns (token de operador). Las peticiones OPTIONS pasan.

Variables de entorno:

VariableEfecto
AUTH_WALL_DISABLED=1Interruptor de emergencia: desactiva el muro por completo. Se registra en logs en cada arranque en frío. Debe estar ausente en producción.
AUTH_INTERNAL_SECRETObligatoria para claves de API y tokens de embed (16 o más caracteres; producción y preview). Sin ella, toda credencial de máquina recibe 503.
EMBED_TOKEN_PEPPERPimienta del hash de los tokens de embed. Sin ella no se pueden crear ni verificar tokens (503).
API_KEY_MAX_PER_MINUTE, CHAT_USER_DAILY_MAXTopes ajustables: 600 por clave y minuto, 500 mensajes de chat por cuenta y día.
AUTH_INTERNAL_ORIGINOrigen al que el muro llama para validar la sesión; por defecto, el del propio despliegue.
VERCEL_AUTOMATION_BYPASS_SECRETSi está definido, el muro lo reenvía para que una preview protegida pueda validarse a sí misma.
AUTH_SIGNUP_DISABLED, AUTH_GOOGLE_DISABLEDPalancas del servidor de autenticación; /login muestra el error correspondiente.

Estado ​

CapacidadEstado
Muro de acceso, /login por código y enlace (correo vía AgentMail), onboardingEn vivo
Historial de chat por cuentaEn vivo
Preferencias y elementos guardados por cuenta, participación identificada, panel /cuenta (perfil, sesiones, exportar, eliminar)En vivo
Organizaciones (roles, invitaciones, compartir), claves de API, tokens de embedEn vivo

Cada cifra con su fuente — la trazabilidad es el contrato.