2
Feed type
FOR_YOU · FOLLOWING
Cursor
Pagination
publicId-based cursor
0
Ranking
chưa có — chỉ sort thời gian
0
Cache
chưa có cache layer
Proposed: Newsfeed Business Flow
Đường đứt nét = bước đề xuất chưa implement. Hiện tại feed chỉ sort theo thời gian, chưa filter visibility hay hidden posts.
Proposed: FOR_YOU Ranking Algorithm
🔮 Đề xuất: Áp dụng theo 2 phase. Phase 1 đã xong (sort time). Phase 2 cần background job tính score + Redis cache.
Implementation Checklist
| # | Task | Chi tiết | Status |
| 01 | Feed FOR_YOU basic GET /posts/news-feed?type=FOR_YOU
| Lấy bài PUBLIC mới nhất, cursor pagination, enrich isLiked + isQuoted cho logged-in user. ✅ Đã có. | done |
| 02 | Feed FOLLOWING ?type=FOLLOWING
| Lấy bài chỉ từ người mình follow. Filter userId IN (SELECT followingId FROM Follow WHERE followerId = me). ✅ Đã có. | done |
| 03 | Filter visibility | Bài FRIENDS_ONLY chỉ hiện cho mutual friends. Bài PRIVATE chỉ hiện cho chủ bài. Cần hàm isMutualFriend. | todo |
| 04 | Filter hidden posts | Bài user đã ẩn (hide) không hiện lên feed. Cần bảng HiddenPost + sub-query NOT IN. | todo |
| 05 | Ranking score (Phase 2) | Cron job 5 phút: tính engagementScore cho bài mới (<48h). Lưu vào Redis sorted set hoặc cột rankScore. | todo |
| 06 | Redis cache feed | Cache kết quả feed per user trong Redis (TTL 60s). Invalidate khi có bài mới từ người follow. | todo |
| 07 | Enrich isSaved | Khi có feature Save, feed cần trả thêm isSaved: boolean cho mỗi bài. | todo |
Potential Issues
N+1Enrich isLiked/isQuoted hiện dùng sub-select trong Prisma findMany. Khi feed lớn (>1M bài), cần chuyển sang Redis lookup hoặc denormalize.
Cold startUser mới chưa follow ai → feed FOLLOWING trống. Giải pháp: fallback sang FOR_YOU, hoặc suggest follow list (onboarding).
Fan-outHiện tại dùng fan-out-on-read (query lúc đọc). Khi scale, cần fan-out-on-write (pre-compute feed khi có bài mới) với BullMQ.
Stale cacheCache feed 60s nhưng bài mới xuất hiện chậm 60s. Trade-off chấp nhận được. Hoặc invalidate cache qua Pusher event khi bài mới được tạo.