al día · la máquina · crescō
Herramienta de casa · plano técnico

La máquina detrás de la pila.

al día se ve como una pila de cartas. Debajo hay una máquina que cosecha por seis llaves, redacta con tu voz, espera cinco segundos por si te arrepientes y ejecuta en el canal correcto. Este es su plano: la base, las clases, las secuencias y dónde viven las llaves. El prototipo es el spec — la máquina se construye para no traicionarlo.

Iel mapa

Cuatro cajas, una regla de tránsito

La PWA habla solo con Supabase. Las APIs externas hablan solo con el routine y el despachador. Ninguna llave cruza jamás hacia el teléfono — esa es la regla que ordena todo el mapa.

el teléfono
PWA
Next.js 15, phone-first, instalable. La pila, el parte, la regla.
  • Lee su pila por RLS
  • Decide: aprueba, edita, pospone
  • Jamás ve una llave ni una API externa
el centro
Supabase crescō
La única puerta. Todo pasa por aquí o no pasa.
  • Auth — el equipo entra con su cuenta
  • Postgres + RLS — cada quien ve solo lo suyo
  • Vault — las seis llaves, cifradas
  • Realtime — la pila se actualiza sola
  • Edge functions — OAuth y el despachador
el redactor
Routine de Claude
Despierta, cosecha, redacta con tu voz, inserta cartas. Por ahora — la interfaz que deja es «algo que escribe cartas», reemplazable sin tocar el resto.
  • Opera con su skill de la casa — el manual de operación, versionado
  • Lee las llaves del Vault
  • Escribe cards y digests
afuera
Las APIs
Los cuatro canales del diseño, con su llave cada uno.
  • Gmail
  • Google Calendar
  • Slack
  • Notion · Mogos, crescō y Trolley

Sin NestJS en la v1: la PWA consume Supabase directo y la lógica de servidor vive en edge functions. Menos piezas, mismo contrato.

IIla base

Nueve tablas y una ley como constraint

Toda tabla lleva RLS user_id = auth.uid(): cada quien ve solo su pila, sus llaves, su voz. Pasa el cursor por una tabla para ver con quién se relaciona. La línea punteada ámbar es la única que sale del esquema: la llave real vive en el Vault, nunca en una tabla nuestra.

profiles
Quién eres y a qué hora quieres el parte.
  • id ⇢ auth.users
  • nombre
  • zona horaria
  • hora del parte
connections
Una fila por llave. Seis hoy; la lista crece sin migrar.
  • user_id ⇢ profiles
  • proveedor · etiqueta
  • scopes mínimos
  • vault_secret_id ⇢ vault.secrets
  • estado · última cosecha
vault.secrets
Cifrado por Supabase. Fuera del esquema público.
  • Se escribe por edge function
  • Se lee solo con service role
  • El navegador no tiene ruta hasta aquí
mutes
Silenciar un canal por hoy. Expira solo — nadie tiene que acordarse.
  • user_id ⇢ profiles
  • canal
  • día
cards
La carta. El centro de todo.
  • connection_id ⇢ connections
  • referencia externa · contexto
  • borrador · destino
  • verbo — mandar · hecha · aceptar
  • esfuerzo · estado
CHECK: sin borrador y destino, no se inserta — la ley, como constraint
connection_sources
Dónde mirar en Notion. Los otros canales traen su inbox; Notion se linkea, base por base.
  • connection_id ⇢ connections
  • data source linkeado
  • propiedad persona — quién eres tú ahí
  • propiedad estado · valor «hecha»
El routine estudia el schema y propone el mapeo; tú apruebas
blacklist
Lo que nunca entra a la pila. Explícita y editable.
  • user_id ⇢ profiles
  • patrón — remitente, canal, tema
  • razón
voice_edits
El diff entre lo propuesto y lo que salió. Editar es entrenar.
  • card_id ⇢ cards
  • borrador · enviado
  • diff · fecha
