Volver a la wiki

Endpoints /api/correo/peticiones · Cola de Encargos de Correo (F2)

Descripción

Conjunto de endpoints que gestionan la cola de peticiones (encargos) que un miembro encola para que la secretaria de correo atienda. Son simples, CRUD sin lógica multiturno.

Autenticación

Dos canales de identidad escopo estricto:

CF Access (Navegador)

resolveTeamMember(request) — extrae la identidad CF Access. Usa X-Forwarded-For o headers CF típicos.

Bearer Token (Pasada Desatendida)

memberFromBearer(request, env) — extrae el token del header Authorization: Bearer <token> y lo mapea a un miembro:

const auth = request.headers.get('Authorization');
if (!auth?.startsWith('Bearer ')) return null;
const token = auth.slice(7);
for (const pair of (env.MCP_TOKENS || '').split(',').filter(Boolean)) {
  const [name, t] = pair.split(':');
  if (t && t === token) {
    const cap = name.trim().charAt(0).toUpperCase() + name.trim().slice(1).toLowerCase();
    return isTeamMember(cap) ? cap : null;
  }
}

Env var MCP_TOKENS = edu:token123,dani:token456,... (pares de nombre:token).

Resolución Unificada

function resolveMember(request: Request, env: Env): TeamMember | null {
  return resolveTeamMember(request) ?? memberFromBearer(request, env);
}

Intenta CF Access primero, luego Bearer. Si ninguno, 403 Forbidden.

GET /api/correo/peticiones

Lista las peticiones del miembro autenticado.

Query params (opcionales):

Ejemplo:

GET /api/correo/peticiones?estado=pendiente&limit=10

Respuesta (200):

[
  {
    "id": 1,
    "owner": "Edu",
    "texto": "Respóndele a Hetzner que confirmen la entrega",
    "estado": "pendiente",
    "respuesta": null,
    "compose_url": null,
    "created_at": "2026-08-12 14:30:00",
    "atendida_at": null
  },
  {
    "id": 2,
    "owner": "Edu",
    "texto": "Aviso a los clientes sobre la caída",
    "estado": "atendida",
    "respuesta": "Estimados, la infraestructura fue afectada...",
    "compose_url": "https://mail.zoho.com/...#compose&to=...",
    "created_at": "2026-08-12 13:15:00",
    "atendida_at": "2026-08-12 14:28:00"
  }
]

POST /api/correo/peticiones

Crea una petición nueva. Solo desde navegador (CF Access).

Body:

{
  "texto": "Respóndele a X que Z"  // ≤1000 chars, obligatorio
}

Validaciones:

Respuesta (201 Created):

{
  "id": 3,
  "owner": "Edu",
  "texto": "Respóndele a X que Z",
  "estado": "pendiente",
  "respuesta": null,
  "compose_url": null,
  "created_at": "2026-08-12 14:35:00",
  "atendida_at": null
}

Errores:

PUT /api/correo/peticiones/:id

Atiende una petición: marca como atendida, añade respuesta y deep-link a Zoho Compose.

Body (todos opcionales, parcial):

{
  "estado": "pendiente|atendida|descartada",  // estado nuevo
  "respuesta": "el borrador que la secretaria generó",
  "compose_url": "https://mail.zoho.com/..."
}

Validaciones:

Lógica:

Respuesta (200):

{
  "id": 2,
  "owner": "Edu",
  "texto": "Aviso a los clientes sobre la caída",
  "estado": "atendida",
  "respuesta": "Estimados, se produjo un corte...",
  "compose_url": "https://mail.zoho.com/...",
  "created_at": "2026-08-12 13:15:00",
  "atendida_at": "2026-08-12 14:28:00"
}

Errores:

DELETE /api/correo/peticiones/:id

Descarta una petición (elimina permanentemente).

Validación:

Respuesta (204 No Content).

Errores:

Flujo de Integración (F2)

Paso 1: Navegador Crea

const response = await fetch('/api/correo/peticiones', {
  method: 'POST',
  body: JSON.stringify({ texto: "Respóndele a Hetzner que confirmen..." })
});

→ Crea fila con estado='pendiente' en correo_peticiones.

Paso 2: Pasada Desatendida Atiende

La pasada de /correo (parte de Paso 7 de claude-method) corre periódicamente y:

  1. Autentica con Bearer {miembro_token} (del MCP_TOKENS).
  2. Llama GET /api/correo/peticiones?estado=pendiente&limit=5 → obtiene hasta 5 peticiones pendientes.
  3. Para cada petición, genera un borrador de correo (en claude-method, Paso 7).
  4. Produce un compose_url de Zoho Compose con el borrador pre-rellenado.
  5. Llama PUT /api/correo/peticiones/:id con {"estado":"atendida", "respuesta":"...", "compose_url":"..."}.

Paso 3: Navegador ve el Resultado

El miembro abre /correo, ve la petición ahora con estado='atendida' + botón compose_url para ir a Zoho y enviar manualmente.

Tabla Underlying (correo_peticiones)

Ver [[entity—correo—table—peticiones]] para schema e índices.

Diseño Aplazado

Véase también

Subir