Skip to content

Profile picture endpoints#113

Open
spokonya wants to merge 41 commits intomainfrom
profile-picture-endpoints
Open

Profile picture endpoints#113
spokonya wants to merge 41 commits intomainfrom
profile-picture-endpoints

Conversation

@spokonya
Copy link
Copy Markdown
Contributor

@spokonya spokonya commented Feb 6, 2026

Description

Adds backend endpoints for user profile picture management with S3 integration. Enables uploading, viewing, and deleting profile pictures.

Why:

  1. Users need profile pictures for identity and personalization.
  2. S3 provides scalable storage without storing files in the database.
  3. Presigned URLs enable direct client-to-S3 uploads, reducing backend load and improving performance.

How it works:

  1. Upload: Client requests a presigned upload URL via /s3/upload-url/{userId}, uploads directly to S3, then saves the S3 key to the user's profile via PUT /users/{userId}/profile-picture.
  2. Client calls GET /users/{userId}/profile-picture, which retrieves the S3 key from the database and returns a presigned read URL for display.
  3. Delete: DELETE /users/{userId}/profile-picture removes the file from S3 and clears the reference in the database.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (code improvement without changing functionality)
  • Documentation update
  • Configuration/infrastructure change
  • Performance improvement
  • Test coverage improvement

Related Issue(s)

Closes #
Related to #51

What Changed?

-Added user profile picture endpoints GET, PUT, and DELETE (/users/{userId}/profile-picture) endpoints for retrieving, updating, and deleting user profile pictures with S3 integration
-Added the S3 presigned URL for access to objects in the bucket (building upon what was in the s3-setup branch which was only a presign URL to put objects in the bucket)
-Implemented repository methods: UpdateProfilePicture, GetKey, and DeleteProfilePicture to manage profile picture S3 keys in the database

Testing & Validation

How this was tested

Screenshots/Recordings

This show the profile picture being stored and removed from the db based on interactions with the frontend

Screenshot 2026-02-06 at 12 52 38 PM Screenshot 2026-02-06 at 12 52 19 PM

Unfinished Work & Known Issues

  • [] None, this PR is complete and production-ready

  • The following items are intentionally deferred:

  • Comments left on the first PR will apply to some of the files in this ex) s3storage.go still needs to be changed based on the comments left on the s3-setup PR

    • users_test.go appears rewritten: The file shows as fully rewritten due to a naming mistake. The test content is correct; the diff reflects the rename/reorganization.
    • Branch confusion during development: Initially added the Get Presigned URL endpoint on the frontend branch by mistake. After switching to the correct branch, changes were moved appropriately. This may have caused some temporary confusion in commit history.
      -There may be overlapping S3-related changes across 3 related PRs. I reviewed branch contents and believe everything is in the correct branch, but some S3 changes may appear in multiple PRs due to the branch mix-up.

Notes & Nuances



Pre-Merge Checklist

Code Quality

  • Code follows the project's style guidelines and conventions
  • Self-review completed (I've reviewed my own code for obvious issues)
  • No debugging code, console logs, or commented-out code left behind
  • [] No merge conflicts with the base branch
  • Meaningful commit messages that explain the "why"

Testing & CI

  • All CI checks are passing
  • All new and existing tests pass locally
  • Test coverage hasn't decreased (or decrease is justified)
  • Linting passes without errors

Documentation

  • Code is self-documenting or includes helpful comments for complex logic
  • API documentation updated (if backend endpoints changed)
  • Type definitions are accurate and up-to-date

Reviewer Notes

  • Areas needing extra attention: ...
  • Questions for reviewers: ...

@spokonya spokonya requested review from Dao-Ho and danctila February 6, 2026 20:58
@Dao-Ho Dao-Ho removed their request for review February 14, 2026 04:10
Copy link
Copy Markdown
Contributor

@Dao-Ho Dao-Ho left a comment

Choose a reason for hiding this comment

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

Just two very quick changes, should be good to be merged otherwise!


"github.com/generate/selfserve/config"
_ "github.com/generate/selfserve/docs"
//_ "github.com/generate/selfserve/docs"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe you still need to uncomment this

}, nil
}

