CreaRack-SL

Widget Team Chat — canal de equipo en el home (s69)

Resumen

El Team Chat es un widget de mensajería interna integrado en el home del Workspace (s69 · 18-05-2026). Funciona como un canal único de grupo estilo WhatsApp para los tres miembros del staff (Edu, Dani, Txell): solo texto, sin destinatarios explícitos, sin threading. Vive permanentemente visible como tercer widget del dashboard compartiendo zona con “Actividad reciente” y “Noticias” en un layout de 3 columnas.

Decisión de diseño: el plan original (Task #32) era un panel lateral colapsable en el header con badge de no leídos. Edu pidió el chat siempre visible como widget del home para mejor UX con un equipo de 3. Task #32 cancelada en consecuencia.


Arquitectura

Tablas D1 (migrations/0030_create_chat.sql)

TablaPropósito
chat_messagesHistórico completo de mensajes (id AUTOINCREMENT, author, body, created_at)
chat_typingEstado efímero “escribiendo…” (author PK, last_typed_at, TTL 5 s)
  • Índice idx_chat_messages_created_at ON chat_messages(created_at DESC) para paginación eficiente.
  • chat_typing usa INSERT … ON CONFLICT(author) DO UPDATE para upsert atómico.
  • Migración aplicada en remote D1 antes del commit.

CF Pages Functions (backend)

ArchivoRuta HTTPMétodos
functions/api/chat/messages/index.tsGET/POST /api/chat/messagesGET paginado + POST nuevo mensaje
functions/api/chat/messages/[messageId].tsDELETE /api/chat/messages/{id}Borrar mensaje propio
functions/api/chat/typing.tsGET/POST /api/chat/typingIndicador “escribiendo…”

Seguridad v1: author validado contra ALLOWED_AUTHORS = {Edu, Dani, Txell}. Auth real delegada a CF Access + middleware. El DELETE verifica el autor real en DB antes de borrar (no solo el claim del cliente).

Paginación: GET /api/chat/messages?limit=N&before=ISO — devuelve mensajes created_at < before ORDER BY DESC, revertidos a ASC antes de enviar al cliente.

Widget React (src/components/widgets/TeamChat.tsx)

TeamChat
├── Lista scrollable (ref listRef)
│   ├── Carga inicial: 100 msgs
│   ├── Scroll-load hacia arriba: ?before=oldest.created_at
│   ├── Polling silencioso cada 15 s
│   └── Auto-scroll al final si nearBottom (<100px)
├── Indicador typing
│   ├── GET /api/chat/typing cada 3 s
│   └── POST /api/chat/typing throttled cada 3 s al teclear
└── Input
    ├── Enter → envía, Shift+Enter → nueva línea
    ├── Optimistic UI (id temporal negativo, sustituye al recibir POST 201)
    └── Rollback al estado anterior en error

Identificación de autor: getCurrentUser() de lib/prefs — resuelve automáticamente sin selección manual.

Renderizado de URLs: regex /(https?:\/\/[^\s<>"]+)/g convierte URLs en <a> clicables con target="_blank".

Borrar mensaje propio: botón × visible en hover, solo para mensajes del autor actual y con id > 0 (no optimísticos). Llama DELETE /api/chat/messages/{id}?author=X.

Entorno local: si window.location.hostname === 'localhost', el widget muestra “Chat disponible en producción” y deshabilita toda la lógica de red.


Integración en el dashboard (src/components/variants/desktop/DesktopA.tsx)

Antes (s68)Después (s69)
Grid 2 columnas: WorklogFeed + NewsFeedGrid 3 columnas: WorklogFeed + NewsFeed + TeamChat
WorklogFeed limit=5WorklogFeed limit=4
—Bento glow-violet con --grad-violet para TeamChat

El widget TeamChat no es colapsable — siempre visible en el home.


Constantes de polling

ConstanteValorPropósito
MSG_POLL_MS15 000 msRefresh silencioso de mensajes
TYPING_POLL_MS3 000 msConsulta estado “escribiendo…”
TYPING_PING_MS3 000 msThrottle del POST typing al teclear
PAGE_SIZE100Mensajes por carga (inicial + páginas)
TYPING_TTL_SECONDS5TTL en DB para typing activo
MAX_BODY_LENGTH4 000 charsCap del body en backend

Limitaciones conocidas

  • Auth débil (v1): el author se pasa como query param / body claim. CF Access protege el acceso general, pero un miembro podría borrar mensajes de otro si manipula la request. Suficiente para equipo de 3 en entorno cerrado.
  • Sin notificaciones push: solo polling. No hay badge de no leídos (Task #32 cancelada).
  • Sin threading ni reacciones: fuera de scope por diseño.
  • Sin soporte multi-tenant: hardcoded a los 3 miembros del staff de CreaRack.

Véase también

  • [[workspace—dashboard]]
  • [[workspace—que-es-workspace]]
  • [[entity—chat—endpoint—chat-messages-api]]