0 Fundaciones ¿Hay dónde construir y cómo mirarlo? 1/4
esperando tu veredicto · v0.0.2
Qué queda construido
- Worker desplegado en una URL viva con health público
- D1 pulso-db / pulso-obra, KV pulso-cache, R2 pulso-media (uat y producción separados)
- Este panel de obra, con los veredictos persistidos en D1 pulso-obra
- Dependencias fijadas exactas, con un test que falla si alguien las desfija
- Entrada por magic link: sin contraseña, sesión firmada con HMAC. Se adelantó aquí porque la auth era el bloqueo del proyecto y había que probarla el día 1
- Esquema completo de D1 aplicado (la fase 1 solo tendrá que sembrar y consultar)
Guión de pruebas
- Abre https://uat-api.pulso.travel/entrar en el móvil, con datos, no en wifi. → Sale un campo de correo. El teclado del móvil aparece con la arroba a mano.
- Escribe lc@cooweb.co y toca «Enviarme el enlace». → Sale un mensaje verde diciendo que si ese correo tiene acceso, le llega un enlace.
- Abre el correo. Mira también en spam si no lo ves en un minuto. → Ha llegado un correo de Pulso con un botón «Entrar».
- Toca «Entrar» en el correo. → Vas directo al panel de obra, ya dentro, y arriba aparece tu correo.
- Sin girar el móvil, desliza de arriba abajo toda la página del panel. → Nada se sale por el lado. No hay barra de scroll horizontal ni hace falta zoom.
- Despliega la Fase 0 y lee los criterios del gate. → Entiendes cada criterio sin preguntarme qué significa.
- Marca ✓ o ✗ en cada criterio humano de la Fase 0. En al menos uno, escribe un comentario. → El botón se queda marcado. Aparece «guardado» con la hora.
- Vuelve a tocar el enlace del correo, el mismo de antes. → Dice que ese enlace ya no vale. Un magic link se usa una vez y solo una.
- Cierra el navegador del todo y vuelve a abrir https://uat-api.pulso.travel/obra → Sigues dentro y tus ✓/✗ y tu comentario siguen ahí. Nada se ha perdido.
- Lee la sección «Pendiente de atender» arriba del panel. → Tu comentario y cualquier ✗ aparecen ahí, esperando respuesta.
Gate
-
autoGET /v1/public/health responde 200 con status ok, versión y entorno
Falla si: No responde 200, o el JSON no trae version y environment
-
autoNinguna dependencia usa rango (^, ~, *, x): todas fijadas exactas
Falla si: Cualquier versión en package.json no es exacta
-
autoUn veredicto enviado al panel se guarda en D1 y reaparece al recargar
Falla si: El veredicto no vuelve en GET /obra/api/estado
-
autoToda fase tiene pregunta, al menos un criterio auto y al menos uno humano
Falla si: Una fase sin pregunta o sin gate humano
-
autoUna cookie de sesión manipulada, caducada o mal formada se rechaza
Falla si: Cualquiera de los tres casos entra
-
autoUn magic link usado dos veces no entra la segunda, y caduca a los 15 minutos
Falla si: El mismo enlace sirve dos veces
-
autoA un correo que no está en la lista no se le envía nada, y la respuesta es idéntica: no se filtra quién tiene acceso
Falla si: La respuesta permite distinguir un correo con acceso de uno sin acceso
-
túAbro la URL desde el móvil y el panel se lee sin hacer zoom ni scroll lateral
Falla si: Tengo que hacer zoom, o algo se sale de la pantalla
-
túPido el enlace en /entrar, me llega al correo, lo toco y entro. Ya puedo marcar veredictos
Falla si: No llega, llega a spam, o al tocarlo no entro
-
túEl plan de 7 fases que veo es el que quiero para Pulso, en ese orden
Falla si: Falta algo importante, o el orden no tiene sentido para mí
-
túPuedo marcar ✓/✗ y dejar un comentario en tres toques, sin teclear nada raro
Falla si: Me cuesta encontrar dónde opinar, o se pierde lo que escribo
1 El feed, con datos sembrados ¿Esto se entiende y apetece? 0/3
sin empezar
Qué queda construido
- Esquema D1 completo de Pulso y migración aplicada
- 20 eventos reales de Castellón sembrados a mano, con sus locations
- GET /v1/events, /events/:id, /events/nearby con bounding box + Haversine
- Vista del feed a 360 px, sin auth, para juzgar si apetece
Gate
-
autoGET /v1/events?city=Castellón devuelve los eventos sembrados paginados
-
autoGET /v1/events/nearby filtra por radio real (Haversine), verificado con distancias conocidas
-
autoHaversine y bounding box tienen test con coordenadas de Castellón y distancias conocidas
-
túMiro el feed y me apetece tocar algo. No parece una tabla de base de datos
Falla si: Lo veo y no me dice nada, o no sé qué hacer con él
-
túDe un evento entiendo qué es, cuándo y dónde sin abrirlo
Falla si: Tengo que abrir el detalle para saber si me interesa
-
túLos 20 eventos me parecen de verdad de Castellón, no de relleno
Falla si: Reconozco que son inventados
2 MCP y scraping real ¿La pieza cara funciona y trae datos de verdad? 0/2
sin empezar
Qué queda construido
- Servidor MCP en mcp.pulso.travel con las 9 tools y 4 resources
- Scraper real de vivecastellon.com con HTMLRewriter
- Browser Rendering como plan B para las fuentes que van por JS (castello.es, dipcas.es)
- source_hash para detectar cambios sin duplicar
Gate
-
autoUn cliente MCP se conecta y lista las 9 tools y los 4 resources
-
autoEl scraper extrae ≥10 eventos reales de vivecastellon.com con título y fecha
Falla si: Extrae menos de 10, o alguno sin fecha parseable
-
autoScrapear dos veces la misma fuente no duplica eventos (source_hash)
-
túDesde Claude pregunto "¿qué hay este finde en Castellón?" y me contesta con eventos reales
Falla si: No conecta, o inventa eventos que no existen
-
túCojo 3 eventos que trajo el scraper y compruebo que existen de verdad
Falla si: Alguno no existe, o la fecha o el sitio están mal
3 Con memoria: quién eres y qué te gusta ¿Recuerda lo que debe? 0/2
sin empezar
Qué queda construido
- Preferencias, ubicación y modo acompañante persistidos
- GET /v1/events/for-you cruzando preferencias × ubicación × compañía
- Zero Trust conectado de verdad: Access Application sobre pulso-travel, IdP y service token. Solo falta el API token con Access:Edit
Gate
-
autoCon AUTH_MODE=access-jwt, un JWT sin firmar, caducado o con audience ajeno recibe 401, validado contra el JWKS real de pulso-travel
Falla si: Alguno de los tres casos entra
-
autoEl mismo usuario entrando dos veces no crea dos filas
-
autofor-you ordena por relevance × peso de preferencia, verificado con pesos fijados
-
túEntro con mi Google por Zero Trust y la app sabe quién soy sin que le diga nada
Falla si: Me pide algo más, o no me reconoce al volver
-
túMarco mis gustos, vuelvo mañana y el feed sigue ajustado a ellos
Falla si: Se olvidó de lo que le dije
4 Con tiempo: crons y digest ¿Aguanta el paso de los días? 0/2
sin empezar
Qué queda construido
- Cron de scraping diario 03:00 UTC vía Queue
- Digest matutino pre-computado en KV a las 06:00
- Cron de recordatorios cada 5 min y limpieza semanal
- Días simulados: 7 ejecuciones seguidas sin duplicar ni romper
Gate
-
autoSimular 7 días de crons no duplica eventos ni deja tareas colgadas
Falla si: Crecen los duplicados, o alguna tarea queda en running para siempre
-
autoGET /v1/users/me/digest se sirve de KV, no recalcula
-
autoLa limpieza archiva eventos de hace más de 7 días y no toca los vivos
-
túLeo el digest de la mañana y me sirve. No es un listado, es un plan
Falla si: Es un volcado de eventos sin criterio
-
túVuelvo tres días después sin tocar nada y hay eventos nuevos
Falla si: La base está igual que la dejé
5 El circuito entero: tiempo real y avisos ¿Funciona de punta a punta? 0/2
sin empezar
Qué queda construido
- Durable Object EventChannel con WebSocket y ring buffer de 50
- Web Push real con VAPID (esto sí es gratis, va de verdad)
- Durable Object SocialListener contra stub determinista (no hay claves de X aún)
- Media a R2, servida por media.pulso.travel
Gate
-
autoDos clientes WS conectados al mismo evento reciben el mismo broadcast
-
autoAl reconectar, el cliente recibe los mensajes que se perdió (hasta 50)
-
autoEl payload de Web Push se cifra correctamente (ECDH + VAPID) y el push service lo acepta
-
autoEl social listening en modo stub lo dice en su respuesta: nunca finge ser real
Falla si: Devuelve datos inventados sin marcarlos como stub
-
túMe suscribo a un evento desde el móvil y me llega la notificación push de verdad
Falla si: No llega, llega tarde, o llega sin decir de qué evento es
-
túCon la app abierta pasa algo en un evento y lo veo aparecer sin recargar
Falla si: Tengo que recargar para verlo
6 El canal real ¿Alguien lo quiere de verdad? 0/2
sin empezar
Qué queda construido
- Dominios finales api / mcp / media .pulso.travel en producción
- Docs con Scalar en /docs, público
- Rutas entre eventos (nearest neighbour + Nominatim, sin Google)
- Hot scoring y rate limiting
Gate
-
autoapi., mcp. y media.pulso.travel responden en producción con TLS válido
-
auto/docs y /v1/openapi.json responden sin auth y el spec valida
-
autoLa ruta entre 3 eventos no cruza la ciudad dos veces (orden mejor que el de entrada)
-
túUn fin de semana lo uso yo de verdad para decidir qué hacer, sin forzarme
Falla si: Abro otra cosa para decidir
-
túLe paso la URL a alguien de Castellón sin avisar de que es un PoC
Falla si: Me da vergüenza enseñarlo