Bỏ qua nội dung

Cập nhật avatar hồ sơ trên web

Feature URL
Module
user
Status
in-development
Priority
P1
Platforms
fe · be
AC progress
8 / 12
Last reviewed
2026-05-29

Mục tiêu

Cho phép user đổi ảnh đại diện trên web để profile, header menu và các public card dễ nhận diện hơn. User module chỉ nhận và lưu avatarUrl đã upload hợp lệ, còn việc upload file thuộc module upload/R2.

Phạm vi

Trong phạm vi (In scope):

  • UI chọn ảnh avatar từ trang profile.
  • Upload ảnh bằng presigned URL của module upload/R2.
  • Lấy public avatarUrl sau upload thành công.
  • Gọi PATCH /api/v1/users/me/avatar để lưu URL vào profile.
  • Cập nhật Redux profile và menu avatar sau khi lưu.
  • Validate URL phía backend theo R2 public domain cấu hình.

Ngoài phạm vi (Out of scope):

  • Crop/chỉnh sửa ảnh nâng cao.
  • Lưu binary file trực tiếp ở user module.
  • Quản lý xoá file avatar cũ trên R2.
  • Avatar cho admin chỉnh sửa user khác.

User Stories

  • user, tôi muốn đổi avatar để tài khoản dễ nhận biết hơn.
  • user vừa upload ảnh, tôi muốn thấy avatar mới trên header/menu ngay sau khi lưu.
  • hệ thống, tôi muốn chỉ chấp nhận avatar URL thuộc storage domain hợp lệ để tránh URL độc hại.

Luồng chức năng

sequenceDiagram
    actor User
    participant Web
    participant Upload as Upload/R2
    participant BE

    User->>Web: Chọn ảnh avatar
    Web->>Upload: Xin presigned URL và upload file
    Upload-->>Web: Public avatarUrl
    Web->>BE: PATCH /api/v1/users/me/avatar {avatarUrl}
    BE->>BE: Validate avatarUrl không blank
    BE->>BE: Validate URL thuộc R2 public domain
    BE->>BE: Lưu user.avatarUrl
    BE-->>Web: UserProfileResponse mới
    Web->>User: Hiển thị avatar mới

Acceptance Criteria

  • AC-1: Backend có PATCH /api/v1/users/me/avatar yêu cầu quyền user:update:self.
  • AC-2: Request body gồm avatarUrl bắt buộc.
  • AC-3: avatarUrl không được blank.
  • AC-4: Backend validate URL bắt đầu bằng R2 public URL cấu hình.
  • AC-5: URL có scheme và host hợp lệ.
  • AC-6: URL chứa .. bị từ chối để tránh path traversal.
  • AC-7: Backend chỉ cập nhật avatar của user hiện tại từ JWT principal.
  • AC-8: Backend trả UserProfileResponse sau khi cập nhật avatar thành công.
  • AC-9: FE cần thêm flow upload avatar qua module upload/R2.
  • AC-10: FE cần gọi ROUTES_API_USER.AVATAR_UPLOAD sau khi có public URL.
  • AC-11: Sau khi lưu thành công, FE phải cập nhật profile.current.avatarUrl để header/menu đổi avatar ngay.
  • AC-12: FE cần xử lý lỗi upload thất bại và lỗi avatar URL không hợp lệ.

Quy tắc nghiệp vụ

  • User module không nhận file upload trực tiếp, chỉ nhận URL sau khi upload hoàn tất.
  • Avatar URL phải thuộc public domain storage được backend cấu hình.
  • Không được chấp nhận URL ngoài domain để tránh tracking, mixed content hoặc nội dung không kiểm soát.
  • Nếu upload R2 thành công nhưng lưu profile thất bại, FE phải báo lỗi và cho user thử lại lưu avatar URL.
  • Avatar mới ảnh hưởng đến profile cá nhân, menu tài khoản và public profile/listing owner card.

Dữ liệu & Trạng thái

Entity nghiệp vụ:

  • User.avatarUrl: URL avatar hiện tại.
  • UpdateAvatarRequest: payload {avatarUrl}.
  • UserProfileResponse: response chứa avatar mới.
  • R2Properties.publicUrl: domain/prefix hợp lệ cho avatar.

Trạng thái user-facing:

  • selecting-file — user chọn ảnh.
  • uploading — đang upload file lên R2.
  • saving-avatar — đang lưu URL vào user profile.
  • avatar-updated — avatar mới đã được lưu và render.
  • upload-error — upload file thất bại.
  • invalid-avatar-url — URL bị backend từ chối.

Liên quan