Newsfeed

post module
Endpoint: GET /posts/news-feed?type=FOR_YOU|FOLLOWING  ·  Pagination: cursor-based (after + take)
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


GET /posts/news-feed?type=...&after=...&take=20 requestAuthToken (optional auth) Feed type? FOR_YOU Lấy bài PUBLIC mới nhất isDeleted=false, type=POST, sort createdAt FOLLOWING Lấy bài từ người mình follow WHERE userId IN (followingIds) 🔮 Filter: ẩn bài + blocked users NOT IN hiddenPosts, NOT IN blockedUsers 🔮 Visibility check FRIENDS_ONLY → chỉ nếu isMutualFriend Enrich: isLiked + isQuoted sub-select likes/derivatives per user buildCursorPagination { rows, pagination: { hasMore, after } } đã implement 🔮 đề xuất thêm

Đườ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


Engagement Score likes×1 + replies×3 + quotes×5 Time Decay score / (hoursSince + 2)^1.5 Affinity Boost ×1.5 nếu bạn bè / tương tác nhiều Final Rank sort DESC → paginate score = (likes×1 + replies×3 + quotes×5) / (hours + 2)^1.5 × affinityMultiplier Hacker News–style decay + social affinity boost. Tính toán trong background job, cache kết quả. ⚡ Phase 1: Sort createdAt (hiện tại) → Phase 2: Score-based (cron job mỗi 5 phút) Lưu score vào Redis sorted set hoặc cột rankScore trong bảng Post

🔮 Đề 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


#TaskChi tiếtStatus
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+1
Enrich 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 start
User 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-out
Hiệ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 cache
Cache 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.