---
title: "Social feeds"
description: "Un social feed regroupe entre SOCIAL_FEED_MEDIA_MIN et SOCIAL_FEED_MEDIA_MAX (par défaut 1 à 15) des médias publiés de l'utilisateur connecté sous un code…"
---

Un **social feed** regroupe entre `SOCIAL_FEED_MEDIA_MIN` et `SOCIAL_FEED_MEDIA_MAX` (par défaut **1 à 15**) des **médias publiés de l'utilisateur connecté** sous un **code court** (Crockford Base32, 4..10 caractères) qu'on peut partager hors-plateforme (réseaux sociaux, e-mail, SMS…). Le destinataire ouvre l'URL `/api/social-feeds/{code}` et reçoit la liste complète du carrousel en un seul appel.

**Codes** : alphabet `0123456789ABCDEFGHJKMNPQRSTVWXYZ` (Crockford, sans I/L/O/U → pas d'ambiguïté oral/saisie). Longueur initiale **4** (env `SOCIAL_FEED_CODE_LENGTH`, ≈ 1.05M codes uniques). Quand les collisions saturent la file de tentatives (`SOCIAL_FEED_CODE_MAX_ATTEMPTS`, défaut 5), le générateur renvoie `503 socialFeed.codeExhausted` — signal d'ops pour passer la longueur à 5, 6, etc., jusqu'à la borne de la colonne (`VARCHAR(10)`). Les codes courts déjà émis restent valides.

**Règles produit** :
- Pas de XP, pas de notification, pas de compteur public.
- Les médias d'un feed doivent **exister, être publiés ET appartenir à l'auteur**. Un média dépublié *après* la création du feed est silencieusement filtré de la lecture publique (la ligne reste en DB).
- L'ordre des `mediaIds` au POST est l'ordre du carrousel (`position` 1..N en base, contrainte UNIQUE).
- Un feed est **permanent** ; seul son auteur peut le supprimer (`DELETE /api/users/me/social-feeds/{code}`).
- Lecture publique anonyme OK (la share URL ne nécessite pas d'auth) ; un viewer authentifié récupère en plus son `viewerReaction` sur chaque média du carrousel.

## `POST /api/users/me/social-feeds`

Crée un feed. Auth requise. Le body accepte la forme JSON:API (`data.attributes.mediaIds`) ou plate (`{ "mediaIds": [...] }`).

```json
{
  "data": {
    "attributes": {
      "mediaIds": [
        "11111111-1111-1111-1111-111111111111",
        "22222222-2222-2222-2222-222222222222",
        "33333333-3333-3333-3333-333333333333"
      ]
    }
  }
}
```

Réponse `201` :

```json
{
  "data": {
    "type": "socialFeeds",
    "id": "7JBQ",
    "attributes": {
      "userId":     "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
      "mediaCount": 3,
      "mediaIds":   [
        "11111111-1111-1111-1111-111111111111",
        "22222222-2222-2222-2222-222222222222",
        "33333333-3333-3333-3333-333333333333"
      ],
      "createdAt":  { "iso": "...", "formatted": { "...": "..." }, "relative": "..." }
    }
  }
}
```

Erreurs (`422` sauf indication) :

| Code                            | Raison |
|---------------------------------|--------|
| `socialFeed.actorNotConfirmed`  | (403) compte non confirmé |
| `socialFeed.actorBanned`        | (403) compte banni |
| `socialFeed.tooFewMedias`       | moins de `SOCIAL_FEED_MEDIA_MIN` médias |
| `socialFeed.tooManyMedias`      | plus de `SOCIAL_FEED_MEDIA_MAX` médias |
| `socialFeed.duplicateMedia`     | un même `mediaId` apparaît plusieurs fois |
| `socialFeed.mediaNotFound`      | un `mediaId` n'existe pas ou n'est pas publié |
| `socialFeed.mediaNotOwned`      | un `mediaId` n'appartient pas à l'utilisateur |
| `socialFeed.codeExhausted`      | (503) bumpez `SOCIAL_FEED_CODE_LENGTH` |

[CreateSocialFeedAction](../src/Http/Action/Api/SocialFeed/CreateSocialFeedAction.php)

## `GET /api/users/me/social-feeds`

Liste les feeds de l'utilisateur authentifié, du plus récent au plus ancien. Paramètre `?limit=` (1..100, défaut 50). Pas de pagination keyset — la volumétrie attendue par utilisateur est faible. `meta.total` est exact.

Chaque ressource expose `mediaIds` (UUIDs ordonnés) — pas les médias complets ; le client utilise les UUIDs pour résoudre les thumbnails via les URLs media existantes. [ListMySocialFeedsAction](../src/Http/Action/Api/SocialFeed/ListMySocialFeedsAction.php)

## `DELETE /api/users/me/social-feeds/{code}`

Supprime un feed appartenant à l'utilisateur connecté. `204` en cas de succès. `404 socialFeed.notFound` lorsque le code n'existe pas **OU** appartient à un autre utilisateur (confusion délibérée pour éviter l'énumération des codes par sonde DELETE). [DeleteSocialFeedAction](../src/Http/Action/Api/SocialFeed/DeleteSocialFeedAction.php)

## `GET /api/social-feeds/{code}`

**Lecture publique** : pas d'auth requise (anonymous OK via `OptionalAuthenticationMiddleware`). Retourne la ressource feed avec :

- `mediaIds` — UUIDs ordonnés du carrousel ;
- `medias` — la liste **complète** des médias hydratés (mêmes attributs que `GET /api/media/{id}` : `url`, `blurhashUrl`, `latitude/longitude`, `author` public, `likesCount`, etc.), dans l'ordre du carrousel. Les médias dépubliés depuis la création sont filtrés ; `medias.length` peut donc être strictement inférieur à `mediaCount`.

Un viewer authentifié reçoit en plus `viewerReaction` sur chaque média.

`404 socialFeed.notFound` si le code n'a pas la bonne forme (longueur/alphabet) ou n'existe pas — même réponse pour les deux cas. [GetSocialFeedAction](../src/Http/Action/Api/SocialFeed/GetSocialFeedAction.php)

---
