Skip to main content

MeiGen: thư viện prompt ảnh miễn phí, và cái MCP server ít người để ý

· 10 min read
Nguyễn Huỳnh Minh Tiến
Middle Fullstack Developer @ Utop.vn
Summary

MeiGen là một thư viện prompt cho các mô hình sinh ảnh và video — duyệt được ngay, không cần tạo tài khoản, và mỗi prompt đều đi kèm ảnh kết quả của chính nó nên bạn biết trước sẽ nhận được gì. Nhưng thứ đáng chú ý với người viết code lại nằm ở mục ít ai bấm vào: MeiGen có MCP server, nghĩa là bạn gắn nó vào Claude Code hay Codex rồi gọi thẳng các tác vụ xoá nền, upscale, dựng ảnh sản phẩm ngay trong phiên làm việc, không cần mở trình duyệt. Duyệt prompt thì miễn phí, còn sinh ảnh qua MCP thì trang tài liệu ghi rõ là tiêu credit đã mua.

Bài này là giới thiệu công cụ, không phải đánh giá từ trải nghiệm dài ngày. Mọi thông tin dưới đây tôi lấy trực tiếp từ meigen.ai và trang MCP của họ; chỗ nào tôi không kiểm chứng được thì tôi nói rõ là không kiểm chứng được.

Your Running Total Is Wrong on the First Row: Window Functions, RANGE, and the Default Nobody Reads

· 12 min read
Nguyễn Huỳnh Minh Tiến
Middle Fullstack Developer @ Utop.vn
Summary

GROUP BY collapses rows; a window function keeps every row while still computing the group total. Measured: on the same 200,000-row table, GROUP BY returns 200 rows and the window returns 200,000 rows. It is also faster than the old approach — replacing a self-join with a window took the query from 79.2 ms down to 22.7 ms. But there is one default that quietly corrupts numbers and almost nobody reads it: OVER (ORDER BY ...) uses a RANGE frame, so every peer row receives the same running total. If you want a row-by-row cumulative sum, you must spell out ROWS.

Window functions turn long-winded reporting queries into a few readable lines. They also carry exactly one trap subtle enough to pass code review: a running total that looks plausible in the middle and is wrong wherever values tie.

This post goes deeper into Recursive Queries and Window Functions from the 30-day SQL series. Every number here was measured on PostgreSQL 16.11.

MailKit trong .NET: gửi email SMTP và dựng HTML email template chạy đúng trên Outlook

· 16 min read
Nguyễn Huỳnh Minh Tiến
Middle Fullstack Developer @ Utop.vn
Summary

MailKit là thư viện mail mã nguồn mở cho .NET (giấy phép MIT, tác giả Jeffrey Stedfast), nói được cả SMTP, IMAP và POP3. Tài liệu chính thức của Microsoft về System.Net.Mail.SmtpClient khuyến nghị thẳng việc dùng MailKit thay thế. Phần khó của việc gửi email không nằm ở chỗ gọi SendAsync — nó nằm ở cái HTML bên trong: Outlook classic render bằng engine của Word nên không có flex hay grid, Gmail cắt thư dài quá 102KB, và một thư chỉ có HTML mà thiếu bản plain-text thì điểm spam tăng ngay.

Gửi được email và gửi được email hiển thị đúng là hai bài toán khác nhau. Bài này giải quyết cả hai: phần đầu là cơ chế MailKit, phần sau là những ràng buộc rất cũ kỹ của HTML email mà không đọc trước thì sẽ mất buổi chiều ngồi hỏi vì sao cái template đẹp trên Chrome lại vỡ tan trên Outlook.

Hai giao dịch cùng cộng 100, số dư chỉ tăng 100: isolation level qua thí nghiệm thật

· 14 min read
Nguyễn Huỳnh Minh Tiến
Middle Fullstack Developer @ Utop.vn
Summary

Isolation level quyết định một giao dịch nhìn thấy gì khi có giao dịch khác chạy song song. Ở mức mặc định của hầu hết database là READ COMMITTED, hai phiên cùng đọc số dư 1000 rồi cùng ghi 1100 sẽ cho kết quả cuối là 1100 — một lần cộng biến mất, không có lỗi nào được ném. Nâng lên REPEATABLE READ thì phiên thứ hai nhận ERROR: could not serialize access due to concurrent update: câu trả lời sai âm thầm biến thành một lỗi rõ ràng mà ứng dụng phải thử lại. Toàn bộ số liệu dưới đây đo bằng hai session psql song song trên PostgreSQL 16.11.

Đây là loại lỗi gần như không thể tái hiện trên máy dev, vì ở đó bạn chỉ có một người dùng. Nó chỉ xuất hiện khi hai request thật chạm vào cùng một dòng trong cùng một khoảnh khắc — và lúc đó nó không sập, không log, chỉ làm sai số liệu.

Bài này đào sâu bài Transactions và ACID trong series học SQL 30 ngày.

Index Exists but the Query Still Scans the Whole Table? Sargability and One Function Call

· 13 min read
Nguyễn Huỳnh Minh Tiến
Middle Fullstack Developer @ Utop.vn
Summary

An index is a structure sorted by the column's values. Wrap a function around the column — date_part('year', created_at), LOWER(email), CAST(...) — and the thing you are comparing is no longer the sorted value, so the database cannot use the index and falls back to scanning the whole table. A condition that can use an index is called sargable. Measured on PostgreSQL 16 with 200,000 rows: the function-wrapped version runs in 29.6 ms with a Seq Scan, the range-rewritten version runs in 5.4 ms with a Bitmap Index Scan — about 5.4× faster, returning the same 37,518 rows.

A familiar situation: the query is slow, you add an index on exactly the column being filtered, you run it again — still just as slow. The index is right there, \d shows it, but the execution plan never mentions it.

This post drills into the Index lesson and the query optimization lesson from my 30-day SQL series. Every number is real output from PostgreSQL 16.11.