func (s *Storage) GeneratePresignedURL(ctx context.Context, key string, expiration time.Duration) (string, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's not really clear what differentiates this from GeneratePresignedGetURL when reading the name. I had to drill down to this logic to find what it's really doing. I think we can probably rename this to be more explicit (also rename the parent function that calls this to ensure it's consistent)

Suggested change
func (s *Storage) GeneratePresignedURL(ctx context.Context, key string, expiration time.Duration) (string, error) {
func (s *Storage) GeneratePresignedUploadURL(ctx context.Context, key string, expiration time.Duration) (string, error) {

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

❌ Patch coverage is 21.08844% with 116 lines in your changes missing coverage. Please review.
✅ Project coverage is 9.33%. Comparing base (6033a10) to head (97c0e55).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
backend/internal/handler/s3.go 0.00% 36 Missing ⚠️
backend/internal/handler/users.go 50.00% 29 Missing and 2 partials ⚠️
backend/internal/service/s3/s3storage.go 0.00% 19 Missing ⚠️
backend/internal/repository/users.go 0.00% 14 Missing ⚠️
backend/internal/service/server.go 0.00% 9 Missing ⚠️
backend/internal/httpx/bind.go 0.00% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #113       +/-   ##
==========================================
- Coverage   20.37%   9.33%   -11.04%     
==========================================
  Files          39     115       +76     
  Lines        1453    4037     +2584     
  Branches        0      24       +24     
==========================================
+ Hits          296     377       +81     
- Misses       1153    3654     +2501     
- Partials        4       6        +2     
Flag Coverage Δ
backend 19.70% <21.08%> (-0.67%) ⬇️
mobile 84.00% <ø> (?)
web 0.75% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
backend/internal/httpx/bind.go 0.00% <0.00%> (ø)
backend/internal/service/server.go 0.00% <0.00%> (ø)
backend/internal/repository/users.go 0.00% <0.00%> (ø)
backend/internal/service/s3/s3storage.go 0.00% <0.00%> (ø)
backend/internal/handler/users.go 50.60% <50.00%> (-9.40%) ⬇️
backend/internal/handler/s3.go 0.00% <0.00%> (ø)

... and 76 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@Dao-Ho Dao-Ho left a comment

Choose a reason for hiding this comment

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

some more small comments

// Supported formats: jpg, jpeg, png, webp
ext := c.Query("ext", "jpg")
allowedExts := map[string]bool{"jpg": true, "jpeg": true, "png": true, "webp": true}
allowedExts := map[string]bool{"jpg": true, "jpeg": true, "png": true, "webp": true}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this should be a const somewhere, it's a config that doesn't feel right to be embedded into the logic, can we just make this a const?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what was wrong with BindAndValidate? validateCreateUser was an old pattern before @zaydaanjahangir implemented our validation system. Was this intentional?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we have clerk_id anymore, clerk id is just our id now, is it throwing for you? Make sure your code is up to date

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same concept as above, should it be clerk id here?

if err != nil {
return "", err
return "", fmt.Errorf("failed to generate presigned get URL with key %s: %w", key, err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit so NOT necessary but since we're throwing a lot of custom errors for s3, feels like custom errors for them could be good here, not needed tho

@spokonya spokonya requested a review from Dao-Ho March 27, 2026 21:16
Copy link
Copy Markdown
Contributor

@Dao-Ho Dao-Ho left a comment

Choose a reason for hiding this comment

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

one removal and it's good to go

Dao-Ho
Dao-Ho previously approved these changes Apr 1, 2026
@Dao-Ho
Copy link
Copy Markdown
Contributor

Dao-Ho commented Apr 1, 2026

LGTM ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants