Video summary
Golang Microservices Full Course #10 - Soft Delete, Upload File, and Pagination Sorting
Main summary
Key takeaways
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_atcolumn (instead of a boolean likeis_deleted), where:- Not deleted:
deleted_at IS NULL - Deleted:
deleted_atset to a timestamp (e.g.,NOW())
- Not deleted:
- Use a
-
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
uploadsdirectory. - 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
- Inputs: user
- 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
userstable:- Add
avatar_urlcolumn (mentioned asVARCHAR(255)), positioned after the password hash field. - Rollback drops
avatar_urlon down migration.
- Add
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.
- Retrieve the user by the authenticated user ID (ensuring
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
PaginationParamsstructure with defaults:pagedefault: 1limitdefault: 10sortdefault: created_atorderdefault: asc- optional
statusfilter (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:
- Count total records for pagination meta:
- Query
COUNT(*)fromtransaction - Filter where:
sender_wallet_id = ? OR receiver_wallet_id = ?
- If
statusis provided (not empty), include:AND status = ?
- Query
- Prepare sorting
- Use a whitelist:
- Example mentioned: only allow sorting by
created_at(or mapping likesortColumn -> created_at).
- Example mentioned: only allow sorting by
- Use whitelisted
order:asc/desc
- Use a whitelist:
-
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.
- Return transactions + pagination meta inputs
- Return total and transactions to handler/service.
-
- Count total records for pagination meta:
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
- Size: reject if
- Save file:
- Ensure
uploads/directory exists - Filename format:
<userId>.<ext>
- Save to
uploads/<filename>
- Ensure
- Update DB:
avatar_urlstored 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 NULLin 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.
Translate summary in another language
Ask questions to this video
Chat for follow-up questions, clarifications, and source-backed answers.