Feature: File Uploads #17
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#17
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#17
Original Author: @icub3d
Original Date: 2026-04-15T14:15:41Z
Feature: File Uploads
Overview
Allow users to upload files and images to text channels with content-addressable storage, server-configurable size and type limits, and inline image previews in the client. This is a core communication feature that enables sharing screenshots, documents, and other media alongside text messages.
Background
The storage design doc (
docs/design/storage.md) defines content-addressable media storage: files are stored by their hash (SHA-256 or BLAKE3), with metadata in the relational database mappingmedia_id -> content_hash. Identical files are automatically deduplicated. The server model (docs/design/server-model.md) defines thefile_uploadsfeature flag (enabled by default) and server config fieldsmax_file_size,allowed_file_types, and the media retention policy. Media is served via the application server or pre-signed URLs for S3 backends.Requirements
max_file_sizefrom config (reject uploads exceeding the limit)allowed_file_typesfrom config (reject disallowed MIME types; empty list = all allowed)file_uploadsfeature flag gates the entire upload capability; when disabled, upload endpoints return 403Cache-Controlheaders for cacheabilityDesign
API / Interface Changes
New REST endpoints:
POST /api/v1/channels/{channel_id}/attachmentsattachment_idvalues.SEND_MESSAGES+ATTACH_FILES), feature flag, file size, and MIME type.201 Createdwith[{ attachment_id, filename, content_hash, size, mime_type, url }]GET /api/v1/media/{content_hash}Content-TypeandCache-Control: public, max-age=31536000, immutable.Modified endpoint:
POST /api/v1/channels/{channel_id}/messagesattachment_ids: Vec<Uuid>field to the message creation body.New gateway event:
MESSAGE_CREATEandMESSAGE_UPDATEevents now include anattachmentsarray in the payload.New Tauri IPC command:
upload_file(server_id, channel_id, file_path)— Reads the file from disk via Tauri core (which has filesystem access), streams it to the server upload endpoint, returns the attachment metadata.Data Model Changes
New table:
attachmentsNew entry in
MediaStoretrait:Component Changes
Server (
server/):server/src/routes/media.rs— New module: upload endpoint, media serving endpointserver/src/models/attachment.rs— Attachment struct and DB operationsserver/src/storage/media.rs— MediaStore trait implementation for SQLite (local disk) backendserver/src/routes/messages.rs— Modify message creation to accept and associate attachment IDsserver/src/config.rs— Ensuremax_file_size,allowed_file_types,file_uploadsflag are parsedserver/src/gateway/events.rs— Add attachments to message event payloadsClient (
client/):client/src-tauri/src/commands/upload.rs— Tauri IPC command for file uploadclient/src/components/MessageInput.tsx— File picker button, drag-and-drop zone, upload progress indicatorclient/src/components/MessageAttachment.tsx— New component: renders inline image preview or file download linkclient/src/components/Message.tsx— Render attachments within message bubblesclient/src/api/media.ts— API client functions for upload and media URL constructionTask List
Server
attachmentstable to SQLite migrations (server/migrations/007_attachments.sql)Attachmentmodel struct and CRUD inserver/src/storage/sqlite/attachments.rsAttachmentStoretrait and SQLite backend (content-addressable blobs viaserver/src/media.rs)POST /api/v1/channels/{channel_id}/attachmentsendpoint with multipart parsing, hash computation, size/type validation, and feature flag check (server/src/attachments/handlers.rs)GET /api/v1/media/{hash}in existing profiles endpoint with correct Content-TypePOST /api/v1/channels/{channel_id}/messagesto accept and associateattachment_idsATTACH_FILESpermission flag enforced on uploadattachmentsarray included in message responses viaenrich_messagesClient
upload_fileTauri IPC command inclient/src-tauri/src/commands/upload.rsclient/src/api/media.tsMessageInput.tsxwith upload progressMessageAttachment.tsxcomponent with inline image preview (thumbnail with lightbox) and file download linkMessageAttachmentintoMessage.tsxfor rendering attachmentsTest List
server/src/media.rs)routes/attachment_tests.rs)file_uploadsfeature flag is disabled (not yet tested — flag check is in handler)Open Questions
max_file_sizebe? 10 MB is reasonable for a starting point.