Descripción
Handler CloudFlare Workers que gestiona la publicación y lectura de informes de buzón Zoho. Implementa un patrón double-method (POST para escribir, GET para leer) sobre el recurso /api/correo/digest.
Archivo: functions/api/correo/digest.ts (194 LOC)
Autenticación
Soporta dos caminos:
- CF Access (sesión del navegador):
resolveTeamMember(request)— trae la identidad del header CF-Access. - Bearer tokens personales (MCP_TOKENS): variable de entorno con pares
nombre:tokenseparados por comas.- Ej:
EDER:abc123,DANI:xyz789 - Mapea nombre normalizado →
TeamMember(Edu, Dani, Txell).
- Ej:
Restricción crítica: tokens de servicio (maintenance-agent, dr-backup, etc.) NO pueden publicar. El informe siempre pertenece a una persona.
Función memberFromBearer(request, env): TeamMember | null
- Extrae
Authorization: Bearer <token>del header. - Itera pares en
MCP_TOKENS, busca token coincidente. - Normaliza nombre (primer char mayúscula, resto minúscula).
- Valida que sea miembro conocido (
isTeamMember(cap)).
Función resolveMember(request, env): TeamMember | null
- Intenta CF Access primero, fallback a Bearer.
- Devuelve
nullsi ninguno aplica (→ 403 Forbidden).
POST /api/correo/digest
Descripción: publica un nuevo informe de pasada.
Identidad requerida: miembro del staff (personal, no servicio).
Request body (JSON):
interface DigestBody {
generated_at: string; // ISO 8601: timestamp de la pasada
resumen?: string; // línea de resumen (opcional)
ruido_count?: number; // nº mensajes filtrados como ruido
items: DigestItem[]; // max 50 items
}
interface DigestItem {
nivel: 'actua' | 'enterate'; // categoría (obligatorio)
urgente?: boolean; // true → entra en alerta general
remitente: string; // dirección o nombre remitente
asunto: string; // línea asunto
porque: string; // síntesis "por qué importa"
zoho_link?: string; // URL del mensaje en Zoho (opcional)
}
Validaciones:
generated_at: string no vacío.items: array con 0–50 elementos.- Cada item:
nivelen {‘actua’, ‘enterate’}, otros campos truncados a 500 chars.
Acción:
- Inserta en tabla
correo_digests(D1). - Poda automática: elimina registros del mismo miembro con
created_at < now - 30 days(decisión grill). - Si hay items con
urgente=true+nivel='actua':- Desactiva alerta anterior (
UPDATE alerts SET active=0). - Crea nueva alerta general con tipo
'warning'. - Llama
logActivity()para auditoría.
- Desactiva alerta anterior (
- Devuelve
{ ok: true, owner, items: count, urgentes: count }(201).
Errores:
403 Forbidden: identidad no válida o es token de servicio.400 Bad Request: body JSON inválido,generated_atvacío, items > 50 o campo truncado.
GET /api/correo/digest
Descripción: obtiene el último informe DEL MIEMBRO que pregunta.
Identidad requerida: miembro del staff.
Respuesta (JSON):
interface DigestResponse {
owner: string; // 'Edu' | 'Dani' | 'Txell'
generated_at: string; // ISO 8601 de la pasada
resumen: string | null;
ruido_count: number;
items: DigestItem[];
created_at: string; // timestamp de inserción en D1
}
Lógica:
- Query:
SELECT ... FROM correo_digests WHERE owner = ? ORDER BY created_at DESC LIMIT 1 - Parsea
payload(JSON) como items. - Si no hay registro, devuelve
null(200). - Si payload está corrupto, devuelve informe sin items (graceful degradation).
Privacidad: cada miembro solo ve su propio informe. Si intenta GET sin autenticación válida → 403.
Tabla D1 correo_digests
Ver [[entity—migrations—table—correo-digests]].
Resumen:
- Columnas:
id,owner,generated_at,resumen,ruido_count,payload(JSON),created_at. - Índice:
(owner, created_at DESC)para queries rápidas por miembro ordenadas.
Componentes y funciones
Importaciones
resolveTeamMember,isTeamMemberde_lib/staff— validación de identidad.logActivityde../mcp/handlers/activity— registro de auditoría (alertas urgentes).
Constantes
MAX_ITEMS = 50: límite de items por pasada.MAX_FIELD = 500: máximo de caracteres por campo (remitente, asunto, porque, zoho_link).
Interfaces
Env: acceso a D1 yMCP_TOKENSenv var.DigestItem,DigestBody: esquema del informe.
Flujo E2E típico
- Miembro ejecuta
/correoen Claude (skill desatendido). - Extrae categorías, remitentes, asuntos del buzón Zoho.
- Envía
POST /api/correo/digest { generated_at, items: [...] }con su token personal. - Handler valida identidad, inserta en D1, poda registros viejos.
- Si hay urgentes, crea alerta visual.
- Miembro abre dashboard o
/correo→ GET trae último informe. - UI pinta secciones Actúa/Entérate con links a Zoho.
Testing
- Local dev: endpoint accesible sin CF Access; pruebas manuales con curl + token.
- E2E en sesión: pasada real de
/correo→ informe en D1 → widget actualizado.
Véase también
- [[feature—workspace—correo-menu-f0]] — contexto y decisiones de la feature.
- [[entity—src—page—correo-ui]] — página y widget que consumen este endpoint.
- [[entity—migrations—table—correo-digests]] — esquema D1.
- [[concept—authentication—personal-tokens]] — autenticación con MCP_TOKENS.
- [[concept—infra—cloudflare-workers]] — contexto de workers CF.