Use a short-lived upload capability, record an upload intent before issuing it, and make the browser report completion only after a separate finalize call succeeds. That is the operationally defensible way to let a Vue frontend send a file directly to private object storage while a Node backend retains authorization and application state.
The deciding constraint is not the progress bar. It is the boundary between bytes accepted by an object store and a file that the application is prepared to expose to a user. A browser can lose its final response, retry a request, or leave a tab halfway through an upload; a system that has no explicit state for those cases will eventually turn a harmless network interruption into an incorrect attachment record or an object nobody can account for.
Keep the data plane out of the API service.…