Skip to content

feat: User pfp + s3 file uploads#75

Merged
anish-sahoo merged 48 commits intomainfrom
user-pfp-s3
Jan 29, 2026
Merged

feat: User pfp + s3 file uploads#75
anish-sahoo merged 48 commits intomainfrom
user-pfp-s3

Conversation

@anish-sahoo
Copy link
Copy Markdown
Member

@anish-sahoo anish-sahoo commented Jan 18, 2026

Description

  • Added code and tests for S3 file uploads using presigned urls to support bulk uploads of multiple file sizes (using client-side compression).
  • Updated DB Tables for user pfp and file storage
  • Updated Doppler to include S3_ENDPOINT for dev that uses the localstack url
  • Added Mockery to help with mocking aws libraries and other complex files
  • Updated the backend/Makefile to support using doppler's backend > dev_personal keys.

Tip

  • please try following the TESTING_S3_UPLOADS.md instructions to get setup.
  • example usage for the frontend hooks are listed as comments in those hooks

Upload flow (explained)

  1. User select an image from the frontend
  2. When uploading, the images gets uploaded in either a small, medium, or large size (there is also a function to upload all three sizes, which is the default except for the [planned] profile picture submissions, which will only upload small.
  3. To explain the file sizes (you can find in frontend/constants/images.ts
    • large - max 6MB
    • medium - scaled down quality and image size to 60% of original (maintains ratio); max 2MB
    • small - scaled down 256x256 at 75% quality; max 512KB
  4. In uploading the image, if the file size is too big (for large), it will get compressed down in quality linearly from 90% of original to 60% in increments of 5%. If quality compression isn't enough, it'll try the same thing by scaling down the dimensions of the image. If both aren't enough, then we throw an error and reject the upload.
  5. Upon a successful compression, the image is sent to the backend for db processing
  6. The frontend sends a request to upload in s3

How has this been tested?

Backend - added mockery mocking library and mocks for s3 sdk, and tested with a bunch of tests, tested file uploads end to end with scripts/test_uploads.sh
Frontend - added jest tests for both the services and utilities folder. We also added a button in the main login page that you can test the flow out yourself.

Checklist

  • I have self-reviewed my code for readability, maintainability, performance, and added comments/documentation where necessary.
  • New and existing tests pass locally with my changes.
  • I have followed the project's coding standards and best practices.
  • Client-side multi-variant image compression + parallel uploads to S3 using presigned PUT URLs; profile-picture uploads restrict to the small variant and users store a UUID reference to images.
  • Backend file API for presigned URL generation (createUploadURLs), upload confirmation (confirmUpload with HeadObject → status transitions), S3 health (HeadBucket), and retrieval of presigned GET URLs (getFile/getFileAllSizes); includes service, repository, controller, router, OpenAPI docs and extensive tests/mocks.
  • Database migrations and schema additions: images table (image_id + size primary key), image_size and upload_status enums, status/timestamps (pending/confirmed/failed), profile_picture as UUID on users with cascade-delete and index, and cleanup for stale pending uploads.
  • Developer tooling, tests and docs: generated testify mocks (mockery), S3 SDK v2 mocks, backend test scripts and TESTING_S3_UPLOADS.md, LocalStack dev wiring (DOPPLER S3_ENDPOINT), Makefile targets (mocks, dev-personal), CI step to install mockery, and frontend Jest tests plus a Test Upload UI.

Categorized change list

  • Features
    • Multi-size compression strategy (large/medium/small) and client iterative-quality + scaling algorithm; default uploads all sizes, profile-picture uploads only small.
    • Presigned PUT flow: createUploadURLs → client uploads → confirmUpload verifies S3 objects and updates DB; presigned GET endpoints for single/all sizes; S3 health endpoint.
    • Frontend hooks and services: uploadImage, uploadProfilePicture, uploadGalleryImage, getImageURL, getImageAllSizes; useGetImage/useGetImageAllSizes hooks and Test Upload screen.
    • Strong OpenAPI/Swagger additions for file endpoints and User.profile_picture.
  • Fixes
    • None specified.
  • Improvements
    • Strongly-typed Go and TypeScript models for file APIs and image entities; image_size validator added.
    • Robust unit/integration test coverage: backend FileService tests, frontend utilities/services tests, autogenerated mocks for S3 and repositories.
    • DX: test scripts (backend/scripts/test_upload.sh), TESTING_S3_UPLOADS.md, frontend Jest config and setup, Test Upload UI button.
  • Infra
    • AWS SDK Go v2 integrated; backend AWS config now supports S3Client + PresignClient and S3_ENDPOINT (LocalStack/path-style).
    • Build/test tooling: mockery integration, Makefile mocks target, CI workflow step to install mockery, Doppler dev_personal/variable support in Docker/compose.

Author contribution summary (approx. lines)

Area Added Removed
Backend (code, migrations, tests, mocks, docs) ~4,200 ~0
Frontend (services, utils, hooks, tests, UI) ~3,000 ~0
Workflows / Docs / Scripts / Tests ~1,100 ~0
Total ~8,300 ~0

Sequence (high-level) — file upload flow
Client -> compress variants -> POST /api/v0/files/upload (createUploadURLs) -> Backend creates pending DB rows + returns presigned PUT URLs -> Client PUT to S3 presigned URLs -> Client POST /api/v0/files/confirm -> Backend HeadObject(s) -> mark Confirmed (or Failed) in DB -> Client GET /api/v0/files/{imageId}/{size} (or /all) -> Backend returns presigned GET URL

Comment thread frontend/__tests__/utilities/images.test.ts Fixed
Comment thread frontend/package-lock.json Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Adds end-to-end S3-backed image uploads: AWS SDK and presign clients, DB migrations and Image models, repository/service/controller/routes for upload/confirm/get, frontend compression/upload utilities and hooks, tests with autogenerated mocks, CI updates, test scripts, and S3 testing documentation.

Changes

Cohort / File(s) Summary
CI / Workflows
/.github/workflows/frontend.yml, /.github/workflows/backend.yml
Add frontend unit-tests job and timeout; install mockery in backend CI.
Mockery & Make
backend/.mockery.yml, backend/Makefile
Add mockery config, mocks Make target, and run mock generation before tests.
Docker / Compose
backend/dev.Dockerfile, backend/docker-compose.yml
Make dev CMD use DOPPLER_CONFIG via shell; add extra_hosts entry for localstack.
AWS SDK & Config
backend/go.mod, backend/internal/config/aws.go, backend/internal/interfaces/s3.go
Add AWS SDK v2 deps; load AWS config; initialize S3 and presign clients; expose HeadBucket and S3 interfaces.
DB Migrations
backend/internal/migrations/*
Add migrations: profile_picture column (TEXT→UUID), images table and enums, upload_status, timestamps, indexes, and cascade-delete trigger.
Backend Models
backend/internal/models/files.go, backend/internal/models/images.go, backend/internal/models/users.go
Add file request/response models, Image model, ImageSize/UploadStatus enums, and ProfilePicture UUID on User/update request.
Repository Layer
backend/internal/repository/repository.go, backend/internal/repository/images.go
Introduce ImageRepository interface and Bun-backed implementation for pending creation, confirmation, failure marking, lookup, deletion, and cleanup.
Service Layer
backend/internal/services/files.go
Add FileService and interface to create presigned PUT URLs, persist pending images, confirm uploads (HeadObject), and generate presigned GET URLs.
Controllers & Routes
backend/internal/controllers/files.go, backend/internal/server/routers/...
Add FileController handlers and wire routes into /api/v0 (testing) and /api/v1.
Backend Tests & Mocks
backend/internal/tests/*, backend/internal/tests/mocks/*, backend/internal/tests/testkit/*
Add extensive FileService tests and many autogenerated testify mocks; test wiring now includes config.
Validator
backend/internal/utilities/validator.go
Register image_size validator and include allowed sizes in validation messages.
Test Script & Docs
backend/scripts/test_upload.sh, docs/TESTING_S3_UPLOADS.md
Add local upload test script and detailed S3 testing documentation.
Frontend Types & Config
frontend/types/images.ts, frontend/constants/images.ts, frontend/tsconfig.json, frontend/package.json
Add image types and IMAGE_CONFIG presets, enable Jest types, add dependencies and test scripts.
Frontend Utilities
frontend/utilities/images.ts
Add image dimension and file utilities, iterative compression pipeline, and uriToBlob.
Frontend Service & Hooks
frontend/services/imageService.ts, frontend/api/files/*, frontend/api/files/index.ts
Add client upload orchestration, retrieval functions, React Query hooks, and barrel export.
Frontend Tests & Jest
frontend/__tests__/**/*.test.ts, frontend/jest.config.js, frontend/jest.setup.js
Add extensive unit tests, Jest config, and test setup mocks for Expo/react-native and global fetch.
Frontend UI / Screen
frontend/app/(app)/index.tsx, frontend/app/(app)/test-upload.tsx
Add Test Image Upload navigation button and TestUploadScreen for manual/e2e testing.
Misc / Generated
backend/internal/tests/mocks/*, backend/internal/tests/*, backend/internal/tests/testkit/*
Many autogenerated mock files, small test helpers, lint suppressions, and minor test-related adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client/App
    participant API as API Server
    participant DB as Database
    participant S3 as S3 Service

    Client->>API: POST /api/v1/files/upload (fileKey, sizes)
    API->>DB: CreatePendingImages(imageID, fileKey, sizes)
    DB-->>API: pending records
    API->>S3: PresignPutObject (per size)
    S3-->>API: presigned PUT URLs
    API-->>Client: imageId, uploadUrls, expiresAt

    Client->>S3: PUT to presigned URLs (parallel)
    S3-->>Client: 200 OK

    Client->>API: POST /api/v1/files/confirm (imageId, optional size)
    API->>S3: HeadObject for relevant sizes
    S3-->>API: object metadata / not found
    API->>DB: Update images status -> confirmed/failed
    DB-->>API: updated records
    API-->>Client: confirm response (status, confirmed count)

    Client->>API: GET /api/v1/files/{imageId}/{size}
    API->>DB: FindByIDAndSize(imageID, size)
    DB-->>API: confirmed record
    API->>S3: PresignGetObject
    S3-->>API: presigned GET URL
    API-->>Client: GET URL
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

Presigned links handed, keys carved neat,
Pending rows wait while clients POST and PUT.
Head checks flip to confirmed, sizes complete,
Frontend shrinks pixels, backend seals the cut.
Tests hum and docs guide — uploads take root.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: User pfp + s3 file uploads' directly summarizes the main changes: adding user profile picture support and S3 file upload functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@in-mai-space in-mai-space left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRAZY WORK GUYS, THIS IS PROBABLY THE BIGGEST PR IN GENERATE HISTORY 🔥🔥🔥

very tiny nits otherwise the overall logic looks good to me

Comment thread backend/internal/server/routers/routers.go
Comment thread docs/TESTING_S3_UPLOADS.md Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@frontend/api/files/useGetImageAllSizes.ts`:
- Around line 40-42: The errors array filter currently only excludes nulls and
may let undefined through; update the filtering in useGetImageAllSizes to ensure
q.error values of both null and undefined are removed (e.g., change the
predicate on queries.map(q => q.error as GetImageError | null) to filter by e =>
e != null or explicitly e !== null && e !== undefined) so the resulting errors:
array is strictly GetImageError values; reference the queries array, q.error,
the errors variable and the GetImageError type when making the change.

Comment thread frontend/api/files/useGetImageAllSizes.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/dev.Dockerfile (1)

1-25: Optional: Consider adding HEALTHCHECK and non-root user for hardened dev images.

Static analysis flags two low-severity items:

  1. No HEALTHCHECK instruction.
  2. No non-root user created.

For a dev container with hot-reload, these are not critical. However, if you want consistency with production practices or run this in orchestrated environments, consider adding them.

Example additions
# Add a non-root user (before WORKDIR)
RUN adduser -D appuser
USER appuser

# Add a healthcheck (after EXPOSE)
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
  CMD curl -f http://localhost:8000/health || exit 1

Note: Non-root user may require adjusting volume mount permissions for local development.

.github/workflows/frontend.yml (1)

46-47: Remove the bun add -D prettier step from the workflow.

Prettier is already listed in frontend/package.json (line 70, version ^3.8.1). This installation step is redundant and mutates the workspace unnecessarily. Relying on bun install alone is sufficient.

Proposed change
-      - name: Install Prettier
-        run: cd frontend && bun add -D prettier
🤖 Fix all issues with AI agents
In `@backend/internal/repository/images.go`:
- Around line 106-114: The MarkFailed function should detect when the UPDATE
matched zero rows and return errs.ErrNotFound instead of nil; modify
imageRepository.MarkFailed to capture the result of Exec(ctx), check if err !=
nil and return it, then call res.RowsAffected() and if it returns 0 return
errs.ErrNotFound, otherwise return nil—follow the same pattern used in
DeleteByID and reference models.Image, models.UploadStatusFailed, and
errs.ErrNotFound when implementing this change.

In `@backend/internal/services/files.go`:
- Around line 168-201: The loop in ConfirmUpload (using f.findPendingImages,
f.s3Client.HeadObject, imageRepo.MarkFailed, imageRepo.ConfirmUpload) currently
swallows per-size failures and only returns confirmedCount; update it to collect
failed size details instead of silently skipping: maintain a slice of failed
sizes (and optional error reasons), increment it when HeadObject or
ConfirmUpload fails (and continue to MarkFailed), and return those failures in
the response (extend models.ConfirmUploadResponse with FailedSizes/FailedCount
and include those fields) or, if desired, return a consolidated error when any
sizes fail; ensure callers receive which image sizes failed and why rather than
only confirmedCount.

In `@backend/internal/utilities/validator.go`:
- Around line 30-39: The allowedImageSizes slice duplicates model constants and
can diverge; replace the hardcoded allowedImageSizes with references to the
model constants (e.g., models.ImageSizeSmall, models.ImageSizeMedium,
models.ImageSizeLarge) and update isAllowedImageSize to iterate over that
derived slice or check directly against those constants so the validator always
uses the canonical values from the models package (update any imports as needed
and keep function name isAllowedImageSize unchanged).

In `@docs/TESTING_S3_UPLOADS.md`:
- Around line 137-201: The fenced Go example contains hard tabs; replace all
tabs with spaces inside the code block to satisfy markdownlint MD010. Edit the
snippet for TestFileController_CreateUploadURLs (including the app setup,
mockFileService setup via mocks.NewMockFileService, controller :=
controllers.NewFileController, the mock On("CreateUploadURLs", ...), request
body creation using models.UploadURLRequest, and the call to
controller.CreateUploadURLs) and convert every tab character to spaces so the
code block uses consistent space indentation.

Comment thread backend/internal/services/files.go
Comment thread backend/internal/utilities/validator.go Outdated
Comment thread docs/TESTING_S3_UPLOADS.md
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@frontend/__tests__/utilities/images.test.ts`:
- Around line 28-31: Capture the original global fetch before overwriting it
(e.g., store it in a variable like originalFetch) and restore it in an afterAll
cleanup so the test suite doesn't leak globalThis.fetch; update the test module
where mockFetch is assigned (the mockFetch and globalThis.fetch assignment) to
save originalFetch first and add an afterAll block that sets globalThis.fetch
back to originalFetch (or undefined if it was undefined).

In `@frontend/app/`(app)/test-upload.tsx:
- Around line 26-34: If profileImageId or galleryImageId can be null, avoid
passing null into hooks: update the calls to useGetImage and useGetImageAllSizes
so they receive an empty array when the id is null (e.g.
useGetImage(profileImageId ? [profileImageId] : [], "small") and
useGetImageAllSizes(galleryImageId ? [galleryImageId] : [])), or alternatively
pass a disabled flag to the hook (e.g. an options { enabled: !!profileImageId })
so the hooks (useGetImage, useGetImageAllSizes) never run with a null ID; adjust
any downstream usages of profileImages[0] and galleryImagesAllSizes[0] to handle
undefined safely (profileImageData/galleryImageAllSizes).

In `@frontend/services/imageService.ts`:
- Around line 103-140: The uploadImage function should validate that the sizes
array is non-empty before doing work: check the UploadImageRequest.sizes (or
local sizes variable) and if sizes.length === 0 throw a clear client-side Error
(e.g., "sizes must contain at least one size") and return early; do this before
calling compressImage, getUploadURLs, or any uploads so compressImage,
getUploadURLs, and confirmUpload are not invoked with an empty sizes list.

In `@frontend/utilities/images.ts`:
- Around line 83-145: In compressWithIterativeQuality the scale loop compounds
because it uses result.width/result.height from previous iterations and
qualitySteps may exceed initialQuality; fix by capturing baselineWidth and
baselineHeight once before the scaleSteps loop and compute scaledWidth/Height
from those baselines (e.g., Math.round(baselineWidth * scale)), and filter
qualitySteps to only include values <= initialQuality before iterating; update
references in the loops that call ImageManipulator.manipulateAsync and
getFileSize and keep the final ImageCompressionError with sizeName unchanged.

Comment thread frontend/__tests__/utilities/images.test.ts
Comment thread frontend/app/(app)/test-upload.tsx
Comment thread frontend/services/imageService.ts
Comment thread frontend/utilities/images.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@backend/internal/repository/images.go`:
- Around line 48-58: The Returning("*") call on the update built with
r.db.NewUpdate().Model(image)...Exec(ctx) is misleading because Exec() does not
populate the model from RETURNING; remove the Returning("*") invocation from the
update chain (the code that sets status to models.UploadStatusConfirmed and
confirmed_at) and leave the existing SELECT that follows to fetch the updated
record so behavior and intent are clear; locate the update built with
r.db.NewUpdate() / Set("status = ?", models.UploadStatusConfirmed) /
Set("confirmed_at = ?", now) and delete the Returning("*") call.

In `@frontend/api/files/useGetImage.ts`:
- Around line 24-43: The aggregate status flags in useGetImage are computed
manually from the raw queries array and incorrectly include skipped queries
(created with skipToken), so refactor useGetImage to pass a combine callback to
useQueries that filters out skipped queries by testing fetchStatus !== 'idle'
(or similar) before computing aggregated values; inside the combine callback
compute data (map q.data and filter to GetImageURLResponse), isLoading
(active.some(q => q.isLoading)), isSettled (active.length > 0 && active.every(q
=> q.isSuccess || q.isError)), isSuccess (active.length > 0 && active.every(q =>
q.isSuccess)), and collect errors (map q.error and filter to GetImageError),
then return useQueries({ queries: imageIds.map(... queryKey/queryFn using
getImageURL and skipToken), combine }) so all callers of useGetImage get correct
aggregated state.

In `@frontend/api/files/useGetImageAllSizes.ts`:
- Around line 19-38: In useGetImageAllSizes, exclude skipped queries (those
where queryFn used skipToken / imageId falsy) before computing aggregate flags:
derive activeQueries = queries.filter(q => q.fetchStatus !== "idle" || q.queryFn
!== skipToken) or better filter by presence of queryKey or q.data !== undefined;
then compute isLoading, isSettled, and isSuccess from activeQueries (isLoading =
activeQueries.some(q => q.isLoading), isSettled = activeQueries.every(q =>
q.isSuccess || q.isError), isSuccess = activeQueries.every(q => q.isSuccess));
keep the existing data mapping from queries.map(q => q.data).filter(...)
unchanged and reference queries, getImageAllSizes, and skipToken when making the
change.

In `@frontend/api/files/useImageUpload.ts`:
- Around line 14-19: The JSDoc for the useImageUpload hook is misleading: update
the comment that currently states "Optional mutation options (cropping, etc.)"
to accurately describe the parameter as React Query mutation options
(UseMutationOptions) used to control the mutation behavior (onSuccess, onError,
retry, etc.); edit the JSDoc for the useImageUpload function/parameter to
reference UseMutationOptions and remove any mention of cropping so readers know
these are React Query mutation configuration options rather than image
processing settings.

Comment thread backend/internal/repository/images.go
Comment thread frontend/api/files/useGetImage.ts Outdated
Comment thread frontend/api/files/useGetImageAllSizes.ts Outdated
Comment thread frontend/api/files/useImageUpload.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@frontend/__tests__/utilities/images.test.ts`:
- Around line 450-472: The test currently asserts parallelism by measuring
wall‑clock time for compressImage, which is flaky; instead modify the test in
frontend/__tests__/utilities/images.test.ts to use a deterministic barrier:
instrument the mocked ImageManipulator.manipulateAsync to push a Promise
resolver into an array and mark when each call starts (e.g., push to a
started[]), then await a “allStarted” Promise that resolves when started.length
=== expected (3) before allowing each manipulateAsync mock to resolve, and
finally assert that all manipulateAsync calls were initiated (started) before
any were resolved; keep references to compressImage and
ImageManipulator.manipulateAsync so the test logic replaces the timing check
with the barrier-based assertion.

Comment thread frontend/__tests__/utilities/images.test.ts
in-mai-space
in-mai-space previously approved these changes Jan 29, 2026
Copy link
Copy Markdown
Contributor

@in-mai-space in-mai-space left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✈️

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@backend/internal/repository/images.go`:
- Around line 105-123: The MarkFailed method on imageRepository currently
updates any image by image_id and size; narrow the update to only pending images
by adding a status filter in the WHERE clause (e.g., add "AND status = ?" with
models.UploadStatusPending) so only images in pending state can be transitioned
to models.UploadStatusFailed; keep the existing rowsAffected==0 ->
errs.ErrNotFound behavior to surface when no pending row was updated.

In `@frontend/__tests__/utilities/images.test.ts`:
- Around line 165-169: The test uses a loose type annotation { size: any } when
mapping results; replace it by importing and using the actual CompressedVariant
type from the images module and annotate the map parameter as (r:
CompressedVariant) => r.size (or the correct exported type name if different) so
TypeScript can catch type errors; apply the same change to the other occurrences
at the map calls around the test (lines referenced use results.map and the other
two map usages).
- Line 471: The linter flags the implicit-return arrow in the call to
resolvers.forEach((r) => r()); — change it to use block syntax so the intent
(calling void resolvers) is explicit; update the forEach callback for the
resolvers array (the resolver variable r) to a block-bodied arrow (e.g., (r) =>
{ r(); }) to silence the warning.

In `@frontend/api/files/useGetImage.ts`:
- Around line 34-53: The aggregate query flags are computed from an `active` set
that currently filters with `r.fetchStatus !== "idle"`, which drops settled
queries; update the filter in useGetImage (the `active` variable derived from
`results`) to include settled queries by using `r.isSuccess || r.isError` (or
equivalently `r.isFetching || r.isSuccess || r.isError`) so that the computed
`isSettled` and `isSuccess` (which reference `active`) reflect completed query
states correctly.

In `@frontend/api/files/useGetImageAllSizes.ts`:
- Around line 29-48: The active query detection filters use fetchStatus and
excludes settled queries; change the filter to use the query's status so settled
results remain in active (e.g., replace results.filter((r) => r.fetchStatus !==
"idle") with results.filter((r) => r.status !== "idle")) so variables active,
isSettled, and isSuccess (in useGetImageAllSizes.ts) correctly reflect completed
queries.

In `@frontend/api/files/useImageUpload.ts`:
- Around line 67-71: The mutationFn wrapper is redundant in useImageUpload;
replace the arrow wrapper used in the useMutation call (currently mutationFn:
(data) => uploadImage(data)) with the uploadImage function reference directly so
mutationFn points to uploadImage; update the useMutation invocation in
useImageUpload accordingly to simplify and avoid the unnecessary lambda.

Comment thread backend/internal/repository/images.go
Comment thread frontend/__tests__/utilities/images.test.ts
Comment thread frontend/__tests__/utilities/images.test.ts
Comment thread frontend/api/files/useGetImage.ts Outdated
Comment thread frontend/api/files/useGetImageAllSizes.ts Outdated
Comment thread frontend/api/files/useImageUpload.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@in-mai-space in-mai-space left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀🚀🚀

@anish-sahoo anish-sahoo merged commit ff15a59 into main Jan 29, 2026
9 checks passed
@anish-sahoo anish-sahoo deleted the user-pfp-s3 branch January 29, 2026 05:52
@coderabbitai coderabbitai Bot mentioned this pull request Mar 2, 2026
3 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Mar 17, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants