Volver a la wiki

Cuaderno · Multiusuario y 7 nuevas funciones (PR#56)

Cuaderno · Multiusuario y 7 nuevas funciones (PR#56)

PR#56 mergeado el 2026-05-20 por @Esquembri. Extiende el módulo Cuaderno con sharing colaborativo entre los miembros del staff y añade 6 herramientas de edición adicionales pedidas por Edu. Trabaja sobre la tabla notebook_notes ya existente.


1. Sharing multiusuario

Modelo de datos (migration 0032)

ALTER TABLE notebook_notes ADD COLUMN shared_with TEXT NOT NULL DEFAULT '';
ALTER TABLE notebook_notes ADD COLUMN version     INTEGER NOT NULL DEFAULT 1;
Valor de shared_withSemántica
'' (vacío)Nota privada — solo el owner la ve
'ALL'Compartida con todo el staff
'edu@esfericlabs.com,dani@esfericlabs.com'CSV de emails específicos

La lógica de acceso en todos los handlers sigue el mismo patrón:

const canAccess =
  row.owner_id === me ||
  row.shared_with === 'ALL' ||
  (row.shared_with !== '' && row.shared_with.includes(me));

Nota de seguridad: el LIKE %email% se considera seguro porque los emails @esfericlabs.com son únicos y sin solapes de substring con el staff actual (3 personas). Documentado en el comentario de 0032_notebook_sharing.sql.

Permisos de operación

AcciónOwnerCollaborator
GET nota✅✅
PUT contenido/título/pin/archivado✅✅
PUT shared_with✅❌ (403)
DELETE nota✅❌ (404)
POST imagen✅✅

UX en frontend

Detección de ediciones concurrentes


2. Undo / Redo — botones visibles

Botones ↶ ↷ en la toolbar del editor. Invocan undo/redo de @codemirror/commands. CodeMirror ya tenía Ctrl+Z ilimitado; los botones añaden descubribilidad para usuarios no técnicos.


3. Toggle autocorrector


4. Tachado + marca Urgente

FunciónSintaxis MarkdownRenderizado
Tachado~~texto~~texto
Urgente!!texto!!<mark class="urgent">⚠ texto</mark> (rojo translúcido + borde izquierdo)

5. Emoji picker


6. Fix layout — botones header desbordando

Ajuste CSS puntual en .cuaderno-header-compact .tools-btn:

/* Antes */  padding: 0.5rem 1rem;   font-size: 0.82rem;
/* Ahora  */  padding: 0.32rem 0.7rem; font-size: 0.74rem;

Los botones de la toolbar ahora encajan en una sola línea en viewports compactos.


7. Insertar imágenes embebidas

Flujo completo de subida e inserción de imágenes en notas:

Botón 🖼 → file input → POST /api/notebook/:id/images
  → validación MIME + tamaño (5MB max)
  → PUT en R2 bucket TASK_ATTACHMENTS (prefix notebook/)
  → INSERT en notebook_attachments
  → inserta ![alt](/api/notebook-images/{id}) en el editor

MIME whitelist: image/png, image/jpeg, image/webp, image/gif.

Borrado en cascada: al eliminar una nota, el handler DELETE recupera primero todas las r2_key de notebook_attachments y las borra de R2, antes de ejecutar el DELETE SQL (la FK ON DELETE CASCADE limpia las rows pero R2 quedaría huérfano sin este paso).


Endpoints nuevos / modificados

MétodoRutaHandlerCambio
GET/api/notebookfunctions/api/notebook/index.tsModificado: lista propias + compartidas
POST/api/notebookfunctions/api/notebook/index.tsModificado: acepta shared_with
GET/PUT/DELETE/api/notebook/:idfunctions/api/notebook/[id]/index.tsReemplaza [id].ts eliminado; añade shared_with, version
GET/api/notebook/:id/versionfunctions/api/notebook/[id]/version.tsNuevo — polling de versión
POST/api/notebook/:id/imagesfunctions/api/notebook/[id]/images.tsNuevo — subida de imágenes
GET/api/notebook-images/:idfunctions/api/notebook-images/[id].tsNuevo — stream de imagen con check de acceso

El fichero functions/api/notebook/[id].ts fue eliminado y sustituido por functions/api/notebook/[id]/index.ts para soportar subrutas (images, version).


Dependencias de infraestructura

RecursoUso
D1 notebook_notesTabla principal — extendida con shared_with + version
D1 notebook_attachmentsNueva tabla — ver [[entity—notebook—table—notebook-attachments]]
R2 TASK_ATTACHMENTSBucket compartido con tareas; prefix notebook/ para las imágenes de notas

Véase también

Subir