Short answer: a Vue frontend can send a file straight to private object storage with an Axios progress bar, but the Node backend must authorize the object key, issue the presigned URL, and control every later read.
That split is the architecture decision. The browser owns bytes and presentation; the backend owns identity, namespace, and attachment state. A successful PUT is useful evidence, but it isn't permission to attach an arbitrary key to an invoice, profile, or case.
What should a Vue frontend, Axios progress bar, presigned URL, and Node backend each own?
Treat the flow as two planes. In the control plane, the authenticated Vue app asks Node for permission to upload a particular file. Node derives a key such as tenant/{tenantId}/user/{userId}/{generatedName} rather than accepting an unchecked key from the browser, requests a presigned upload URL, and returns the short-lived result. In the data plane, Axios sends the bytes directly to that returned URL and maps its upload progress events to the UI.…