Bộ ôn phỏng vấn cho Trần Nam Phong — Frontend / Agentic Developer. Mọi câu trả lời neo vào commit thật của bạn trong TWDAgentsHub, Shiru, MoneyFi. Đào càng sâu càng đáng tin — vì bạn thật sự viết phần khó nhất.
Phỏng vấn không kiểm tra "có làm không" — nó kiểm tra hiểu sâu tới đâu và có trung thực về ranh giới đóng góp không. Vũ khí mạnh nhất: git lịch sử đứng về phía bạn.
I built / I own phần bạn là tác giả chính · I co-led / contributed phần bạn #2 · I integrated / consumed phần đồng nghiệp viết. Sai động từ = bị bắt bài. Đúng động từ = vừa sâu vừa tin.
claim 1 câu → kiến trúc → 1 quyết định/tradeoff → 1 war story. Dừng sau mỗi tầng để interviewer kéo bạn xuống sâu hơn. Đổ hết = nghe như học vẹt.
Situation → Task → Action → Result → Change ("nếu làm lại tôi sẽ…"). Câu "what I'd change" làm bạn trông như senior, không phải coder thừa hành.
Công nhận ranh giới → bắc cầu sang phần bạn ĐÃ làm: "Phần X là platform infra của team; cái tôi sở hữu và build lên trên là Y — để tôi nói về Y."
Thả tên thật: BullMQ upsertJobScheduler, Redis SETNX, AsyncMutex, generateObject + Zod, ICP 0–100, squarified treemap. Con số + tên riêng > tính từ.
Đây là lưới an toàn. Mọi project đều là TEAM project — nhưng commit chứng minh bạn sở hữu đúng những phần khó. Claim theo cột "Nói thế nào".
| Phần việc | Verdict | Nói thế nào |
|---|---|---|
| TWDAgentsHub — MCP server + ~20 tools | Own | "Tôi xây MCP layer" |
| TWDAgentsHub — LLM orchestrator | Own | "Tôi build orchestrator" |
| TWDAgentsHub — lead agents / WF2 scoring / Telegram | Own | "Tôi build lead pipeline" |
| TWDAgentsHub — chat-widget + admin-ui | Own | "Tôi build cả 2 frontend" |
| TWDAgentsHub — ERP adapters | Co-led | "Tôi đồng chủ trì adapter layer" |
TWDAgentsHub — LLM provider factory (api/src/llm) | Hedge | "Platform infra, tôi consume qua fast/smart tier" |
| Shiru — admin console (cả repo) | Sole owner | "Tôi là sole owner — AUA, treemap, KYB, XLSX" |
| Shiru — frontend (~94%) | Own | "Tôi phụ trách chính FE" |
| Shiru — KYB backend + mail | Own | "Tôi owner KYB backend" |
| Shiru — auth password / account-deletion / username | Co-led | "Tôi viết các DTO & flow này" |
| Shiru — multi-chain token resolution | Hedge | "Đồng nghiệp BE viết resolver core, tôi integrate" |
| MoneyFi — boost engine (treasure/countdown/tier/claim) | Own | "Tôi build boost engine (162 commit)" |
| MoneyFi — dual-wallet + VPN/geo gating (client) | Own | "Tôi build onboarding 2 ví + region gate" |
| MoneyFi — geo worker endpoint | Note | "Teammate deploy worker; tôi build lớp client consume" |
| MoneyFi — tổng thể sản phẩm (team lớn) | Contributed | "Tôi build phần user-facing" — KHÔNG nói "tôi build MoneyFi" |
| moneyfi-SDK-example (~86%) | Own | Reference tích hợp SDK, của bạn |
Mỗi project 1 câu chuyện "cái khó tôi đã giải". Click để mở. Tập kể trôi từ trí nhớ theo nhãn S/T/A/R/C.
Redis SETNX + TTL 5 phút theo khoá requestId/botId:updateId — key đã tồn tại thì bỏ qua, không xử lý lại.AsyncMutex theo tenant bao quanh sales_assign_rep — 2 lead không thể cùng chiếm 1 rep.HMAC-SHA256 bằng timingSafeEqual trước khi đẩy vào BullMQ queue (sales-contact, retry 3 lần exp backoff).AsyncMutex chỉ atomic trong 1 instance. Scale ra nhiều instance API thì tôi đổi sang distributed lock (Redis Redlock) để giữ atomic xuyên tiến trình.check-email gọi TRƯỚC khi cho upload — chặn sớm nếu email đã tồn tại.UPLOADING) rồi enqueue BullMQ job; worker đẩy file lên Cloudinary bằng signed params (URL có hạn), xong đổi SUBMITTED. UI poll public-status (không cần JWT).409 thay vì ghi đè.invalidate đúng 3 query key (USER_STATISTICS, USER_TIER, CAMPAIGN_TRANSACTION_HISTORY) để TanStack Query refetch, UI cập nhật ngay.special > first > normal > consolation > no_prize, show 1 modal gọn.setQueryData cập nhật cache ngay tại chỗ (true optimistic) rồi rollback nếu lỗi — mượt hơn, đỡ 1 vòng refetch.Click card để hiện đáp án. Lọc theo project. Bấm ☆ để đánh dấu "đã thuộc" (lưu trong máy). Mục tiêu: nói trôi từ trí nhớ, không đọc.
Định nghĩa gọn — phải bật ra ngay khi được hỏi "X là gì?".
Một câu hỏi ngẫu nhiên hiện lên. Tự trả lời thành tiếng → bấm "Hiện đáp án" để đối chiếu → "Câu tiếp". Mô phỏng áp lực bị hỏi bất ngờ.