Saved Posts
Members can bookmark posts and reopen them later from a private Saved collection. Saves are per user — other members cannot see what you saved.
Overview
Saved posts let users:
- Bookmark a post from the feed, profile, hashtag pages, or post detail
- Browse saved posts newest-first on Saved (
/profile/saved) - Remove a bookmark from the post card or from the Saved page
- See whether a post is already saved (
isSaved) on feed and post responses
Saves do not change post privacy, notify the author, or appear in public profiles.
In the app (UI)
Save or unsave a post
- Open any post (feed, profile, hashtag, or post detail).
- Use the bookmark control on the post card (Save / Remove from saved).
- A toast confirms success or shows an error if the request fails.
Open your Saved collection
- Profile menu → Saved posts, or
- Navigate to
/profile/saved
The page lists posts you can still see, newest saves first, with pagination. Unsaving a post removes it from the list immediately.
You must be signed in. Guests see a sign-in prompt on the Saved page.
API
All endpoints use api/Post and require authentication (User, Moderator, or Admin).
Save a post
POST /api/Post/{postId}/save
Authorization: Bearer {token}
Response (success):
{
"success": true,
"message": "Post saved",
"data": {
"isSaved": true
}
}
Saving an already-saved post is idempotent (isSaved: true).
Unsave a post
DELETE /api/Post/{postId}/save
Authorization: Bearer {token}
Response (success):
{
"success": true,
"message": "Post unsaved",
"data": {
"isSaved": false
}
}
List saved posts
GET /api/Post/saved?page=1&pageSize=10
Authorization: Bearer {token}
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | int | 1 | Page number (1-based) |
| pageSize | int | 10 | Posts per page |
Response (success):
{
"success": true,
"data": {
"posts": [],
"totalCount": 0,
"page": 1,
"pageSize": 10,
"totalPages": 0,
"hasMore": false
}
}
Each post in posts includes the usual post DTO fields and isSaved: true.
isSaved on other reads
When the caller is authenticated, feed, user posts, hashtag posts, and single-post responses include isSaved so the UI can show the bookmark state without a separate round trip.
Visibility rules
The Saved list only returns posts the current user is allowed to see:
- Your own posts (any visibility), or
- Posts that are Public and not hidden
If a saved post becomes private, hidden, or deleted, it no longer appears in /api/Post/saved (and deleted posts cascade-remove the save row).
Data model
PostgreSQL table SavedPosts:
| Column | Notes |
|---|---|
| Id | UUID primary key |
| UserId | Owner of the save (FK → Users, cascade delete) |
| PostId | Saved post (FK → Posts, cascade delete) |
| CreatedAt | When the post was saved (list sorts newest first) |
Unique index on (UserId, PostId) — one save per user per post.
On self-host upgrades, schema may come from db-migration / custom migrations, or the hotfix SQL under tools/hotfix/2026-09-07-saved-posts.sql if the publisher instructs a manual apply. See Release notes.
Related
- Posts — create, feed, privacy
- Save / unsave API
- Get Post — feed and single post (
isSaved) - Save a post (tutorial)