outbox
Lo aprobado, esperando su ventana de arrepentimiento.
  • card_id ⇢ cards
  • payload final — lo editado, si editaste
  • execute_after — ahora + 5 s
  • intentos · error · estado
digests
El parte: una fila por día. Los números y la frase.
  • user_id ⇢ profiles
  • día
  • números por canal
  • la frase

En pantallas angostas las relaciones se leen en cada tarjeta (⇢); en anchas, se dibujan.

IIIlas clases

Una interfaz, cuatro canales

El corazón del dominio es ChannelAdapter. El routine cosecha por ella, el despachador ejecuta por ella, y ninguno sabe qué proveedor tiene enfrente. Agregar WhatsApp mañana es un adapter más — cero migración, cero cambio en la PWA.

interfaz
ChannelAdapter
  • harvest(desde) → lo que espera decisión, con contexto
  • execute(orden) → la salida aprobada, en el canal
  • revoke() → suelta la llave y muere en paz
Gmail
1 llave
Hilos que esperan tu respuesta. Ejecutar = responder en el hilo, con tu firma.
Slack
1 llave
Menciones y DMs que piden decisión. Ejecutar = publicar en el hilo, como tú.
Notion
×3 — una instancia por workspace
Sin inbox en la API: lee las bases linkeadas en connection_sources, filtrando por tu propiedad de persona. Ejecutar = marcar hecha en ese espacio.
Calendar
1 llave
Invitaciones por contestar. Ejecutar = aceptar o proponer otra hora.
consume harvest()
La cosechadora
El routine de Claude. Junta lo crudo, filtra la lista negra, redacta y deja cartas.
consume execute()
El despachador
Edge function. Toma del outbox lo que ya venció su ventana, saca la llave del Vault y ejecuta.
no conoce adapters
La PWA
Solo lee cartas y escribe decisiones. El canal es un dato, no una dependencia.
IVlas secuencias

Tres historias que cuentan todo el sistema

Cómo nace una carta, qué pasa cuando firmas, y cómo entra una llave. La segunda está viva: apruébala tú.

secuencia 01 · cada media hora
La cosecha — cómo nace una carta
  1. routineDespierta. Lee las connections activas de cada usuario.
  2. vaultEntrega cada llave — solo lectura, solo aquí.
  3. adaptersharvest() por canal: hilos sin responder, menciones, invitaciones — y en Notion, las bases linkeadas de connection_sources.
  4. routineFiltra contra blacklist y mutes. Lo silenciado hoy no existe hoy.
  5. routineArma el prompt de voz: el manual vivo + tus últimas ediciones. Redacta un borrador por ítem.
  6. postgresInserta cards — cada una con borrador, destino y verbo, o el CHECK la rechaza.
  7. realtimeLa pila del teléfono se actualiza sola. Sin refrescar.
  8. routineA tu hora elegida: escribe el digest y manda la única notificación del día.
secuencia 02 · en vivo
La firma — tap, cinco segundos, y sale
tú · pwa
La carta
Correo a Valentina, redactado. El verbo dice a dónde va.
postgres
outbox
execute_after = ahora + 5 s
correo → Valentinapendiente
vault
La llave
El despachador la pide con service role. Nadie más puede.
solo el despachador
gmail
El canal
Sale en el hilo, con tu firma.
Salió. La edición quedó en voice_edits.
La misma barra sDrain del prototipo — y es el mismo reloj del servidor.

El poka-yoke del diseño, como arquitectura: aprobar no envía — encola con cinco segundos de ventana. Deshacer borra la fila y no pasó nada. El despachador solo ejecuta lo que ya venció.

secuencia 03 · una vez por llave
Conectar una llave — cómo entra un canal
  1. tú · pwaEliges el proveedor — «notion · Trolley», por ejemplo.
  2. proveedorSu pantalla de OAuth, pidiendo solo los scopes mínimos de la tabla de llaves.
  3. edge functionRecibe el callback. El token nunca toca el navegador.
  4. vaultGuarda el secret cifrado; devuelve su id.
  5. postgresInserta la fila en connections con etiqueta, scopes y vault_secret_id.
  6. routineEn la próxima pasada, la primera cosecha. La pila crece sola.
