Files & Photos
Weavestream stores uploaded files on the local filesystem with one directory per tenant for storage-layer isolation. Images receive automatic thumbnail generation. A photo gallery view is available per tenant.
Supported File Types
The allowed MIME type list is configurable via ALLOWED_UPLOAD_MIME in .env. Browser-active content types — text/html, application/xhtml+xml, and XML-based image types such as image/svg+xml — are rejected at startup even if added to the list, because they can execute script when rendered inline.
Storage Architecture
Each tenant has a dedicated directory under ${FILE_STORAGE_DIR}/<tenantId>/:
${FILE_STORAGE_DIR}/<tenantId>/uploads/<uploadId>/<filename>
${FILE_STORAGE_DIR}/<tenantId>/thumbs/<uploadId>.webp
${FILE_STORAGE_DIR}/<tenantId>/exports/<exportId>.pdf
- The api and worker share the same host-bind-mounted directory.
- Browsers never read the directory directly — every access streams through the API on the same origin as the web app, which authorizes the request against the requested tenant before opening the file.
- Writes are atomic (write to a temp sibling, then
rename), so anrsyncof the host directory while the stack is running never sees partial files.
Image Processing
When an image is uploaded, the worker service:
- Generates a thumbnail using Sharp (libvips)
- Stores image dimensions (width × height) as metadata
- Makes both the original and thumbnail available via stable, same-origin streaming URLs (
/uploads/:id/imageand/uploads/:id/image?v=thumb)
Photo Gallery
Each tenant has a Photo Gallery view that displays all uploaded images in a grid layout with thumbnail previews. Click any image to view the full-size original.
File Metadata
Each upload record stores:
Upload Limits
The maximum upload size is controlled by MAX_UPLOAD_MB in .env (default: 25 MB). The client-side mirror variable NEXT_PUBLIC_MAX_UPLOAD_MB should be kept in sync.
The web app's request proxy sizes its body buffer from the same MAX_UPLOAD_MB value (apps/web/next.config.js), so no separate proxy tuning is needed — but the web container must be restarted for a changed value to take effect. If an external reverse proxy (nginx, Caddy, Traefik) sits in front, its own body-size limit must still be raised separately; see docs/deployment/tls.md.
Filenames
Filenames are normalised when an upload is initiated: the name is NFC-composed (macOS delivers decomposed accents), then characters outside printable latin-1 — emoji, CJK, control characters — are stripped and whitespace runs collapsed. A name with nothing usable left gets a file stem (e.g. an emoji-only 📸.png is stored as file.png). Accented European names (café.pdf) are preserved. This keeps every stored name valid HTTP header material for Content-Disposition when the file is served.
Asset Field Attachments
The FILE field type on Asset Layouts allows attaching documents directly to asset records. Files attached this way appear inline on the asset detail page.
Company Logos
Each company record can have one logo image. Logos are uploaded into the tenant's directory and displayed in the company list and sidebar.