Módulo File
src/app/modules/file/
Gestiona la subida y almacenamiento de archivos adjuntos (imágenes, audio, video y documentos) en un almacenamiento privado compatible con S3/MinIO. Los mensajes referencian estos archivos por su _id.
Modelo — File
Colección files, con timestamps.
| Campo | Tipo | Descripción |
|---|---|---|
_id | ObjectId | ID de MongoDB |
tenantId | ObjectId → Tenant | Tenant propietario |
filename | string | Nombre del archivo (la extensión puede cambiar tras la conversión) |
url | string | URL guardada al subir; no es accesible directamente (ver Gotchas) |
storageKey | string | Clave del objeto en el almacenamiento: tenantId/año/mes/carpeta/uuid.ext |
mimetype | string | Tipo MIME final |
size | number | Tamaño en bytes del contenido guardado |
type | enum | image, audio, video o document |
durationSeconds | number | Solo audio |
waveform | number[] | Solo audio: 64 niveles de 0 a 100 |
thumbnail | string | Solo video: primer fotograma en JPEG base64 |
createdAt / updatedAt | Date | Timestamps |
Endpoints
Base: /api/v1/files. Controlador con @Auth() y PermissionsGuard; todo se limita al tenant del usuario.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
POST | /files/upload | FILE_CREATE | Sube un archivo (multipart/form-data, campo file) |
GET | /files/get-all | FILE_READ | Lista los archivos del tenant (data.results), con URL firmada |
GET | /files/get-one/:id | FILE_READ | Metadatos de un archivo, con URL firmada |
DELETE | /files/remove/:id | FILE_DELETE | Elimina el objeto del almacenamiento y el registro |
DTOs y parámetros
El módulo no define DTOs de class-validator; la validación ocurre en FileService.
| Parámetro | Ubicación | Tipo | Obligatorio | Validación | Usado en |
|---|---|---|---|---|---|
file | body multipart | archivo | Sí | Campo file; tipo MIME permitido y tamaño máximo por tipo; en audio, duración de 1 s a 2 min. Si no se cumple, 400 | POST /files/upload |
id | ruta | string | Sí | Ninguna en el controlador; se busca por _id y tenant, y si no existe responde 404 | get-one/:id, remove/:id |
Tipos permitidos y límites
| Tipo | MIME permitidos | Tamaño máximo |
|---|---|---|
image | image/jpeg, image/png, image/gif, image/webp | 5 MB |
audio | audio/webm, audio/ogg, audio/mp4, audio/mpeg, audio/wav, audio/x-m4a | 15 MB |
video | video/mp4, video/webm, video/quicktime, video/x-msvideo, video/x-matroska, video/mpeg, video/3gpp, video/x-flv | 20 MB |
document | PDF, Word (doc, docx) y Excel (xls, xlsx) | 10 MB |
El parámetro del MIME se normaliza (se descarta lo que sigue a ;).
Flujo de subida
Las imágenes se reprocesan, los videos se procesan y generan una miniatura, y los audios se convierten y generan duración y forma de onda. La duración de un audio se valida antes de convertirlo.
Gotchas
- El bucket es privado: la
urlguardada nunca es accesible. Cada lectura (upload,get-all,get-one) la sustituye por una URL firmada de corta duración generada desdestorageKey. - Los archivos que entran por canales externos (WhatsApp, Meta) se guardan con
storeIncoming, que no valida el tipo MIME ni reprocesa el contenido. - El endpoint público del widget sube archivos con el token de la conexión y reutiliza
FileService.upload(ver Widget). - Quien sube el archivo no se registra: el modelo no tiene
uploadedBy.