Endpoints Chat — /api/chat/ (CF Pages Functions)
Resumen
Conjunto de tres CF Pages Functions que implementan el backend del Team Chat (s69). Persisten datos en D1 (chat_messages, chat_typing). No requieren sesión Django — la autenticación externa la provee CF Access + middleware del workspace.
Endpoints
GET /api/chat/messages
Devuelve mensajes ordenados cronológicamente (ASC).
| Param | Tipo | Default | Descripción |
|---|---|---|---|
limit | int | 100 | Máx mensajes a devolver (cap 500) |
before | ISO string | — | Paginación: mensajes con created_at < before |
Respuesta 200:
[
{ "id": 42, "author": "Edu", "body": "...", "created_at": "2026-05-18 13:10:00" },
...
]
La query interna usa ORDER BY DESC + cap, luego invierte a ASC antes de serializar.
POST /api/chat/messages
Crea un nuevo mensaje.
Body:
{ "author": "Txell", "body": "Texto del mensaje" }
| Validación | Código |
|---|---|
author o body vacíos | 400 |
author no en allowlist | 400 |
| Error D1 insert | 500 |
Respuesta 201: el mensaje creado tal como queda en DB (con id real e created_at definitivo).
El frontend usa Optimistic UI: inserta con
idnegativo temporal y lo sustituye al recibir el 201. Si recibe error, hace rollback.
DELETE /api/chat/messages/{messageId}?author=X
Borra un mensaje. Solo el autor puede borrar el suyo.
| Paso | Descripción |
|---|---|
| 1 | Lee ?author del query param |
| 2 | Consulta SELECT author FROM chat_messages WHERE id = ? |
| 3 | Compara msg.author !== claimedAuthor → 403 si no coincide |
| 4 | Ejecuta DELETE |
Respuestas: 204 éxito · 400 sin author param · 403 no es el autor · 404 mensaje no existe · 500 error D1.
GET /api/chat/typing
Devuelve array de nombres de autores con typing activo (last_typed_at dentro de los últimos 5 s).
["Dani"]
POST /api/chat/typing
Refresca el last_typed_at del autor (upsert). El frontend lo llama throttled cada 3 s mientras el usuario teclea.
Body: { "author": "Edu" }
Respuesta: 204 · 400 si author inválido.
SQL: INSERT … ON CONFLICT(author) DO UPDATE SET last_typed_at = datetime('now')
Seguridad
- Allowlist:
ALLOWED_AUTHORS = { 'Edu', 'Dani', 'Txell' }hardcodeada en ambos handlers de messages y typing. - Verificación en DB: el DELETE no confía solo en el claim del cliente; lee el
authorreal de la fila. - Auth de perímetro: CF Access controla el acceso al dominio. Sin CF Access, estos endpoints no son alcanzables desde el exterior.
- Limitación v1: no hay token de sesión por mensaje; un actor interno con acceso a la red podría suplantar autores en POST. Aceptado para equipo de 3.
Esquema D1
CREATE TABLE chat_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author TEXT NOT NULL, -- Edu | Dani | Txell
body TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_chat_messages_created_at ON chat_messages(created_at DESC);
CREATE TABLE chat_typing (
author TEXT PRIMARY KEY, -- Edu | Dani | Txell
last_typed_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Migración: migrations/0030_create_chat.sql — aplicada en remote D1 el 18-05-2026.
Véase también
- [[feature—home—team-chat-widget]]
- [[workspace—dashboard]]
- [[workspace—que-es-workspace]]