Temporary File Upload
Overview
A shared upload service used by both forms (file_upload questions) and the bulletin board (images in posts and comments). Files land under the temp/ prefix first, and the owning feature moves them to permanent storage when the real record is saved.
This feature never touches the database, and both endpoints are public — no LIFF token required. They should therefore be read together with the consumer-side commit mechanism, which is what actually proves ownership of a file.
Business Flow
POST /api/upload-file/temp (multipart, field named file)
- A missing or unreadable
filefield returns 400file must be a file(the equivalent of@IsFile()). - Anything over 10 MB returns 400
file must be smaller than or equal to 10485760 bytes(the equivalent of@MaxFileSize). - The buffer is read and the mime type is detected from the actual file content via
util.DetectExtensionandutil.MIMEForExt; the client-suppliedContent-Typeis not trusted. This mirrors the behavior ofnestjs-form-data. - Allowed mime types are
image/jpeg,image/jpg,image/png, andapplication/pdf. Anything else returns 400file has invalid mime type. PutTempwrites the object astemp/temp-{unixMilli}.{ext}and returns{path: publicURL}.
POST /api/upload-file/temp-base64 (JSON with a file field)
- DTO validation requires
fileto be a non-empty string (@IsStringand@IsNotEmpty). DetectExtensionFromBase64identifies the type from the file signature. If it cannot, the response is 400Unable to detect file type. Supported types: jpg, png, gif, pdf, webp— note that this set is broader than the multipart endpoint's.createFileFromBase64strips the data-URI prefix (everything before the first,) and base64-decodes, trying standard encoding first and then raw. A failed decode leaves an empty buffer and falls through to the next check (in the source, JSBuffer.fromnever throws, so the catch was dead code). An empty buffer returns 400Empty file content; an unmappable mime becomesapplication/octet-stream; andoriginalNameis set tofile-{unixMilli}.PutTempwrites the object astemp/temp-{unixMilli}.{ext}and captures the public URL.CopyObjectthen copies topublic/mock-line-oa-hash/images/{filename}. This was ported straight from the source even though nothing consumes that destination — deliberate parity.- The response is
{path: publicURL}, pointing at the file intemp/, not at the copy.
What happens next
The follow-up steps matter more than the endpoints themselves.
- Forms: the returned value is a URL under
temp/. At submit time, Form Answer Submission copies it toform-builder/{formId}/{filename}, validating the filename against^[a-zA-Z0-9._-]+$. - Bulletin board: post writing goes through an image committer that calls
HeadObjectto prove the object really exists before copying. This is the only barrier against referencing another tenant's object or a key that was never uploaded, and it accepts both a public URL and a raw key matching^temp/temp-[0-9]+\.[A-Za-z0-9]+$. - Objects under
temp/are never deleted by any request; sweeping that prefix is a separate operations task.
Key Files & Functions
| Route | Handler |
|---|---|
POST /api/upload-file/temp | internal/uploadfile/handler.go → (*Handler).UploadFileTemp |
POST /api/upload-file/temp-base64 | (*Handler).UploadFileTempBase64 |
internal/uploadfile/register.go→Register(r, deps)internal/uploadfile/service.go→NewService,UploadFileTemp,UploadFileTempBase64,createFileFromBase64,nowMilli, plus thestorageinterfaceinternal/uploadfile/handler.go→tempBase64DTO,allowedTempMimes, andmaxTempFileSizeset to10*1024*1024internal/storagex/storagex.go→New(cfg),PutTemp,GetPublicURL,CopyObject,HeadObject,IsFileExist, and theUploadFiletypeinternal/s3x/s3x.go— the client built on aws-sdk-go-v2internal/util/hash.goandbase64.go→DetectExtension,DetectExtensionFromBase64,MIMEForExt
Connections to Other Services
- Object storage (S3/MinIO) only — no database, no Redis.
- The
deps.Config.Storageconfiguration: endpoint, bucket, andPublicHost, the last of which is used to strip the prefix during the form-side copy. - Downstream consumers: Form Answer Submission, plus bulletin post and comment writing.
- The related client-web feature is
file-upload.