Skip to content

fix: replace stub OptionalProfileImageInterceptor with real Fastify multipart file uploadΒ #120

Description

@Josue19-08

πŸ”– Title

Fix profile image upload β€” `OptionalProfileImageInterceptor` is a no-op stub; `@fastify/multipart` is not installed


πŸ“„ Description

`POST /auth/register` advertises profile image upload support, but the implementation is broken at every layer:

Layer 1 β€” Missing package: `@fastify/multipart` is not installed. Only `@fastify/cors`, `@fastify/formbody`, and `@fastify/middie` are present. `multer` (Express-only) is listed as a dependency but is incompatible with the Fastify adapter.

Layer 2 β€” Stub interceptor: `OptionalProfileImageInterceptor` in `auth.controller.ts` is a complete no-op β€” it calls `next.handle()` and does nothing else. `@UploadedFile()` will always receive `undefined`.

Layer 3 β€” No plugin registration: even if the package were installed, `@fastify/multipart` must be registered on the Fastify adapter instance in `main.ts` before requests can be parsed as multipart.

As a result, profile images are silently ignored for all users β€” no error, no upload, the `profileImageUrl` field in the database is always null.


βœ… Tasks to complete

  • Add `@fastify/multipart` to `package.json` and install; remove `multer` if it has no other usages
  • Register `@fastify/multipart` plugin in `src/main.ts` with appropriate file size limit (read from env: `MAX_FILE_SIZE_MB`, default 5MB)
  • Replace `OptionalProfileImageInterceptor` stub in `src/modules/auth/auth.controller.ts` with real Fastify multipart handling using `request.file()`; make file optional (register succeeds with no image)
  • Update `src/modules/auth/auth.service.ts` β€” ensure `register()` correctly receives the file buffer and calls the storage upload function when a file is present
  • Update `src/database/repositories/users.repository.ts` β€” verify `updateAvatar()` (or equivalent) handles the Fastify file object shape (buffer, mimetype, filename)
  • Add `MAX_FILE_SIZE_MB` and allowed MIME types (`image/jpeg`, `image/png`, `image/webp`) to `src/config/env.ts` validation
  • Add unit tests in `test/unit/modules/auth/auth.controller.spec.ts`: register with valid image β†’ `profileImageUrl` set; register without image β†’ succeeds with null URL; register with oversized file β†’ 413; register with invalid MIME β†’ 400

πŸ“š Documentation/context for AI

(This link never should removed)
https://github.com/TrustUp-app/TrustUp-API/tree/main/docs

Relevant files:

  • `src/main.ts`
  • `src/modules/auth/auth.controller.ts` (OptionalProfileImageInterceptor)
  • `src/modules/auth/auth.service.ts`
  • `src/database/repositories/users.repository.ts`
  • `src/config/env.ts`

πŸ—’οΈ Additional notes

  • Use `@fastify/multipart` directly via `request.file()` inside the controller; do not use NestJS `FileInterceptor` which requires the Express adapter
  • Validate MIME type before uploading; reject non-image files with a clear 400 error code `FILE_INVALID_TYPE`
  • File size validation should happen at the Fastify plugin level (via `limits.fileSize`), not just in the controller
  • If a user registers without a profile image, `profileImageUrl` should be `null` in the DB β€” this is the current (silently broken) behavior that should now work explicitly

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions