Pro Favorites
Summary
Pros can save programmes (new-build developments) or individual lots as favorites for quick access. Each ProFavorite record points to either a Programme or a Lot — never both simultaneously. The constraint is enforced at both the API layer (XOR validation) and at the DB level (unique index prevents duplicates). Favorites are listed newest-first with eager-loaded programme/lot summaries.
State Diagram
stateDiagram-v2 state "Non sauvegardé" as NotFavorited state "En favoris" as Favorited [*] --> NotFavorited NotFavorited --> Favorited: pro adds a favourite Favorited --> NotFavorited: pro removes a favourite Favorited --> [*] NotFavorited --> [*]
Steps
1. List Favorites (Actor: pro)
GET /pro/favorites. Returns all ProFavorite records where proId = request.proId, ordered by createdAt DESC.
Each record is returned with:
- If it’s a programme favorite:
programme { id, slug, name, ville, prixMin, prixMax, photos } - If it’s a lot favorite:
lot { id, type, surface, price, status, isComplete }
The fields not targeted (e.g. lot on a programme favorite) will be null.
Returns { data: favorites[] }.
Triggers: Pro opens their saved items view Outcome: Full list of favorites with embedded programme/lot summaries
2. Add Favorite (Actor: pro)
POST /pro/favorites with body validated by addFavoriteSchema. Must provide exactly one of programmeId or lotId — providing both or neither returns 400 INVALID_FAVORITE.
prisma.proFavorite.create({ data: { proId, programmeId, lotId } }).
On Prisma error:
P2002(unique constraint) → 409DUPLICATE(“Already in favorites”)P2003(foreign key violation — programme/lot doesn’t exist) → 400NOT_FOUND
Returns the created ProFavorite record with HTTP 201.
Triggers: Pro clicks a “Sauvegarder” button on a programme or lot page
Outcome: Favorite created; { data: favorite } returned
3. Remove Favorite (Actor: pro)
DELETE /pro/favorites/:id.
Ownership check: prisma.proFavorite.findFirst({ where: { id, proId: request.proId } }). If not found (or belongs to another pro) → 404 NOT_FOUND.
prisma.proFavorite.delete({ where: { id } }).
Returns { success: true }.
Triggers: Pro removes a saved item Outcome: Favorite record deleted
Error States
- Both
programmeIdandlotIdprovided → 400INVALID_FAVORITE - Neither
programmeIdnorlotIdprovided → 400INVALID_FAVORITE - Programme or lot does not exist → 400
NOT_FOUND(P2003) - Already favorited → 409
DUPLICATE(P2002) - Favorite not found or owned by different pro (delete) → 404
NOT_FOUND - Unauthenticated → 401 (authenticatePro hook)
- CNI gate active → 403
CNI_REQUIRED
Related Processes
- registration — pro must be authenticated to manage favorites