Lưu bài (Save Post)

post module
Endpoint: POST /posts/:publicId/save  ·  Trạng thái tổng: STUB — chỉ có route, chưa có logic
1
Endpoint
POST /:publicId/save
Stub
Logic hiện tại
return void — no-op
0
Bảng DB
chưa có bảng SavedPost
0
API lấy saved
chưa có endpoint list

User Perspective


Lưu
Nhấn nút "Lưu" (bookmark icon) trên bài viết → bài được thêm vào danh sách "Bài đã lưu". Nhấn lại → bỏ lưu.
Xem
Vào trang cá nhân → tab "Đã lưu" → xem danh sách bài đã bookmark, sắp xếp theo thời gian lưu.
Riêng tư
Danh sách bài đã lưu chỉ mình người dùng nhìn thấy. Không ai khác biết bạn lưu bài nào.

Proposed Implementation Flow


POST /:publicId/save findByPublicId(publicId) kiểm tra bài tồn tại Đã lưu? chưa → save INSERT savedPost (userId, postId) rồi → unsave DELETE savedPost (userId, postId) Response: { saved: true/false } ⚠ CHƯA IMPLEMENT — flowchart dự kiến

Đường đứt nét = chưa implement. Hiện tại postService.save() trả về void (no-op).

Implementation Checklist


# Task Mô tả chi tiết Trạng thái
01
Route + Controller
POST /:publicId/save
Route đã có, controller gọi postService.save() rồi trả { saved: true }. Nhưng service chỉ return void. stub
02
Tạo bảng SavedPost
Prisma migration
Bảng mới: SavedPost { id, userId, postId, createdAt }. Unique constraint trên (userId, postId) để tránh lưu trùng. todo
03
Toggle save logic
Service layer
Kiểm tra bài tồn tại → check đã save chưa → nếu chưa thì INSERT, nếu rồi thì DELETE (toggle). todo
04
API lấy bài đã lưu
GET /posts/me/saved
Endpoint mới: trả danh sách bài đã lưu của user hiện tại, cursor pagination, sắp xếp theo thời gian lưu. todo
05
Check isSaved trong feed
Feed mapper
Khi lấy news feed / bài viết, check xem user hiện tại đã save chưa → trả thêm field isSaved: boolean. todo

Implementation Progress


✅ Đã có (sườn)
Route POST /:publicId/save đã đăng ký
Controller gọi service và trả response
Service method save() tồn tại (nhưng no-op)
⏳ Cần implement
Tạo Prisma model SavedPost + migration
Repository: toggle save/unsave
Service: logic check + toggle
Endpoint GET /posts/me/saved
Feed mapper: thêm field isSaved

Design Notes


Toggle
Nên dùng 1 endpoint toggle (giống like) thay vì 2 endpoint save/unsave riêng. FE chỉ cần gọi 1 API.
Riêng tư
Danh sách saved là private. Không ai ngoài chủ account nhìn thấy. Không có API public cho việc này.
Approach
Có thể dùng DB thuần (Prisma) vì save ít tần suất hơn like. Không cần Redis layer cho feature này.