Skip to main content

Uploads médias

Tous les uploads transitent par le backend (scan AV + validation) avant d’atterrir sur Cloudflare R2.

Matrice des médias

MédiaBucketRôleFormatsTaille maxRatio
Logo entreprisepublicOWNERPNG, JPG2 Mocarré
Bannière entreprisepublicOWNERJPG5 Mo16:9
Photo staffpublicOWNERJPG3 Mo4:3
Photo profil candidatpublicCANDIDATPNG, JPG1 Mocarré
CV candidatprivateCANDIDATPDF5 Mo
Cover blogpublicADMINJPG, WebP5 Mo16:9
KYCprivateRECRUTEURPDF, JPG10 Mo

Pipeline général

1. Logo entreprise

POST /v1/api/recruiters/me/entreprise/logo HTTP/1.1
Authorization: Bearer <OWNER_TOKEN>
Content-Type: multipart/form-data

file=@logo.png
Traitement image : Réponse :
{
  "logoUrl": "https://cdn.wethehivers.com/public/entreprises/18/logo.webp",
  "variants": {
    "512": "https://cdn.wethehivers.com/public/entreprises/18/logo-512.webp",
    "256": "https://cdn.wethehivers.com/public/entreprises/18/logo-256.webp",
    "128": "https://cdn.wethehivers.com/public/entreprises/18/logo-128.webp"
  }
}

2. Bannière entreprise

Ratio imposé 16:9 (erreur 422 sinon).
POST /v1/api/recruiters/me/entreprise/banner HTTP/1.1
file=@banner-1920x1080.jpg

3. Photos staff

Jusqu’à 10 photos par entreprise.
POST /v1/api/recruiters/me/entreprise/staff-photos HTTP/1.1
Content-Type: multipart/form-data

files=@photo1.jpg
files=@photo2.jpg
caption=Équipe dev Douala

Réorganiser

PUT /v1/api/recruiters/me/entreprise/staff-photos/order
{ "order": [15, 12, 18, 14] }

Supprimer

DELETE /v1/api/recruiters/me/entreprise/staff-photos/12

4. Photo profil candidat

POST /v1/api/candidats/me/photo HTTP/1.1
file=@profile.jpg
Le backend génère un avatar circulaire 256x256 WebP.

5. CV candidat (privé)

Voir URLs pré-signées pour les règles d’accès.
POST /v1/api/candidats/me/cv HTTP/1.1
file=@cv.pdf

6. Cover blog (admin)

POST /v1/api/admin/blog/14/cover HTTP/1.1
file=@cover.jpg
Conversion automatique en WebP + variants responsive :
VariantTailleUsage
cover-1920.webp1920×1080Desktop full width
cover-1200.webp1200×675Tablet
cover-600.webp600×338Mobile / cards

7. Gestion des erreurs

8. Quotas de stockage

RôleQuota totalRetry après dépassement
CANDIDAT50 MoSupprimer anciens uploads
RECRUTEUR (OWNER)100 Mo entrepriseIdem ou upgrade plan
ADMINIllimité

9. URLs signées (fichiers privés)

Pour les CV et KYC, utiliser :
GET /v1/api/files/cv/17  → 200 {url, expiresAt} ou 302 redirect
L’URL signée expire en 15 minutes. Voir URLs pré-signées.

10. Suppression

DELETE /v1/api/candidats/me/cv/17
DELETE /v1/api/recruiters/me/entreprise/logo
La suppression est immédiate en R2 + marquage files_metadata.status=DELETED. Pas de corbeille.

Snippet JS — upload avec progression

async function uploadCV(file, onProgress) {
  const form = new FormData();
  form.append('file', file);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', '/v1/api/candidats/me/cv');
  xhr.setRequestHeader('Authorization', `Bearer ${token}`);
  xhr.upload.onprogress = (e) => {
    if (e.lengthComputable) onProgress(e.loaded / e.total);
  };
  return new Promise((resolve, reject) => {
    xhr.onload = () => resolve(JSON.parse(xhr.response));
    xhr.onerror = () => reject(new Error('Upload failed'));
    xhr.send(form);
  });
}

Voir aussi