CreaRack-SL

Endpoints vínculos task ↔ Zoho Mail (GET/POST/DELETE /api/tasks/{id}/links/email)

Endpoints vínculos task ↔ Zoho Mail

functions/api/tasks/[id]/links/email.ts — añadido en s68 (commit 7617371, 2026-05-17).

Persiste en D1 referencias a mensajes de Zoho Mail vinculados a una task desde TaskModal. El mensaje real vive en Zoho Mail; esta tabla es el registro de vínculos local.

Endpoints

GET /api/tasks/{id}/links/email

Lista todos los emails vinculados a la task ordenados por linked_at DESC.

Respuesta 200:

[
  {
    "task_id": 42,
    "zoho_message_id": "msg789",
    "thread_id": "thread001",
    "subject": "Oferta Rack 2U · Referencia XYZ",
    "from_address": "proveedor@example.com",
    "email_date": "2026-05-16T09:00:00Z",
    "url": "https://mail.zoho.eu/zm/#mail/folder/inbox/message/msg789",
    "linked_by": "Dani",
    "linked_at": "2026-05-17T10:45:00"
  }
]

POST /api/tasks/{id}/links/email

Vincula un mensaje de Zoho Mail a la task. Típicamente llamado desde el picker de emails en TaskZohoLinks.

Body requerido:

{
  "zoho_message_id": "string",
  "thread_id": "string (opcional)",
  "subject": "string (opcional)",
  "from_address": "string (opcional)",
  "email_date": "ISO string (opcional)",
  "url": "string (opcional)"
}

Autenticación: requiere CF Access. linked_by = TeamMember resuelto vía resolveTeamMember(request).

Conflicto: ON CONFLICT(task_id, zoho_message_id) DO UPDATE — actualiza metadatos del mensaje si ya vinculado.

Respuesta 201: el row insertado/actualizado.

Errores:

  • 400 — task_id inválido o zoho_message_id ausente.
  • 403 — actor no identificado como TeamMember.
  • 404 — task no encontrada en D1.

DELETE /api/tasks/{id}/links/email?message_id={zoho_message_id}

Elimina el vínculo (no borra el mensaje en Zoho Mail).

Query param requerido: message_id.

Respuesta 200: { "deleted": 1 } (o 0 si no existía).

Tabla D1: task_emails

CREATE TABLE task_emails (
  task_id          INTEGER NOT NULL REFERENCES tasks(id),
  zoho_message_id  TEXT NOT NULL,
  thread_id        TEXT,
  subject          TEXT,
  from_address     TEXT,
  email_date       TEXT,
  url              TEXT,
  linked_by        TEXT NOT NULL,  -- TeamMember
  linked_at        TEXT DEFAULT (datetime('now')),
  PRIMARY KEY (task_id, zoho_message_id)
);

Creada en Migration 0027.

Integración con GET /api/tasks

El listado de tasks incluye email_count calculado en SQL:

(SELECT COUNT(*) FROM task_emails WHERE task_id = tasks.id) AS email_count

Permite badges en KanbanMini, TaskTableView, TaskCalendar sin round-trips adicionales.

Flujo típico desde TaskModal

Usuario clicka "Vincular email" en TaskZohoLinks
  → GET /api/zoho/mail/search?q=...  (picker)
  ← [{ id, subject, from, date, url }, ...]
  → Usuario selecciona un mensaje
  → POST /api/tasks/{id}/links/email  { zoho_message_id, subject, from_address, url, ... }
  ← 201 LinkRow
  → TaskZohoLinks re-fetchea GET /api/tasks/{id}/links/email

Para nuevo email (deep-link compose):

Usuario clicka "Nuevo email" en TaskZohoLinks
  → GET /api/zoho/mail/compose-url?subject=...&body=...
  ← { url: "https://mail.zoho.eu/zm/#mail/compose?..." }
  → window.open(url)   (el usuario completa y envía desde Zoho)

El email enviado no se vincula automáticamente; el usuario puede vincularlo manualmente tras enviarlo.

Véase también

  • [[entity—workers—endpoint—task-calendar-links]]
  • [[entity—workers—service—zoho-lib]]
  • [[entity—workers—service—staff-lib]]
  • [[feature—zoho—per-user-oauth]]
  • [[decision—20260517—integracion-zoho-calendar-mail-pivot]]