Vlas llaves

Seis llaves, scopes mínimos

Una llave por espacio conectado, como manda el diseño. Cada una pide lo mínimo que su canal necesita: leer para armar la pila, escribir únicamente en el momento de ejecutar.

llave
scopes
lee · escribe
correo · Gmail
gmail.readonly + gmail.send
Lee hilos que esperan tu respuesta · envía solo al ejecutar
calendario · Google
calendar.events
Lee invitaciones y choques · responde asistencia
slack · crescō
user token — lectura de menciones + chat:write
Lee menciones y DMs · publica en el hilo, como tú
notion · Mogos
Tres integraciones internas, una por workspace — lectura de contenido + actualizar páginas. La API de Notion no expone tu bandeja ni tus menciones: cada llave lee las bases linkeadas en connection_sources, filtrando por tu propiedad de persona, y solo puede marcar hecha ahí. El routine estudia el schema del workspace y propone el mapeo; tú apruebas. Una llave comprometida nunca alcanza a los otros dos espacios.
notion · crescō
ídem, sobre el HQ de la casa
Lee · marca hecha
notion · Trolley
ídem, sobre el espacio del cliente
Lee · marca hecha

La llave se escribe una vez, se lee en un solo lugar, y el teléfono jamás la ve.

Entra por la edge function del OAuth. La leen el routine y el despachador, con service role. La PWA no tiene ninguna ruta que la devuelva. Revocar es borrar el secret: la conexión muere al instante y su adapter hace revoke().
VIla voz

La voz no se configura: se lee

El routine no tiene personalidad propia. Antes de redactar, lee el manual de marca en vivo — la sección de voz ya es fetchable en producción y trae su AI prompt listo — y le suma tus últimas ediciones como ejemplos. Cada corrección tuya vale más que cualquier prompt.

fuente 1 · el manual vivo
La voz de la casa
Los siete principios, el dial, los sí/no y el AI prompt del manual. Si el manual cambia, la voz cambia en la próxima cosecha — sin deploy.
design.cresco.so/manual/sections/voz.html
fuente 2 · tus ediciones
voice_edits
Las últimas correcciones borrador → enviado, como few-shots. Editar es entrenar: la pila mejora sola, sin reentrenar nada.
salida
El borrador
Declarativo, sin jerga, una idea por párrafo, cero emojis en producto — las reglas del manual, aplicadas a tu correo. Tú solo firmas o corriges.

El redactor opera con un skill, no con un prompt suelto.

El skill del routine —creado con la skill-factory de la casa, versionado en cresco-skills— fija exactamente qué cosecha, cómo filtra, cómo arma el prompt de voz, qué inserta y qué jamás hace. Cambiar el comportamiento del redactor es un PR con revisión, no editar un prompt en un dashboard. Y cuando el routine se reemplace, el skill queda: es la especificación ejecutable del oficio.
VIIel pwa

Instalable, offline, y fiel al píxel

Se instala desde el navegador con el manifest en tinta y lino. La pila viaja contigo: decidir offline funciona — las decisiones caen a una cola local que sincroniza al volver la señal. Y una sola notificación al día, a la hora de tu parte.

