Almacenamiento
Adjuntos y activos en S3/B2/R2.
BloomX guarda el contenido de los correos y los adjuntos en un almacenamiento S3-compatible: AWS S3, Cloudflare R2, MinIO o Backblaze B2. Usa @aws-sdk/lib-storage con forcePathStyle.
Configuración#
S3_ENDPOINT="https://<cuenta>.r2.cloudflarestorage.com" # AWS, R2, MinIO o Backblaze B2
S3_REGION="auto"
S3_ACCESS_KEY="<access-key-id>"
S3_SECRET_KEY="<secret-access-key>"
S3_BUCKET="bloomx-uploads"
# S3_SSE="AES256" # o "aws:kms": cifrado del lado del proveedor (opcional)- Las variables
B2_*son un alias heredado deS3_*(prioridad aS3_*). En el backend el almacenamiento usa soloB2_*(B2_ENDPOINT,B2_REGION,B2_BUCKET,B2_ACCESS_KEY,B2_SECRET_KEY) y son obligatorias para almacenar extensiones y archivos. - Sin
S3_ACCESS_KEYoS3_BUCKET, el frontend cae a disco local (<cwd>/.gemini/storage, con protección contra path traversal): útil solo en desarrollo; no sirve en Vercel (sistema de ficheros efímero). S3_SSE=AES256|aws:kmsactiva el cifrado del lado del proveedor. BloomX no cifra cuerpos ni adjuntos a nivel de aplicación (sí cifra secretos, tokens y mensajes sellados: Seguridad).
Claves de objeto#
| Contenido | Clave |
|---|---|
| Correo entrante | emails/<fecha>/<uuid>/content.html, content.txt, raw.json |
| Adjuntos entrantes | emails/<fecha>/<uuid>/… (se evitan colisiones con un sufijo hexadecimal) |
| Adjuntos subidos | attachments/<correo>/<timestamp>-<hex>-<nombre> |
| Cuerpo enviado | sent/<correo>/<timestamp>-<asunto>.html y .txt |
Invitaciones .ics | attachments/<correo>/<timestamp>-<archivo>.ics |
| Mensajes sellados | secure/<uuid>.sealed (los antiguos .msg) |
Los nombres se sanean ([^a-zA-Z0-9.-] pasa a _). Las claves contienen el correo del usuario: es información personal en el nombre del objeto (limitación conocida).
Cómo se sirven los adjuntos#
- El navegador nunca habla con el bucket: descarga por el proxy
/api/assets/<clave>con URL firmada por HMAC (Seguridad). - La subida previa usa
POST /api/upload(hasta 200 MB por archivo, validación de tipo real, antivirus opcional). - Borrar un correo borra de forma completa HTML, texto,
raw.jsony adjuntos con conteo de referencias. - Las operaciones masivas usan
DeleteObjectsen lotes de 1000;deleteStoragePrefixrechaza prefijos amplios. Estas operaciones no se probaron contra S3/B2 reales.
Almacén público del backend#
GET /api/storage/<clave> del backend sirve objetos públicos (por ejemplo logos) con Content-Security-Policy: default-src 'none'; sandbox. Solo las imágenes se sirven inline; el resto como descarga. Bloquea extensions/, . y _. Define `STORAGE_PUBLIC_PREFIXES` (por ejemplo public/,logos/) para que solo esos prefijos sean accesibles; sin ella no hay lista blanca.