Acheteur Favorites

Summary

Authenticated acheteurs can save programmes or individual lots as favorites for later reference. Each favorite record links an acheteur to exactly one target — either a programmeId or a lotId, never both. Favorites are returned in reverse chronological order and include a lightweight join to the target’s key fields (name, price, surface, status). Duplicates are rejected (Prisma unique constraint P2002). Favorites cascade-delete when the acheteur account is deleted.

State Diagram

stateDiagram-v2
    state "Aucun favori" as NoFavorites
    state "Favori ajouté" as FavoriteAdded
    state "Favori supprimé" as FavoriteRemoved
    [*] --> NoFavorites: authenticated acheteur, empty list
    NoFavorites --> FavoriteAdded: acheteur adds a favourite
    FavoriteAdded --> FavoriteAdded: acheteur adds another favourite
    FavoriteAdded --> FavoriteRemoved: acheteur removes a favourite
    FavoriteRemoved --> NoFavorites: list empty again
    FavoriteAdded --> [*]: acheteur lists favourites
    NoFavorites --> [*]: acheteur lists favourites (empty)

Steps

1. List Favorites (Actor: acheteur)

GET /acheteur/favorites returns all favorites for the authenticated acheteur. Each favorite includes:

  • For a programme favorite: { id, slug, name, ville, prixMin, prixMax, photos }.
  • For a lot favorite: { id, type, surface, price, status, isComplete }.

Ordered by createdAt DESC.

Outcome: { data: favorites[] }.

2. Add Favorite (Actor: acheteur)

POST /acheteur/favorites accepts { programmeId?, lotId? }.

Exactly one of programmeId or lotId must be provided — if neither or both are given, returns 400 INVALID_FAVORITE.

The favorite is created in prisma.favorite. On Prisma error:

  • P2002 (unique constraint) → 409 DUPLICATE — “Already in favorites”.
  • P2003 (foreign key violation, target doesn’t exist) → 400 NOT_FOUND — “Programme or lot not found”.

Outcome: 201 { data: favorite } on success.

3. Remove Favorite (Actor: acheteur)

DELETE /acheteur/favorites/:id first checks that the favorite exists and belongs to the requesting acheteur (ownership check via findFirst { where: { id, acheteurId } }). If not found or not owned → 404 NOT_FOUND.

On success, the row is deleted.

Outcome: { success: true }.

Error States

  • Neither programmeId nor lotId provided → 400 INVALID_FAVORITE
  • Both programmeId and lotId provided → 400 INVALID_FAVORITE
  • Programme or lot does not exist (FK violation) → 400 NOT_FOUND
  • Favorite already exists for this (acheteur, target) → 409 DUPLICATE
  • Favorite not found or not owned by acheteur → 404 NOT_FOUND
  • browsing — favorites are typically added from programme/property detail pages
  • registration-email-verification — authentication required; this process depends on a verified account existing
  • account-deletion — all favorites are cascade-deleted when the account is anonymized