Favorite Users — Technical Reference
Where this lives
Backend
apps/backend/graphql/resolvers/user-favorites.resolver.js- resolvesfavoriteUsers,isFavoriteUser,getFavoritesStats,addToFavorites,removeFromFavorites,reorderFavorites(own dedicated resolver file, not inline inuser.resolver.js)apps/backend/graphql/types/favorites.type.js- favorites schema typesapps/backend/managers/user-managers/favorites.manager.js- favorites business logic, called frommanagers/user-managers/index.js. Enforces a 50-favorite cap per user (maxFavoritesinaddToFavorites), throwingfavorites.limit_exceededonce reached.apps/backend/data-access-services/user/user-favorite.access-service.js- favorites DB access
Frontend
apps/frontend-nextjs/src/page-components/settings/FavoritesPage.tsx(routed at/settings/favorites) — lists favorited accounts with per-row reorder (up/down) and remove actions, plus the stats header; wired tofavoriteUsers,removeFromFavorites,reorderFavorites, andgetFavoritesStats. Has no "add" affordance of its own.apps/frontend-nextjs/src/page-components/PublicProfilePage.tsx— a profile's ⋯ More options menu (MoreOptionsMenu) shows an "Agregar a favoritos" / "Quitar de favoritos" toggle backed byisFavoriteUser,addToFavorites, andremoveFromFavorites. This is the only place a favorite can be added from the UI today.
Technical implementation checklist
-
addToFavorites— wired inuser-favorites.resolver.js; consumed byPublicProfilePage.tsx's favorite toggle -
removeFromFavorites— wired; consumed by bothFavoritesPage.tsxandPublicProfilePage.tsx -
favoriteUsers— wired; consumed byFavoritesPage.tsx -
isFavoriteUser— wired; consumed byPublicProfilePage.tsxto render the toggle's current state -
reorderFavorites— wired inuser-favorites.resolver.js; consumed byFavoritesPage.tsx's up/down row controls -
getFavoritesStats— wired; consumed byFavoritesPage.tsx's stat header. Fixed this session:mutualFavorites/recentAdditions/mostFavoritedUserused to be hardcoded to0/0/null; all three are now real aggregate queries (see Queries below) - Real persistence —
favorites.manager.jsdelegates touser-favorite.access-service.js(create / destroy / getUserFavorites / getFavoritesCount / update), backed by theUserFavoriteSequelize model (migration20250109000003-create-user-favorites-table.js). No mock scaffolding.
Queries
favoriteUsers returns the current user's full favorites list, with each entry's position (the sort order) and addedAt timestamp. Use limit and offset for paginated rendering.
isFavoriteUser is a lightweight boolean check — used by PublicProfilePage.tsx to render the "Add to favorites" / "Remove from favorites" toggle state in a profile's More options menu without fetching the full list.
getFavoritesStats declares fields for aggregate metrics (total, mutual, recent additions, most-favorited), and all of them are now real. Fixed this session: mutualFavorites/recentAdditions/mostFavoritedUser used to be hardcoded to 0/0/null. favorites.manager.js#getFavoritesStats now runs real queries against user_favorites: mutualFavorites counts reciprocal favoriting (users who have also favorited you back), recentAdditions counts favorites added in the last 7 days, and mostFavoritedUser is the one of your favorites with the highest total favorite count system-wide.
query FavoriteUsers($limit: Int, $offset: Int) {
favoriteUsers(limit: $limit, offset: $offset) {
total limit offset
favorites {
id position addedAt
user { id username profilePicture isVerified }
}
}
}
query IsFavorite($userId: ID!) {
isFavoriteUser(userId: $userId)
}
query FavoritesStats {
getFavoritesStats {
totalFavorites
mutualFavorites # users who have also favorited you
recentAdditions # added in the last 7 days
mostFavoritedUser { username profilePicture }
}
}
Mutations
addToFavorites adds a user to the favorites list and assigns them the next available position. The schema declares a nullable favorite: FavoriteUser field on the response. Fixed this session: the manager used to return a favoriteUser key, which doesn't exist on the schema at all (the field is named favorite), so it always resolved to null. It now returns a proper favorite: { id, user, addedAt, position } object matching FavoriteUser, so the mutation response can be used to insert the new entry without a re-fetch.
removeFromFavorites removes a user from the list. It does not recompact the remaining position values — gaps are left behind and simply don't affect ordering, since the list is always sorted by position ASC.
reorderFavorites accepts the complete ordered list of user IDs. The server replaces the existing order with the new sequence, updating position for every entry. To move one user, pass the full list with that user at the desired index.
mutation AddFavorite($userId: ID!) {
addToFavorites(userId: $userId) {
success message
favorite { id position addedAt user { username } }
}
}
mutation RemoveFavorite($userId: ID!) {
removeFromFavorites(userId: $userId) { success message }
}
# Pass the complete ordered list of user IDs to update all positions at once
mutation ReorderFavorites($userIds: [ID!]!) {
reorderFavorites(userIds: $userIds) { success message }
}
reorderFavorites accepts the complete ordered list of user IDs and updates position for each entry.