la regla de oro
El prototipo v19 es el spec visual
Las animaciones no se recrean: se copian. Mismos nombres, mismos milisegundos, mismos cubic-bezier. La verificación de cada fase incluye el diff de keyframes contra el prototipo — y debe dar cero.
offline
La pila cacheada, la decisión encolada
El service worker guarda el shell y la última pila. Sin señal puedes leer y decidir; al volver, la cola local se vacía en el outbox — y la ventana de deshacer corre desde la sincronización, no desde el tap.
el aviso
Un push al día, con el número
A la hora que elegiste en tu perfil, con los números del parte. Nunca un aviso por carta — eso sería un quinto inbox y volvimos al principio.
animaciónqué haceduraeasing
bRiseEl parte se materializa — 8 retrasos escalonados, .15 s → 1.98 s.9 scubic-bezier(.22,1,.36,1)
bBreatheEl resplandor respira9 s ∞ease-in-out
bScanLa línea barre la pantalla — una sola vez2.6 scubic-bezier(.22,1,.36,1) · +.35 s
bWipeEl botón se vuelve pantalla.9 scubic-bezier(.22,1,.36,1)
bOutLa salida en cascada inversa — retrasos 0 → .21 s.46 scubic-bezier(.4,0,1,1)
bDimEl resplandor cede.5 scubic-bezier(.22,1,.36,1)
bInLa pila entra.85 scubic-bezier(.22,1,.36,1)
sInEl recibo de enviado sube.42 scubic-bezier(.22,1,.36,1)
sTickEl check se dibuja.42 scubic-bezier(.22,1,.36,1) · +.1 s
sDrainLa ventana de deshacer se drena — el reloj del servidor5 slinear
sOutEl recibo se va.3 scubic-bezier(.4,0,1,1)

Este es el checklist de fidelidad que heredan los goals: pixel-perfect no es una aspiración — es una lista con once filas, y cada una se verifica.

VIIIel orden

Seis fases, cada una cierra contra el prototipo

El orden de construcción que se vuelve goals. Ninguna fase abre hasta que la anterior verificó — y verificar siempre incluye mirar el prototipo al lado.

  1. El esqueleto
    Schema con sus nueve tablas y el CHECK de la ley, RLS en todas, auth del equipo, Vault listo.
    cierra cuando: dos cuentas no pueden verse nada entre sí
  2. La pantalla
    Shell PWA instalable con la pila mock: el parte, las cartas, la regla, los filtros — portados del prototipo.
    cierra cuando: el diff de los once keyframes contra el prototipo da cero
  3. La cosecha
    Gmail primero — el primer sub-proyecto de conector: escribir el skill del redactor (su manual de operación), conectar la llave, cosechar, y ver cartas reales en la pila con tu voz en el borrador.
    cierra cuando: una carta real llega con borrador, destino y verbo correctos — generada por el skill
  4. La firma
    Aprobar → outbox → la ventana de 5 s → el despachador ejecuta. Deshacer cancela de verdad.
    cierra cuando: un correo real sale, y uno deshecho jamás sale
  5. Los demás canales — un sub-proyecto por conector
    Slack, Notion ×3 y calendario, cada uno como sub-proyecto colgado del proyecto madre: estudiar su documentación —scopes reales, límites de rate, webhooks o polling—, decidir, y entregar su adapter contra la misma interfaz. Notion además trae el linkeo de bases: el routine propone el mapeo y tú lo apruebas.
    cierra cuando: las seis llaves cosechan y ejecutan
  6. El parte
    El digest diario, la única notificación push, y offline con su cola local.
    cierra cuando: el aviso llega a tu hora, y decidir sin señal sincroniza al volver
IXcontestado

Las seis preguntas del diseño, cerradas

El capítulo VII del diseño dejó seis preguntas abiertas «para no olvidarlas». Esta página existe para contestarlas.

¿Cómo aprende tu voz?
Se lee, no se configura: el manual vivo + tus ediciones como ejemplos. § la voz
¿Aprende de la edición?
Sí. Cada diff queda en voice_edits y entra al prompt siguiente. § la base
¿Y deshacer?
Ventana de 5 segundos del servidor: outbox.execute_after. La barra del prototipo es el mismo reloj. § la firma
¿Dónde viven las llaves?
En el Vault de Supabase, seis secrets con scopes mínimos. El teléfono jamás las ve. § las llaves
¿Qué NO entra nunca?
La blacklist es una tabla, explícita y editable — no una promesa. § la base
¿Cuándo llega el aviso?
Un push al día, a la hora del parte, con el número. Nunca por carta. § el pwa
crescō · herramienta de casa· Plano técnico · ago 2026· el diseño· Siguiente: los goals, fase por fase