Video summary

Golang Microservices Full Course #10 - Soft Delete, Upload File, and Pagination Sorting

Main summary

Key takeaways

Educational

Main ideas / lessons

  • Episode goals (Episode #10 of a Go microservices course)

    • Implement soft delete for users.
    • Implement pagination + sorting for transaction history queries.
    • Implement file upload (saving a user avatar/profile picture).
  • What “soft delete” means

    • Instead of physically removing a row from the database, the record remains in the DB.
    • The “deleted” state is stored in a timestamp/column (e.g., deleted_at), so:
      • Referential integrity is preserved (foreign-key relationships won’t break).
      • Historical/business-critical data (e.g., transfer history / ledger-related data) remains consistent.
      • A user could theoretically be prevented from “disappearing” from related records.
  • Soft delete approach used in this project

    • Use a deleted_at column (instead of a boolean like is_deleted), where:
      • Not deleted: deleted_at IS NULL
      • Deleted: deleted_at set to a timestamp (e.g., NOW())
  • Why pagination + sorting are needed

    • Without pagination, queries can become extremely slow with huge datasets (thousands/millions of rows).
    • Pagination and sorting improve API response time and user experience.
  • Security note for sorting

    • Sorting must use whitelists for allowed sort columns and allowed sort directions to prevent SQL injection / query manipulation.
  • File upload (avatar/profile picture)

    • Accept multipart form file upload.
    • Validate:
      • Maximum file size (mentioned as 2MB).
      • File type/extension (allowed: JPG/JPEG/PNG).
    • Save file into an uploads directory.
    • Store the resulting file URL/path in the database.
    • Update the user’s avatar URL while ensuring the user is not soft-deleted.

Methodology / implementation outline (as described)

A) Soft delete implementation (users)

Repository changes (User repository)

  • Add a repository method to perform soft delete, e.g.:
    • Inputs: user id (string)
    • Output: error
  • Implement an SQL update like:
    • UPDATE users SET deleted_at = NOW() WHERE id = ?;
  • Execute using the provided context and DB handle.

Database migration for avatar URL

  • Create an additional migration to alter the users table:
    • Add avatar_url column (mentioned as VARCHAR(255)), positioned after the password hash field.
    • Rollback drops avatar_url on down migration.

Query filtering to exclude soft-deleted users

  • Update relevant “get user” queries to include:
    • WHERE deleted_at IS NULL

Service layer: delete account endpoint logic

  • Add a service method (e.g. DeleteAccount)
  • Logic:
    • Retrieve the user by the authenticated user ID (ensuring deleted_at IS NULL).
    • If the user doesn’t exist, return a not-found style error.
    • Call the repository soft-delete method (sets deleted_at).
    • Return appropriate server response.

Handler layer integration

  • Add a protected route/handler method for “delete me” (self-delete).
  • Obtain the authenticated user ID from JWT/context.
  • Call the service’s delete method.
  • Return a success response (discussion around common status codes like 200/204, but ultimately “account deleted successfully”).

B) Pagination + sorting for transaction history

Pagination parameter model

  • Create/define a PaginationParams structure with defaults:
    • page default: 1
    • limit default: 10
    • sort default: created_at
    • order default: asc
    • optional status filter (string)

Pagination meta/response

  • Include pagination metadata in responses:
    • page, limit, total, totalPage

Pagination calculations

  • Compute:
    • offset = (page - 1) * limit

Transaction repository: get paginated history

  • Add a method like GetHistory(ctx, walletId, paginationParams) returning:
    • list of transactions
    • total count for meta
  • Steps:
    1. Count total records for pagination meta:
      • Query COUNT(*) from transaction
      • Filter where:
        • sender_wallet_id = ? OR receiver_wallet_id = ?
      • If status is provided (not empty), include:
        • AND status = ?
    2. Prepare sorting
      • Use a whitelist:
        • Example mentioned: only allow sorting by created_at (or mapping like sortColumn -> created_at).
      • Use whitelisted order:
        • asc / desc
    3. Fetch paginated rows

      • Select explicit columns (avoid SELECT *):

        • id, sender_wallet_id, receiver_wallet_id, amount, description, item_pontency_key, status, created_at (and any other mentioned fields)
      • Apply:

        • sender/receiver wallet filter
        • optional status filter
        • ORDER BY <sortColumn> <sortOrder>
        • LIMIT ? OFFSET ? 4. Map rows into transaction models
      • Iterate rows, scan fields, append to result slice.
      • If scanning/mapping errors occur, return errors.
        1. Return transactions + pagination meta inputs
      • Return total and transactions to handler/service.

Service layer: enforce limit and compute total pages

  • Cap limit (mentioned as max 100 in service).
  • Compute:
    • totalPages = total / limit (+1 if there is remainder)

Handler layer

  • Parse query params into PaginationParams.
  • Fetch history for the authenticated user’s wallet:
    • get wallet by user id
    • then get transaction history by wallet id + pagination params
  • Return JSON with:
    • data array
    • success boolean
    • meta pagination

C) File upload: avatar/profile picture

User repository: update avatar URL

  • Add a repository method like UpdateAvatar(ctx, id, avatarPath) error
  • SQL update:
    • UPDATE users SET avatar_url = ? WHERE id = ? AND deleted_at IS NULL;

Service layer: update avatar

  • Wrap repository update call.

Handler layer: avatar upload endpoint

  • Obtain authenticated user ID from JWT/context.
  • Read uploaded file from multipart form:
    • c.FormFile("avatar")
  • Validate file:
    • Size: reject if > 2MB
    • Extension/type: allow only jpg, jpeg, png
  • Save file:
    • Ensure uploads/ directory exists
    • Filename format:
      • <userId>.<ext>
    • Save to uploads/<filename>
  • Update DB:
    • avatar_url stored as something like:
      • uploads/<filename> (or configured URL prefix + filename)
  • Return success response including the stored URL/path.

Route protection

  • Endpoint is protected (authenticated users only).
  • User is not allowed to upload/update if the user record is soft-deleted (enforced via deleted_at IS NULL in update query).

Speakers / sources featured

  • Single speaker (in the video): the course instructor/author (unnamed in subtitles) teaching “Golang Microservices Full Course #10” and giving step-by-step implementation guidance.
  • Sources: none besides the instructor (no external named authors/tools referenced as primary sources).

Rate this summary

Your feedback will help improve summaries.

Improve this summary

Reprocess with a stronger model when the summary feels incomplete or inaccurate.

Pro

Translate summary in another language

Pro

Ask questions to this video

Chat for follow-up questions, clarifications, and source-backed answers.

Coming soon

Share this summary

Original video