{"openapi":"3.0.0","info":{"title":"ReservaBabi API","version":"2.0.0","description":"\n# ReservaBabi Backend API\n\nAPI REST complète pour la plateforme de réservation ReservaBabi.\n\n## Vue d'ensemble\n\nCette API permet de gérer:\n- **Hotels** - Réservation de chambres d'hôtel\n- **Restaurants** - Réservation de tables et consultation de menus\n- **Agences de location** - Location de véhicules\n- **Parkings** - Réservation de places de parking\n- **Établissements** - Salons, spas, cabinets médicaux (rendez-vous)\n- **Prestataires** - Gestion des prestataires de services\n- **Finance** - Wallets, transactions, retraits et commissions\n- **Covoiturage (Carpool)** - Covoiturage client-to-client monétisé par crédits\n- **Crédits** - Système de crédits prépayés pour publier/réserver des covoiturages\n- **Événements** - Gestion d'événements, billetterie et check-in avec QR codes\n- **Avis** - Système de notation et avis clients\n- **Paiements** - Initiation, vérification et historique des paiements\n- **Panier** - Panier d'achat multi-services avec checkout\n- **Factures** - Génération et téléchargement de factures PDF\n- **Messagerie** - Conversations en temps réel et notifications push\n- **Suivi Véhicule** - Localisation GPS en temps réel et alertes de déviation\n- **Chatbot IA** - Assistant conversationnel avec streaming SSE\n- **Insights IA** - Recommandations tarifaires et optimisation des créneaux\n- **Blog** - Articles, génération IA et workflow de validation\n- **Addons** - Services supplémentaires activables par abonnement\n- **Favoris** - Gestion des entités favorites\n- **Vitrines** - Boutiques en ligne des propriétaires\n- **Remboursements** - Demandes et gestion des remboursements\n- **Fraude** - Détection et gestion des alertes de fraude\n- **Modération** - Modération de contenu automatique et manuelle\n- **Permissions** - Gestion granulaire des permissions par rôle\n- **Transport** - Agences de transport, trajets, réservations et billetterie\n- **Appels Vidéo** - Visioconférence avec LiveKit, chat et enregistrement\n- **Parrainage** - Programme de parrainage avec codes et commissions\n- **Publication** - Workflow de publication/validation des entités\n- **BYC** - Vérification documentaire des entreprises\n- **Banque de Fichiers** - Documents numériques téléchargeables\n- **Alertes Sécurité** - Monitoring et gestion des alertes de sécurité\n- **Phases de Service** - Services multi-étapes\n- **Brevo** - Intégration CRM et automatisation email\n\n## Authentification\n\nL'API utilise JWT (JSON Web Tokens) pour l'authentification.\nIncluez le token dans le header Authorization:\n\n```\nAuthorization: Bearer <votre_token>\n```\n\n### Flux d'authentification\n\n1. **Login** - POST /auth/login (retourne accessToken + refreshToken)\n2. **2FA** (si activé) - POST /2fa/verify\n3. **Refresh** - POST /auth/refresh (renouvelle les tokens)\n4. **Logout** - POST /auth/logout\n\n## API Externe (Clé API)\n\nPour les intégrations partenaires, une authentification par clé API est disponible.\nIncluez la clé dans le header X-API-Key:\n\n```\nX-API-Key: <votre_cle_api>\n```\n\nLes endpoints `/external/*` permettent de créer des hôtels et propriétaires sans authentification utilisateur.\nContactez l'équipe pour obtenir une clé API.\n\n## Rôles utilisateurs\n\n| Rôle | Description | Accès |\n|------|-------------|-------|\n| superAdmin | Super administrateur | Accès complet |\n| admin | Administrateur | Dashboard admin, gestion utilisateurs |\n| proprio | Propriétaire | Gestion de ses établissements |\n| agent | Agent/Staff | Accès back-office du propriétaire |\n| prestataire | Prestataire | Dashboard prestataire, ses RDV |\n| client | Client | Réservations, avis |\n\n## Codes d'erreur courants\n\n| Code | Description |\n|------|-------------|\n| 400 | Bad Request - Requête invalide |\n| 401 | Unauthorized - Token manquant ou invalide |\n| 403 | Forbidden - Permissions insuffisantes |\n| 404 | Not Found - Ressource non trouvée |\n| 409 | Conflict - Conflit (ex: email déjà utilisé) |\n| 422 | Validation Error - Données invalides |\n| 429 | Too Many Requests - Rate limit dépassé |\n| 500 | Internal Server Error - Erreur serveur |\n\n## Pagination\n\nToutes les listes paginées utilisent le format suivant:\n\n```json\n{\n  \"success\": true,\n  \"data\": [...],\n  \"meta\": {\n    \"total\": 150,\n    \"page\": 1,\n    \"limit\": 20,\n    \"totalPages\": 8,\n    \"hasNextPage\": true,\n    \"hasPrevPage\": false\n  }\n}\n```\n\nParamètres de pagination:\n- `page` - Numéro de page (défaut: 1)\n- `limit` - Éléments par page (défaut: 20, max: 100)\n\n## Filtrage et Tri\n\nLa plupart des endpoints supportent:\n- `search` - Recherche textuelle\n- `sortBy` - Champ de tri\n- `sortOrder` - asc ou desc\n\n## Format des dates\n\nToutes les dates sont au format ISO 8601:\n`2024-03-20T14:00:00Z`\n    ","contact":{"name":"ReservaBabi Support","email":"support@reservababi.com"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://backend-test.reservababi.com/api","description":"Staging/Test"}],"tags":[{"name":"Auth","description":"Authentification et gestion des sessions"},{"name":"Users","description":"Gestion des utilisateurs et profils"},{"name":"Hotels","description":"Gestion des hôtels et chambres"},{"name":"Restaurants","description":"Gestion des restaurants, menus et tables"},{"name":"Rental Agencies","description":"Gestion des agences de location et véhicules"},{"name":"Parkings","description":"Gestion des parkings et places"},{"name":"Establishments","description":"Établissements de rendez-vous (salons, spas, etc.)"},{"name":"Reservations","description":"Gestion des réservations"},{"name":"Reviews","description":"Avis et notations clients"},{"name":"Providers","description":"Gestion des prestataires de services"},{"name":"Finance","description":"Gestion financière - Wallets, transactions, retraits et commissions"},{"name":"Finance - Owner","description":"Finance - Endpoints propriétaires"},{"name":"Finance - Admin","description":"Finance - Endpoints admin/superAdmin"},{"name":"Promo Codes","description":"Codes promotionnels et réductions"},{"name":"Promo Codes - Admin","description":"Promo Codes - Gestion admin"},{"name":"Carpool","description":"Covoiturage client-to-client — publier, rechercher, réserver, noter"},{"name":"Carpool Admin","description":"Covoiturage — supervision admin, carte temps réel, finance"},{"name":"Credits","description":"Crédits prépayés — wallet, transactions, achat via la factory multi-provider (préfixe CRD-)"},{"name":"Credits Admin","description":"Crédits — gestion des packs et ajustements wallets"},{"name":"Events - Public","description":"Événements - Recherche publique et consultation"},{"name":"Events - Client","description":"Événements - Achat de billets et avis"},{"name":"Events - Owner","description":"Événements - Gestion de mes événements"},{"name":"Events - Admin","description":"Événements - Administration et modération"},{"name":"Search","description":"Recherche unifiée"},{"name":"Location","description":"Géolocalisation et calcul de distances"},{"name":"Amenities","description":"Commodités des établissements"},{"name":"Calendar","description":"Vue calendrier des réservations"},{"name":"Archive - Admin","description":"Archivage système - Sauvegarde et restauration (Admin/SuperAdmin)"},{"name":"Upload","description":"Upload de fichiers et images"},{"name":"Audit Logs","description":"Journal d'audit et traçabilité"},{"name":"KYC","description":"Vérification d'identité (Know Your Customer)"},{"name":"Gift Cards - Admin","description":"Cartes cadeaux - Gestion admin"},{"name":"Gift Cards - Client","description":"Cartes cadeaux - Utilisation client"},{"name":"Loyalty - Admin","description":"Programme de fidélité - Gestion admin"},{"name":"Loyalty - Client","description":"Programme de fidélité - Utilisation client"},{"name":"Reservation Attempts","description":"Tentatives de réservation sur entités sans propriétaire"},{"name":"Possible Owners","description":"Contacts potentiels des propriétaires"},{"name":"Possible Owner Notifications","description":"Notifications multi-canal aux possible owners"},{"name":"Trash - Admin","description":"Corbeille - Gestion admin (restauration, suppression définitive, purge)"},{"name":"Trash - Owner","description":"Corbeille - Gestion propriétaire (voir et restaurer ses éléments supprimés)"},{"name":"External API","description":"API externe protégée par clé API - Création d'hôtels et propriétaires pour intégrations partenaires"},{"name":"AI Chatbot","description":"Chatbot IA avec streaming SSE - Conversations, sessions et historique"},{"name":"AI Chatbot - Admin","description":"Chatbot IA - Administration et consultation des sessions"},{"name":"Content Generation","description":"Génération de contenu IA - Descriptions, menus et textes alternatifs"},{"name":"Vehicle Tracking - Proprio","description":"Suivi véhicule - Gestion des sessions par le propriétaire"},{"name":"Vehicle Tracking - Client","description":"Suivi véhicule - Consultation client (passager/locataire)"},{"name":"Vehicle Tracking - Admin","description":"Suivi véhicule - Administration et modération"},{"name":"Addon Services - Owner","description":"Services supplémentaires - Gestion des abonnements par le propriétaire"},{"name":"Addon Services - Admin","description":"Services supplémentaires - Administration des définitions d'addons"},{"name":"Messaging","description":"Messagerie - Conversations, messages et notifications push"},{"name":"AI Insights - Owner","description":"Insights IA - Recommandations, tarification dynamique et optimisation des créneaux (propriétaire)"},{"name":"AI Insights - Admin","description":"Insights IA - Consultation des insights pour un propriétaire (admin/superAdmin)"},{"name":"Blog - Public","description":"Blog - Articles publics, categories et consultation"},{"name":"Blog - Admin","description":"Blog - Gestion des articles, generation IA et workflow de validation (marketing/admin)"},{"name":"Claims - Owner","description":"Revendications - Demandes de revendication et suppression d'entites (proprietaire)"},{"name":"Claims - Admin","description":"Revendications - Administration des demandes (admin/superAdmin)"},{"name":"Email Logs","description":"Journal des emails envoyes - Consultation et suivi (admin)"},{"name":"Notifications","description":"Notifications plateforme - Gestion des notifications utilisateur"},{"name":"Payments","description":"Paiements - Initiation, verification et historique des paiements"},{"name":"Saved Payment Methods","description":"Methodes de paiement sauvegardees - Mobile money et autres"},{"name":"Favorites","description":"Favoris - Gestion des entites favorites de l'utilisateur"},{"name":"Shops - Public","description":"Vitrines - Consultation publique des boutiques proprietaires"},{"name":"Shops - Owner","description":"Vitrines - Gestion de la boutique proprietaire"},{"name":"Carts","description":"Panier - Gestion du panier d'achat multi-services"},{"name":"Invoices","description":"Factures - Telechargement et verification de factures"},{"name":"Countries","description":"Pays - Liste des pays, indicatifs telephoniques et codes ISO"},{"name":"Permissions - Admin","description":"Permissions - Gestion de la matrice de permissions par role (superAdmin)"},{"name":"Permissions - User","description":"Permissions - Consultation des permissions de l'utilisateur connecte"},{"name":"Refunds - Client","description":"Remboursements - Demandes de remboursement client"},{"name":"Refunds - Admin","description":"Remboursements - Administration et validation (admin/superAdmin)"},{"name":"Fraud - Admin","description":"Detection de fraude - Alertes et historique (admin/superAdmin)"},{"name":"Content Moderation - Admin","description":"Moderation de contenu - File d'attente et actions de moderation (admin/superAdmin)"},{"name":"Brevo","description":"Integration Brevo - Tracking et webhooks"},{"name":"Brevo - Admin","description":"Brevo - Synchronisation et administration"},{"name":"BYC - Owner","description":"Business Verification - Soumission de documents (proprietaire)"},{"name":"BYC - Admin","description":"Business Verification - Validation et administration"},{"name":"File Bank - Owner","description":"Banque de fichiers - Gestion des documents numeriques (proprietaire)"},{"name":"File Bank - Client","description":"Banque de fichiers - Achat et telechargement (client)"},{"name":"File Bank - Public","description":"Banque de fichiers - Consultation publique"},{"name":"File Bank - Admin","description":"Banque de fichiers - Administration"},{"name":"Parrain","description":"Programme de parrainage - Code, filleuls et invitations"},{"name":"Parrain - Admin","description":"Programme de parrainage - Administration"},{"name":"Publication - Owner","description":"Publication - Soumettre/depublier des entites (proprietaire)"},{"name":"Publication - Admin","description":"Publication - Validation et rejet (admin)"},{"name":"Security Alerts - Admin","description":"Alertes de securite - Monitoring et gestion (admin)"},{"name":"Service Phases - Owner","description":"Phases de service - Gestion multi-etapes (proprietaire)"},{"name":"Service Phases - Public","description":"Phases de service - Consultation publique"},{"name":"Transport - Public","description":"Transport - Recherche de trajets et gares"},{"name":"Transport - Client","description":"Transport - Reservations client"},{"name":"Transport - Proprio","description":"Transport - Gestion agence, vehicules, trajets (proprietaire)"},{"name":"Transport - Admin","description":"Transport - Administration et moderation"},{"name":"Video Calls - Owner","description":"Appels video - Gestion des appels et enregistrements (proprietaire)"},{"name":"Video Calls - Client","description":"Appels video - Inscription et paiement (client)"},{"name":"Video Calls - Public","description":"Appels video - Rejoindre, chat et consultation"},{"name":"Video Calls - Admin","description":"Appels video - Administration"},{"name":"Campaigns - Admin","description":"Campagnes multi-canal (SMS/email/WhatsApp) - templates de contenu et segments d'audience (superAdmin)"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT access token obtenu via /auth/login"},"apiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Clé API pour les intégrations partenaires. Contactez l'équipe pour obtenir une clé."}},"schemas":{"ErrorResponse":{"type":"object","description":"Structure standard des erreurs API","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Une erreur est survenue"},"code":{"type":"string","example":"VALIDATION_ERROR","description":"Code d'erreur unique pour identification programmatique"},"errors":{"type":"object","description":"Erreurs de validation par champ","additionalProperties":{"type":"array","items":{"type":"string"}},"example":{"email":["Format d'email invalide"],"password":["Le mot de passe doit contenir au moins 8 caracteres"]}}},"required":["success","message"]},"SuccessResponse":{"type":"object","description":"Structure standard des reponses succes","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Operation effectuee avec succes"},"data":{"type":"object","description":"Donnees de la reponse"}},"required":["success"]},"PaginationMeta":{"type":"object","description":"Metadonnees de pagination","properties":{"total":{"type":"integer","example":150,"description":"Nombre total d'elements"},"page":{"type":"integer","example":1,"description":"Page actuelle"},"limit":{"type":"integer","example":20,"description":"Nombre d'elements par page"},"totalPages":{"type":"integer","example":8,"description":"Nombre total de pages"},"hasNextPage":{"type":"boolean","example":true,"description":"Indique s'il y a une page suivante"},"hasPrevPage":{"type":"boolean","example":false,"description":"Indique s'il y a une page precedente"}}},"UserRole":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"],"description":"\n      Roles utilisateurs:\n      - superAdmin: Acces complet au systeme\n      - admin: Administration du dashboard\n      - proprio: Proprietaire d'etablissement\n      - agent: Staff d'un proprietaire\n      - organisateur: Organisateur d'evenements\n      - prestataire: Prestataire de services\n      - client: Client final\n    "},"EstablishmentStatus":{"type":"string","enum":["draft","pending","active","closed"],"description":"\n      Statut des etablissements:\n      - draft: Brouillon, non visible\n      - pending: En attente de validation admin\n      - active: Actif et visible au public\n      - closed: Ferme temporairement ou definitivement\n    "},"ReservationStatus":{"type":"string","enum":["pending","confirmed","cancelled","completed","no_show"],"description":"\n      Statut des reservations:\n      - pending: En attente de confirmation\n      - confirmed: Confirmee par l'etablissement\n      - cancelled: Annulee\n      - completed: Terminee avec succes\n      - no_show: Client absent\n    "},"ReservationType":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"],"description":"Type de reservation selon le type d'etablissement"},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"role":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"]},"profileImage":{"type":"string","nullable":true},"isActive":{"type":"boolean"},"isVerified":{"type":"boolean"},"twoFactorEnabled":{"type":"boolean"},"kycStatus":{"type":"string","enum":["none","pending","approved","rejected"],"nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Address":{"type":"object","description":"Adresse complete d'un etablissement","properties":{"street":{"type":"string","example":"Avenue Houphouet Boigny"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","example":"Cote d'Ivoire"},"postalCode":{"type":"string","example":"00225"},"latitude":{"type":"number","format":"double","example":5.3599,"description":"Coordonnee GPS latitude"},"longitude":{"type":"number","format":"double","example":-4.0083,"description":"Coordonnee GPS longitude"}}},"WorkingHours":{"type":"object","description":"Horaires d'ouverture par jour de la semaine","properties":{"monday":{"$ref":"#/components/schemas/DaySchedule"},"tuesday":{"$ref":"#/components/schemas/DaySchedule"},"wednesday":{"$ref":"#/components/schemas/DaySchedule"},"thursday":{"$ref":"#/components/schemas/DaySchedule"},"friday":{"$ref":"#/components/schemas/DaySchedule"},"saturday":{"$ref":"#/components/schemas/DaySchedule"},"sunday":{"$ref":"#/components/schemas/DaySchedule"}}},"DaySchedule":{"type":"object","properties":{"isOpen":{"type":"boolean","example":true},"openTime":{"type":"string","example":"08:00","description":"Heure d'ouverture (HH:mm)"},"closeTime":{"type":"string","example":"18:00","description":"Heure de fermeture (HH:mm)"},"breakStart":{"type":"string","example":"12:00","description":"Debut de la pause (optionnel)"},"breakEnd":{"type":"string","example":"14:00","description":"Fin de la pause (optionnel)"}}},"Amenity":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Nom de la commodité"},"description":{"type":"string","nullable":true,"description":"Description"},"icon":{"type":"string","nullable":true,"description":"Icône"},"category":{"type":"string","enum":["general","comfort","service","food","business","entertainment","accessibility","safety"],"description":"Catégorie"},"price":{"type":"number","description":"Prix (0 si gratuit)"},"isFree":{"type":"boolean","description":"Gratuit ou non"},"isActive":{"type":"boolean","description":"Actif ou non"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"OwnerStats":{"type":"object","description":"Statistiques pour un proprietaire","properties":{"totalEstablishments":{"type":"integer","example":5},"activeEstablishments":{"type":"integer","example":4},"totalReservations":{"type":"integer","example":150},"pendingReservations":{"type":"integer","example":12},"totalRevenue":{"type":"number","example":2500000},"monthlyRevenue":{"type":"number","example":450000},"averageRating":{"type":"number","example":4.5},"totalReviews":{"type":"integer","example":45}}},"Hotel":{"type":"object","description":"Hotel avec toutes ses informations","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Hotel Ivoire","minLength":2,"maxLength":100},"slug":{"type":"string","example":"hotel-ivoire-cocody"},"description":{"type":"string","example":"Hotel 5 etoiles au coeur de Cocody","maxLength":2000},"address":{"type":"string","example":"Boulevard de France, Cocody"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","example":"Cote d'Ivoire","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double","example":5.3599},"longitude":{"type":"number","format":"double","example":-4.0083},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email","example":"contact@hotelivoire.ci"},"website":{"type":"string","format":"uri","example":"https://hotelivoire.ci"},"starRating":{"type":"integer","minimum":1,"maximum":5,"example":5},"checkInTime":{"type":"string","example":"14:00","description":"Heure d'arrivee (HH:mm)"},"checkOutTime":{"type":"string","example":"12:00","description":"Heure de depart (HH:mm)"},"coverImage":{"type":"string","format":"uri","example":"https://storage.example.com/hotels/cover.jpg"},"images":{"type":"array","items":{"type":"string","format":"uri"},"example":["https://storage.example.com/hotels/img1.jpg","https://storage.example.com/hotels/img2.jpg"]},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.5},"reviewCount":{"type":"integer","example":128},"ownerId":{"type":"string","format":"uuid"},"amenities":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}},"rooms":{"type":"array","items":{"$ref":"#/components/schemas/Room"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Room":{"type":"object","description":"Chambre d'hotel","properties":{"id":{"type":"string","format":"uuid"},"hotelId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Suite Presidentielle","minLength":2,"maxLength":100},"description":{"type":"string","example":"Suite luxueuse avec vue sur la lagune","maxLength":1000},"type":{"type":"string","enum":["single","double","twin","suite","family","deluxe"],"example":"suite"},"capacity":{"type":"integer","minimum":1,"maximum":10,"example":2,"description":"Nombre de personnes"},"bedType":{"type":"string","enum":["single","double","king","queen","twin"],"example":"king"},"size":{"type":"number","example":45,"description":"Surface en m2"},"pricePerNight":{"type":"number","minimum":0,"example":150000,"description":"Prix par nuit en FCFA"},"quantity":{"type":"integer","minimum":1,"example":5,"description":"Nombre de chambres de ce type"},"availableCount":{"type":"integer","example":3,"description":"Nombre disponible actuellement"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"amenities":{"type":"array","items":{"type":"string"},"example":["wifi","tv","minibar","coffre-fort"]},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RoomExtra":{"type":"object","description":"Supplément/Extra pour une chambre d'hôtel","properties":{"id":{"type":"string","format":"uuid"},"hotelId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Petit-déjeuner","minLength":2,"maxLength":100},"description":{"type":"string","example":"Petit-déjeuner continental buffet","maxLength":500},"price":{"type":"number","minimum":0,"example":5000,"description":"Prix en FCFA"},"pricingType":{"type":"string","enum":["per_night","per_stay","per_person"],"example":"per_person","description":"Type de tarification: par nuit (x nuits x chambres), par séjour (fixe), ou par personne (x personnes)"},"isActive":{"type":"boolean","example":true,"description":"Si l'extra est actuellement proposé"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateRoomExtraInput":{"type":"object","required":["name","price","pricingType"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Petit-déjeuner"},"description":{"type":"string","maxLength":500,"example":"Petit-déjeuner continental buffet"},"price":{"type":"number","minimum":0,"example":5000},"pricingType":{"type":"string","enum":["per_night","per_stay","per_person"],"example":"per_person"},"isActive":{"type":"boolean","default":true}}},"UpdateRoomExtraInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":500},"price":{"type":"number","minimum":0},"pricingType":{"type":"string","enum":["per_night","per_stay","per_person"]},"isActive":{"type":"boolean"}}},"CreateHotelInput":{"type":"object","required":["name","address","city","phone"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Hotel Ivoire"},"description":{"type":"string","maxLength":2000,"example":"Hotel 5 etoiles au coeur de Cocody"},"address":{"type":"string","example":"Boulevard de France, Cocody"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"starRating":{"type":"integer","minimum":1,"maximum":5},"checkInTime":{"type":"string","example":"14:00"},"checkOutTime":{"type":"string","example":"12:00"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}}}},"UpdateHotelInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"starRating":{"type":"integer","minimum":1,"maximum":5},"checkInTime":{"type":"string"},"checkOutTime":{"type":"string"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"}}},"CreateRoomInput":{"type":"object","required":["name","type","capacity","pricePerNight","quantity"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Chambre Standard"},"description":{"type":"string","maxLength":1000},"type":{"type":"string","enum":["single","double","twin","suite","family","deluxe"]},"capacity":{"type":"integer","minimum":1,"maximum":10,"example":2},"bedType":{"type":"string","enum":["single","double","king","queen","twin"]},"size":{"type":"number","example":25},"pricePerNight":{"type":"number","minimum":0,"example":50000},"quantity":{"type":"integer","minimum":1,"example":10},"images":{"type":"array","items":{"type":"string","format":"uri"}},"amenities":{"type":"array","items":{"type":"string"}}}},"UpdateRoomInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":1000},"type":{"type":"string","enum":["single","double","twin","suite","family","deluxe"]},"capacity":{"type":"integer","minimum":1,"maximum":10},"bedType":{"type":"string","enum":["single","double","king","queen","twin"]},"size":{"type":"number"},"pricePerNight":{"type":"number","minimum":0},"quantity":{"type":"integer","minimum":1},"images":{"type":"array","items":{"type":"string","format":"uri"}},"amenities":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"}}},"HotelStats":{"type":"object","properties":{"totalHotels":{"type":"integer","example":5},"activeHotels":{"type":"integer","example":4},"totalRooms":{"type":"integer","example":120},"occupiedRooms":{"type":"integer","example":85},"occupancyRate":{"type":"number","example":70.8},"totalReservations":{"type":"integer","example":450},"pendingReservations":{"type":"integer","example":12},"monthlyRevenue":{"type":"number","example":15000000},"averageRating":{"type":"number","example":4.3}}},"Restaurant":{"type":"object","description":"Restaurant avec toutes ses informations","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Le Gourmet","minLength":2,"maxLength":100},"slug":{"type":"string","example":"le-gourmet-cocody"},"description":{"type":"string","example":"Restaurant gastronomique francais","maxLength":2000},"cuisineType":{"type":"string","enum":["francaise","italienne","africaine","asiatique","libanaise","indienne","fusion","fast-food","autre"],"example":"francaise"},"address":{"type":"string","example":"Rue des Jardins, Cocody"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","example":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double","example":5.3599},"longitude":{"type":"number","format":"double","example":-4.0083},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"priceRange":{"type":"string","enum":["$","$$","$$$","$$$$"],"description":"Gamme de prix ($ = economique, $$$$ = luxe)","example":"$$$"},"averagePrice":{"type":"number","example":15000,"description":"Prix moyen par personne en FCFA"},"capacity":{"type":"integer","example":80,"description":"Capacite totale du restaurant"},"openingHours":{"$ref":"#/components/schemas/WorkingHours"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.2},"reviewCount":{"type":"integer","example":85},"hasDelivery":{"type":"boolean","example":true},"hasTakeaway":{"type":"boolean","example":true},"acceptsReservations":{"type":"boolean","example":true},"ownerId":{"type":"string","format":"uuid"},"amenities":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}},"menu":{"type":"array","items":{"$ref":"#/components/schemas/MenuItem"}},"tables":{"type":"array","items":{"$ref":"#/components/schemas/Table"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MenuItem":{"type":"object","description":"Item du menu","properties":{"id":{"type":"string","format":"uuid"},"restaurantId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Entrecote grillee","minLength":2,"maxLength":100},"description":{"type":"string","example":"Entrecote de boeuf avec frites maison","maxLength":500},"category":{"type":"string","enum":["entree","plat","dessert","boisson","accompagnement","menu"],"example":"plat"},"price":{"type":"number","minimum":0,"example":12000,"description":"Prix en FCFA"},"image":{"type":"string","format":"uri"},"isAvailable":{"type":"boolean","example":true},"isVegetarian":{"type":"boolean","example":false},"isVegan":{"type":"boolean","example":false},"isGlutenFree":{"type":"boolean","example":false},"spicyLevel":{"type":"integer","minimum":0,"maximum":3,"example":0},"preparationTime":{"type":"integer","example":25,"description":"Temps de preparation en minutes"},"allergens":{"type":"array","items":{"type":"string"},"example":["gluten","lactose"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Table":{"type":"object","description":"Table du restaurant","properties":{"id":{"type":"string","format":"uuid"},"restaurantId":{"type":"string","format":"uuid"},"number":{"type":"string","example":"T-12","description":"Numero de table"},"capacity":{"type":"integer","minimum":1,"maximum":20,"example":4},"location":{"type":"string","enum":["interieur","terrasse","prive","bar"],"example":"terrasse"},"isAvailable":{"type":"boolean","example":true},"isActive":{"type":"boolean","example":true},"minSpend":{"type":"number","example":50000,"description":"Montant minimum de commande (optionnel)"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateRestaurantInput":{"type":"object","required":["name","address","city","phone","cuisineType"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"cuisineType":{"type":"string","enum":["francaise","italienne","africaine","asiatique","libanaise","indienne","fusion","fast-food","autre"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"country":{"type":"string","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"priceRange":{"type":"string","enum":["$","$$","$$$","$$$$"]},"averagePrice":{"type":"number"},"capacity":{"type":"integer"},"hasDelivery":{"type":"boolean","default":false},"hasTakeaway":{"type":"boolean","default":false},"acceptsReservations":{"type":"boolean","default":true},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}}}},"UpdateRestaurantInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"cuisineType":{"type":"string","enum":["francaise","italienne","africaine","asiatique","libanaise","indienne","fusion","fast-food","autre"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"priceRange":{"type":"string","enum":["$","$$","$$$","$$$$"]},"averagePrice":{"type":"number"},"capacity":{"type":"integer"},"hasDelivery":{"type":"boolean"},"hasTakeaway":{"type":"boolean"},"acceptsReservations":{"type":"boolean"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"}}},"CreateMenuItemInput":{"type":"object","required":["name","category","price"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":500},"category":{"type":"string","enum":["entree","plat","dessert","boisson","accompagnement","menu"]},"price":{"type":"number","minimum":0},"image":{"type":"string","format":"uri"},"isVegetarian":{"type":"boolean","default":false},"isVegan":{"type":"boolean","default":false},"isGlutenFree":{"type":"boolean","default":false},"spicyLevel":{"type":"integer","minimum":0,"maximum":3,"default":0},"preparationTime":{"type":"integer"},"allergens":{"type":"array","items":{"type":"string"}}}},"UpdateMenuItemInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":500},"category":{"type":"string","enum":["entree","plat","dessert","boisson","accompagnement","menu"]},"price":{"type":"number","minimum":0},"image":{"type":"string","format":"uri"},"isAvailable":{"type":"boolean"},"isVegetarian":{"type":"boolean"},"isVegan":{"type":"boolean"},"isGlutenFree":{"type":"boolean"},"spicyLevel":{"type":"integer","minimum":0,"maximum":3},"preparationTime":{"type":"integer"},"allergens":{"type":"array","items":{"type":"string"}}}},"CreateTableInput":{"type":"object","required":["number","capacity"],"properties":{"number":{"type":"string","example":"T-12"},"capacity":{"type":"integer","minimum":1,"maximum":20},"location":{"type":"string","enum":["interieur","terrasse","prive","bar"],"default":"interieur"},"minSpend":{"type":"number"}}},"UpdateTableInput":{"type":"object","properties":{"number":{"type":"string"},"capacity":{"type":"integer","minimum":1,"maximum":20},"location":{"type":"string","enum":["interieur","terrasse","prive","bar"]},"isAvailable":{"type":"boolean"},"isActive":{"type":"boolean"},"minSpend":{"type":"number"}}},"RestaurantStats":{"type":"object","properties":{"totalRestaurants":{"type":"integer","example":3},"activeRestaurants":{"type":"integer","example":3},"totalTables":{"type":"integer","example":45},"totalMenuItems":{"type":"integer","example":120},"totalReservations":{"type":"integer","example":320},"pendingReservations":{"type":"integer","example":8},"monthlyRevenue":{"type":"number","example":8500000},"averageRating":{"type":"number","example":4.4}}},"Parking":{"type":"object","description":"Parking avec toutes ses informations","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Parking Centre-Ville","minLength":2,"maxLength":100},"slug":{"type":"string","example":"parking-centre-ville-plateau"},"description":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["public","prive","souterrain","aerien","couvert","exterieur"],"example":"souterrain"},"address":{"type":"string","example":"Avenue de la Republique"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Plateau"},"country":{"type":"string","example":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double","example":5.3167},"longitude":{"type":"number","format":"double","example":-4.0167},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email"},"totalSpots":{"type":"integer","example":200,"description":"Nombre total de places"},"availableSpots":{"type":"integer","example":45,"description":"Places disponibles actuellement"},"hourlyRate":{"type":"number","example":500,"description":"Tarif horaire en FCFA"},"dailyRate":{"type":"number","example":5000,"description":"Tarif journalier en FCFA"},"monthlyRate":{"type":"number","example":50000,"description":"Tarif mensuel en FCFA"},"openingHours":{"$ref":"#/components/schemas/WorkingHours"},"is24Hours":{"type":"boolean","example":true,"description":"Ouvert 24h/24"},"hasElectricCharging":{"type":"boolean","example":true,"description":"Bornes de recharge electrique"},"hasHandicapSpots":{"type":"boolean","example":true,"description":"Places handicapes"},"hasSecurity":{"type":"boolean","example":true,"description":"Gardiennage/surveillance"},"hasCCTV":{"type":"boolean","example":true,"description":"Video surveillance"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.1},"reviewCount":{"type":"integer","example":42},"ownerId":{"type":"string","format":"uuid"},"spots":{"type":"array","items":{"$ref":"#/components/schemas/ParkingSpot"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ParkingSpot":{"type":"object","description":"Place de parking individuelle","properties":{"id":{"type":"string","format":"uuid"},"parkingId":{"type":"string","format":"uuid"},"number":{"type":"string","example":"A-15","description":"Numero de la place"},"floor":{"type":"string","example":"-1","description":"Etage/niveau"},"type":{"type":"string","enum":["standard","handicap","moto","electrique","vip","camion"],"example":"standard"},"size":{"type":"string","enum":["small","medium","large","xl"],"example":"medium","description":"Taille de la place"},"isAvailable":{"type":"boolean","example":true},"isReserved":{"type":"boolean","example":false},"hourlyRate":{"type":"number","example":500,"description":"Tarif specifique (optionnel)"},"features":{"type":"array","items":{"type":"string"},"example":["proche_ascenseur","eclairee"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateParkingInput":{"type":"object","required":["name","address","city","totalSpots"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["public","prive","souterrain","aerien","couvert","exterieur"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"country":{"type":"string","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"totalSpots":{"type":"integer","minimum":1},"hourlyRate":{"type":"number","minimum":0},"dailyRate":{"type":"number","minimum":0},"monthlyRate":{"type":"number","minimum":0},"is24Hours":{"type":"boolean","default":false},"hasElectricCharging":{"type":"boolean","default":false},"hasHandicapSpots":{"type":"boolean","default":true},"hasSecurity":{"type":"boolean","default":false},"hasCCTV":{"type":"boolean","default":false},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}}}},"UpdateParkingInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["public","prive","souterrain","aerien","couvert","exterieur"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"totalSpots":{"type":"integer","minimum":1},"hourlyRate":{"type":"number","minimum":0},"dailyRate":{"type":"number","minimum":0},"monthlyRate":{"type":"number","minimum":0},"is24Hours":{"type":"boolean"},"hasElectricCharging":{"type":"boolean"},"hasHandicapSpots":{"type":"boolean"},"hasSecurity":{"type":"boolean"},"hasCCTV":{"type":"boolean"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"}}},"CreateSpotInput":{"type":"object","required":["number"],"properties":{"number":{"type":"string","example":"A-15"},"floor":{"type":"string","example":"-1"},"type":{"type":"string","enum":["standard","handicap","moto","electrique","vip","camion"],"default":"standard"},"size":{"type":"string","enum":["small","medium","large","xl"],"default":"medium"},"hourlyRate":{"type":"number","minimum":0},"features":{"type":"array","items":{"type":"string"}}}},"UpdateSpotInput":{"type":"object","properties":{"number":{"type":"string"},"floor":{"type":"string"},"type":{"type":"string","enum":["standard","handicap","moto","electrique","vip","camion"]},"size":{"type":"string","enum":["small","medium","large","xl"]},"isAvailable":{"type":"boolean"},"hourlyRate":{"type":"number","minimum":0},"features":{"type":"array","items":{"type":"string"}}}},"ParkingStats":{"type":"object","properties":{"totalParkings":{"type":"integer","example":2},"activeParkings":{"type":"integer","example":2},"totalSpots":{"type":"integer","example":350},"availableSpots":{"type":"integer","example":120},"occupancyRate":{"type":"number","example":65.7},"totalReservations":{"type":"integer","example":890},"activeReservations":{"type":"integer","example":230},"monthlyRevenue":{"type":"number","example":2500000},"averageRating":{"type":"number","example":4.1}}},"RentalAgency":{"type":"object","description":"Agence de location de vehicules","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"CI Location","minLength":2,"maxLength":100},"slug":{"type":"string","example":"ci-location-plateau"},"description":{"type":"string","maxLength":2000},"address":{"type":"string","example":"Boulevard Lagunaire"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Plateau"},"country":{"type":"string","example":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double","example":5.3167},"longitude":{"type":"number","format":"double","example":-4.0167},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"openingHours":{"$ref":"#/components/schemas/WorkingHours"},"hasDelivery":{"type":"boolean","example":true,"description":"Livraison du vehicule"},"hasDriver":{"type":"boolean","example":true,"description":"Propose des chauffeurs"},"hasInsurance":{"type":"boolean","example":true,"description":"Assurance incluse"},"minimumAge":{"type":"integer","example":21,"description":"Age minimum requis"},"minimumLicenseYears":{"type":"integer","example":2,"description":"Annees de permis minimum"},"depositRequired":{"type":"boolean","example":true},"depositAmount":{"type":"number","example":100000,"description":"Montant de la caution en FCFA"},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"],"example":"moderate"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.3},"reviewCount":{"type":"integer","example":67},"ownerId":{"type":"string","format":"uuid"},"fleet":{"type":"array","items":{"$ref":"#/components/schemas/Vehicle"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Vehicle":{"type":"object","description":"Vehicule de la flotte","properties":{"id":{"type":"string","format":"uuid"},"rentalAgencyId":{"type":"string","format":"uuid"},"brand":{"type":"string","example":"Toyota"},"model":{"type":"string","example":"Land Cruiser Prado"},"year":{"type":"integer","example":2023},"category":{"type":"string","enum":["economique","compact","berline","suv","luxe","utilitaire","minibus","moto"],"example":"suv"},"transmission":{"type":"string","enum":["manual","automatic"],"example":"automatic"},"fuelType":{"type":"string","enum":["essence","diesel","hybride","electrique"],"example":"diesel"},"seats":{"type":"integer","example":7,"description":"Nombre de places"},"doors":{"type":"integer","example":5,"description":"Nombre de portes"},"airConditioning":{"type":"boolean","example":true},"gps":{"type":"boolean","example":true},"bluetooth":{"type":"boolean","example":true},"licensePlate":{"type":"string","example":"1234 AB 01"},"color":{"type":"string","example":"Blanc"},"mileage":{"type":"integer","example":45000,"description":"Kilometrage"},"dailyRate":{"type":"number","example":75000,"description":"Tarif journalier en FCFA"},"weeklyRate":{"type":"number","example":400000,"description":"Tarif hebdomadaire en FCFA"},"monthlyRate":{"type":"number","example":1200000,"description":"Tarif mensuel en FCFA"},"driverRate":{"type":"number","example":25000,"description":"Supplement chauffeur par jour"},"depositAmount":{"type":"number","example":150000,"description":"Caution specifique"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"features":{"type":"array","items":{"type":"string"},"example":["Camera de recul","Siege cuir","Toit ouvrant"]},"isAvailable":{"type":"boolean","example":true},"isActive":{"type":"boolean","example":true},"nextAvailableDate":{"type":"string","format":"date","description":"Prochaine disponibilite si reserve"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateRentalAgencyInput":{"type":"object","required":["name","address","city","phone"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"country":{"type":"string","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"hasDelivery":{"type":"boolean","default":false},"hasDriver":{"type":"boolean","default":false},"hasInsurance":{"type":"boolean","default":true},"minimumAge":{"type":"integer","default":21},"minimumLicenseYears":{"type":"integer","default":2},"depositRequired":{"type":"boolean","default":true},"depositAmount":{"type":"number"},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"],"default":"moderate"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}}}},"UpdateRentalAgencyInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"hasDelivery":{"type":"boolean"},"hasDriver":{"type":"boolean"},"hasInsurance":{"type":"boolean"},"minimumAge":{"type":"integer"},"minimumLicenseYears":{"type":"integer"},"depositRequired":{"type":"boolean"},"depositAmount":{"type":"number"},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"]},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"}}},"CreateVehicleInput":{"type":"object","required":["brand","model","year","category","dailyRate"],"properties":{"brand":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer","minimum":2000,"maximum":2030},"category":{"type":"string","enum":["economique","compact","berline","suv","luxe","utilitaire","minibus","moto"]},"transmission":{"type":"string","enum":["manual","automatic"],"default":"automatic"},"fuelType":{"type":"string","enum":["essence","diesel","hybride","electrique"],"default":"essence"},"seats":{"type":"integer","minimum":1,"maximum":20},"doors":{"type":"integer","minimum":2,"maximum":5},"airConditioning":{"type":"boolean","default":true},"gps":{"type":"boolean","default":false},"bluetooth":{"type":"boolean","default":true},"licensePlate":{"type":"string"},"color":{"type":"string"},"mileage":{"type":"integer"},"dailyRate":{"type":"number","minimum":0},"weeklyRate":{"type":"number","minimum":0},"monthlyRate":{"type":"number","minimum":0},"driverRate":{"type":"number","minimum":0},"depositAmount":{"type":"number","minimum":0},"images":{"type":"array","items":{"type":"string","format":"uri"}},"features":{"type":"array","items":{"type":"string"}}}},"UpdateVehicleInput":{"type":"object","properties":{"brand":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer"},"category":{"type":"string","enum":["economique","compact","berline","suv","luxe","utilitaire","minibus","moto"]},"transmission":{"type":"string","enum":["manual","automatic"]},"fuelType":{"type":"string","enum":["essence","diesel","hybride","electrique"]},"seats":{"type":"integer"},"doors":{"type":"integer"},"airConditioning":{"type":"boolean"},"gps":{"type":"boolean"},"bluetooth":{"type":"boolean"},"color":{"type":"string"},"mileage":{"type":"integer"},"dailyRate":{"type":"number"},"weeklyRate":{"type":"number"},"monthlyRate":{"type":"number"},"driverRate":{"type":"number"},"depositAmount":{"type":"number"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"features":{"type":"array","items":{"type":"string"}},"isAvailable":{"type":"boolean"},"isActive":{"type":"boolean"}}},"RentalAgencyStats":{"type":"object","properties":{"totalAgencies":{"type":"integer","example":2},"activeAgencies":{"type":"integer","example":2},"totalVehicles":{"type":"integer","example":25},"availableVehicles":{"type":"integer","example":18},"rentedVehicles":{"type":"integer","example":7},"totalReservations":{"type":"integer","example":156},"activeReservations":{"type":"integer","example":7},"monthlyRevenue":{"type":"number","example":4500000},"averageRating":{"type":"number","example":4.3}}},"Establishment":{"type":"object","description":"Etablissement de rendez-vous (salon, spa, salle de sport, cabinet medical, etc.)","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Salon Beaute Elite","minLength":2,"maxLength":100},"slug":{"type":"string","example":"salon-beaute-elite-cocody"},"description":{"type":"string","maxLength":2000},"businessType":{"type":"string","enum":["salon_coiffure","spa","salle_sport","cabinet_medical","centre_esthetique","autre"],"example":"salon_coiffure","description":"Type d'activite de l'etablissement"},"address":{"type":"string","example":"Rue des Fleurs, Cocody"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","example":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double","example":5.3599},"longitude":{"type":"number","format":"double","example":-4.0083},"phone":{"type":"string","example":"+2250700000000"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"workingHours":{"$ref":"#/components/schemas/WorkingHours"},"slotDuration":{"type":"integer","example":30,"description":"Duree par defaut d'un creneau en minutes"},"bufferTime":{"type":"integer","example":10,"description":"Temps de pause entre rendez-vous en minutes"},"maxAdvanceBookingDays":{"type":"integer","example":30,"description":"Nombre de jours max pour reserver a l'avance"},"minAdvanceBookingHours":{"type":"integer","example":2,"description":"Heures minimum avant un rendez-vous"},"allowOnlinePayment":{"type":"boolean","example":true},"requireDeposit":{"type":"boolean","example":false},"depositPercentage":{"type":"number","example":30},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"],"example":"moderate"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.6},"reviewCount":{"type":"integer","example":92},"ownerId":{"type":"string","format":"uuid"},"services":{"type":"array","items":{"$ref":"#/components/schemas/Service"}},"providers":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}},"amenities":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Service":{"type":"object","description":"Service propose par l'etablissement","properties":{"id":{"type":"string","format":"uuid"},"establishmentId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Coupe homme","minLength":2,"maxLength":100},"description":{"type":"string","example":"Coupe classique avec shampooing","maxLength":500},"category":{"type":"string","example":"coiffure","description":"Categorie du service"},"duration":{"type":"integer","example":30,"description":"Duree en minutes"},"price":{"type":"number","example":5000,"description":"Prix en FCFA"},"priceFrom":{"type":"number","example":3000,"description":"Prix a partir de (si variable)"},"priceTo":{"type":"number","example":8000,"description":"Prix jusqu'a (si variable)"},"image":{"type":"string","format":"uri"},"isActive":{"type":"boolean","example":true},"requiresProvider":{"type":"boolean","example":true,"description":"Necessite un prestataire specifique"},"maxConcurrentBookings":{"type":"integer","example":1,"description":"Reservations simultanees max"},"bookingAvailabilityReason":{"type":"string","example":"SERVICE_NOT_AVAILABLE_FOR_BOOKING","description":"Present si isActive=false : code stable aligne sur les erreurs 400 reservation/panier (lecture seule)."},"unavailableMessage":{"type":"string","example":"Ce service n'est pas disponible à la réservation.","description":"Message utilisateur lorsque la reservation en ligne est indisponible pour ce service."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AvailableSlot":{"type":"object","description":"Creneau disponible pour reservation","properties":{"date":{"type":"string","format":"date","example":"2024-03-15"},"startTime":{"type":"string","example":"10:00"},"endTime":{"type":"string","example":"10:30"},"providerId":{"type":"string","format":"uuid","nullable":true},"providerName":{"type":"string","nullable":true},"serviceId":{"type":"string","format":"uuid"},"serviceName":{"type":"string"},"isAvailable":{"type":"boolean","example":true}}},"CreateEstablishmentInput":{"type":"object","required":["name","businessType","address","city","phone"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"businessType":{"type":"string","enum":["salon_coiffure","spa","salle_sport","cabinet_medical","centre_esthetique","autre"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"country":{"type":"string","default":"Cote d'Ivoire"},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"slotDuration":{"type":"integer","default":30},"bufferTime":{"type":"integer","default":10},"maxAdvanceBookingDays":{"type":"integer","default":30},"minAdvanceBookingHours":{"type":"integer","default":2},"allowOnlinePayment":{"type":"boolean","default":true},"requireDeposit":{"type":"boolean","default":false},"depositPercentage":{"type":"number"},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"],"default":"moderate"},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"providers":{"type":"array","description":"Creation/lien de prestataires. Si email existe deja, envoyer linkExistingUser=true (ou omettre password) pour lier le compte existant.","items":{"type":"object","required":["firstname","lastname","email","tel"],"properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"password":{"type":"string","minLength":8},"linkExistingUser":{"type":"boolean","default":false},"assignedServiceIds":{"type":"array","items":{"type":"string"}},"bio":{"type":"string"},"specialties":{"type":"array","items":{"type":"string"}},"yearsOfExperience":{"type":"integer","minimum":0}}}}}},"UpdateEstablishmentInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":2000},"businessType":{"type":"string","enum":["salon_coiffure","spa","salle_sport","cabinet_medical","centre_esthetique","autre"]},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","format":"email"},"website":{"type":"string","format":"uri"},"slotDuration":{"type":"integer"},"bufferTime":{"type":"integer"},"maxAdvanceBookingDays":{"type":"integer"},"minAdvanceBookingHours":{"type":"integer"},"allowOnlinePayment":{"type":"boolean"},"requireDeposit":{"type":"boolean"},"depositPercentage":{"type":"number"},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict"]},"coverImage":{"type":"string","format":"uri"},"images":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"$ref":"#/components/schemas/EstablishmentStatus"},"providers":{"type":"array","description":"Meme semantique que POST /owner/establishments pour creation/lien de prestataires","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"password":{"type":"string","minLength":8},"linkExistingUser":{"type":"boolean","default":false},"assignedServiceIds":{"type":"array","items":{"type":"string"}},"bio":{"type":"string"},"specialties":{"type":"array","items":{"type":"string"}},"yearsOfExperience":{"type":"integer","minimum":0}}}}}},"CreateServiceInput":{"type":"object","required":["name","duration","price"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":500},"category":{"type":"string"},"duration":{"type":"integer","minimum":5,"maximum":480},"price":{"type":"number","minimum":0},"priceFrom":{"type":"number"},"priceTo":{"type":"number"},"image":{"type":"string","format":"uri"},"requiresProvider":{"type":"boolean","default":true},"maxConcurrentBookings":{"type":"integer","default":1}}},"UpdateServiceInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","maxLength":500},"category":{"type":"string"},"duration":{"type":"integer","minimum":5,"maximum":480},"price":{"type":"number","minimum":0},"priceFrom":{"type":"number"},"priceTo":{"type":"number"},"image":{"type":"string","format":"uri"},"isActive":{"type":"boolean"},"requiresProvider":{"type":"boolean"},"maxConcurrentBookings":{"type":"integer"}}},"WorkingHoursInput":{"type":"object","description":"Horaires de travail par jour","properties":{"monday":{"$ref":"#/components/schemas/DaySchedule"},"tuesday":{"$ref":"#/components/schemas/DaySchedule"},"wednesday":{"$ref":"#/components/schemas/DaySchedule"},"thursday":{"$ref":"#/components/schemas/DaySchedule"},"friday":{"$ref":"#/components/schemas/DaySchedule"},"saturday":{"$ref":"#/components/schemas/DaySchedule"},"sunday":{"$ref":"#/components/schemas/DaySchedule"}}},"EstablishmentStats":{"type":"object","properties":{"totalEstablishments":{"type":"integer","example":3},"activeEstablishments":{"type":"integer","example":3},"totalServices":{"type":"integer","example":25},"totalProviders":{"type":"integer","example":8},"totalReservations":{"type":"integer","example":450},"pendingReservations":{"type":"integer","example":15},"completedReservations":{"type":"integer","example":380},"monthlyRevenue":{"type":"number","example":3500000},"averageRating":{"type":"number","example":4.6}}},"Reservation":{"type":"object","description":"Reservation complete avec tous les details","properties":{"id":{"type":"string","format":"uuid"},"reservationNumber":{"type":"string","example":"RES-ABC12345","description":"Numero de reservation unique"},"type":{"$ref":"#/components/schemas/ReservationType"},"status":{"$ref":"#/components/schemas/ReservationStatus"},"clientId":{"type":"string","format":"uuid"},"client":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string"},"tel":{"type":"string"}}},"hotelId":{"type":"string","format":"uuid","nullable":true},"restaurantId":{"type":"string","format":"uuid","nullable":true},"rentalAgencyId":{"type":"string","format":"uuid","nullable":true},"parkingId":{"type":"string","format":"uuid","nullable":true},"establishmentId":{"type":"string","format":"uuid","nullable":true},"establishment":{"type":"object","description":"Etablissement concerne","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string"},"address":{"type":"string"},"phone":{"type":"string"}}},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"guestCount":{"type":"integer","example":2},"notes":{"type":"string","maxLength":1000,"nullable":true},"specialRequests":{"type":"string","maxLength":1000,"nullable":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/ReservationItem"}},"subtotal":{"type":"number","example":150000},"discount":{"type":"number","example":15000,"description":"Reduction appliquee"},"taxes":{"type":"number","example":13500},"total":{"type":"number","example":148500},"promoCode":{"type":"object","nullable":true,"properties":{"code":{"type":"string","example":"PROMO20"},"type":{"type":"string","enum":["percentage","fixed"]},"value":{"type":"number"}}},"providerId":{"type":"string","format":"uuid","nullable":true},"provider":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"}}},"paymentStatus":{"type":"string","enum":["pending","partial","paid","refunded"],"example":"pending"},"paymentMethod":{"type":"string","enum":["cash","card","mobile_money","bank_transfer"],"nullable":true},"paidAmount":{"type":"number","example":0},"cancelledAt":{"type":"string","format":"date-time","nullable":true},"cancellationReason":{"type":"string","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"confirmedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ReservationItem":{"type":"object","description":"Element individuel d'une reservation","properties":{"id":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid"},"itemType":{"type":"string","enum":["room","table","vehicle","spot","service"]},"itemId":{"type":"string","format":"uuid"},"itemName":{"type":"string","example":"Chambre Deluxe"},"quantity":{"type":"integer","example":1},"unitPrice":{"type":"number","example":75000},"totalPrice":{"type":"number","example":75000},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","confirmed","rejected","cancelled"],"example":"pending"},"rejectionReason":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"CreateReservationInput":{"type":"object","required":["type","startDate","endDate","items"],"properties":{"type":{"$ref":"#/components/schemas/ReservationType"},"startDate":{"type":"string","format":"date-time","example":"2024-03-20T14:00:00Z"},"endDate":{"type":"string","format":"date-time","example":"2024-03-22T12:00:00Z"},"guestCount":{"type":"integer","default":1,"minimum":1},"notes":{"type":"string","maxLength":1000},"specialRequests":{"type":"string","maxLength":1000},"promoCode":{"type":"string","description":"Code promo optionnel"},"hotelId":{"type":"string","format":"uuid"},"restaurantId":{"type":"string","format":"uuid"},"rentalAgencyId":{"type":"string","format":"uuid"},"parkingId":{"type":"string","format":"uuid"},"establishmentId":{"type":"string","format":"uuid"},"providerId":{"type":"string","format":"uuid","description":"Prestataire souhaite (optionnel)"},"items":{"type":"array","minItems":1,"items":{"type":"object","properties":{"quantity":{"type":"integer","default":1},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"roomId":{"type":"string","format":"uuid"},"tableId":{"type":"string","format":"uuid"},"vehicleId":{"type":"string","format":"uuid"},"spotId":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"}}}}}},"CancelReservationInput":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"description":"Raison de l'annulation"}}},"ConfirmItemInput":{"type":"object","required":["itemId"],"properties":{"itemId":{"type":"string","format":"uuid","description":"ID de l'element a confirmer"}}},"RejectItemInput":{"type":"object","required":["itemId","reason"],"properties":{"itemId":{"type":"string","format":"uuid","description":"ID de l'element a rejeter"},"reason":{"type":"string","maxLength":500,"description":"Raison du rejet"}}},"ReservationStats":{"type":"object","properties":{"total":{"type":"integer","example":450},"byStatus":{"type":"object","properties":{"pending":{"type":"integer","example":15},"confirmed":{"type":"integer","example":25},"completed":{"type":"integer","example":380},"cancelled":{"type":"integer","example":25},"no_show":{"type":"integer","example":5}}},"byType":{"type":"object","properties":{"hotel":{"type":"integer"},"restaurant":{"type":"integer"},"vehicle":{"type":"integer"},"parking":{"type":"integer"},"appointment":{"type":"integer"}}},"totalRevenue":{"type":"number","example":25000000},"monthlyRevenue":{"type":"number","example":3500000},"averageValue":{"type":"number","example":55556},"conversionRate":{"type":"number","example":85.5}}},"Review":{"type":"object","description":"Avis client sur un etablissement, service ou prestataire","properties":{"id":{"type":"string","format":"uuid"},"clientId":{"type":"string","format":"uuid"},"client":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"profileImage":{"type":"string","format":"uri","nullable":true}}},"reservationId":{"type":"string","format":"uuid","description":"Reservation associee"},"establishmentId":{"type":"string","format":"uuid","nullable":true},"establishment":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string"}}},"providerId":{"type":"string","format":"uuid","nullable":true},"provider":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"}}},"serviceId":{"type":"string","format":"uuid","nullable":true},"service":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"rating":{"type":"integer","minimum":1,"maximum":5,"example":4},"title":{"type":"string","example":"Excellente experience","maxLength":100},"comment":{"type":"string","example":"Service impeccable, personnel tres professionnel","maxLength":2000},"pros":{"type":"array","items":{"type":"string"},"example":["Proprete","Personnel accueillant","Bon rapport qualite-prix"]},"cons":{"type":"array","items":{"type":"string"},"example":["Parking limite"]},"images":{"type":"array","items":{"type":"string","format":"uri"},"description":"Photos jointes a l'avis"},"isVerified":{"type":"boolean","example":true,"description":"Avis verifie (reservation confirmee)"},"isPublished":{"type":"boolean","example":true,"description":"Avis publie/visible"},"ownerResponse":{"type":"object","nullable":true,"properties":{"response":{"type":"string","maxLength":1000},"respondedAt":{"type":"string","format":"date-time"}}},"helpfulCount":{"type":"integer","example":12,"description":"Nombre de votes 'utile'"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ReviewStats":{"type":"object","description":"Statistiques des avis","properties":{"totalReviews":{"type":"integer","example":128},"averageRating":{"type":"number","format":"float","example":4.3},"ratingDistribution":{"type":"object","properties":{"1":{"type":"integer","example":5},"2":{"type":"integer","example":8},"3":{"type":"integer","example":15},"4":{"type":"integer","example":45},"5":{"type":"integer","example":55}}},"recommendationRate":{"type":"number","example":92.5,"description":"Pourcentage de recommandation"},"responseRate":{"type":"number","example":85,"description":"Taux de reponse du proprietaire"},"averageResponseTime":{"type":"string","example":"2h","description":"Temps moyen de reponse"}}},"CreateReviewInput":{"type":"object","required":["reservationId","rating","comment"],"properties":{"reservationId":{"type":"string","format":"uuid","description":"ID de la reservation concernee"},"establishmentId":{"type":"string","format":"uuid"},"providerId":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"title":{"type":"string","maxLength":100},"comment":{"type":"string","minLength":10,"maxLength":2000},"pros":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":5},"cons":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":5},"images":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":5}}},"UpdateReviewInput":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5},"title":{"type":"string","maxLength":100},"comment":{"type":"string","minLength":10,"maxLength":2000},"pros":{"type":"array","items":{"type":"string"},"maxItems":5},"cons":{"type":"array","items":{"type":"string"},"maxItems":5},"images":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":5}}},"RespondToReviewInput":{"type":"object","required":["response"],"properties":{"response":{"type":"string","minLength":10,"maxLength":1000,"description":"Reponse du proprietaire"}}},"Provider":{"type":"object","description":"Prestataire de services (coiffeur, estheticienne, masseur, etc.)","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string","example":"Marie"},"lastname":{"type":"string","example":"Kouassi"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"profileImage":{"type":"string","format":"uri","nullable":true}}},"establishmentId":{"type":"string","format":"uuid"},"establishment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"businessType":{"type":"string"}}},"specialties":{"type":"array","items":{"type":"string"},"example":["Coupe homme","Coloration","Lissage bresilien"]},"bio":{"type":"string","example":"Coiffeuse professionnelle avec 10 ans d'experience","maxLength":1000},"experience":{"type":"integer","example":10,"description":"Annees d'experience"},"certifications":{"type":"array","items":{"type":"string"},"example":["CAP Coiffure","Formation L'Oreal"]},"languages":{"type":"array","items":{"type":"string"},"example":["Francais","Anglais"]},"workingHours":{"$ref":"#/components/schemas/WorkingHours"},"isAvailable":{"type":"boolean","example":true},"unavailableUntil":{"type":"string","format":"date-time","nullable":true,"description":"Date de retour si indisponible"},"rating":{"type":"number","format":"float","minimum":0,"maximum":5,"example":4.8},"reviewCount":{"type":"integer","example":67},"completedAppointments":{"type":"integer","example":450},"services":{"type":"array","items":{"$ref":"#/components/schemas/ProviderService"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ProviderService":{"type":"object","description":"Service assigne a un prestataire","properties":{"id":{"type":"string","format":"uuid"},"providerId":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"},"service":{"$ref":"#/components/schemas/Service"},"customPrice":{"type":"number","nullable":true,"description":"Prix personnalise (optionnel)"},"customDuration":{"type":"integer","nullable":true,"description":"Duree personnalisee en minutes"},"isActive":{"type":"boolean","example":true}}},"ProviderStats":{"type":"object","properties":{"totalAppointments":{"type":"integer","example":450},"completedAppointments":{"type":"integer","example":420},"cancelledAppointments":{"type":"integer","example":25},"noShowAppointments":{"type":"integer","example":5},"averageRating":{"type":"number","example":4.8},"totalReviews":{"type":"integer","example":67},"monthlyRevenue":{"type":"number","example":850000},"averageAppointmentValue":{"type":"number","example":12500},"upcomingAppointments":{"type":"integer","example":8},"todayAppointments":{"type":"integer","example":5}}},"CreateProviderInput":{"type":"object","required":["firstname","lastname","email","tel"],"properties":{"firstname":{"type":"string","minLength":2,"maxLength":50},"lastname":{"type":"string","minLength":2,"maxLength":50},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"password":{"type":"string","minLength":8,"description":"Requis uniquement pour la creation d'un nouveau compte e-mail"},"linkExistingUser":{"type":"boolean","description":"Si true, lie un compte prestataire deja existant a cet etablissement","default":false},"assignedServiceIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Services a affecter au prestataire dans l'etablissement courant"},"specialties":{"type":"array","items":{"type":"string"}},"bio":{"type":"string","maxLength":1000},"experience":{"type":"integer","minimum":0},"certifications":{"type":"array","items":{"type":"string"}},"languages":{"type":"array","items":{"type":"string"}}}},"UpdateProviderInput":{"type":"object","properties":{"specialties":{"type":"array","items":{"type":"string"}},"bio":{"type":"string","maxLength":1000},"experience":{"type":"integer","minimum":0},"certifications":{"type":"array","items":{"type":"string"}},"languages":{"type":"array","items":{"type":"string"}}}},"AssignServiceInput":{"type":"object","required":["serviceId"],"properties":{"serviceId":{"type":"string","format":"uuid"},"customPrice":{"type":"number","minimum":0},"customDuration":{"type":"integer","minimum":5}}},"UpdateAvailabilityInput":{"type":"object","properties":{"isAvailable":{"type":"boolean"},"unavailableUntil":{"type":"string","format":"date-time","nullable":true},"reason":{"type":"string","maxLength":200}}},"SearchResult":{"type":"object","description":"Resultat de recherche unifie","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["hotel","restaurant","rental_agency","parking","establishment","service"],"description":"Type de resultat"},"name":{"type":"string","example":"Hotel Ivoire"},"slug":{"type":"string","example":"hotel-ivoire-cocody"},"description":{"type":"string"},"image":{"type":"string","format":"uri"},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"rating":{"type":"number","format":"float","example":4.5},"reviewCount":{"type":"integer","example":128},"priceRange":{"type":"string","example":"$$$"},"minPrice":{"type":"number","example":50000},"maxPrice":{"type":"number","example":250000},"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"},"distance":{"type":"number","description":"Distance en km (si recherche geographique)"},"highlights":{"type":"array","items":{"type":"string"},"description":"Extraits pertinents avec la recherche"},"score":{"type":"number","description":"Score de pertinence"}}},"SearchSuggestion":{"type":"object","description":"Suggestion d'autocompletion","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["hotel","restaurant","rental_agency","parking","establishment","service","city","category"]},"text":{"type":"string","example":"Hotel Ivoire Cocody"},"category":{"type":"string","example":"Hotels"},"image":{"type":"string","format":"uri","nullable":true}}},"SearchFilters":{"type":"object","description":"Filtres disponibles pour affiner la recherche","properties":{"cities":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"}}}},"types":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"label":{"type":"string"},"count":{"type":"integer"}}}},"priceRanges":{"type":"array","items":{"type":"object","properties":{"range":{"type":"string"},"count":{"type":"integer"}}}},"ratings":{"type":"array","items":{"type":"object","properties":{"rating":{"type":"integer"},"count":{"type":"integer"}}}}}},"ReindexResult":{"type":"object","properties":{"indexed":{"type":"integer","example":150},"failed":{"type":"integer","example":2},"duration":{"type":"string","example":"2.5s"}}},"TopDestinationItem":{"type":"object","description":"Destination (hotel, restaurant, parking, salon, evenement, agence de location)","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Hotel Ivoire"},"slug":{"type":"string","example":"hotel-ivoire"},"entityType":{"type":"string","enum":["hotel","restaurant","parking","establishment","event","rental_agency"],"description":"Type d'entite"},"coverImage":{"type":"string","format":"uri","nullable":true},"city":{"type":"string","example":"Cocody"},"address":{"type":"string","example":"Boulevard de France"},"latitude":{"type":"number","format":"double","nullable":true},"longitude":{"type":"number","format":"double","nullable":true},"rating":{"type":"number","format":"float","example":4.8,"description":"Note moyenne (0-5)"},"reviewCount":{"type":"integer","example":120,"description":"Nombre d'avis"},"reservationCount":{"type":"integer","example":350,"description":"Nombre de reservations completees"},"price":{"type":"number","nullable":true,"example":45000,"description":"Prix indicatif en XOF"},"priceLabel":{"type":"string","example":"45 000 XOF / nuit","description":"Label prix formate"}}},"PopularCityItem":{"type":"object","description":"Ville populaire avec statistiques agregees","properties":{"city":{"type":"string","example":"Cocody"},"coverImage":{"type":"string","format":"uri","nullable":true},"entityCount":{"type":"integer","example":45,"description":"Nombre total d'entites"},"entities":{"type":"object","properties":{"hotel":{"type":"integer","example":12},"restaurant":{"type":"integer","example":15},"parking":{"type":"integer","example":5},"establishment":{"type":"integer","example":8},"event":{"type":"integer","example":3},"rental_agency":{"type":"integer","example":2}}},"averageRating":{"type":"number","format":"float","example":4.2,"description":"Note moyenne de toutes les entites"},"totalReviewCount":{"type":"integer","example":850,"description":"Nombre total d'avis"},"totalReservationCount":{"type":"integer","example":1200,"description":"Nombre total de reservations completees"}}},"Coordinates":{"type":"object","description":"Coordonnees GPS","properties":{"lat":{"type":"number","format":"double","example":5.3599,"description":"Latitude"},"lng":{"type":"number","format":"double","example":-4.0083,"description":"Longitude"}},"required":["lat","lng"]},"GeocodedAddress":{"type":"object","description":"Adresse geocodee avec coordonnees","properties":{"formattedAddress":{"type":"string","example":"Boulevard de France, Cocody, Abidjan, Cote d'Ivoire"},"street":{"type":"string","example":"Boulevard de France"},"city":{"type":"string","example":"Abidjan"},"commune":{"type":"string","example":"Cocody"},"country":{"type":"string","example":"Cote d'Ivoire"},"postalCode":{"type":"string","nullable":true},"coordinates":{"$ref":"#/components/schemas/Coordinates"},"placeId":{"type":"string","description":"Google Place ID"}}},"DistanceResult":{"type":"object","description":"Resultat de calcul de distance","properties":{"origin":{"$ref":"#/components/schemas/Coordinates"},"destination":{"$ref":"#/components/schemas/Coordinates"},"distance":{"type":"object","properties":{"text":{"type":"string","example":"5.2 km"},"value":{"type":"number","example":5200,"description":"Distance en metres"}}},"duration":{"type":"object","properties":{"text":{"type":"string","example":"15 min"},"value":{"type":"number","example":900,"description":"Duree en secondes"}}},"mode":{"type":"string","enum":["driving","walking","bicycling","transit"],"example":"driving"}}},"NearbyEstablishment":{"type":"object","description":"Etablissement proche","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["hotel","restaurant","rental_agency","parking","establishment"]},"address":{"type":"string"},"city":{"type":"string"},"coordinates":{"$ref":"#/components/schemas/Coordinates"},"distance":{"type":"number","example":1.5,"description":"Distance en km"},"rating":{"type":"number","example":4.5},"image":{"type":"string","format":"uri"}}},"GeocodeAddressInput":{"type":"object","required":["address"],"properties":{"address":{"type":"string","example":"Boulevard de France, Cocody, Abidjan"},"city":{"type":"string","example":"Abidjan"},"country":{"type":"string","example":"Cote d'Ivoire","default":"Cote d'Ivoire"}}},"ReverseGeocodeInput":{"type":"object","required":["lat","lng"],"properties":{"lat":{"type":"number","format":"double","example":5.3599},"lng":{"type":"number","format":"double","example":-4.0083}}},"CalculateDistanceInput":{"type":"object","required":["origin","destination"],"properties":{"origin":{"$ref":"#/components/schemas/Coordinates"},"destination":{"$ref":"#/components/schemas/Coordinates"},"mode":{"type":"string","enum":["driving","walking","bicycling","transit"],"default":"driving"}}},"CalculateDistancesInput":{"type":"object","required":["userLocation","establishmentIds"],"properties":{"userLocation":{"$ref":"#/components/schemas/Coordinates"},"establishmentIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"IDs des etablissements","maxItems":25},"mode":{"type":"string","enum":["driving","walking","bicycling","transit"],"default":"driving"}}},"Wallet":{"type":"object","properties":{"id":{"type":"string"},"ownerId":{"type":"string"},"balance":{"type":"number","description":"Available balance in XOF"},"pendingBalance":{"type":"number","description":"Pending balance in XOF"},"totalEarnings":{"type":"number","description":"Total earnings (all-time)"},"totalWithdrawn":{"type":"number","description":"Total withdrawn amount"},"currency":{"type":"string","default":"XOF"},"lastMonthlyFeeDate":{"type":"string","format":"date-time","nullable":true},"monthlyFeeAmount":{"type":"number","description":"Monthly fee amount"},"monthlyFeeThreshold":{"type":"number","description":"Revenue threshold to avoid fee"},"isMonthlyFeeEnabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WalletStats":{"type":"object","properties":{"totalEarnings":{"type":"number"},"currentBalance":{"type":"number"},"pendingBalance":{"type":"number"},"totalWithdrawn":{"type":"number"},"totalCommissionPaid":{"type":"number"},"revenueThisMonth":{"type":"number"},"revenueLastMonth":{"type":"number"},"growthPercentage":{"type":"number"}}},"WalletTransaction":{"type":"object","properties":{"id":{"type":"string"},"walletId":{"type":"string"},"type":{"type":"string","enum":["CREDIT","DEBIT","COMMISSION","PAYOUT","REFUND","MONTHLY_FEE"]},"amount":{"type":"number"},"fee":{"type":"number"},"netAmount":{"type":"number"},"status":{"type":"string","enum":["PENDING","COMPLETED","FAILED","CANCELLED"]},"description":{"type":"string"},"balanceBefore":{"type":"number"},"balanceAfter":{"type":"number"},"createdAt":{"type":"string","format":"date-time"}}},"CommissionTier":{"type":"object","properties":{"id":{"type":"string"},"minAmount":{"type":"number","description":"Minimum transaction amount"},"maxAmount":{"type":"number","nullable":true,"description":"Maximum amount (null = unlimited)"},"type":{"type":"string","enum":["PERCENTAGE","FIXED"],"description":"Commission type"},"value":{"type":"number","description":"Commission value (percentage or fixed amount)"},"isActive":{"type":"boolean"},"priority":{"type":"integer","description":"Evaluation priority (lower = first)"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"PromoCode":{"type":"object","description":"Code promotionnel pour reductions sur les reservations","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","example":"SUMMER2024"},"description":{"type":"string","example":"Promotion d'ete - 20% de reduction"},"type":{"type":"string","enum":["percentage","fixed"],"example":"percentage"},"value":{"type":"number","example":20,"description":"Pourcentage (0-100) ou montant fixe"},"minPurchase":{"type":"number","example":10000,"description":"Montant minimum requis"},"maxDiscount":{"type":"number","example":50000,"description":"Reduction maximale"},"usageLimit":{"type":"integer","example":100,"description":"Nombre d'utilisations max"},"usageCount":{"type":"integer","example":25,"description":"Nombre d'utilisations actuelles"},"perUserLimit":{"type":"integer","example":1,"description":"Utilisations max par utilisateur"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"isActive":{"type":"boolean","example":true},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]},"example":["hotel","restaurant"]},"ownerId":{"type":"string","format":"uuid","nullable":true,"description":"null pour codes globaux admin"},"owner":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"hotelId":{"type":"string","format":"uuid","nullable":true},"restaurantId":{"type":"string","format":"uuid","nullable":true},"rentalAgencyId":{"type":"string","format":"uuid","nullable":true},"parkingId":{"type":"string","format":"uuid","nullable":true},"appointmentId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreatePromoCodeInput":{"type":"object","required":["code","type","value","startDate","endDate","applicableTypes"],"properties":{"code":{"type":"string","minLength":3,"maxLength":20,"example":"SUMMER2024"},"description":{"type":"string","maxLength":500},"type":{"type":"string","enum":["percentage","fixed"],"example":"percentage"},"value":{"type":"number","minimum":0,"example":20},"minPurchase":{"type":"number","minimum":0},"maxDiscount":{"type":"number","minimum":0},"usageLimit":{"type":"integer","minimum":1},"perUserLimit":{"type":"integer","minimum":1,"default":1},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]},"minItems":1},"hotelId":{"type":"string","format":"uuid"},"restaurantId":{"type":"string","format":"uuid"},"rentalAgencyId":{"type":"string","format":"uuid"},"parkingId":{"type":"string","format":"uuid"},"appointmentId":{"type":"string","format":"uuid"}}},"UpdatePromoCodeInput":{"type":"object","properties":{"description":{"type":"string","maxLength":500},"type":{"type":"string","enum":["percentage","fixed"]},"value":{"type":"number","minimum":0},"minPurchase":{"type":"number","minimum":0},"maxDiscount":{"type":"number","minimum":0},"usageLimit":{"type":"integer","minimum":1},"perUserLimit":{"type":"integer","minimum":1},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"isActive":{"type":"boolean"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]}},"hotelId":{"type":"string","format":"uuid","nullable":true},"restaurantId":{"type":"string","format":"uuid","nullable":true},"rentalAgencyId":{"type":"string","format":"uuid","nullable":true},"parkingId":{"type":"string","format":"uuid","nullable":true},"appointmentId":{"type":"string","format":"uuid","nullable":true}}},"ValidatePromoCodeInput":{"type":"object","required":["code","type","establishmentId","subtotal"],"properties":{"code":{"type":"string","example":"SUMMER2024"},"type":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]},"establishmentId":{"type":"string","format":"uuid"},"subtotal":{"type":"number","minimum":0,"example":25000},"userId":{"type":"string","format":"uuid"}}},"ValidatePromoCodeResult":{"type":"object","properties":{"valid":{"type":"boolean"},"message":{"type":"string","example":"Promo code is valid"},"promoCodeId":{"type":"string","format":"uuid"},"discountAmount":{"type":"number","example":5000},"finalAmount":{"type":"number","example":20000}}},"PromoCodeStats":{"type":"object","properties":{"totalUsage":{"type":"integer","example":25},"remainingUses":{"type":"integer","example":75},"totalDiscountGiven":{"type":"number","example":125000},"averageDiscountPerUse":{"type":"number","example":5000},"uniqueUsers":{"type":"integer","example":18}}},"CarpoolTripStatus":{"type":"string","enum":["draft","published","full","inProgress","completed","cancelled","expired"]},"CarpoolReservationStatus":{"type":"string","enum":["pending","confirmed","cancelled","completed","noShow"]},"CarpoolVehicleType":{"type":"string","enum":["sedan","suv","van","pickup","motorcycle","other"]},"CarpoolTrip":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"publisherUserId":{"type":"string","format":"uuid"},"departureCity":{"type":"string"},"departureLocation":{"type":"string"},"departureLat":{"type":"number"},"departureLng":{"type":"number"},"destinationCity":{"type":"string"},"destinationLocation":{"type":"string"},"destinationLat":{"type":"number"},"destinationLng":{"type":"number"},"departureDate":{"type":"string","format":"date-time"},"arrivalDate":{"type":"string","format":"date-time","nullable":true},"distance":{"type":"number","nullable":true},"duration":{"type":"integer","nullable":true},"totalSeats":{"type":"integer"},"availableSeats":{"type":"integer"},"pricePerSeat":{"type":"number"},"currency":{"type":"string","default":"XOF"},"vehicleType":{"$ref":"#/components/schemas/CarpoolVehicleType"},"vehicleBrand":{"type":"string","nullable":true},"vehicleModel":{"type":"string","nullable":true},"vehicleColor":{"type":"string","nullable":true},"vehiclePlate":{"type":"string","nullable":true},"vehiclePhotos":{"type":"array","items":{"type":"string"}},"status":{"$ref":"#/components/schemas/CarpoolTripStatus"},"description":{"type":"string","nullable":true},"rules":{"type":"string","nullable":true},"creditCostPaid":{"type":"integer"}}},"PublishCarpoolTripInput":{"type":"object","required":["departureCity","departureLocation","departureLat","departureLng","destinationCity","destinationLocation","destinationLat","destinationLng","departureDate","totalSeats","pricePerSeat","vehicleType"],"properties":{"departureCity":{"type":"string"},"departureLocation":{"type":"string"},"departureLat":{"type":"number"},"departureLng":{"type":"number"},"destinationCity":{"type":"string"},"destinationLocation":{"type":"string"},"destinationLat":{"type":"number"},"destinationLng":{"type":"number"},"departureDate":{"type":"string","format":"date-time"},"arrivalDate":{"type":"string","format":"date-time"},"totalSeats":{"type":"integer","minimum":1,"maximum":20},"pricePerSeat":{"type":"number"},"vehicleType":{"$ref":"#/components/schemas/CarpoolVehicleType"},"vehicleBrand":{"type":"string"},"vehicleModel":{"type":"string"},"vehicleColor":{"type":"string"},"vehiclePlate":{"type":"string"},"vehiclePhotos":{"type":"array","items":{"type":"string"}},"description":{"type":"string"},"rules":{"type":"string"}}},"CarpoolReservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tripId":{"type":"string","format":"uuid"},"passengerId":{"type":"string","format":"uuid"},"seatsBooked":{"type":"integer"},"pickupLocation":{"type":"string","nullable":true},"dropoffLocation":{"type":"string","nullable":true},"reference":{"type":"string"},"qrCode":{"type":"string","nullable":true},"checkedIn":{"type":"boolean"},"checkedOut":{"type":"boolean"},"status":{"$ref":"#/components/schemas/CarpoolReservationStatus"},"creditCostPaid":{"type":"integer"},"passengerNote":{"type":"string","nullable":true}}},"ReserveCarpoolSeatsInput":{"type":"object","required":["seatsBooked"],"properties":{"seatsBooked":{"type":"integer","minimum":1},"pickupLocation":{"type":"string"},"pickupLat":{"type":"number"},"pickupLng":{"type":"number"},"dropoffLocation":{"type":"string"},"dropoffLat":{"type":"number"},"dropoffLng":{"type":"number"},"boardingWaypointId":{"type":"string","format":"uuid"},"alightingWaypointId":{"type":"string","format":"uuid"},"passengerNote":{"type":"string"}}},"CarpoolSurveyInput":{"type":"object","required":["responses"],"properties":{"reservationId":{"type":"string","format":"uuid"},"responses":{"type":"object","required":["safetyScore","comfortScore","punctualityScore","priceHonored","npsScore","wouldTravelAgain"],"properties":{"safetyScore":{"type":"integer","minimum":1,"maximum":5},"comfortScore":{"type":"integer","minimum":1,"maximum":5},"punctualityScore":{"type":"integer","minimum":1,"maximum":5},"priceHonored":{"type":"boolean"},"extraChargedXof":{"type":"number"},"issues":{"type":"array","items":{"type":"string"}},"behaviorConcerns":{"type":"array","items":{"type":"string"}},"npsScore":{"type":"integer","minimum":0,"maximum":10},"wouldTravelAgain":{"type":"boolean"},"comment":{"type":"string"}}}}},"CreditWallet":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"balance":{"type":"integer"},"totalPurchased":{"type":"integer"},"totalSpent":{"type":"integer"},"unitPriceXof":{"type":"number","description":"Prix d'1 crédit (XOF) — configurable"}}},"CreditTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["PURCHASE","SPEND_PUBLISH","SPEND_RESERVE","REFUND_ADMIN","ADJUSTMENT_ADMIN","REFUND_AUTO"]},"amount":{"type":"integer","description":"Positif = crédit, négatif = débit"},"balanceAfter":{"type":"integer"},"reference":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"CreditPackage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"credits":{"type":"integer"},"priceXof":{"type":"number","nullable":true,"description":"Si null, calculé = credits × unitPriceXof"},"active":{"type":"boolean"},"order":{"type":"integer"}}},"InitiateCreditPurchaseInput":{"type":"object","required":["method"],"properties":{"packageId":{"type":"string","format":"uuid"},"credits":{"type":"integer","minimum":1,"description":"Obligatoire si packageId absent"},"method":{"type":"string","enum":["mobile_money","card","bank_transfer"]},"operator":{"type":"string","enum":["orange","mtn","wave"]}}},"InitiateCreditPurchaseResponse":{"type":"object","properties":{"reference":{"type":"string","example":"CRD-ABC123XYZ456"},"credits":{"type":"integer"},"amountXof":{"type":"number"},"paymentUrl":{"type":"string"},"message":{"type":"string"}}},"Event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ownerId":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Festival de Musique 2026"},"description":{"type":"string","example":"Un grand festival de musique avec des artistes internationaux"},"category":{"type":"string","enum":["music","sport","conference","exhibition","workshop","party","other"],"example":"music"},"coverImage":{"type":"string","nullable":true,"example":"https://example.com/image.jpg"},"images":{"type":"array","items":{"type":"string"},"example":[]},"location":{"type":"string","example":"Stade Omnisports, Abidjan"},"lat":{"type":"number","format":"double","example":5.316667},"lng":{"type":"number","format":"double","example":-4.033333},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"standardTicketPrice":{"type":"number","example":5000},"vipTicketPrice":{"type":"number","nullable":true,"example":15000},"earlyBirdPrice":{"type":"number","nullable":true,"example":3500},"earlyBirdDeadline":{"type":"string","format":"date-time","nullable":true},"totalSeats":{"type":"integer","example":1000},"availableSeats":{"type":"integer","example":850},"status":{"type":"string","enum":["draft","published","completed","cancelled"],"example":"published"},"isFeatured":{"type":"boolean","example":false},"isVerified":{"type":"boolean","example":false},"tags":{"type":"array","items":{"type":"string"},"example":["music","live","international"]},"averageRating":{"type":"number","nullable":true,"example":4.5},"reviewCount":{"type":"integer","example":25},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"owner":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"profilePicture":{"type":"string","nullable":true}}}}},"CreateEventInput":{"type":"object","required":["title","description","category","location","lat","lng","startDate","endDate","standardTicketPrice","totalSeats"],"properties":{"title":{"type":"string","minLength":3,"maxLength":200,"example":"Festival de Musique 2026"},"description":{"type":"string","minLength":10,"example":"Un grand festival de musique avec des artistes internationaux"},"category":{"type":"string","enum":["music","sport","conference","exhibition","workshop","party","other"],"example":"music"},"coverImage":{"type":"string","nullable":true,"example":"https://example.com/image.jpg"},"images":{"type":"array","items":{"type":"string"},"example":[]},"location":{"type":"string","example":"Stade Omnisports, Abidjan"},"lat":{"type":"number","format":"double","example":5.316667},"lng":{"type":"number","format":"double","example":-4.033333},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"standardTicketPrice":{"type":"number","minimum":0,"example":5000},"vipTicketPrice":{"type":"number","minimum":0,"nullable":true,"example":15000},"earlyBirdPrice":{"type":"number","minimum":0,"nullable":true,"example":3500},"earlyBirdDeadline":{"type":"string","format":"date-time","nullable":true},"totalSeats":{"type":"integer","minimum":1,"example":1000},"tags":{"type":"array","items":{"type":"string"},"example":["music","live","international"]}}},"UpdateEventInput":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":200},"description":{"type":"string","minLength":10},"category":{"type":"string","enum":["music","sport","conference","exhibition","workshop","party","other"]},"coverImage":{"type":"string","nullable":true},"images":{"type":"array","items":{"type":"string"}},"location":{"type":"string"},"lat":{"type":"number","format":"double"},"lng":{"type":"number","format":"double"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"standardTicketPrice":{"type":"number","minimum":0},"vipTicketPrice":{"type":"number","minimum":0,"nullable":true},"earlyBirdPrice":{"type":"number","minimum":0,"nullable":true},"earlyBirdDeadline":{"type":"string","format":"date-time","nullable":true},"totalSeats":{"type":"integer","minimum":1},"tags":{"type":"array","items":{"type":"string"}}}},"Ticket":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid"},"attendeeId":{"type":"string","format":"uuid"},"ticketType":{"type":"string","enum":["standard","vip","early_bird","group","free"],"example":"standard"},"quantity":{"type":"integer","example":2},"unitPrice":{"type":"number","example":5000},"subtotal":{"type":"number","example":10000},"discount":{"type":"number","example":500},"commissionAmount":{"type":"number","example":475},"totalAmount":{"type":"number","example":9500},"qrCode":{"type":"string","example":"base64-encoded-qr-code"},"status":{"type":"string","enum":["pending","confirmed","cancelled"],"example":"confirmed"},"reference":{"type":"string","example":"TKT-2026-ABCD1234"},"checkedInAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"location":{"type":"string"},"coverImage":{"type":"string","nullable":true}}},"attendee":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}}}}},"PurchaseTicketInput":{"type":"object","required":["eventId","ticketType","quantity"],"properties":{"eventId":{"type":"string","format":"uuid"},"ticketType":{"type":"string","enum":["standard","vip","early_bird"],"example":"standard"},"quantity":{"type":"integer","minimum":1,"maximum":10,"example":2},"promoCode":{"type":"string","nullable":true,"example":"SUMMER2026"}}},"CheckInInput":{"type":"object","required":["qrCode"],"properties":{"qrCode":{"type":"string","example":"base64-encoded-qr-code"}}},"EventReview":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5,"example":5},"comment":{"type":"string","nullable":true,"example":"Amazing event! Highly recommended."},"createdAt":{"type":"string","format":"date-time"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"profilePicture":{"type":"string","nullable":true}}},"event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"coverImage":{"type":"string","nullable":true}}}}},"CreateEventReviewInput":{"type":"object","required":["eventId","rating"],"properties":{"eventId":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5,"example":5},"comment":{"type":"string","minLength":10,"maxLength":1000,"nullable":true,"example":"Amazing event!"}}},"EventStats":{"type":"object","properties":{"totalEvents":{"type":"integer","example":25},"upcomingEvents":{"type":"integer","example":10},"completedEvents":{"type":"integer","example":15},"totalTicketsSold":{"type":"integer","example":5420},"totalRevenue":{"type":"number","example":27100000},"averageRating":{"type":"number","example":4.6}}},"Archive":{"type":"object","description":"Archive systeme contenant les sauvegardes","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["full","database","files","incremental"],"description":"Type d'archive"},"status":{"type":"string","enum":["pending","in_progress","completed","failed","verified"],"description":"Statut de l'archive"},"filename":{"type":"string","example":"archive_2024-01-15T14-30-00_full.tar.gz"},"filepath":{"type":"string","example":"/app/archives/2024/01/archive_xxx.tar.gz"},"sizeBytes":{"type":"integer","format":"int64","nullable":true,"example":1073741824},"checksum":{"type":"string","nullable":true,"example":"sha256:abc123..."},"includesDatabase":{"type":"boolean","default":true},"includesUploads":{"type":"boolean","default":true},"includesTypesense":{"type":"boolean","default":true},"includesConfig":{"type":"boolean","default":false},"tablesCount":{"type":"integer","nullable":true,"example":85},"recordsCount":{"type":"integer","nullable":true,"example":150000},"filesCount":{"type":"integer","nullable":true,"example":2500},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"durationMs":{"type":"integer","nullable":true,"example":45000},"errorMessage":{"type":"string","nullable":true},"createdBy":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"isAutomatic":{"type":"boolean","default":false,"description":"True si cree par cron"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"isProtected":{"type":"boolean","default":false,"description":"Protege contre suppression auto"},"restoredAt":{"type":"string","format":"date-time","nullable":true},"restoredBy":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ArchiveConfig":{"type":"object","description":"Configuration de l'archivage automatique","properties":{"id":{"type":"string","format":"uuid"},"isAutoArchiveEnabled":{"type":"boolean","default":false},"cronExpression":{"type":"string","example":"0 2 * * *","description":"Expression cron"},"retentionDays":{"type":"integer","default":30,"description":"Jours de retention"},"maxArchives":{"type":"integer","default":100,"description":"Nombre max d'archives"},"defaultIncludeDatabase":{"type":"boolean","default":true},"defaultIncludeUploads":{"type":"boolean","default":true},"defaultIncludeTypesense":{"type":"boolean","default":true},"defaultIncludeConfig":{"type":"boolean","default":false},"compressionLevel":{"type":"integer","minimum":1,"maximum":9,"default":6},"notifyOnComplete":{"type":"boolean","default":true},"notifyOnFailure":{"type":"boolean","default":true},"notificationEmails":{"type":"array","items":{"type":"string","format":"email"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateArchiveInput":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["full","database","files","incremental"],"description":"Type d'archive a creer"},"includeDatabase":{"type":"boolean","default":true},"includeUploads":{"type":"boolean","default":true},"includeTypesense":{"type":"boolean","default":true},"includeConfig":{"type":"boolean","default":false},"description":{"type":"string","maxLength":500}}},"UpdateArchiveConfigInput":{"type":"object","properties":{"isAutoArchiveEnabled":{"type":"boolean"},"cronExpression":{"type":"string","pattern":"^[\\d\\s\\*\\/\\-,]+$"},"retentionDays":{"type":"integer","minimum":1,"maximum":365},"maxArchives":{"type":"integer","minimum":1,"maximum":1000},"defaultIncludeDatabase":{"type":"boolean"},"defaultIncludeUploads":{"type":"boolean"},"defaultIncludeTypesense":{"type":"boolean"},"defaultIncludeConfig":{"type":"boolean"},"compressionLevel":{"type":"integer","minimum":1,"maximum":9},"notifyOnComplete":{"type":"boolean"},"notifyOnFailure":{"type":"boolean"},"notificationEmails":{"type":"array","items":{"type":"string","format":"email"}}}},"ArchiveProgress":{"type":"object","description":"Progression d'un archivage en cours","properties":{"archiveId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","in_progress","completed","failed","verified"]},"currentStep":{"type":"string","example":"Archiving database..."},"progress":{"type":"number","minimum":0,"maximum":100,"example":45},"steps":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string","enum":["pending","in_progress","completed","failed"]},"message":{"type":"string"}}}}}},"ArchiveStats":{"type":"object","description":"Statistiques globales des archives","properties":{"totalArchives":{"type":"integer","example":50},"totalSizeBytes":{"type":"integer","format":"int64","example":10737418240},"successfulArchives":{"type":"integer","example":48},"failedArchives":{"type":"integer","example":2},"lastArchiveAt":{"type":"string","format":"date-time","nullable":true},"oldestArchiveAt":{"type":"string","format":"date-time","nullable":true},"archivesByType":{"type":"object","properties":{"full":{"type":"integer"},"database":{"type":"integer"},"files":{"type":"integer"},"incremental":{"type":"integer"}}},"archivesByStatus":{"type":"object","properties":{"pending":{"type":"integer"},"in_progress":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"},"verified":{"type":"integer"}}}}},"VerifyResult":{"type":"object","description":"Resultat de verification d'integrite","properties":{"isValid":{"type":"boolean"},"checksumMatch":{"type":"boolean"},"expectedChecksum":{"type":"string"},"actualChecksum":{"type":"string"},"fileExists":{"type":"boolean"},"fileSizeMatch":{"type":"boolean"}}},"CleanupResult":{"type":"object","description":"Resultat du nettoyage des archives expirees","properties":{"deletedCount":{"type":"integer","example":5},"freedBytes":{"type":"integer","format":"int64","example":5368709120},"deletedArchiveIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"ProtectArchiveInput":{"type":"object","required":["isProtected"],"properties":{"isProtected":{"type":"boolean"}}},"LoginInput":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","description":"Adresse email de l'utilisateur","example":"user@example.com"},"password":{"type":"string","description":"Mot de passe","example":"Password123!"}}},"LoginResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT access token"},"refreshToken":{"type":"string","description":"JWT refresh token"},"user":{"$ref":"#/components/schemas/UserProfile"}}},"message":{"type":"string","example":"Connexion réussie"}}},"TwoFactorRequiredResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"requires2FA":{"type":"boolean","example":true},"userId":{"type":"string","format":"uuid"}}},"message":{"type":"string","example":"Code 2FA requis"}}},"RegisterInput":{"type":"object","required":["firstname","lastname","email","tel","password","confirmPassword"],"properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom","example":"Jean"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille","example":"Dupont"},"email":{"type":"string","format":"email","description":"Adresse email","example":"jean.dupont@example.com"},"tel":{"type":"string","pattern":"^\\+?[0-9]{10,15}$","description":"Numéro de téléphone (10-15 chiffres)","example":"+22507070707"},"password":{"type":"string","minLength":8,"description":"Mot de passe (8+ chars, 1 majuscule, 1 minuscule, 1 chiffre, 1 spécial)","example":"Password123!"},"confirmPassword":{"type":"string","description":"Confirmation du mot de passe","example":"Password123!"},"role":{"type":"string","enum":["client","proprio","prestataire","organisateur"],"default":"client","description":"Rôle de l'utilisateur"}}},"OtpInput":{"type":"object","required":["code"],"properties":{"code":{"type":"string","minLength":6,"maxLength":6,"description":"Code OTP à 6 chiffres","example":"123456"},"userId":{"type":"string","format":"uuid","description":"ID utilisateur (pour 2FA)"}}},"Toggle2FAInput":{"type":"object","required":["enable"],"properties":{"enable":{"type":"boolean","description":"Activer ou désactiver le 2FA","example":true}}},"ForgotPasswordInput":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Adresse email pour la réinitialisation","example":"user@example.com"}}},"ResetPasswordInput":{"type":"object","required":["token","password","confirmPassword"],"properties":{"token":{"type":"string","description":"Token de réinitialisation reçu par email"},"password":{"type":"string","minLength":8,"description":"Nouveau mot de passe","example":"NewPassword123!"},"confirmPassword":{"type":"string","description":"Confirmation du nouveau mot de passe","example":"NewPassword123!"}}},"ChangePasswordInput":{"type":"object","required":["currentPassword","newPassword","confirmPassword"],"properties":{"currentPassword":{"type":"string","description":"Mot de passe actuel","example":"OldPassword123!"},"newPassword":{"type":"string","minLength":8,"description":"Nouveau mot de passe","example":"NewPassword123!"},"confirmPassword":{"type":"string","description":"Confirmation du nouveau mot de passe","example":"NewPassword123!"}}},"RefreshTokenInput":{"type":"object","required":["refreshToken"],"properties":{"refreshToken":{"type":"string","description":"Refresh token pour renouveler l'access token"}}},"UserProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"role":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"]},"profileImage":{"type":"string","nullable":true},"isActive":{"type":"boolean"},"isVerified":{"type":"boolean"},"twoFactorEnabled":{"type":"boolean"},"kycStatus":{"type":"string","enum":["none","pending","approved","rejected"],"nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"AcceptDriverInvitationInput":{"type":"object","required":["token","password","confirmPassword"],"properties":{"token":{"type":"string","description":"Token d'invitation reçu par email"},"password":{"type":"string","minLength":8,"description":"Mot de passe pour le nouveau compte","example":"Password123!"},"confirmPassword":{"type":"string","description":"Confirmation du mot de passe","example":"Password123!"}}},"CreateUserInput":{"type":"object","required":["firstname","lastname","email","tel","password","role"],"properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom","example":"Jean"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille","example":"Dupont"},"email":{"type":"string","format":"email","description":"Adresse email","example":"jean.dupont@example.com"},"tel":{"type":"string","description":"Numéro de téléphone","example":"+22507070707"},"password":{"type":"string","minLength":8,"description":"Mot de passe","example":"Password123!"},"role":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"],"description":"Rôle de l'utilisateur","example":"client"},"isActive":{"type":"boolean","default":true,"description":"Compte actif"},"isVerified":{"type":"boolean","default":false,"description":"Email vérifié"}}},"UpdateUserInput":{"type":"object","properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille"},"email":{"type":"string","format":"email","description":"Adresse email"},"tel":{"type":"string","description":"Numéro de téléphone"},"role":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"],"description":"Rôle de l'utilisateur"},"isActive":{"type":"boolean","description":"Compte actif"},"isVerified":{"type":"boolean","description":"Email vérifié"},"profileImage":{"type":"string","format":"uri","nullable":true,"description":"URL de l'image de profil"}}},"VerifyDocumentInput":{"type":"object","required":["verified"],"properties":{"verified":{"type":"boolean","description":"Document vérifié ou non","example":true},"notes":{"type":"string","description":"Notes de vérification","example":"Document valide"}}},"CreateAgentInput":{"type":"object","required":["firstname","lastname","email","tel","password"],"properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom de l'agent","example":"Marie"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille de l'agent","example":"Koné"},"email":{"type":"string","format":"email","description":"Email de l'agent","example":"marie.kone@example.com"},"tel":{"type":"string","description":"Téléphone de l'agent","example":"+22507080809"},"password":{"type":"string","minLength":8,"description":"Mot de passe de l'agent","example":"Agent123!"}}},"UpdateAgentInput":{"type":"object","properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom de l'agent"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille de l'agent"},"email":{"type":"string","format":"email","description":"Email de l'agent"},"tel":{"type":"string","description":"Téléphone de l'agent"},"isActive":{"type":"boolean","description":"Agent actif"}}},"UpdateProfileInput":{"type":"object","properties":{"firstname":{"type":"string","minLength":2,"maxLength":50,"description":"Prénom"},"lastname":{"type":"string","minLength":2,"maxLength":50,"description":"Nom de famille"},"tel":{"type":"string","description":"Numéro de téléphone"},"profileImage":{"type":"string","format":"uri","nullable":true,"description":"URL de l'image de profil"}}},"UserStats":{"type":"object","properties":{"totalUsers":{"type":"integer","description":"Nombre total d'utilisateurs"},"activeUsers":{"type":"integer","description":"Utilisateurs actifs"},"verifiedUsers":{"type":"integer","description":"Utilisateurs vérifiés"},"byRole":{"type":"object","properties":{"superAdmin":{"type":"integer"},"admin":{"type":"integer"},"proprio":{"type":"integer"},"agent":{"type":"integer"},"organisateur":{"type":"integer"},"prestataire":{"type":"integer"},"client":{"type":"integer"}}},"newUsersThisMonth":{"type":"integer"},"newUsersLastMonth":{"type":"integer"}}},"TeamStats":{"type":"object","properties":{"totalAgents":{"type":"integer","description":"Nombre total d'agents"},"activeAgents":{"type":"integer","description":"Agents actifs"},"totalEstablishments":{"type":"integer","description":"Nombre d'établissements"},"reservationsThisMonth":{"type":"integer","description":"Réservations ce mois"}}},"Agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"isActive":{"type":"boolean"},"ownerId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"CreateAmenityInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Nom de la commodité","example":"WiFi Gratuit"},"description":{"type":"string","maxLength":500,"description":"Description","example":"Connexion WiFi haut débit gratuite"},"icon":{"type":"string","maxLength":100,"description":"Icône (nom ou URL)","example":"wifi"},"category":{"type":"string","enum":["general","comfort","service","food","business","entertainment","accessibility","safety"],"default":"general","description":"Catégorie"},"price":{"type":"number","minimum":0,"default":0,"description":"Prix (0 si gratuit)"},"isFree":{"type":"boolean","default":true,"description":"Gratuit ou non"},"isActive":{"type":"boolean","default":true,"description":"Actif ou non"}}},"UpdateAmenityInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Nom de la commodité"},"description":{"type":"string","maxLength":500,"nullable":true,"description":"Description"},"icon":{"type":"string","maxLength":100,"nullable":true,"description":"Icône"},"category":{"type":"string","enum":["general","comfort","service","food","business","entertainment","accessibility","safety"],"description":"Catégorie"},"price":{"type":"number","minimum":0,"description":"Prix"},"isFree":{"type":"boolean","description":"Gratuit ou non"},"isActive":{"type":"boolean","description":"Actif ou non"}}},"AssignAmenitiesToEstablishmentInput":{"type":"object","required":["amenityIds"],"properties":{"amenityIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"description":"Liste des IDs de commodités à assigner","example":["uuid1","uuid2"]}}},"CalendarReservationSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["hotel","restaurant","appointment","rentalAgency","parking"],"description":"Type d'établissement"},"establishmentId":{"type":"string","format":"uuid"},"establishmentName":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","confirmed","completed","cancelled"]},"customerName":{"type":"string"},"totalAmount":{"type":"number"},"notes":{"type":"string","nullable":true}}},"CalendarDateRange":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"CalendarResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/CalendarReservationSummary"}},"meta":{"type":"object","properties":{"view":{"type":"string","enum":["day","week","month"]},"dateRange":{"$ref":"#/components/schemas/CalendarDateRange"},"totalReservations":{"type":"integer"}}}}},"UploadResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"url":{"type":"string","example":"/uploads/abc.jpg","description":"Chemin relatif du fichier"},"filename":{"type":"string","description":"Nom du fichier"},"mimetype":{"type":"string","description":"Type MIME du fichier"},"size":{"type":"integer","description":"Taille en bytes"}}},"message":{"type":"string","example":"Image uploadée avec succès"}}},"UploadBatchUrlsResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string","example":"/uploads/1700000000000-abc123.jpg"},"description":"Chemins relatifs /uploads/..."},"count":{"type":"integer","example":2}}}}},"MultipleUploadResponse":{"$ref":"#/components/schemas/UploadBatchUrlsResponse"},"AuditLog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string","description":"Type d'action effectuée","example":"CREATE"},"resourceType":{"type":"string","description":"Type de ressource concernée","example":"reservation"},"resourceId":{"type":"string","format":"uuid","description":"ID de la ressource concernée"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"ID de l'utilisateur qui a effectué l'action"},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string"}}},"userRole":{"type":"string","nullable":true,"description":"Rôle de l'utilisateur au moment de l'action"},"visibility":{"type":"string","enum":["admin","owner","self","system"],"description":"Niveau de visibilité du log"},"ownerId":{"type":"string","format":"uuid","nullable":true,"description":"ID du propriétaire concerné"},"isSystemAction":{"type":"boolean","description":"Action système automatique"},"severity":{"type":"string","enum":["info","warning","error","critical"],"description":"Niveau de sévérité"},"previousData":{"type":"object","nullable":true,"description":"Données avant modification (pour UPDATE/DELETE)"},"newData":{"type":"object","nullable":true,"description":"Nouvelles données (pour CREATE/UPDATE)"},"metadata":{"type":"object","nullable":true,"description":"Métadonnées additionnelles"},"ipAddress":{"type":"string","nullable":true,"description":"Adresse IP"},"userAgent":{"type":"string","nullable":true,"description":"User-Agent"},"createdAt":{"type":"string","format":"date-time"}}},"AuditLogStats":{"type":"object","properties":{"totalLogs":{"type":"integer"},"logsToday":{"type":"integer"},"logsThisWeek":{"type":"integer"},"logsThisMonth":{"type":"integer"},"byAction":{"type":"object","additionalProperties":{"type":"integer"}},"byResourceType":{"type":"object","additionalProperties":{"type":"integer"}},"bySeverity":{"type":"object","properties":{"info":{"type":"integer"},"warning":{"type":"integer"},"error":{"type":"integer"},"critical":{"type":"integer"}}}}},"KycDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"documentType":{"type":"string","enum":["identity_document","establishment_proof","business_registration","selfie_photo"],"description":"Type de document"},"documentUrl":{"type":"string","format":"uri","description":"URL du document"},"documentNumber":{"type":"string","nullable":true,"description":"Numéro du document"},"status":{"type":"string","enum":["pending","approved","rejected"],"description":"Statut de vérification"},"rejectionReason":{"type":"string","nullable":true,"description":"Raison du rejet"},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"verifiedBy":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"KycStatus":{"type":"object","properties":{"status":{"type":"string","enum":["none","pending","approved","rejected"],"description":"Statut global du KYC"},"documents":{"type":"object","properties":{"identity_document":{"type":"object","nullable":true,"properties":{"status":{"type":"string","enum":["pending","approved","rejected"]},"url":{"type":"string","format":"uri"}}},"establishment_proof":{"type":"object","nullable":true,"properties":{"status":{"type":"string","enum":["pending","approved","rejected"]},"url":{"type":"string","format":"uri"}}},"business_registration":{"type":"object","nullable":true,"properties":{"status":{"type":"string","enum":["pending","approved","rejected"]},"url":{"type":"string","format":"uri"}}},"selfie_photo":{"type":"object","nullable":true,"properties":{"status":{"type":"string","enum":["pending","approved","rejected"]},"url":{"type":"string","format":"uri"}}}}},"submittedAt":{"type":"string","format":"date-time","nullable":true},"rejectionReason":{"type":"string","nullable":true}}},"UploadKycDocumentInput":{"type":"object","required":["documentType"],"properties":{"documentType":{"type":"string","enum":["identity_document","establishment_proof","business_registration","selfie_photo"],"description":"Type de document à uploader"},"documentNumber":{"type":"string","description":"Numéro du document (optionnel)","example":"CI123456789"}}},"RejectKycInput":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"description":"Raison du rejet","example":"Document illisible, veuillez en fournir un plus clair"}}},"KycSubmission":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"tel":{"type":"string"},"role":{"type":"string"}}},"status":{"type":"string","enum":["pending","approved","rejected"]},"documents":{"type":"array","items":{"$ref":"#/components/schemas/KycDocument"}},"submittedAt":{"type":"string","format":"date-time"},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"reviewedBy":{"type":"string","format":"uuid","nullable":true}}},"KycStats":{"type":"object","properties":{"total":{"type":"integer","description":"Total des soumissions"},"pending":{"type":"integer","description":"En attente de vérification"},"approved":{"type":"integer","description":"Approuvés"},"rejected":{"type":"integer","description":"Rejetés"},"thisMonth":{"type":"integer","description":"Soumissions ce mois"},"avgProcessingTime":{"type":"number","description":"Temps moyen de traitement (heures)"}}},"GiftCard":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","description":"Code unique de la carte cadeau","example":"GIFT-ABC1-23XY-Z456"},"initialValue":{"type":"number","description":"Valeur initiale","example":50000},"currentBalance":{"type":"number","description":"Solde actuel","example":35000},"currency":{"type":"string","default":"XOF","example":"XOF"},"status":{"type":"string","enum":["pending","active","redeemed","expired","cancelled"],"description":"Statut de la carte (pending = en attente de paiement)"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"activatedAt":{"type":"string","format":"date-time","nullable":true,"description":"Date d'activation (après paiement)"},"purchasedBy":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string"}},"description":"Client qui a acheté la carte"},"recipientEmail":{"type":"string","format":"email","nullable":true},"recipientName":{"type":"string","nullable":true},"personalMessage":{"type":"string","nullable":true,"description":"Message personnalisé pour le destinataire"},"recipientUser":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"}},"description":"Utilisateur qui a utilisé la carte"},"paymentMethod":{"type":"string","nullable":true,"description":"Méthode de paiement utilisée"},"paymentStatus":{"type":"string","nullable":true,"enum":["pending","completed","failed"]},"paidAt":{"type":"string","format":"date-time","nullable":true},"isPromoCard":{"type":"boolean","description":"true si carte promo gratuite créée par admin"},"createdBy":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"}},"description":"Admin qui a créé la carte promo"},"minPurchase":{"type":"number","nullable":true,"description":"Montant minimum d'achat requis"},"maxDiscount":{"type":"number","nullable":true,"description":"Réduction maximale applicable"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]},"description":"Types de réservation applicables"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"_count":{"type":"object","properties":{"redemptions":{"type":"integer","description":"Nombre d'utilisations"}}}}},"PurchaseGiftCardInput":{"type":"object","required":["amount","method"],"properties":{"amount":{"type":"number","minimum":500,"description":"Montant de la carte (min 500 XOF)","example":50000},"currency":{"type":"string","default":"XOF"},"recipientEmail":{"type":"string","format":"email"},"recipientName":{"type":"string","maxLength":100},"personalMessage":{"type":"string","maxLength":500},"method":{"type":"string","enum":["mobile_money","card","bank_transfer"],"description":"Méthode de paiement (routée via la factory multi-provider)"},"operator":{"type":"string","enum":["orange","mtn","wave"],"description":"Opérateur mobile (si method = mobile_money)"}}},"PurchaseGiftCardResponse":{"type":"object","properties":{"giftCardId":{"type":"string","format":"uuid"},"reference":{"type":"string","example":"GFT-ABC123XYZ456"},"amount":{"type":"number"},"currency":{"type":"string"},"paymentUrl":{"type":"string"},"message":{"type":"string"}}},"ConfirmPaymentInput":{"type":"object","required":["giftCardId","paymentId"],"properties":{"giftCardId":{"type":"string","format":"uuid","description":"ID de la carte cadeau"},"paymentId":{"type":"string","description":"ID du paiement (externe)","example":"pay_123456789"}}},"CreatePromoCardInput":{"type":"object","required":["initialValue"],"properties":{"initialValue":{"type":"number","minimum":1,"description":"Valeur de la carte promo","example":25000},"currency":{"type":"string","default":"XOF"},"expiresAt":{"type":"string","format":"date-time","description":"Date d'expiration"},"recipientEmail":{"type":"string","format":"email","description":"Email du destinataire"},"recipientName":{"type":"string","maxLength":100},"minPurchase":{"type":"number","description":"Montant minimum d'achat requis"},"maxDiscount":{"type":"number","description":"Réduction maximale applicable"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]}}}},"CreateBulkPromoCardsInput":{"type":"object","required":["count","initialValue"],"properties":{"count":{"type":"integer","minimum":1,"maximum":100,"description":"Nombre de cartes à créer (max 100)","example":10},"prefix":{"type":"string","maxLength":10,"description":"Préfixe pour les codes","example":"XMAS"},"initialValue":{"type":"number","minimum":1,"example":25000},"currency":{"type":"string","default":"XOF"},"expiresAt":{"type":"string","format":"date-time"},"recipientEmail":{"type":"string","format":"email"},"recipientName":{"type":"string"},"minPurchase":{"type":"number"},"maxDiscount":{"type":"number"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]}}}},"UpdateGiftCardInput":{"type":"object","properties":{"expiresAt":{"type":"string","format":"date-time"},"recipientEmail":{"type":"string","format":"email"},"recipientName":{"type":"string","maxLength":100},"minPurchase":{"type":"number"},"maxDiscount":{"type":"number"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"]}},"status":{"type":"string","enum":["pending","active","redeemed","expired","cancelled"]}}},"ValidateCodeInput":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Code de la carte cadeau","example":"GIFT-ABC1-23XY-Z456"},"reservationType":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"],"description":"Type de réservation pour vérifier l'applicabilité"},"amount":{"type":"number","description":"Montant pour vérifier le minimum d'achat","example":75000}}},"ValidateCodeResponse":{"type":"object","properties":{"isValid":{"type":"boolean"},"message":{"type":"string"},"giftCard":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"},"currentBalance":{"type":"number"},"currency":{"type":"string"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"minPurchase":{"type":"number","nullable":true},"maxDiscount":{"type":"number","nullable":true},"applicableTypes":{"type":"array","items":{"type":"string"}}}}}},"RedeemInput":{"type":"object","required":["code","reservationId","reservationType","amount","ownerId"],"properties":{"code":{"type":"string","description":"Code de la carte cadeau","example":"GIFT-ABC1-23XY-Z456"},"reservationId":{"type":"string","format":"uuid","description":"ID de la réservation"},"reservationType":{"type":"string","enum":["hotel","restaurant","vehicle","parking","appointment"],"description":"Type de réservation"},"amount":{"type":"number","minimum":1,"description":"Montant à utiliser","example":25000},"ownerId":{"type":"string","format":"uuid","description":"ID du propriétaire de l'établissement (pour recevoir le paiement)"}}},"RedeemResponse":{"type":"object","properties":{"redemption":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"giftCardId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid"},"amount":{"type":"number"},"balanceBefore":{"type":"number"},"balanceAfter":{"type":"number"},"ownerAmount":{"type":"number","description":"Montant versé au propriétaire"},"commissionAmount":{"type":"number","description":"Commission prélevée"},"redeemedAt":{"type":"string","format":"date-time"}}},"amountRedeemed":{"type":"number","description":"Montant utilisé","example":25000},"ownerAmount":{"type":"number","description":"Montant versé au propriétaire","example":23750},"commissionAmount":{"type":"number","description":"Commission (5%)","example":1250},"remainingBalance":{"type":"number","description":"Solde restant","example":10000},"cardStatus":{"type":"string","enum":["active","redeemed"]}}},"BalanceResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string"},"currentBalance":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","active","redeemed","expired","cancelled"]},"expiresAt":{"type":"string","format":"date-time","nullable":true},"activatedAt":{"type":"string","format":"date-time","nullable":true}}},"GiftCardStats":{"type":"object","properties":{"totalCards":{"type":"integer","description":"Nombre total de cartes"},"pendingCards":{"type":"integer","description":"Cartes en attente de paiement"},"activeCards":{"type":"integer","description":"Cartes actives"},"redeemedCards":{"type":"integer","description":"Cartes utilisées"},"expiredCards":{"type":"integer","description":"Cartes expirées"},"cancelledCards":{"type":"integer","description":"Cartes annulées"},"totalPurchasedValue":{"type":"number","description":"Valeur totale achetée par clients"},"totalPromoValue":{"type":"number","description":"Valeur totale des cartes promo"},"totalRedeemed":{"type":"number","description":"Valeur totale utilisée"},"remainingBalance":{"type":"number","description":"Solde total restant"},"totalCommissions":{"type":"number","description":"Total des commissions prélevées"}}},"GiftCardRedemption":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"giftCardId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid"},"reservationType":{"type":"string"},"amount":{"type":"number"},"balanceBefore":{"type":"number"},"balanceAfter":{"type":"number"},"ownerId":{"type":"string","format":"uuid"},"ownerAmount":{"type":"number"},"commissionAmount":{"type":"number"},"commissionRate":{"type":"number"},"redeemedAt":{"type":"string","format":"date-time"},"user":{"type":"object","properties":{"id":{"type":"string"},"firstname":{"type":"string"},"lastname":{"type":"string"}}},"owner":{"type":"object","properties":{"id":{"type":"string"},"firstname":{"type":"string"},"lastname":{"type":"string"}}}}},"LoyaltyBalance":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"points":{"type":"integer","description":"Points actuels"},"lifetimePoints":{"type":"integer","description":"Points totaux gagnés"},"tier":{"type":"string","enum":["Bronze","Silver","Gold","Platinum"],"description":"Niveau de fidélité"},"tierMultiplier":{"type":"number","description":"Multiplicateur de points"},"nextTier":{"type":"string","nullable":true,"description":"Prochain niveau"},"pointsToNextTier":{"type":"integer","nullable":true,"description":"Points restants pour le prochain niveau"}}},"LoyaltyTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["earn","redeem","expire","adjust"],"description":"Type de transaction"},"points":{"type":"integer","description":"Points (positif pour gain, négatif pour utilisation)"},"description":{"type":"string","description":"Description de la transaction"},"reservationId":{"type":"string","format":"uuid","nullable":true},"reservationType":{"type":"string","enum":["hotel","restaurant","rentalAgency","parking","establishment","event"],"nullable":true},"metadata":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"RewardTier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pointsRequired":{"type":"integer","description":"Points requis pour débloquer"},"rewardValue":{"type":"integer","description":"Valeur de la réduction en XOF"},"name":{"type":"string","nullable":true,"description":"Nom du palier"},"description":{"type":"string","nullable":true,"description":"Description"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TiersInfo":{"type":"object","properties":{"Bronze":{"type":"object","properties":{"threshold":{"type":"integer"},"multiplier":{"type":"number"},"benefits":{"type":"array","items":{"type":"string"}}}},"Silver":{"type":"object","properties":{"threshold":{"type":"integer"},"multiplier":{"type":"number"},"benefits":{"type":"array","items":{"type":"string"}}}},"Gold":{"type":"object","properties":{"threshold":{"type":"integer"},"multiplier":{"type":"number"},"benefits":{"type":"array","items":{"type":"string"}}}},"Platinum":{"type":"object","properties":{"threshold":{"type":"integer"},"multiplier":{"type":"number"},"benefits":{"type":"array","items":{"type":"string"}}}}}},"LoyaltyConfig":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"xofPerPoint":{"type":"integer","description":"XOF nécessaires pour 1 point","example":1000},"maxDiscountPercent":{"type":"number","description":"Réduction max en %","example":50},"silverThreshold":{"type":"integer","description":"Points pour niveau Silver"},"goldThreshold":{"type":"integer","description":"Points pour niveau Gold"},"platinumThreshold":{"type":"integer","description":"Points pour niveau Platinum"},"bronzeMultiplier":{"type":"number","description":"Multiplicateur Bronze"},"silverMultiplier":{"type":"number","description":"Multiplicateur Silver"},"goldMultiplier":{"type":"number","description":"Multiplicateur Gold"},"platinumMultiplier":{"type":"number","description":"Multiplicateur Platinum"},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","rentalAgency","parking","establishment","event"]},"description":"Types de réservation où les points sont gagnés"},"isActive":{"type":"boolean","description":"Programme actif"}}},"UpdateLoyaltyConfigInput":{"type":"object","properties":{"xofPerPoint":{"type":"integer","minimum":100,"maximum":100000},"maxDiscountPercent":{"type":"number","minimum":1,"maximum":100},"silverThreshold":{"type":"integer","minimum":1},"goldThreshold":{"type":"integer","minimum":1},"platinumThreshold":{"type":"integer","minimum":1},"bronzeMultiplier":{"type":"number","minimum":1,"maximum":10},"silverMultiplier":{"type":"number","minimum":1,"maximum":10},"goldMultiplier":{"type":"number","minimum":1,"maximum":10},"platinumMultiplier":{"type":"number","minimum":1,"maximum":10},"applicableTypes":{"type":"array","items":{"type":"string","enum":["hotel","restaurant","rentalAgency","parking","establishment","event"]}},"isActive":{"type":"boolean"}}},"CreateRewardTierInput":{"type":"object","required":["pointsRequired","rewardValue"],"properties":{"pointsRequired":{"type":"integer","minimum":1,"description":"Points requis"},"rewardValue":{"type":"integer","minimum":1,"description":"Valeur de la récompense en XOF"},"name":{"type":"string","maxLength":100,"description":"Nom du palier"},"description":{"type":"string","maxLength":500,"description":"Description"}}},"UpdateRewardTierInput":{"type":"object","properties":{"pointsRequired":{"type":"integer","minimum":1},"rewardValue":{"type":"integer","minimum":1},"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500},"isActive":{"type":"boolean"}}},"ValidateRedemptionInput":{"type":"object","required":["tierId","orderTotal"],"properties":{"tierId":{"type":"string","format":"uuid","description":"ID du palier de récompense"},"orderTotal":{"type":"number","minimum":0,"description":"Montant total de la commande"}}},"RedeemLoyaltyInput":{"type":"object","required":["tierId","reservationId"],"properties":{"tierId":{"type":"string","format":"uuid","description":"ID du palier de récompense"},"reservationId":{"type":"string","format":"uuid","description":"ID de la réservation"}}},"AdjustPointsInput":{"type":"object","required":["points","reason"],"properties":{"points":{"type":"integer","description":"Points à ajouter (positif) ou retirer (négatif)"},"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Raison de l'ajustement"}}},"LoyaltyStats":{"type":"object","properties":{"totalMembers":{"type":"integer","description":"Nombre total de membres"},"activeMembers":{"type":"integer","description":"Membres actifs ce mois"},"totalPointsIssued":{"type":"integer","description":"Points totaux émis"},"totalPointsRedeemed":{"type":"integer","description":"Points totaux utilisés"},"totalPointsExpired":{"type":"integer","description":"Points expirés"},"membersByTier":{"type":"object","properties":{"Bronze":{"type":"integer"},"Silver":{"type":"integer"},"Gold":{"type":"integer"},"Platinum":{"type":"integer"}}},"redemptionRate":{"type":"number","description":"Taux d'utilisation en %"}}},"TopMember":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"user":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"points":{"type":"integer"},"lifetimePoints":{"type":"integer"},"tier":{"type":"string","enum":["Bronze","Silver","Gold","Platinum"]}}},"ClaimableEntityType":{"type":"string","enum":["hotel","restaurant","parking","rentalAgency","establishment"],"description":"Type d'entité revendicable"},"ReservationAttemptStatus":{"type":"string","enum":["pending","notified","owner_responded","expired","converted"],"description":"Statut de la tentative"},"PossibleOwnerResponse":{"type":"string","enum":["no_response","interested","not_owner","not_interested","claimed"],"description":"Reponse du possible owner"},"NotificationChannel":{"type":"string","enum":["email","sms","whatsapp"],"description":"Canal de notification"},"NotificationType":{"type":"string","enum":["reservation_attempt","follow_up","claim_invitation","bulk_opportunities"],"description":"Type de notification"},"ReservationAttempt":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"clientName":{"type":"string"},"clientEmail":{"type":"string","format":"email","nullable":true},"clientPhone":{"type":"string"},"attemptedDate":{"type":"string","format":"date-time"},"guestsCount":{"type":"integer","nullable":true},"additionalDetails":{"type":"string","nullable":true},"notificationsSent":{"type":"integer"},"lastNotifiedAt":{"type":"string","format":"date-time","nullable":true},"status":{"$ref":"#/components/schemas/ReservationAttemptStatus"},"possibleOwnerId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateReservationAttemptDto":{"type":"object","required":["entityType","entityId","clientName","clientPhone","attemptedDate"],"properties":{"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"clientName":{"type":"string","minLength":2},"clientEmail":{"type":"string","format":"email"},"clientPhone":{"type":"string","minLength":8},"attemptedDate":{"type":"string","format":"date-time"},"guestsCount":{"type":"integer","minimum":1},"additionalDetails":{"type":"string","maxLength":1000}}},"PossibleOwner":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"whatsapp":{"type":"string","nullable":true},"source":{"type":"string","nullable":true},"sourceNotes":{"type":"string","nullable":true},"isVerified":{"type":"boolean"},"isContacted":{"type":"boolean"},"lastContactAt":{"type":"string","format":"date-time","nullable":true},"contactCount":{"type":"integer"},"responseStatus":{"$ref":"#/components/schemas/PossibleOwnerResponse"},"responseNotes":{"type":"string","nullable":true},"respondedAt":{"type":"string","format":"date-time","nullable":true},"claimedByUserId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreatePossibleOwnerDto":{"type":"object","required":["entityType","entityId","name"],"properties":{"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"name":{"type":"string","minLength":2},"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":8},"whatsapp":{"type":"string","minLength":8},"source":{"type":"string","maxLength":50},"sourceNotes":{"type":"string","maxLength":500}}},"UpdatePossibleOwnerDto":{"type":"object","properties":{"name":{"type":"string","minLength":2},"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":8},"whatsapp":{"type":"string","minLength":8},"source":{"type":"string","maxLength":50},"sourceNotes":{"type":"string","maxLength":500}}},"UpdatePossibleOwnerResponseDto":{"type":"object","required":["responseStatus"],"properties":{"responseStatus":{"$ref":"#/components/schemas/PossibleOwnerResponse"},"responseNotes":{"type":"string","maxLength":1000}}},"SendNotificationDto":{"type":"object","required":["possibleOwnerId","channels","type"],"properties":{"possibleOwnerId":{"type":"string","format":"uuid"},"channels":{"type":"array","items":{"$ref":"#/components/schemas/NotificationChannel"},"minItems":1},"type":{"$ref":"#/components/schemas/NotificationType"},"reservationAttemptId":{"type":"string","format":"uuid"},"customMessage":{"type":"string","maxLength":1000}}},"SendBulkNotificationsDto":{"type":"object","required":["possibleOwnerIds","channels","type"],"properties":{"possibleOwnerIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1},"channels":{"type":"array","items":{"$ref":"#/components/schemas/NotificationChannel"},"minItems":1},"type":{"$ref":"#/components/schemas/NotificationType"}}},"NotificationResult":{"type":"object","properties":{"channel":{"$ref":"#/components/schemas/NotificationChannel"},"success":{"type":"boolean"},"error":{"type":"string","nullable":true}}},"AttemptStats":{"type":"object","properties":{"total":{"type":"integer"},"pending":{"type":"integer"},"notified":{"type":"integer"},"converted":{"type":"integer"},"byEntityType":{"type":"object","additionalProperties":{"type":"integer"}},"last30Days":{"type":"integer"}}},"PossibleOwnerStats":{"type":"object","properties":{"total":{"type":"integer"},"contacted":{"type":"integer"},"verified":{"type":"integer"},"notContacted":{"type":"integer"},"byResponse":{"type":"object","additionalProperties":{"type":"integer"}},"byEntityType":{"type":"object","additionalProperties":{"type":"integer"}}}},"TrashableEntityType":{"type":"string","enum":["hotel","restaurant","parking","rentalAgency","appointment","appointmentService","reservation","vehicle","room","roomTemplate","menuItem","restaurantTable","parkingSpot","giftCard","user"],"description":"Type d'entité pouvant être mis en corbeille","example":"restaurant"},"TrashItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID de l'élément"},"entityType":{"$ref":"#/components/schemas/TrashableEntityType"},"name":{"type":"string","description":"Nom de l'élément","example":"Restaurant Le Gourmet"},"deletedAt":{"type":"string","format":"date-time","description":"Date de suppression"},"expiresAt":{"type":"string","format":"date-time","description":"Date d'expiration (suppression définitive auto)"},"ownerId":{"type":"string","format":"uuid","description":"ID du propriétaire","nullable":true},"ownerName":{"type":"string","description":"Nom du propriétaire","nullable":true},"parentId":{"type":"string","format":"uuid","description":"ID de l'entité parente (si applicable)","nullable":true},"parentType":{"type":"string","description":"Type de l'entité parente","nullable":true}},"required":["id","entityType","deletedAt"]},"TrashStats":{"type":"object","properties":{"totalCount":{"type":"integer","description":"Nombre total d'éléments en corbeille","example":42},"byEntityType":{"type":"array","items":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/TrashableEntityType"},"label":{"type":"string","description":"Libellé français du type","example":"Restaurants"},"count":{"type":"integer","description":"Nombre d'éléments de ce type","example":5}}}},"itemsExpiringSoon":{"type":"integer","description":"Nombre d'éléments expirant dans les 7 prochains jours","example":3}},"required":["totalCount","byEntityType","itemsExpiringSoon"]},"RestoreResult":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/TrashableEntityType"},"entityId":{"type":"string","format":"uuid"},"success":{"type":"boolean"},"error":{"type":"string","nullable":true},"restoredChildren":{"type":"integer","description":"Nombre d'éléments enfants restaurés","nullable":true}},"required":["entityType","entityId","success"]},"PurgeResult":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/TrashableEntityType"},"deletedCount":{"type":"integer","description":"Nombre d'éléments supprimés définitivement"},"errors":{"type":"array","items":{"type":"string"},"nullable":true}},"required":["deletedCount"]},"BulkRestoreInput":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/TrashableEntityType"},"entityId":{"type":"string","format":"uuid"}},"required":["entityType","entityId"]},"minItems":1,"maxItems":100}},"required":["items"],"example":{"items":[{"entityType":"restaurant","entityId":"123e4567-e89b-12d3-a456-426614174000"},{"entityType":"menuItem","entityId":"123e4567-e89b-12d3-a456-426614174001"}]}},"TrashListResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TrashItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"TrashStatsResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TrashStats"}}},"RestoreResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Item restored successfully"},"data":{"$ref":"#/components/schemas/RestoreResult"}}},"BulkRestoreResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Restored 5 items, 0 failed"},"data":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/RestoreResult"}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"success":{"type":"integer"},"failed":{"type":"integer"}}}}}}},"PurgeResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Purged 10 items from trash"},"data":{"$ref":"#/components/schemas/PurgeResult"}}},"PossibleOwnerInput":{"type":"object","description":"Contact potentiel du propriétaire de l'entité","properties":{"name":{"type":"string","minLength":2,"example":"Jean Dupont","description":"Nom du contact"},"email":{"type":"string","format":"email","example":"jean.dupont@example.com","description":"Email du contact (optionnel)","nullable":true},"phone":{"type":"string","minLength":8,"example":"+2250700000000","description":"Téléphone du contact (optionnel)","nullable":true},"whatsapp":{"type":"string","minLength":8,"example":"+2250700000000","description":"WhatsApp du contact (optionnel)","nullable":true},"source":{"type":"string","maxLength":50,"example":"google_maps","description":"Source de l'information (ex: google_maps, facebook, referral)"},"sourceNotes":{"type":"string","maxLength":500,"description":"Notes sur la source"}}},"CreateUnclaimedHotelInput":{"type":"object","description":"Données pour créer un hôtel non réclamé (en attente de revendication)","required":["name","address","city"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Hôtel Ivoire"},"description":{"type":"string","maxLength":2000,"example":"Un magnifique hôtel au cœur d'Abidjan"},"address":{"type":"string","minLength":5,"maxLength":200,"example":"Boulevard Lagunaire, Plateau"},"city":{"type":"string","minLength":2,"maxLength":100,"example":"Abidjan"},"country":{"type":"string","default":"Côte d'Ivoire"},"latitude":{"type":"number","minimum":-90,"maximum":90,"example":5.3167},"longitude":{"type":"number","minimum":-180,"maximum":180,"example":-4.0333},"email":{"type":"string","format":"email","example":"contact@hotel-ivoire.ci"},"phone":{"type":"string","example":"+22527000000"},"website":{"type":"string","format":"uri","example":"https://www.hotel-ivoire.ci"},"coverImage":{"type":"string","description":"URL de l'image de couverture"},"images":{"type":"array","items":{"type":"string"},"description":"Liste des URLs des images"},"hasPool":{"type":"boolean","default":false},"hasSpa":{"type":"boolean","default":false},"hasGym":{"type":"boolean","default":false},"hasRestaurant":{"type":"boolean","default":false},"hasBar":{"type":"boolean","default":false},"hasParking":{"type":"boolean","default":false},"hasWifi":{"type":"boolean","default":false},"hasBreakfast":{"type":"boolean","default":false},"hasRoomService":{"type":"boolean","default":false},"hasBusinessCenter":{"type":"boolean","default":false},"hasConferenceRooms":{"type":"boolean","default":false},"hasAirportShuttle":{"type":"boolean","default":false},"isPetFriendly":{"type":"boolean","default":false},"isFamilyFriendly":{"type":"boolean","default":false},"customAmenities":{"type":"array","items":{"type":"string"},"maxItems":20},"possibleOwner":{"$ref":"#/components/schemas/PossibleOwnerInput"}}},"CreateUnclaimedRestaurantInput":{"type":"object","description":"Données pour créer un restaurant non réclamé","required":["name","address","city"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Restaurant Le Gourmet"},"description":{"type":"string","maxLength":2000},"cuisineType":{"type":"string","enum":["african","french","italian","asian","american","mediterranean","international","seafood","vegetarian","fast_food"],"default":"international"},"address":{"type":"string","minLength":5,"maxLength":200},"city":{"type":"string","minLength":2,"maxLength":100},"country":{"type":"string","default":"Côte d'Ivoire"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"website":{"type":"string","format":"uri"},"coverImage":{"type":"string"},"images":{"type":"array","items":{"type":"string"}},"possibleOwner":{"$ref":"#/components/schemas/PossibleOwnerInput"}}},"CreateUnclaimedParkingInput":{"type":"object","description":"Données pour créer un parking non réclamé","required":["name","address","city"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Parking Centre Ville"},"description":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["couvert","plein_air","souterrain","multi_niveaux"],"default":"plein_air"},"address":{"type":"string","minLength":5,"maxLength":200},"city":{"type":"string","minLength":2,"maxLength":100},"country":{"type":"string","default":"Côte d'Ivoire"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"coverImage":{"type":"string"},"totalSpots":{"type":"integer","minimum":1,"description":"Nombre total de places"},"pricePerHour":{"type":"number","minimum":0,"description":"Prix par heure (FCFA)"},"pricePerDay":{"type":"number","minimum":0,"description":"Prix par jour (FCFA)"},"possibleOwner":{"$ref":"#/components/schemas/PossibleOwnerInput"}}},"CreateUnclaimedRentalAgencyInput":{"type":"object","description":"Données pour créer une agence de location non réclamée","required":["name","address","city"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"AutoLoc CI"},"description":{"type":"string","maxLength":2000},"address":{"type":"string","minLength":5,"maxLength":200},"city":{"type":"string","minLength":2,"maxLength":100},"country":{"type":"string","default":"Côte d'Ivoire"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"website":{"type":"string","format":"uri"},"coverImage":{"type":"string"},"images":{"type":"array","items":{"type":"string"}},"possibleOwner":{"$ref":"#/components/schemas/PossibleOwnerInput"}}},"CreateUnclaimedEstablishmentInput":{"type":"object","description":"Données pour créer un établissement non réclamé (salon, spa, cabinet, etc.)","required":["name","address","city","businessType"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"example":"Salon Beauté Plus"},"description":{"type":"string","maxLength":2000},"businessType":{"type":"string","minLength":2,"example":"salon_coiffure","description":"Type d'activité"},"address":{"type":"string","minLength":5,"maxLength":200},"city":{"type":"string","minLength":2,"maxLength":100},"country":{"type":"string","default":"Côte d'Ivoire"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"website":{"type":"string","format":"uri"},"coverImage":{"type":"string"},"images":{"type":"array","items":{"type":"string"}},"possibleOwner":{"$ref":"#/components/schemas/PossibleOwnerInput"}}},"UnclaimedEntityResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"entity":{"type":"object","description":"L'entité créée"},"possibleOwner":{"type":"object","nullable":true,"description":"Le contact potentiel créé (si fourni)"},"entityType":{"type":"string","example":"hotel"},"message":{"type":"string","example":"Hôtel créé avec succès (en attente de revendication)"}}}}},"BulkUnclaimedEntityResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"success":{"type":"array","items":{"type":"object"},"description":"Entités créées avec succès"},"failed":{"type":"array","items":{"type":"object"},"description":"Entités en échec avec raison"},"entityType":{"type":"string","example":"hotel"},"totalSuccess":{"type":"integer","example":8},"totalFailed":{"type":"integer","example":2},"message":{"type":"string","example":"8 hôtels créés, 2 échecs"}}}}},"ChatMessage":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user"],"description":"Role de l'expediteur (toujours 'user' pour les requetes)"},"content":{"type":"string","minLength":1,"maxLength":1000,"description":"Contenu du message"}}},"ChatRequestInput":{"type":"object","required":["message"],"properties":{"message":{"$ref":"#/components/schemas/ChatMessage"},"sessionId":{"type":"string","format":"uuid","description":"ID de session existante (optionnel, cree une nouvelle session si absent)"},"metadata":{"type":"object","properties":{"page":{"type":"string","description":"Page courante de l'utilisateur"},"language":{"type":"string","description":"Langue preferee de l'utilisateur"}},"description":"Metadonnees contextuelles optionnelles"}}},"SSEEvent":{"type":"object","properties":{"type":{"type":"string","enum":["text_delta","tool_call","tool_result","action","quick_reply","request_feedback","error","done"],"description":"Type d'evenement SSE"},"content":{"type":"string","description":"Contenu textuel (pour text_delta)"},"toolName":{"type":"string","description":"Nom de l'outil appele (pour tool_call)"},"toolCallId":{"type":"string","description":"ID de l'appel d'outil"},"args":{"type":"object","description":"Arguments de l'outil (pour tool_call)"},"result":{"type":"object","description":"Resultat de l'outil (pour tool_result)"},"sessionId":{"type":"string","format":"uuid","description":"ID de la session"},"error":{"type":"string","description":"Message d'erreur (pour error)"},"actionType":{"type":"string","enum":["navigate","open_cart"],"description":"Type d'action (pour action)"},"actionPayload":{"type":"object","properties":{"webUrl":{"type":"string","description":"URL web pour la navigation"},"mobileRoute":{"type":"string","description":"Route mobile pour la navigation"},"label":{"type":"string","description":"Label du bouton d'action"}}},"quickReplies":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"Texte affiche du bouton"},"value":{"type":"string","description":"Valeur envoyee au clic"}}},"description":"Boutons de reponse rapide (pour quick_reply)"}}},"ChatSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true,"description":"Titre genere de la session"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ChatHistoryResponse":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true,"description":"Titre de la session"},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant","system","tool"],"description":"Role de l'auteur du message"},"content":{"type":"string","nullable":true,"description":"Contenu du message"}}},"description":"Liste des messages de la session"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"FeedbackInput":{"type":"object","required":["rating"],"properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Note de satisfaction (1 a 5)"},"comment":{"type":"string","maxLength":1000,"description":"Commentaire optionnel"}}},"AdminChatSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"userId":{"type":"string","format":"uuid","nullable":true},"user":{"type":"object","nullable":true,"properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"messageCount":{"type":"integer","description":"Nombre de messages dans la session"},"rating":{"type":"integer","nullable":true,"description":"Note de satisfaction"},"feedback":{"type":"string","nullable":true,"description":"Commentaire de feedback"},"hasOrdered":{"type":"boolean","description":"L'utilisateur a-t-il passe une commande"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AdminChatSessionDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"userId":{"type":"string","format":"uuid","nullable":true},"user":{"type":"object","nullable":true,"properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant","system","tool"]},"content":{"type":"string","nullable":true}}}},"rating":{"type":"integer","nullable":true},"feedback":{"type":"string","nullable":true},"hasOrdered":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"GenerateDescriptionInput":{"type":"object","required":["type","keywords"],"properties":{"type":{"type":"string","enum":["hotel","restaurant","activity","event"],"description":"Type d'etablissement ou d'entite"},"keywords":{"type":"string","minLength":3,"description":"Mots-cles decrivant l'etablissement (minimum 3 caracteres)","example":"luxe piscine vue mer spa"},"context":{"type":"string","description":"Contexte supplementaire pour affiner la generation","example":"Hotel 5 etoiles a Abidjan, quartier Cocody"}}},"GenerateMenuDescriptionInput":{"type":"object","required":["dishName","keywords"],"properties":{"dishName":{"type":"string","minLength":2,"description":"Nom du plat","example":"Poulet braise"},"keywords":{"type":"string","minLength":3,"description":"Mots-cles decrivant le plat (minimum 3 caracteres)","example":"epice grille sauce tomate oignons"}}},"GenerateAltTextInput":{"type":"object","required":["imageDescription"],"properties":{"imageDescription":{"type":"string","minLength":5,"description":"Description de l'image pour generer un texte alternatif (minimum 5 caracteres)","example":"Photo de la facade de l'hotel avec piscine au premier plan"}}},"GeneratedDescription":{"type":"object","properties":{"description":{"type":"string","description":"Description generee par l'IA"}}},"GeneratedAltText":{"type":"object","properties":{"altText":{"type":"string","description":"Texte alternatif genere par l'IA"}}},"TrackingSessionType":{"type":"string","enum":["rental"],"description":"Type de session de suivi"},"TrackingSessionStatus":{"type":"string","enum":["active","paused","completed","cancelled"],"description":"Statut de la session de suivi"},"TrackingParticipant":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"firstname":{"type":"string","description":"Prénom du participant"},"lastname":{"type":"string","description":"Nom du participant"},"profileImage":{"type":"string","nullable":true,"description":"URL de la photo de profil"},"role":{"type":"string","enum":["driver","passenger","renter"],"description":"Rôle dans la session"},"lastLocation":{"type":"object","nullable":true,"properties":{"latitude":{"type":"number","description":"Latitude"},"longitude":{"type":"number","description":"Longitude"},"speed":{"type":"number","nullable":true,"description":"Vitesse en km/h"},"heading":{"type":"number","nullable":true,"description":"Direction en degrés (0-360)"},"recordedAt":{"type":"string","format":"date-time","description":"Date d'enregistrement"}}}}},"TrackingSession":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/TrackingSessionType"},"status":{"$ref":"#/components/schemas/TrackingSessionStatus"},"participants":{"type":"array","items":{"$ref":"#/components/schemas/TrackingParticipant"}},"expectedRoute":{"type":"array","items":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"orderIndex":{"type":"integer"}}},"description":"Itinéraire prévu (covoiturage uniquement)"},"deviationThresholdKm":{"type":"number","description":"Seuil de déviation en km"},"totalDeviationAlerts":{"type":"integer","description":"Nombre total d'alertes de déviation"},"startedAt":{"type":"string","format":"date-time","description":"Date de début"},"completedAt":{"type":"string","format":"date-time","nullable":true,"description":"Date de fin"},"tripInfo":{"type":"object","nullable":true,"description":"Infos du trajet (covoiturage)","properties":{"id":{"type":"string","format":"uuid"},"departureLocation":{"type":"string"},"destinationLocation":{"type":"string"},"departureDate":{"type":"string","format":"date-time"}}},"rentalInfo":{"type":"object","nullable":true,"description":"Infos de la location","properties":{"reservationId":{"type":"string","format":"uuid"},"rentalAgencyName":{"type":"string"}}}}},"TrackingSessionListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/TrackingSessionType"},"status":{"$ref":"#/components/schemas/TrackingSessionStatus"},"trackedUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"profileImage":{"type":"string","nullable":true}}},"totalDeviationAlerts":{"type":"integer"},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true},"tripInfo":{"type":"object","nullable":true,"properties":{"departureLocation":{"type":"string"},"destinationLocation":{"type":"string"}}}}},"TrackingLocationLog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sessionId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"accuracy":{"type":"number","nullable":true,"description":"Précision en mètres"},"speed":{"type":"number","nullable":true,"description":"Vitesse en km/h"},"heading":{"type":"number","nullable":true,"minimum":0,"maximum":360,"description":"Direction en degrés"},"altitude":{"type":"number","nullable":true,"description":"Altitude en mètres"},"deviationKm":{"type":"number","nullable":true,"description":"Déviation par rapport à l'itinéraire en km"},"isDeviating":{"type":"boolean","description":"Indique si le véhicule dévie"},"recordedAt":{"type":"string","format":"date-time"}}},"CreateTrackingSessionInput":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["rental"],"description":"Type de suivi"},"reservationId":{"type":"string","format":"uuid","description":"ID de la réservation de location (requis si type = rental)"},"deviationThresholdKm":{"type":"number","minimum":0.5,"maximum":10,"description":"Seuil de déviation en km (défaut: 2 km)"}}},"LocationUpdateInput":{"type":"object","required":["sessionId","latitude","longitude"],"properties":{"sessionId":{"type":"string","format":"uuid","description":"ID de la session"},"latitude":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude"},"longitude":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude"},"accuracy":{"type":"number","description":"Précision GPS en mètres"},"speed":{"type":"number","description":"Vitesse en km/h"},"heading":{"type":"number","minimum":0,"maximum":360,"description":"Direction en degrés"},"altitude":{"type":"number","description":"Altitude en mètres"}}},"AddonDefinition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"Identifiant unique du service","example":"ai-insights"},"name":{"type":"string","description":"Nom du service","example":"IA Business Insights"},"description":{"type":"string","description":"Description du service"},"icon":{"type":"string","nullable":true,"description":"Nom de l'icone","example":"BrainCircuit"},"billingType":{"type":"string","enum":["MONTHLY","ONE_TIME"],"description":"Type de facturation"},"price":{"type":"number","description":"Prix en XOF","example":5000},"isActive":{"type":"boolean","description":"Service actif"},"sortOrder":{"type":"integer","description":"Ordre d'affichage"},"metadata":{"type":"object","nullable":true,"description":"Donnees supplementaires"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AddonDefinitionWithCount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","example":"ai-insights"},"name":{"type":"string","example":"IA Business Insights"},"description":{"type":"string"},"icon":{"type":"string","nullable":true},"billingType":{"type":"string","enum":["MONTHLY","ONE_TIME"]},"price":{"type":"number"},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"},"metadata":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"subscriberCount":{"type":"integer","description":"Nombre d'abonnes actifs"}}},"AddonWithSubscription":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","example":"ai-insights"},"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string","nullable":true},"billingType":{"type":"string","enum":["MONTHLY","ONE_TIME"]},"price":{"type":"number"},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"},"subscription":{"type":"object","nullable":true,"description":"Abonnement actuel du proprietaire (null si non abonne)","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["ACTIVE","CANCELLED","EXPIRED","PAST_DUE"],"description":"Statut de l'abonnement"},"startDate":{"type":"string","format":"date-time","nullable":true},"endDate":{"type":"string","format":"date-time","nullable":true},"nextPaymentDate":{"type":"string","format":"date-time","nullable":true},"cancelledAt":{"type":"string","format":"date-time","nullable":true}}}}},"AddonRegistryEntry":{"type":"object","properties":{"slug":{"type":"string","description":"Slug du service enregistre","example":"ai-insights"},"defaultName":{"type":"string","example":"IA Business Insights"},"defaultDescription":{"type":"string"},"defaultIcon":{"type":"string","example":"BrainCircuit"},"defaultBillingType":{"type":"string","enum":["MONTHLY","ONE_TIME"]},"defaultPrice":{"type":"number","example":5000},"existsInDb":{"type":"boolean","description":"Existe deja en base de donnees"},"dbAddonId":{"type":"string","format":"uuid","nullable":true,"description":"ID en base (null si pas encore cree)"}}},"AddonStats":{"type":"object","properties":{"addon":{"$ref":"#/components/schemas/AddonDefinition"},"subscriberCount":{"type":"integer","description":"Nombre d'abonnes actifs"},"monthlyRevenue":{"type":"number","description":"Revenu mensuel en XOF (0 pour ONE_TIME)"},"subscribers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"}}},"description":"Liste des abonnes actifs"}}},"AddonAccessResult":{"type":"object","properties":{"hasAccess":{"type":"boolean","description":"Le proprietaire a acces au service"},"addonPrice":{"type":"number","nullable":true,"description":"Prix du service (present si pas d'acces)"},"addonName":{"type":"string","nullable":true,"description":"Nom du service (present si pas d'acces)"}}},"SubscribePaymentResult":{"type":"object","properties":{"success":{"type":"boolean"},"paymentMethod":{"type":"string","enum":["wallet"],"description":"Methode de paiement utilisee (si paiement wallet)"},"paymentRequired":{"type":"boolean","description":"True si un paiement externe est necessaire"},"paymentUrl":{"type":"string","format":"uri","description":"URL de paiement CinetPay (si paiement externe)"},"breakdown":{"type":"object","nullable":true,"description":"Detail du paiement (si paiement externe)","properties":{"totalCost":{"type":"number","description":"Cout total en XOF"},"fees":{"type":"number","description":"Frais CinetPay"},"totalWithFees":{"type":"number","description":"Total avec frais"},"walletBalance":{"type":"number","description":"Solde du portefeuille"},"walletDeduction":{"type":"number","description":"Montant deduit du portefeuille"},"cinetpayAmount":{"type":"number","description":"Montant a payer via CinetPay"}}},"message":{"type":"string","description":"Message de resultat"}}},"UnsubscribeResult":{"type":"object","properties":{"message":{"type":"string","example":"Abonnement annule. Le service reste actif jusqu'a la fin de la periode payee."}}},"CreateAddonDefinitionInput":{"type":"object","required":["slug","name","description","billingType","price"],"properties":{"slug":{"type":"string","minLength":2,"maxLength":50,"pattern":"^[a-z0-9-]+$","description":"Slug unique (lettres minuscules, chiffres et tirets)","example":"sms-notifications"},"name":{"type":"string","minLength":2,"maxLength":100,"description":"Nom du service","example":"Notifications SMS"},"description":{"type":"string","minLength":10,"description":"Description detaillee du service"},"icon":{"type":"string","description":"Nom de l'icone (optionnel)","example":"MessageSquare"},"billingType":{"type":"string","enum":["MONTHLY","ONE_TIME"],"description":"Type de facturation"},"price":{"type":"number","minimum":0,"description":"Prix en XOF","example":2000},"isActive":{"type":"boolean","default":true,"description":"Activer le service immediatement"},"sortOrder":{"type":"integer","default":0,"description":"Ordre d'affichage"},"metadata":{"type":"object","description":"Donnees supplementaires (optionnel)"}}},"UpdateAddonDefinitionInput":{"type":"object","properties":{"slug":{"type":"string","minLength":2,"maxLength":50,"pattern":"^[a-z0-9-]+$"},"name":{"type":"string","minLength":2,"maxLength":100},"description":{"type":"string","minLength":10},"icon":{"type":"string"},"billingType":{"type":"string","enum":["MONTHLY","ONE_TIME"]},"price":{"type":"number","minimum":0},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"},"metadata":{"type":"object"}}},"SubscribeAddonInput":{"type":"object","required":["addonSlug"],"properties":{"addonSlug":{"type":"string","minLength":1,"description":"Slug du service","example":"ai-insights"},"paymentMethod":{"type":"string","description":"Methode de paiement (optionnel, defaut: MOBILE_MONEY)","example":"MOBILE_MONEY"}}},"UnsubscribeAddonInput":{"type":"object","required":["addonSlug"],"properties":{"addonSlug":{"type":"string","minLength":1,"description":"Slug du service","example":"ai-insights"}}},"SupportTicketCategory":{"type":"string","enum":["general","account","payment","reservation","technical","billing","complaint","feature_request","other"],"description":"Categorie du ticket de support (uniquement platform_support)"},"ConversationParticipant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"profileImage":{"type":"string","nullable":true},"role":{"type":"string"}}},"LastMessageSummary":{"type":"object","properties":{"content":{"type":"string","nullable":true},"type":{"type":"string","enum":["text","image","document"]},"createdAt":{"type":"string","format":"date-time"},"senderId":{"type":"string","format":"uuid"}}},"ConversationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["establishment_support","platform_support"],"description":"Type de conversation"},"status":{"type":"string","enum":["active","archived","closed"],"description":"Statut de la conversation"},"reference":{"type":"string","nullable":true,"description":"Reference humaine du ticket de support (ex: SUP-A1B2C3D4)"},"subject":{"type":"string","nullable":true,"description":"Sujet du ticket de support"},"category":{"allOf":[{"$ref":"#/components/schemas/SupportTicketCategory"}],"nullable":true},"establishmentType":{"type":"string","nullable":true,"description":"Type d'etablissement"},"establishmentId":{"type":"string","format":"uuid","nullable":true,"description":"ID de l'etablissement"},"client":{"$ref":"#/components/schemas/ConversationParticipant"},"owner":{"allOf":[{"$ref":"#/components/schemas/ConversationParticipant"}],"nullable":true},"lastMessage":{"allOf":[{"$ref":"#/components/schemas/LastMessageSummary"}],"nullable":true},"unreadCount":{"type":"integer","description":"Nombre de messages non lus"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MessageAttachment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Type de piece jointe (image, document)"},"url":{"type":"string","format":"uri"},"filename":{"type":"string","nullable":true},"mimeType":{"type":"string","nullable":true},"size":{"type":"integer","nullable":true,"description":"Taille en octets"},"thumbnailUrl":{"type":"string","format":"uri","nullable":true}}},"MessageResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"sender":{"$ref":"#/components/schemas/ConversationParticipant"},"type":{"type":"string","enum":["text","image","document"],"description":"Type de message"},"content":{"type":"string","nullable":true,"description":"Contenu textuel du message"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/MessageAttachment"},"description":"Pieces jointes"},"isRead":{"type":"boolean","description":"Message lu ou non"},"readAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"CreateConversationInput":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["establishment_support","platform_support"],"description":"Type de conversation"},"establishmentType":{"type":"string","description":"Type d'etablissement (requis pour establishment_support)"},"establishmentId":{"type":"string","format":"uuid","description":"ID de l'etablissement (requis pour establishment_support)"},"initialMessage":{"type":"string","maxLength":5000,"description":"Message initial optionnel"},"subject":{"type":"string","maxLength":200,"description":"Sujet du ticket (utile pour platform_support)"},"category":{"allOf":[{"$ref":"#/components/schemas/SupportTicketCategory"}],"description":"Categorie du ticket. Ignoree pour les conversations etablissement. Defaut: general."},"attachmentUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10,"description":"URLs des pieces jointes initiales (issues de /api/upload/images ou /api/upload/documents). Envoyees dans le premier message du ticket."}}},"UpdateConversationStatusInput":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["active","archived","closed"]}}},"UpdateConversationCategoryInput":{"type":"object","required":["category"],"properties":{"category":{"$ref":"#/components/schemas/SupportTicketCategory"}}},"SendMessageInput":{"type":"object","properties":{"type":{"type":"string","enum":["text","image","document"],"default":"text","description":"Type de message"},"content":{"type":"string","maxLength":5000,"description":"Contenu textuel du message"},"attachmentUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10,"description":"URLs des pieces jointes"}},"description":"Au moins content ou attachmentUrls doit etre fourni"},"RegisterPushTokenInput":{"type":"object","required":["token","platform"],"properties":{"token":{"type":"string","minLength":1,"description":"Token de notification push"},"platform":{"type":"string","enum":["ios","android"],"description":"Plateforme mobile"}}},"RemovePushTokenInput":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Token a supprimer"}}},"InsightItem":{"type":"object","properties":{"type":{"type":"string","enum":["recommendation","alert","prediction","comparison"],"description":"Type d'insight"},"category":{"type":"string","enum":["revenue","reviews","occupancy","operations","marketing"],"description":"Catégorie de l'insight"},"severity":{"type":"string","enum":["info","warning","success"],"description":"Niveau de sévérité"},"title":{"type":"string","description":"Titre court (max 60 caractères)"},"description":{"type":"string","description":"Explication détaillée"},"actionSuggestion":{"type":"string","nullable":true,"description":"Action concrète à prendre"},"confidence":{"type":"number","nullable":true,"minimum":0,"maximum":100,"description":"Niveau de confiance (0-100), pour les prédictions"}}},"InsightsResponse":{"type":"object","properties":{"insights":{"type":"array","items":{"$ref":"#/components/schemas/InsightItem"},"description":"Liste des insights générés"},"generatedAt":{"type":"string","format":"date-time","description":"Date de génération"},"nextRefreshAt":{"type":"string","format":"date-time","description":"Prochaine date de rafraîchissement"},"dataSnapshot":{"type":"object","properties":{"period":{"type":"string","description":"Période analysée","example":"30 derniers jours"},"totalRevenue":{"type":"number","description":"Revenu total sur la période"},"totalReservations":{"type":"integer","description":"Nombre total de réservations"},"averageRating":{"type":"number","description":"Note moyenne des avis"}}}}},"AiInsightsAccessResponse":{"type":"object","properties":{"hasAccess":{"type":"boolean","description":"Si le propriétaire a accès à l'addon AI Insights"},"addonPrice":{"type":"number","nullable":true,"description":"Prix de l'addon (si pas d'accès)"},"addonName":{"type":"string","nullable":true,"description":"Nom de l'addon (si pas d'accès)"}}},"PricingSuggestion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entityType":{"type":"string","enum":["hotel","restaurant","parking","event"],"description":"Type d'entité"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"itemId":{"type":"string","nullable":true,"description":"ID de l'item concerné (chambre, plat, etc.)"},"itemName":{"type":"string","nullable":true,"description":"Nom de l'item concerné"},"currentPrice":{"type":"number","description":"Prix actuel en XOF"},"suggestedPrice":{"type":"number","description":"Prix suggéré en XOF"},"changePercent":{"type":"number","description":"Pourcentage de changement"},"reason":{"type":"string","description":"Titre court de la raison"},"reasoning":{"type":"string","description":"Explication détaillée"},"factors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Nom du facteur"},"impact":{"type":"string","enum":["positive","negative","neutral"]},"description":{"type":"string"}}},"description":"Facteurs ayant influencé la suggestion"},"demandLevel":{"type":"string","enum":["low","medium","high","very_high"],"description":"Niveau de demande estimé"},"expectedRevenueImpact":{"type":"number","description":"Impact estimé sur le revenu en XOF"},"confidence":{"type":"number","minimum":0,"maximum":100,"description":"Niveau de confiance"},"validUntil":{"type":"string","format":"date-time","description":"Date de validité de la suggestion"},"status":{"type":"string","enum":["pending","accepted","rejected"],"description":"Statut de la suggestion"}}},"DemandPrediction":{"type":"object","properties":{"date":{"type":"string","format":"date","description":"Date prédite"},"dayOfWeek":{"type":"string","description":"Jour de la semaine"},"predictedOccupancy":{"type":"number","description":"Taux d'occupation prédit (%)"},"demandLevel":{"type":"string","enum":["low","medium","high","very_high"]},"recommendedPriceMultiplier":{"type":"number","description":"Multiplicateur de prix recommandé"},"confidence":{"type":"number","minimum":0,"maximum":100}}},"PromotionSuggestion":{"type":"object","properties":{"title":{"type":"string","description":"Titre de la promotion"},"description":{"type":"string","description":"Description détaillée"},"discountPercent":{"type":"number","description":"Pourcentage de réduction"},"validDays":{"type":"array","items":{"type":"string"},"description":"Jours de validité"},"targetOccupancy":{"type":"string","description":"Cible d'occupation"},"expectedImpact":{"type":"string","description":"Impact attendu"}}},"PricingOptimizationResponse":{"type":"object","properties":{"entityType":{"type":"string"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"currentOccupancyRate":{"type":"number","description":"Taux d'occupation actuel (%)"},"averageOccupancyRate":{"type":"number","description":"Taux d'occupation moyen (%)"},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/PricingSuggestion"}},"demandPredictions":{"type":"array","items":{"$ref":"#/components/schemas/DemandPrediction"}},"promotionSuggestions":{"type":"array","items":{"$ref":"#/components/schemas/PromotionSuggestion"}},"generatedAt":{"type":"string","format":"date-time"},"nextRefreshAt":{"type":"string","format":"date-time"}}},"SlotOptimizationSuggestion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["overbooking","slot_duration","peak_alert","no_show_reduction","schedule_optimization"],"description":"Type de suggestion"},"title":{"type":"string","description":"Titre court"},"description":{"type":"string","description":"Description détaillée"},"currentValue":{"type":"string","nullable":true,"description":"Valeur actuelle"},"suggestedValue":{"type":"string","nullable":true,"description":"Valeur suggérée"},"impact":{"type":"string","enum":["low","medium","high"],"description":"Niveau d'impact estimé"},"estimatedGain":{"type":"string","nullable":true,"description":"Gain estimé"},"actionRequired":{"type":"string","description":"Action à effectuer"},"priority":{"type":"integer","enum":[1,2,3],"description":"Priorité (1 = haute)"},"status":{"type":"string","enum":["pending","accepted","rejected"],"description":"Statut de la suggestion"}}},"PeakDemandAlert":{"type":"object","properties":{"date":{"type":"string","format":"date"},"dayOfWeek":{"type":"string"},"timeSlot":{"type":"string","nullable":true,"description":"Créneau horaire concerné"},"predictedDemand":{"type":"number","description":"Demande prédite"},"currentCapacity":{"type":"number","description":"Capacité actuelle"},"utilizationRate":{"type":"number","description":"Taux d'utilisation (%)"},"alertLevel":{"type":"string","enum":["info","warning","critical"],"description":"Niveau d'alerte"},"recommendation":{"type":"string","description":"Recommandation"}}},"SlotOptimizationResponse":{"type":"object","properties":{"entityType":{"type":"string"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"stats":{"type":"object","properties":{"noShowRate":{"type":"number","description":"Taux de no-show (%)"},"averageSlotDuration":{"type":"number","description":"Durée moyenne des créneaux (minutes)"},"peakDays":{"type":"array","items":{"type":"string"},"description":"Jours de forte demande"},"lowDemandDays":{"type":"array","items":{"type":"string"},"description":"Jours de faible demande"},"utilizationRate":{"type":"number","description":"Taux d'utilisation (%)"},"totalSlots30d":{"type":"integer","description":"Total des créneaux sur 30 jours"},"wastedSlots30d":{"type":"integer","description":"Créneaux perdus sur 30 jours (no-show + annulations)"}}},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SlotOptimizationSuggestion"}},"peakAlerts":{"type":"array","items":{"$ref":"#/components/schemas/PeakDemandAlert"}},"generatedAt":{"type":"string","format":"date-time"},"nextRefreshAt":{"type":"string","format":"date-time"}}},"BlogArticle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","description":"Titre de l'article"},"slug":{"type":"string","description":"Slug unique pour l'URL"},"excerpt":{"type":"string","description":"Resume court de l'article"},"content":{"type":"string","description":"Contenu complet en Markdown"},"category":{"type":"string","description":"Categorie de l'article"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags de l'article"},"coverImage":{"type":"string","nullable":true,"description":"URL de l'image de couverture"},"status":{"type":"string","enum":["draft","pending_review","published","archived"],"description":"Statut de l'article"},"readTime":{"type":"integer","description":"Temps de lecture estime en minutes"},"seoTitle":{"type":"string","nullable":true,"description":"Titre SEO (max 70 caracteres)"},"seoDescription":{"type":"string","nullable":true,"description":"Description SEO (max 160 caracteres)"},"authorId":{"type":"string","format":"uuid"},"author":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"},"profileImage":{"type":"string","nullable":true}}},"reviewedBy":{"type":"string","format":"uuid","nullable":true,"description":"ID de l'admin qui a valide/rejete"},"reviewNote":{"type":"string","nullable":true,"description":"Note de validation/rejet"},"publishedAt":{"type":"string","format":"date-time","nullable":true,"description":"Date de publication"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateBlogArticleInput":{"type":"object","required":["title","excerpt","content","category","tags"],"properties":{"title":{"type":"string","minLength":5,"maxLength":200,"description":"Titre de l'article (5-200 caracteres)"},"excerpt":{"type":"string","minLength":10,"maxLength":500,"description":"Resume court (10-500 caracteres)"},"content":{"type":"string","minLength":50,"description":"Contenu en Markdown (min 50 caracteres)"},"category":{"type":"string","minLength":2,"maxLength":50,"description":"Categorie"},"tags":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10,"description":"Tags (1 a 10)"},"coverImage":{"type":"string","description":"URL de l'image de couverture"},"seoTitle":{"type":"string","maxLength":70,"description":"Titre SEO"},"seoDescription":{"type":"string","maxLength":160,"description":"Description SEO"}}},"UpdateBlogArticleInput":{"type":"object","properties":{"title":{"type":"string","minLength":5,"maxLength":200},"excerpt":{"type":"string","minLength":10,"maxLength":500},"content":{"type":"string","minLength":50},"category":{"type":"string","minLength":2,"maxLength":50},"tags":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"coverImage":{"type":"string"},"seoTitle":{"type":"string","maxLength":70},"seoDescription":{"type":"string","maxLength":160}}},"GenerateArticleInput":{"type":"object","required":["topic","keywords","category"],"properties":{"topic":{"type":"string","minLength":5,"description":"Sujet de l'article (min 5 caracteres)"},"keywords":{"type":"string","minLength":3,"description":"Mots-cles separes par des virgules"},"category":{"type":"string","minLength":2,"maxLength":50,"description":"Categorie cible"},"tone":{"type":"string","description":"Ton souhaite (ex: professionnel, decontracte)"}}},"ReviewArticleInput":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["approve","reject"],"description":"Action de validation"},"note":{"type":"string","description":"Note optionnelle (raison du rejet, commentaires)"},"publishAt":{"type":"string","format":"date-time","description":"Si action=approve : date/heure ISO de publication planifiee (dans le futur). Absent = publication immediate."}}},"SchedulePublicationInput":{"type":"object","required":["publishAt"],"properties":{"publishAt":{"type":"string","format":"date-time","description":"Date/heure ISO de publication (doit etre dans le futur)"}}},"BlogStats":{"type":"object","properties":{"total":{"type":"integer","description":"Nombre total d'articles"},"published":{"type":"integer","description":"Articles visibles sur le site public (publies et date effective passee)"},"scheduled":{"type":"integer","description":"Articles publies mais avec date de mise en ligne dans le futur"},"pendingReview":{"type":"integer","description":"Articles en attente de validation"},"drafts":{"type":"integer","description":"Brouillons"}}},"BlogPagination":{"type":"object","properties":{"page":{"type":"integer","description":"Page actuelle"},"limit":{"type":"integer","description":"Elements par page"},"total":{"type":"integer","description":"Nombre total d'elements"},"totalPages":{"type":"integer","description":"Nombre total de pages"}}},"OwnershipRequestType":{"type":"string","enum":["claim","removal"],"description":"Type de demande: claim = revendication, removal = suppression"},"OwnershipRequestStatus":{"type":"string","enum":["pending","approved","rejected","cancelled"],"description":"Statut de la demande"},"UnclaimedEntity":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/ClaimableEntityType"},"name":{"type":"string"},"slug":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"description":{"type":"string","nullable":true},"coverImage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"OwnershipRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/OwnershipRequestType"},"status":{"$ref":"#/components/schemas/OwnershipRequestStatus"},"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string"},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"supportingDocuments":{"type":"array","items":{"type":"string","format":"uri"}},"requestNote":{"type":"string","nullable":true},"reviewedBy":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"}}},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"reviewNote":{"type":"string","nullable":true},"batchId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ClaimStats":{"type":"object","properties":{"totalPending":{"type":"integer"},"totalApproved":{"type":"integer"},"totalRejected":{"type":"integer"},"claimsPending":{"type":"integer"},"removalsPending":{"type":"integer"},"byEntityType":{"type":"object","additionalProperties":{"type":"integer"}}}},"CreateClaimRequestInput":{"type":"object","required":["entityType","entityId"],"properties":{"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"supportingDocuments":{"type":"array","items":{"type":"string","format":"uri"}},"requestNote":{"type":"string","maxLength":1000}}},"CreateBulkClaimInput":{"type":"object","required":["claims"],"properties":{"claims":{"type":"array","minItems":1,"maxItems":10,"items":{"$ref":"#/components/schemas/CreateClaimRequestInput"}}}},"CreateRemovalRequestInput":{"type":"object","required":["entityType","entityId"],"properties":{"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"requestNote":{"type":"string","maxLength":1000}}},"ProcessRequestInput":{"type":"object","properties":{"reviewNote":{"type":"string","maxLength":1000}}},"BulkProcessInput":{"type":"object","required":["requestIds"],"properties":{"requestIds":{"type":"array","minItems":1,"items":{"type":"string","format":"uuid"}},"reviewNote":{"type":"string","maxLength":1000}}},"BulkClaimResult":{"type":"object","properties":{"batchId":{"type":"string","format":"uuid"},"success":{"type":"array","items":{"$ref":"#/components/schemas/OwnershipRequest"}},"failed":{"type":"array","items":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid"},"error":{"type":"string"}}}}}},"BulkProcessResult":{"type":"object","properties":{"success":{"type":"array","items":{"type":"string","format":"uuid"}},"failed":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"error":{"type":"string"}}}}}},"EmailLogStatus":{"type":"string","enum":["sent","failed"],"description":"Statut de l'envoi email"},"EmailLog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"to":{"type":"string","format":"email","example":"user@example.com"},"from":{"type":"string","example":"Reservababi <noreply@reservababi.com>"},"subject":{"type":"string","example":"Bienvenue sur Reservababi !"},"htmlBody":{"type":"string","description":"Contenu HTML de l'email"},"templateType":{"type":"string","nullable":true,"example":"welcome","description":"Type de template (welcome, password_reset, 2fa_code, etc.)"},"status":{"$ref":"#/components/schemas/EmailLogStatus"},"resendId":{"type":"string","nullable":true,"description":"ID Resend de l'email"},"errorMessage":{"type":"string","nullable":true},"userId":{"type":"string","format":"uuid","nullable":true},"user":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"email":{"type":"string","format":"email"}}},"metadata":{"type":"object","nullable":true},"sentAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"EmailLogStats":{"type":"object","properties":{"total":{"type":"integer","example":1250},"sent":{"type":"integer","example":1200},"failed":{"type":"integer","example":50},"byTemplateType":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","example":"welcome"},"count":{"type":"integer","example":350}}}}}},"PlatformNotificationType":{"type":"string","enum":["claim_submitted","claim_approved","claim_rejected","removal_submitted","removal_approved","removal_rejected","new_claim_request","new_removal_request","kyc_approved","kyc_rejected","system_announcement","platform_support_ticket_resolved"],"description":"Type de notification plateforme"},"PlatformNotification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/PlatformNotificationType"},"title":{"type":"string"},"message":{"type":"string"},"ownershipRequestId":{"type":"string","format":"uuid","nullable":true},"entityType":{"$ref":"#/components/schemas/ClaimableEntityType"},"entityId":{"type":"string","format":"uuid","nullable":true},"emailSent":{"type":"boolean"},"emailSentAt":{"type":"string","format":"date-time","nullable":true},"pushSent":{"type":"boolean"},"pushSentAt":{"type":"string","format":"date-time","nullable":true},"isRead":{"type":"boolean"},"readAt":{"type":"string","format":"date-time","nullable":true},"metadata":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"UnreadCountResponse":{"type":"object","properties":{"count":{"type":"integer"}}},"MarkReadResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true}}},"MarkAllReadResponse":{"type":"object","properties":{"markedCount":{"type":"integer"}}},"PaymentSession":{"type":"object","properties":{"sessionId":{"type":"string","description":"ID de session de paiement"},"paymentUrl":{"type":"string","format":"uri","description":"URL de paiement"},"reference":{"type":"string","description":"Reference de paiement"},"amount":{"type":"number","description":"Montant"},"currency":{"type":"string","description":"Devise"},"method":{"type":"string","description":"Methode de paiement"}}},"Payment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid","nullable":true},"cartId":{"type":"string","nullable":true},"amount":{"type":"number","description":"Montant du paiement"},"currency":{"type":"string","example":"XOF"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","REFUNDED"],"description":"Statut du paiement"},"method":{"type":"string","description":"Methode de paiement (CARD, MOBILE_MONEY, WALLET, BANK_TRANSFER)"},"provider":{"type":"string","nullable":true,"description":"Fournisseur de paiement"},"externalId":{"type":"string","nullable":true,"description":"ID externe du provider"},"reference":{"type":"string","description":"Reference interne unique"},"metadata":{"type":"object","nullable":true},"errorMessage":{"type":"string","nullable":true},"paidAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"PaymentWithReservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid","nullable":true},"amount":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","REFUNDED"]},"method":{"type":"string"},"provider":{"type":"string","nullable":true},"externalId":{"type":"string","nullable":true},"reference":{"type":"string"},"metadata":{"type":"object","nullable":true},"errorMessage":{"type":"string","nullable":true},"paidAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"reservation":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"reference":{"type":"string"},"type":{"type":"string"}}}}},"InitiatePaymentInput":{"type":"object","required":["reservationId","method"],"properties":{"reservationId":{"type":"string","format":"uuid","description":"ID de la reservation"},"method":{"type":"string","enum":["card","mobile_money","wallet","bank_transfer"],"description":"Methode de paiement"},"operator":{"type":"string","enum":["orange","mtn","wave"],"nullable":true,"description":"Operateur mobile money (requis si method = mobile_money)"},"currency":{"type":"string","enum":["XOF","XAF","USD","GNF","CDF"],"default":"XOF","description":"Devise du paiement"}}},"VerifyPaymentResponse":{"type":"object","properties":{"status":{"type":"string","description":"Statut du paiement (completed, pending, failed)"},"paid":{"type":"boolean","description":"Indique si le paiement est effectue"}}},"RefundInput":{"type":"object","properties":{"amount":{"type":"number","minimum":0,"description":"Montant du remboursement (partiel). Si omis, remboursement total."},"reason":{"type":"string","maxLength":500,"description":"Raison du remboursement"}}},"RefundResult":{"type":"object","properties":{"success":{"type":"boolean","description":"Indique si le remboursement a reussi"},"refundId":{"type":"string","description":"ID du remboursement chez le provider"},"amount":{"type":"number","description":"Montant rembourse"}}},"SavedPaymentMethod":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"label":{"type":"string","nullable":true,"description":"Label personnalise","example":"Mon Orange Money"},"type":{"type":"string","default":"MOBILE_MONEY","description":"Type de methode de paiement"},"provider":{"type":"string","enum":["ORANGE_MONEY","MTN_MONEY","WAVE","MOOV_MONEY"],"description":"Fournisseur de paiement"},"phoneNumber":{"type":"string","description":"Numero de telephone associe","example":"+2250700000000"},"isDefault":{"type":"boolean","description":"Methode par defaut"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateSavedPaymentMethodInput":{"type":"object","required":["provider","phoneNumber"],"properties":{"provider":{"type":"string","enum":["ORANGE_MONEY","MTN_MONEY","WAVE","MOOV_MONEY"],"description":"Fournisseur de paiement"},"phoneNumber":{"type":"string","minLength":8,"maxLength":20,"description":"Numero de telephone (min 8, max 20 caracteres)","example":"+2250700000000"},"label":{"type":"string","maxLength":50,"description":"Label personnalise (optionnel)","example":"Mon Orange Money"}}},"UpdateSavedPaymentMethodInput":{"type":"object","properties":{"label":{"type":"string","maxLength":50,"nullable":true,"description":"Label personnalise"},"isDefault":{"type":"boolean","description":"Definir comme methode par defaut"}}},"Favorite":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"entityType":{"type":"string","enum":["hotel","restaurant","establishment","parking","rental_agency","event"],"description":"Type d'entite mise en favori"},"entityId":{"type":"string","format":"uuid","description":"ID de l'entite"},"createdAt":{"type":"string","format":"date-time"}}},"AddFavoriteInput":{"type":"object","required":["entityType","entityId"],"properties":{"entityType":{"type":"string","enum":["hotel","restaurant","establishment","parking","rental_agency","event"],"description":"Type d'entite a ajouter en favori"},"entityId":{"type":"string","format":"uuid","description":"ID de l'entite"}}},"FavoriteCheck":{"type":"object","properties":{"isFavorited":{"type":"boolean","description":"Indique si l'entite est en favori"},"favoriteId":{"type":"string","format":"uuid","nullable":true,"description":"ID du favori si existe"}}},"FavoriteStats":{"type":"object","properties":{"total":{"type":"integer","description":"Nombre total de favoris"},"byType":{"type":"object","properties":{"hotel":{"type":"integer"},"restaurant":{"type":"integer"},"establishment":{"type":"integer"},"parking":{"type":"integer"},"rental_agency":{"type":"integer"},"event":{"type":"integer"}},"description":"Nombre de favoris par type"}}},"Shop":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ownerId":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Nom de la boutique"},"slug":{"type":"string","description":"Slug URL unique"},"description":{"type":"string","nullable":true,"description":"Description de la boutique"},"logo":{"type":"string","format":"uri","nullable":true,"description":"URL du logo"},"coverImage":{"type":"string","format":"uri","nullable":true,"description":"URL de l'image de couverture"},"images":{"type":"array","items":{"type":"string","format":"uri"},"description":"Galerie d'images (max 10)"},"primaryColor":{"type":"string","nullable":true,"description":"Couleur principale (hex)","example":"#FF5733"},"accentColor":{"type":"string","nullable":true,"description":"Couleur d'accent (hex)","example":"#33FF57"},"phone":{"type":"string","nullable":true,"description":"Telephone de contact"},"email":{"type":"string","format":"email","nullable":true,"description":"Email de contact"},"website":{"type":"string","format":"uri","nullable":true,"description":"Site web"},"socialLinks":{"type":"object","nullable":true,"properties":{"facebook":{"type":"string","format":"uri","nullable":true},"instagram":{"type":"string","format":"uri","nullable":true},"twitter":{"type":"string","format":"uri","nullable":true},"whatsapp":{"type":"string","nullable":true}}},"isPublic":{"type":"boolean","description":"Boutique visible publiquement"},"qrCodeData":{"type":"string","nullable":true,"description":"Donnees du QR code"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateShopInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Nom de la boutique"},"description":{"type":"string","maxLength":2000,"nullable":true,"description":"Description"},"logo":{"type":"string","format":"uri","nullable":true,"description":"URL du logo"},"coverImage":{"type":"string","format":"uri","nullable":true,"description":"URL de l'image de couverture"},"images":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10,"description":"Galerie d'images"},"primaryColor":{"type":"string","nullable":true,"description":"Couleur principale (hex #RRGGBB)"},"accentColor":{"type":"string","nullable":true,"description":"Couleur d'accent (hex #RRGGBB)"},"phone":{"type":"string","maxLength":20,"nullable":true,"description":"Telephone"},"email":{"type":"string","format":"email","nullable":true,"description":"Email"},"website":{"type":"string","format":"uri","nullable":true,"description":"Site web"},"socialLinks":{"type":"object","nullable":true,"properties":{"facebook":{"type":"string","format":"uri","nullable":true},"instagram":{"type":"string","format":"uri","nullable":true},"twitter":{"type":"string","format":"uri","nullable":true},"whatsapp":{"type":"string","nullable":true}}},"isPublic":{"type":"boolean","description":"Rendre la boutique publique"}}},"UpdateShopInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Nom de la boutique"},"description":{"type":"string","maxLength":2000,"nullable":true},"logo":{"type":"string","format":"uri","nullable":true},"coverImage":{"type":"string","format":"uri","nullable":true},"images":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10},"primaryColor":{"type":"string","nullable":true},"accentColor":{"type":"string","nullable":true},"phone":{"type":"string","maxLength":20,"nullable":true},"email":{"type":"string","format":"email","nullable":true},"website":{"type":"string","format":"uri","nullable":true},"socialLinks":{"type":"object","nullable":true,"properties":{"facebook":{"type":"string","format":"uri","nullable":true},"instagram":{"type":"string","format":"uri","nullable":true},"twitter":{"type":"string","format":"uri","nullable":true},"whatsapp":{"type":"string","nullable":true}}},"isPublic":{"type":"boolean"}}},"ShopServices":{"type":"object","properties":{"hotels":{"type":"array","items":{"type":"object"},"description":"Liste des hotels"},"restaurants":{"type":"array","items":{"type":"object"},"description":"Liste des restaurants"},"rentalAgencies":{"type":"array","items":{"type":"object"},"description":"Liste des agences de location"},"parkings":{"type":"array","items":{"type":"object"},"description":"Liste des parkings"},"events":{"type":"array","items":{"type":"object"},"description":"Liste des evenements"}}},"ShopServicesCount":{"type":"object","properties":{"hotels":{"type":"integer"},"restaurants":{"type":"integer"},"rentalAgencies":{"type":"integer"},"parkings":{"type":"integer"},"events":{"type":"integer"},"total":{"type":"integer"}}},"ToggleVisibilityInput":{"type":"object","properties":{"isPublic":{"type":"boolean","description":"Rendre la boutique publique ou privee"}}},"CartItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["hotel","restaurant","food_order","vehicle","parking","appointment","event","transport","vtc"],"description":"Type de service"},"entityId":{"type":"string","format":"uuid","description":"ID de l'entite"},"entityName":{"type":"string","description":"Nom de l'entite"},"entityImage":{"type":"string","format":"uri","nullable":true,"description":"Image de l'entite"},"entityOwnerId":{"type":"string","format":"uuid","nullable":true,"description":"ID du proprietaire"},"itemType":{"type":"string","description":"Type d'article (room, table, vehicle, spot, service, menuItem)"},"itemId":{"type":"string","format":"uuid","description":"ID de l'article"},"itemName":{"type":"string","description":"Nom de l'article"},"quantity":{"type":"integer","minimum":1,"description":"Quantite"},"unitPrice":{"type":"number","minimum":0,"description":"Prix unitaire"},"startDate":{"type":"string","format":"date-time","nullable":true,"description":"Date de debut"},"endDate":{"type":"string","format":"date-time","nullable":true,"description":"Date de fin"},"guestCount":{"type":"integer","minimum":1,"nullable":true,"description":"Nombre d'invites"},"extras":{"type":"object","nullable":true,"description":"Options supplementaires"},"notes":{"type":"string","nullable":true,"description":"Notes"},"providerId":{"type":"string","format":"uuid","nullable":true,"description":"ID du prestataire"}}},"Cart":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CartItem"}},"promoCode":{"type":"string","nullable":true,"description":"Code promo applique"},"subtotal":{"type":"number","description":"Sous-total avant reduction"},"discount":{"type":"number","description":"Montant de la reduction"},"total":{"type":"number","description":"Total a payer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AddCartItemInput":{"type":"object","required":["type","entityId","entityName","itemType","itemId","itemName","unitPrice"],"properties":{"type":{"type":"string","enum":["hotel","restaurant","food_order","vehicle","parking","appointment","event","transport","vtc"],"description":"Type de service"},"entityId":{"type":"string","format":"uuid","description":"ID de l'entite"},"entityName":{"type":"string","minLength":1,"maxLength":200,"description":"Nom de l'entite"},"entityImage":{"type":"string","format":"uri","description":"Image de l'entite"},"entityOwnerId":{"type":"string","format":"uuid","description":"ID du proprietaire (optionnel, sera recherche automatiquement)"},"itemType":{"type":"string","minLength":1,"maxLength":50,"description":"Type d'article"},"itemId":{"type":"string","format":"uuid","description":"ID de l'article"},"itemName":{"type":"string","minLength":1,"maxLength":200,"description":"Nom de l'article"},"quantity":{"type":"integer","minimum":1,"default":1,"description":"Quantite"},"unitPrice":{"type":"number","minimum":0,"description":"Prix unitaire"},"startDate":{"type":"string","format":"date-time","description":"Date de debut"},"endDate":{"type":"string","format":"date-time","description":"Date de fin"},"guestCount":{"type":"integer","minimum":1,"default":1,"description":"Nombre d'invites"},"extras":{"type":"object","description":"Options supplementaires"},"notes":{"type":"string","maxLength":500,"description":"Notes"},"providerId":{"type":"string","format":"uuid","description":"ID du prestataire"}}},"UpdateCartItemInput":{"type":"object","properties":{"quantity":{"type":"integer","minimum":1,"description":"Quantite"},"startDate":{"type":"string","format":"date-time","description":"Date de debut"},"endDate":{"type":"string","format":"date-time","description":"Date de fin"},"guestCount":{"type":"integer","minimum":1,"description":"Nombre d'invites"},"extras":{"type":"object","description":"Options supplementaires"},"notes":{"type":"string","maxLength":500,"description":"Notes"},"providerId":{"type":"string","format":"uuid","description":"ID du prestataire"}}},"ApplyPromoCodeInput":{"type":"object","required":["code"],"properties":{"code":{"type":"string","minLength":1,"maxLength":50,"description":"Code promotionnel"}}},"InitiateCartPaymentInput":{"type":"object","required":["method"],"properties":{"method":{"type":"string","enum":["card","mobile_money","wallet","bank_transfer"],"description":"Methode de paiement"},"operator":{"type":"string","enum":["orange","mtn","wave"],"description":"Operateur mobile money (requis si method = mobile_money)"},"currency":{"type":"string","enum":["XOF","XAF","USD","GNF","CDF"],"default":"XOF","description":"Devise de paiement"},"phone":{"type":"string","minLength":8,"maxLength":20,"description":"Numero de telephone (requis pour mobile money USSD)"}}},"CheckoutResult":{"type":"object","properties":{"checkoutGroupId":{"type":"string","description":"ID du groupe de checkout"},"reservations":{"type":"array","items":{"type":"object"},"description":"Reservations creees"},"total":{"type":"number","description":"Montant total"}}},"PaymentVerification":{"type":"object","properties":{"status":{"type":"string","enum":["pending","completed","failed","cancelled"],"description":"Statut du paiement"},"reference":{"type":"string","description":"Reference de paiement"},"amount":{"type":"number","description":"Montant paye"},"currency":{"type":"string","description":"Devise"}}},"InvoiceSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"checkoutGroupId":{"type":"string","description":"ID du groupe de checkout"},"type":{"type":"string","enum":["global","owner"],"description":"Type de facture (globale ou par proprietaire)"},"ownerId":{"type":"string","format":"uuid","nullable":true,"description":"ID du proprietaire (si type = owner)"},"ownerName":{"type":"string","nullable":true,"description":"Nom du proprietaire"},"amount":{"type":"number","description":"Montant de la facture"},"currency":{"type":"string","description":"Devise","example":"XOF"},"status":{"type":"string","enum":["pending","paid","cancelled"],"description":"Statut de la facture"},"createdAt":{"type":"string","format":"date-time"}}},"ScanInvoiceQRInput":{"type":"object","required":["qrData"],"properties":{"qrData":{"type":"string","minLength":1,"description":"Donnees du QR code scanne"}}},"ScanInvoiceQRResult":{"type":"object","properties":{"valid":{"type":"boolean","description":"QR code valide"},"checkoutGroupId":{"type":"string","description":"ID du groupe de checkout"},"ownerId":{"type":"string","format":"uuid","description":"ID du proprietaire"},"reservations":{"type":"array","items":{"type":"object"},"description":"Reservations associees"},"amount":{"type":"number","description":"Montant total"},"currency":{"type":"string","description":"Devise"}}},"Country":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Nom du pays","example":"Senegal"},"isoAlpha2":{"type":"string","description":"Code ISO alpha-2","example":"SN"},"isoAlpha3":{"type":"string","description":"Code ISO alpha-3","example":"SEN"},"dialCode":{"type":"string","description":"Indicatif telephonique","example":"+221"},"currency":{"type":"string","description":"Code devise","example":"XOF"},"flag":{"type":"string","nullable":true,"description":"Emoji drapeau","example":"🇸🇳"},"isActive":{"type":"boolean","description":"Pays actif dans l'application"}}},"DialCodeEntry":{"type":"object","properties":{"dialCode":{"type":"string","description":"Indicatif telephonique","example":"+221"},"country":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Senegal"},"isoAlpha2":{"type":"string","example":"SN"},"flag":{"type":"string","nullable":true,"example":"🇸🇳"}}}}},"Permission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","description":"Code unique de la permission","example":"users.read"},"name":{"type":"string","description":"Nom lisible","example":"Lire les utilisateurs"},"description":{"type":"string","nullable":true,"description":"Description de la permission"},"module":{"type":"string","description":"Module auquel appartient la permission","example":"users"}}},"GroupedPermissions":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Permission"}},"description":"Permissions groupees par module"},"PermissionMatrix":{"type":"object","properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/Permission"},"description":"Liste de toutes les permissions"},"matrix":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","format":"uuid"}},"description":"Map role -> liste de permission IDs"},"roles":{"type":"array","items":{"type":"string"},"description":"Liste des roles editables"}}},"RolePermissions":{"type":"object","properties":{"role":{"type":"string","description":"Nom du role"},"permissions":{"type":"array","items":{"$ref":"#/components/schemas/Permission"}}}},"SetPermissionsInput":{"type":"object","required":["permissionIds"],"properties":{"permissionIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Liste des IDs de permissions a attribuer au role"}}},"TogglePermissionInput":{"type":"object","required":["permissionId"],"properties":{"permissionId":{"type":"string","format":"uuid","description":"ID de la permission a activer/desactiver"}}},"TogglePermissionResult":{"type":"object","properties":{"action":{"type":"string","enum":["granted","revoked"],"description":"Action effectuee"},"permissionId":{"type":"string","format":"uuid"}}},"RefundItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reservationItemId":{"type":"string","format":"uuid"},"amount":{"type":"number","description":"Montant du remboursement demande"}}},"RefundRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"reservationId":{"type":"string","format":"uuid"},"reason":{"type":"string","description":"Raison du remboursement"},"status":{"type":"string","enum":["pending","approved","rejected","refunded","cancelled"],"description":"Statut de la demande"},"totalAmount":{"type":"number","description":"Montant total du remboursement"},"reviewNote":{"type":"string","nullable":true,"description":"Note de l'admin"},"reviewedBy":{"type":"string","format":"uuid","nullable":true},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"$ref":"#/components/schemas/RefundItem"}}}},"CreateRefundRequestInput":{"type":"object","required":["reservationId","reason","items"],"properties":{"reservationId":{"type":"string","format":"uuid","description":"ID de la reservation"},"reason":{"type":"string","minLength":10,"maxLength":2000,"description":"Raison du remboursement (min 10 caracteres)"},"items":{"type":"array","minItems":1,"items":{"type":"object","required":["reservationItemId","amount"],"properties":{"reservationItemId":{"type":"string","format":"uuid","description":"ID de l'element de reservation"},"amount":{"type":"number","minimum":0,"exclusiveMinimum":true,"description":"Montant a rembourser"}}},"description":"Elements a rembourser (au moins un)"}}},"ApproveRefundInput":{"type":"object","properties":{"reviewNote":{"type":"string","maxLength":2000,"description":"Note optionnelle de l'admin"}}},"RejectRefundInput":{"type":"object","required":["reviewNote"],"properties":{"reviewNote":{"type":"string","minLength":5,"maxLength":2000,"description":"Raison du rejet (obligatoire)"}}},"RefundStats":{"type":"object","properties":{"total":{"type":"integer","description":"Nombre total de demandes"},"pending":{"type":"integer","description":"Demandes en attente"},"approved":{"type":"integer","description":"Demandes approuvees"},"rejected":{"type":"integer","description":"Demandes rejetees"},"refunded":{"type":"integer","description":"Remboursements effectues"},"totalAmount":{"type":"number","description":"Montant total rembourse"}}},"FraudAlert":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["rapid_cancellations","excessive_refunds","repeated_payment_failures","suspicious_account","high_value_anomaly","velocity_abuse"],"description":"Type de fraude detectee"},"description":{"type":"string","description":"Description de l'alerte"},"severity":{"type":"string","enum":["warning","error","critical"],"description":"Niveau de severite"},"status":{"type":"string","enum":["open","investigating","resolved","false_positive"],"description":"Statut de l'alerte"},"metadata":{"type":"object","nullable":true,"description":"Donnees supplementaires"},"resolvedBy":{"type":"string","format":"uuid","nullable":true},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"notes":{"type":"string","nullable":true,"description":"Notes de l'admin"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"FraudAlertActionInput":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["investigating","resolved","false_positive"],"description":"Nouveau statut de l'alerte"},"notes":{"type":"string","maxLength":2000,"description":"Notes de l'admin"}}},"FraudStats":{"type":"object","properties":{"totalAlerts":{"type":"integer","description":"Nombre total d'alertes"},"bySeverity":{"type":"object","properties":{"warning":{"type":"integer"},"error":{"type":"integer"},"critical":{"type":"integer"}},"description":"Alertes par niveau de severite"},"byType":{"type":"object","additionalProperties":{"type":"integer"},"description":"Alertes par type de fraude"},"blockedTransactions":{"type":"integer","description":"Nombre de transactions bloquees"},"topFlaggedUsers":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"alertCount":{"type":"integer"}}},"description":"Utilisateurs les plus signales"},"dailyAlerts":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"count":{"type":"integer"}}},"description":"Alertes par jour"}}},"UserFraudHistory":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstname":{"type":"string"},"lastname":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"alerts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string"},"metadata":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"recentPayments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"amount":{"type":"number"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}},"recentRefunds":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"totalAmount":{"type":"number"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}},"recentCancellations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"total":{"type":"number"},"cancelledAt":{"type":"string","format":"date-time","nullable":true},"cancellationReason":{"type":"string","nullable":true}}}},"summary":{"type":"object","properties":{"totalAlerts":{"type":"integer","description":"Nombre total d'alertes"},"failedPayments30d":{"type":"integer","description":"Paiements echoues (30 jours)"},"refunds30d":{"type":"integer","description":"Remboursements (30 jours)"},"cancellations30d":{"type":"integer","description":"Annulations (30 jours)"},"accountAge":{"type":"integer","description":"Age du compte en jours"}}}}},"ModerationItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contentType":{"type":"string","enum":["REVIEW","MESSAGE","IMAGE"],"description":"Type de contenu signale"},"contentId":{"type":"string","format":"uuid","description":"ID du contenu original"},"status":{"type":"string","enum":["PENDING","APPROVED","REJECTED","AUTO_APPROVED","AUTO_REJECTED"],"description":"Statut de la moderation"},"reason":{"type":"string","nullable":true,"description":"Raison du signalement"},"reviewedBy":{"type":"string","format":"uuid","nullable":true},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"note":{"type":"string","nullable":true,"description":"Note du moderateur"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ModerationActionInput":{"type":"object","properties":{"note":{"type":"string","maxLength":2000,"description":"Note optionnelle du moderateur"}}},"ModerationStats":{"type":"object","properties":{"total":{"type":"integer","description":"Nombre total d'elements"},"pending":{"type":"integer","description":"En attente de moderation"},"approved":{"type":"integer","description":"Elements approuves"},"rejected":{"type":"integer","description":"Elements rejetes"},"autoApproved":{"type":"integer","description":"Approuves automatiquement"},"autoRejected":{"type":"integer","description":"Rejetes automatiquement"},"byContentType":{"type":"object","properties":{"REVIEW":{"type":"integer"},"MESSAGE":{"type":"integer"},"IMAGE":{"type":"integer"}},"description":"Repartition par type de contenu"}}},"ModerationDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contentType":{"type":"string","enum":["REVIEW","MESSAGE","IMAGE"]},"contentId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","APPROVED","REJECTED","AUTO_APPROVED","AUTO_REJECTED"]},"reason":{"type":"string","nullable":true},"reviewedBy":{"type":"string","format":"uuid","nullable":true},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"note":{"type":"string","nullable":true},"content":{"type":"object","description":"Apercu du contenu original"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"BrevoSyncStatus":{"type":"object","properties":{"totalUsers":{"type":"integer","example":1500},"syncedContacts":{"type":"integer","example":1480},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["idle","syncing","error"],"example":"idle"}}},"BrevoTrackViewInput":{"type":"object","required":["entityType","entityId","entityName"],"properties":{"entityType":{"type":"string","example":"hotel"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string","example":"Hotel Ibis Abidjan"}}},"BycDocumentType":{"type":"string","enum":["registre_commerce","licence_debit_boisson","bail_local","titre_propriete","licence_exploitation_hoteliere","autorisation_municipale","carte_grise","assurance_vehicule","licence_professionnelle","certificat_hygiene","visite_technique","autre"],"description":"Type de document BYC"},"BycStatus":{"type":"string","enum":["pending","submitted","approved","rejected"],"description":"Statut de la verification BYC"},"BycDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"documentType":{"$ref":"#/components/schemas/BycDocumentType"},"documentNumber":{"type":"string","nullable":true},"fileUrl":{"type":"string","format":"uri"},"comment":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected"]},"createdAt":{"type":"string","format":"date-time"}}},"BycSubmission":{"type":"object","properties":{"serviceType":{"type":"string","example":"hotel"},"entityId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/BycStatus"},"documents":{"type":"array","items":{"$ref":"#/components/schemas/BycDocument"}},"submittedAt":{"type":"string","format":"date-time","nullable":true},"reviewedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"BycDocumentConfig":{"type":"object","properties":{"serviceType":{"type":"string"},"requiredDocuments":{"type":"array","items":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/BycDocumentType"},"label":{"type":"string"},"required":{"type":"boolean"}}}}}},"BycStats":{"type":"object","properties":{"total":{"type":"integer"},"pending":{"type":"integer"},"submitted":{"type":"integer"},"approved":{"type":"integer"},"rejected":{"type":"integer"}}},"FileBankItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Guide touristique PDF"},"description":{"type":"string","nullable":true},"fileUrl":{"type":"string","format":"uri"},"fileName":{"type":"string"},"fileSize":{"type":"integer","description":"Taille en octets"},"mimeType":{"type":"string","example":"application/pdf"},"thumbnailUrl":{"type":"string","format":"uri","nullable":true},"isFree":{"type":"boolean","default":false},"price":{"type":"number","nullable":true,"example":2500},"createdAt":{"type":"string","format":"date-time"}}},"FileBankPack":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Pack complet"},"description":{"type":"string","nullable":true},"price":{"type":"number","example":5000},"items":{"type":"array","items":{"$ref":"#/components/schemas/FileBankItem"}},"createdAt":{"type":"string","format":"date-time"}}},"FileBank":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Documents hotel"},"description":{"type":"string","nullable":true},"eventId":{"type":"string","format":"uuid","nullable":true},"appointmentId":{"type":"string","format":"uuid","nullable":true},"serviceId":{"type":"string","format":"uuid","nullable":true},"requiresTicket":{"type":"boolean","default":false},"requiresReservation":{"type":"boolean","default":false},"items":{"type":"array","items":{"$ref":"#/components/schemas/FileBankItem"}},"packs":{"type":"array","items":{"$ref":"#/components/schemas/FileBankPack"}},"createdAt":{"type":"string","format":"date-time"}}},"FileBankCreateInput":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"eventId":{"type":"string","format":"uuid"},"appointmentId":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"},"requiresTicket":{"type":"boolean"},"requiresReservation":{"type":"boolean"}}},"FileBankItemInput":{"type":"object","required":["title","fileUrl","fileName","fileSize","mimeType"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"fileUrl":{"type":"string","format":"uri"},"fileName":{"type":"string"},"fileSize":{"type":"integer"},"mimeType":{"type":"string"},"thumbnailUrl":{"type":"string","format":"uri"},"isFree":{"type":"boolean"},"price":{"type":"number"}}},"FileBankPurchase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"itemId":{"type":"string","format":"uuid","nullable":true},"packId":{"type":"string","format":"uuid","nullable":true},"amount":{"type":"number"},"purchasedAt":{"type":"string","format":"date-time"}}},"ParrainStats":{"type":"object","properties":{"referralCode":{"type":"string","example":"REF-A1B2C3D4"},"totalFilleuls":{"type":"integer","example":12},"activeFilleuls":{"type":"integer","example":8},"totalCommissionEarned":{"type":"number","example":150000},"pendingCommission":{"type":"number","example":25000}}},"Filleul":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string","example":"Jean"},"lastname":{"type":"string","example":"Dupont"},"email":{"type":"string","format":"email"},"joinedAt":{"type":"string","format":"date-time"},"totalRevenue":{"type":"number","example":500000},"commissionEarned":{"type":"number","example":10000}}},"ParrainAdminOverview":{"type":"object","properties":{"totalParrains":{"type":"integer"},"totalFilleuls":{"type":"integer"},"totalCommissionsPaid":{"type":"number"},"parrains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstname":{"type":"string"},"lastname":{"type":"string"},"referralCode":{"type":"string"},"filleulsCount":{"type":"integer"},"totalCommission":{"type":"number"}}}}}},"PublicationEntityType":{"type":"string","enum":["hotel","restaurant","parking","rental_agency","establishment","event"],"description":"Type d'entite publiable"},"PublicationStatus":{"type":"string","enum":["draft","pending","published","rejected"]},"PublicationCompleteness":{"type":"object","properties":{"isComplete":{"type":"boolean","example":false},"missingFields":{"type":"array","items":{"type":"string"},"example":["photos","description","pricing"]},"completionPercentage":{"type":"integer","example":75}}},"PendingPublication":{"type":"object","properties":{"entityType":{"$ref":"#/components/schemas/PublicationEntityType"},"entityId":{"type":"string","format":"uuid"},"entityName":{"type":"string","example":"Hotel Ivoire"},"ownerName":{"type":"string","example":"Jean Dupont"},"status":{"$ref":"#/components/schemas/PublicationStatus"},"submittedAt":{"type":"string","format":"date-time"}}},"SecurityAlertSeverity":{"type":"string","enum":["low","medium","high","critical"]},"SecurityAlertStatus":{"type":"string","enum":["new","acknowledged","resolved","dismissed"]},"SecurityAlert":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","example":"brute_force"},"severity":{"$ref":"#/components/schemas/SecurityAlertSeverity"},"status":{"$ref":"#/components/schemas/SecurityAlertStatus"},"message":{"type":"string","example":"Tentatives de connexion multiples echouees"},"metadata":{"type":"object","nullable":true},"userId":{"type":"string","format":"uuid","nullable":true},"ipAddress":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"acknowledgedAt":{"type":"string","format":"date-time","nullable":true},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"SecurityAlertStats":{"type":"object","properties":{"total":{"type":"integer"},"new":{"type":"integer"},"acknowledged":{"type":"integer"},"resolved":{"type":"integer"},"dismissed":{"type":"integer"},"bySeverity":{"type":"object","properties":{"low":{"type":"integer"},"medium":{"type":"integer"},"high":{"type":"integer"},"critical":{"type":"integer"}}}}},"ServicePhase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Consultation initiale"},"description":{"type":"string","nullable":true},"duration":{"type":"integer","description":"Duree en minutes","example":30},"price":{"type":"number","nullable":true,"example":15000},"phaseOrder":{"type":"integer","example":1},"dayOffset":{"type":"integer","nullable":true,"description":"Decalage en jours par rapport a la phase precedente"},"createdAt":{"type":"string","format":"date-time"}}},"ServicePhaseCreateInput":{"type":"object","required":["name","duration","phaseOrder"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"duration":{"type":"integer","minimum":1},"price":{"type":"number"},"phaseOrder":{"type":"integer","minimum":1},"dayOffset":{"type":"integer"}}},"MultiPhaseToggle":{"type":"object","required":["isMultiPhase"],"properties":{"isMultiPhase":{"type":"boolean"},"pricingMode":{"type":"string","enum":["per_phase","total"],"description":"Mode de tarification"}}},"TransportAgency":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"UTB Transport"},"slug":{"type":"string","example":"utb-transport"},"description":{"type":"string","nullable":true},"logo":{"type":"string","format":"uri","nullable":true},"status":{"type":"string","enum":["draft","pending","active","suspended"]},"ownerId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"TransportStation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Gare routiere Adjame"},"city":{"type":"string","example":"Abidjan"},"address":{"type":"string","nullable":true},"latitude":{"type":"number","nullable":true},"longitude":{"type":"number","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"TransportRoute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agencyId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Abidjan - Yamoussoukro"},"departureStationId":{"type":"string","format":"uuid"},"arrivalStationId":{"type":"string","format":"uuid"},"estimatedDuration":{"type":"integer","description":"Duree estimee en minutes"},"distance":{"type":"number","nullable":true,"description":"Distance en km"},"stops":{"type":"array","items":{"$ref":"#/components/schemas/TransportStation"}},"createdAt":{"type":"string","format":"date-time"}}},"TransportVehicle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agencyId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Bus Confort 50 places"},"type":{"type":"string","example":"bus"},"capacity":{"type":"integer","example":50},"plateNumber":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"TransportTrip":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"vehicleId":{"type":"string","format":"uuid"},"departureAt":{"type":"string","format":"date-time"},"arrivalAt":{"type":"string","format":"date-time","nullable":true},"price":{"type":"number","example":5000},"availableSeats":{"type":"integer","example":35},"status":{"type":"string","enum":["scheduled","boarding","departed","arrived","cancelled"]},"route":{"$ref":"#/components/schemas/TransportRoute"},"vehicle":{"$ref":"#/components/schemas/TransportVehicle"},"createdAt":{"type":"string","format":"date-time"}}},"TransportBooking":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tripId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"seatNumber":{"type":"string","nullable":true},"passengerName":{"type":"string"},"passengerPhone":{"type":"string","nullable":true},"amount":{"type":"number","example":5000},"status":{"type":"string","enum":["pending","confirmed","checked_in","cancelled","completed"]},"qrCode":{"type":"string","nullable":true},"trip":{"$ref":"#/components/schemas/TransportTrip"},"createdAt":{"type":"string","format":"date-time"}}},"TransportSchedule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"vehicleId":{"type":"string","format":"uuid"},"departureTime":{"type":"string","example":"08:00"},"daysOfWeek":{"type":"array","items":{"type":"integer"},"example":[1,2,3,4,5]},"isActive":{"type":"boolean"}}},"TransportServiceTier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agencyId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"VIP"},"description":{"type":"string","nullable":true},"priceMultiplier":{"type":"number","example":1.5},"amenities":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"}}},"TransportStats":{"type":"object","properties":{"totalTrips":{"type":"integer"},"totalBookings":{"type":"integer"},"totalRevenue":{"type":"number"},"occupancyRate":{"type":"number","example":0.78}}},"VideoCallStatus":{"type":"string","enum":["scheduled","live","completed","cancelled"]},"VideoCall":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Consultation en ligne"},"slug":{"type":"string","example":"consultation-en-ligne-abc123"},"description":{"type":"string","nullable":true},"scheduledAt":{"type":"string","format":"date-time"},"duration":{"type":"integer","description":"Duree en minutes (1-480)","example":60},"status":{"$ref":"#/components/schemas/VideoCallStatus"},"isFree":{"type":"boolean","default":false},"price":{"type":"number","nullable":true,"example":10000},"requiresReservation":{"type":"boolean","default":false},"maxSlots":{"type":"integer","nullable":true},"clientRecordingEnabled":{"type":"boolean","default":false},"eventId":{"type":"string","format":"uuid","nullable":true},"appointmentId":{"type":"string","format":"uuid","nullable":true},"serviceId":{"type":"string","format":"uuid","nullable":true},"ownerId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"VideoCallCreateInput":{"type":"object","required":["title","scheduledAt","duration"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"scheduledAt":{"type":"string","format":"date-time"},"duration":{"type":"integer","minimum":1,"maximum":480},"isFree":{"type":"boolean"},"price":{"type":"number"},"requiresReservation":{"type":"boolean"},"maxSlots":{"type":"integer"},"clientRecordingEnabled":{"type":"boolean"},"eventId":{"type":"string","format":"uuid"},"appointmentId":{"type":"string","format":"uuid"},"serviceId":{"type":"string","format":"uuid"}}},"VideoCallJoinRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"userName":{"type":"string"},"status":{"type":"string","enum":["pending","accepted","rejected"]},"createdAt":{"type":"string","format":"date-time"}}},"VideoCallRecording":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"videoCallId":{"type":"string","format":"uuid"},"fileUrl":{"type":"string","format":"uri"},"fileSize":{"type":"integer"},"duration":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}},"VideoCallChatMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"userName":{"type":"string"},"content":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"CampaignChannel":{"type":"string","enum":["sms","email","whatsapp"]},"CampaignStatus":{"type":"string","enum":["draft","sending","completed","failed"]},"CampaignContactInput":{"type":"object","properties":{"name":{"type":"string"},"phoneNumber":{"type":"string"},"email":{"type":"string","format":"email"}},"description":"Au moins phoneNumber OU email doit etre renseigne."},"CreateCampaignInput":{"type":"object","required":["name","channels"],"properties":{"name":{"type":"string","maxLength":200},"channels":{"type":"array","items":{"$ref":"#/components/schemas/CampaignChannel"},"minItems":1},"smsMessage":{"type":"string","maxLength":800},"emailSubject":{"type":"string","maxLength":300},"emailHtml":{"type":"string"},"whatsappMessage":{"type":"string","maxLength":1000},"contacts":{"type":"array","maxItems":5000,"items":{"$ref":"#/components/schemas/CampaignContactInput"},"description":"Liste inline de destinataires. Si absente, segmentId doit etre fourni."},"segmentId":{"type":"string","format":"uuid","description":"Audience evaluee a l'envoi (snapshot fige). Exclusive ou complementaire de contacts[]."},"templateId":{"type":"string","format":"uuid","description":"Template source (informatif). Le payload reste autoritaire."},"mode":{"type":"string","enum":["draft","send"],"default":"send","description":"send = envoi immediat (comportement historique). draft = creation sans envoi, lancer ensuite via POST /campaigns/:id/send."}}},"Campaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"channels":{"type":"array","items":{"$ref":"#/components/schemas/CampaignChannel"}},"smsMessage":{"type":"string","nullable":true},"emailSubject":{"type":"string","nullable":true},"emailHtml":{"type":"string","nullable":true},"whatsappMessage":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/CampaignStatus"},"totalCount":{"type":"integer"},"sentCount":{"type":"integer"},"failedCount":{"type":"integer"},"templateId":{"type":"string","format":"uuid","nullable":true},"segmentId":{"type":"string","format":"uuid","nullable":true},"segmentSnapshot":{"type":"object","nullable":true,"description":"Snapshot fige au passage draft->sending : {segmentId, version, criteriaVersion, source, count, resolvedAt, truncated}"},"segmentVersion":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CampaignTemplateVariable":{"type":"string","enum":["firstName","lastName","fullName","email","phone"]},"CampaignTemplate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"channels":{"type":"array","items":{"$ref":"#/components/schemas/CampaignChannel"}},"smsMessage":{"type":"string","nullable":true},"emailSubject":{"type":"string","nullable":true},"emailHtml":{"type":"string","nullable":true},"whatsappMessage":{"type":"string","nullable":true},"allowedVariables":{"type":"array","items":{"$ref":"#/components/schemas/CampaignTemplateVariable"}},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateCampaignTemplateInput":{"type":"object","required":["name","channels"],"properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"channels":{"type":"array","items":{"$ref":"#/components/schemas/CampaignChannel"},"minItems":1},"smsMessage":{"type":"string","maxLength":800},"emailSubject":{"type":"string","maxLength":300},"emailHtml":{"type":"string"},"whatsappMessage":{"type":"string","maxLength":1000},"allowedVariables":{"type":"array","items":{"$ref":"#/components/schemas/CampaignTemplateVariable"}},"isActive":{"type":"boolean","default":true}},"description":"Les variables {{xxx}} presentes dans les messages doivent etre listees dans allowedVariables."},"ApplyCampaignTemplateInput":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"segmentId":{"type":"string","format":"uuid"}}},"CampaignSegmentSource":{"type":"string","enum":["users","contacts"]},"CampaignUsersCriteria":{"type":"object","required":["source"],"properties":{"source":{"type":"string","enum":["users"]},"roles":{"type":"array","items":{"type":"string"}},"clientTypes":{"type":"array","items":{"type":"string","enum":["particulier","professionnel"]}},"countryIds":{"type":"array","items":{"type":"string","format":"uuid"}},"isActive":{"type":"boolean"},"isVerified":{"type":"boolean"},"hasPhone":{"type":"boolean"},"hasEmail":{"type":"boolean"},"createdAfter":{"type":"string","format":"date-time"},"createdBefore":{"type":"string","format":"date-time"}}},"CampaignContactsCriteria":{"type":"object","required":["source"],"properties":{"source":{"type":"string","enum":["contacts"]},"listIds":{"type":"array","items":{"type":"string","format":"uuid"}},"categories":{"type":"array","items":{"type":"string"}},"cities":{"type":"array","items":{"type":"string"}},"hasPhone":{"type":"boolean"},"hasEmail":{"type":"boolean"}}},"CampaignSegmentCriteria":{"oneOf":[{"$ref":"#/components/schemas/CampaignUsersCriteria"},{"$ref":"#/components/schemas/CampaignContactsCriteria"}],"discriminator":{"propertyName":"source"}},"CampaignSegment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"source":{"$ref":"#/components/schemas/CampaignSegmentSource"},"criteria":{"$ref":"#/components/schemas/CampaignSegmentCriteria"},"criteriaVersion":{"type":"integer"},"version":{"type":"integer"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateCampaignSegmentInput":{"type":"object","required":["name","criteria"],"properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"criteria":{"$ref":"#/components/schemas/CampaignSegmentCriteria"},"isActive":{"type":"boolean","default":true}}},"PreviewSegmentCountInput":{"type":"object","required":["criteria"],"properties":{"criteria":{"$ref":"#/components/schemas/CampaignSegmentCriteria"},"withSample":{"type":"boolean","default":false},"sampleSize":{"type":"integer","minimum":1,"maximum":20,"default":5}}},"SegmentCountResponse":{"type":"object","properties":{"count":{"type":"integer"},"truncatedAt":{"type":"integer","description":"Limite stricte de resolution pour l'envoi."},"sample":{"type":"array","description":"Echantillon anonymise (emails et telephones masques).","items":{"type":"object","properties":{"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phoneNumber":{"type":"string","nullable":true}}}}}},"CsvImportMetaResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object","properties":{"serviceType":{"type":"string","enum":["restaurant","hotel","event","transport","establishment","parking","rental_agency"]},"label":{"type":"string"},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"services"},"label":{"type":"string","example":"Prestations"}}}}}}}}}}},"CsvImportPreviewResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"serviceType":{"type":"string"},"section":{"type":"string"},"parentId":{"type":"string","format":"uuid"},"totalRows":{"type":"integer"},"validCount":{"type":"integer"},"invalidCount":{"type":"integer"},"duplicateNames":{"type":"array","items":{"type":"string"}},"missingImages":{"type":"array","items":{"type":"string"}},"unmatchedImages":{"type":"array","items":{"type":"string"}},"canCommit":{"type":"boolean","description":"Au moins une ligne valide (mode partial)"},"canCommitStrict":{"type":"boolean","description":"Aucune erreur ni image manquante (mode strict)"},"rows":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"Unauthorized":{"description":"Non authentifie - Token manquant ou invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Token d'authentification invalide","code":"UNAUTHORIZED"}}}},"Forbidden":{"description":"Acces refuse - Permissions insuffisantes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Vous n'avez pas les droits pour effectuer cette action","code":"FORBIDDEN"}}}},"NotFound":{"description":"Ressource non trouvee","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Ressource non trouvee","code":"NOT_FOUND"}}}},"ValidationError":{"description":"Erreur de validation des donnees","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Donnees invalides","code":"VALIDATION_ERROR","errors":{"email":["Format d'email invalide"]}}}}},"Conflict":{"description":"Conflit - Ressource existante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Cette ressource existe deja","code":"CONFLICT"}}}}}},"paths":{"/auth/login":{"post":{"tags":["Auth"],"summary":"Connexion utilisateur","description":"Authentifie un utilisateur avec email et mot de passe. Retourne les tokens JWT.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginInput"}}}},"responses":{"200":{"description":"Connexion réussie","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"202":{"description":"2FA requis","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TwoFactorRequiredResponse"}}}},"401":{"description":"Email ou mot de passe incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/auth/register":{"post":{"tags":["Auth"],"summary":"Inscription utilisateur","description":"Crée un nouveau compte utilisateur. Un email de vérification est envoyé.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterInput"}}}},"responses":{"201":{"description":"Inscription réussie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UserProfile"},"message":{"type":"string","example":"Inscription réussie. Vérifiez votre email."}}}}}},"409":{"description":"Email déjà utilisé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/auth/forgot-password":{"post":{"tags":["Auth"],"summary":"Mot de passe oublié","description":"Envoie un email avec un lien de réinitialisation du mot de passe.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordInput"}}}},"responses":{"200":{"description":"Email envoyé si l'adresse existe","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Si cet email existe, un lien de réinitialisation a été envoyé."}}}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/auth/reset-password":{"post":{"tags":["Auth"],"summary":"Réinitialiser le mot de passe","description":"Réinitialise le mot de passe avec le token reçu par email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordInput"}}}},"responses":{"200":{"description":"Mot de passe réinitialisé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Mot de passe réinitialisé avec succès"}}}}}},"400":{"description":"Token invalide ou expiré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/auth/refresh":{"post":{"tags":["Auth"],"summary":"Renouveler les tokens","description":"Utilise le refresh token pour obtenir de nouveaux tokens JWT.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenInput"}}}},"responses":{"200":{"description":"Tokens renouvelés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Refresh token invalide ou expiré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/logout":{"post":{"tags":["Auth"],"summary":"Déconnexion","description":"Invalide le token actuel et déconnecte l'utilisateur.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Déconnexion réussie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Déconnexion réussie"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/auth/logout-all":{"post":{"tags":["Auth"],"summary":"Déconnexion de tous les appareils","description":"Invalide tous les tokens de l'utilisateur sur tous les appareils.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Déconnexion de tous les appareils réussie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Déconnexion de tous les appareils réussie"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/auth/me":{"get":{"tags":["Auth"],"summary":"Obtenir le profil courant","description":"Retourne les informations de l'utilisateur connecté.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Profil utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UserProfile"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/2fa/verify":{"post":{"tags":["Auth"],"summary":"Vérifier le code 2FA","description":"Vérifie le code OTP pour compléter la connexion 2FA.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpInput"}}}},"responses":{"200":{"description":"2FA vérifié","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Code invalide ou expiré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/2fa/resend":{"post":{"tags":["Auth"],"summary":"Renvoyer le code 2FA","description":"Renvoie un nouveau code OTP par email/SMS.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Code renvoyé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Code renvoyé"}}}}}},"429":{"description":"Trop de tentatives","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/2fa/toggle":{"post":{"tags":["Auth"],"summary":"Activer/Désactiver le 2FA","description":"Active ou désactive l'authentification à deux facteurs.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Toggle2FAInput"}}}},"responses":{"200":{"description":"2FA mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"twoFactorEnabled":{"type":"boolean"}}},"message":{"type":"string","example":"2FA activé"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/password/change-password":{"post":{"tags":["Auth"],"summary":"Changer le mot de passe","description":"Change le mot de passe de l'utilisateur connecté.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordInput"}}}},"responses":{"200":{"description":"Mot de passe changé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Mot de passe modifié avec succès"}}}}}},"400":{"description":"Mot de passe actuel incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/users":{"get":{"tags":["Users"],"summary":"Liste des utilisateurs (Admin)","description":"Retourne la liste paginée de tous les utilisateurs.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10},"description":"Éléments par page"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom ou email"},{"name":"role","in":"query","schema":{"type":"string","enum":["superAdmin","admin","proprio","agent","organisateur","prestataire","client"]},"description":"Filtrer par rôle"},{"name":"isActive","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filtrer par statut actif"},{"name":"isVerified","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filtrer par vérification"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","email","firstname","lastname","role"],"default":"createdAt"},"description":"Champ de tri"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Ordre de tri"}],"responses":{"200":{"description":"Liste des utilisateurs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Users"],"summary":"Créer un utilisateur (Admin)","description":"Crée un nouvel utilisateur avec le rôle spécifié.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserInput"}}}},"responses":{"201":{"description":"Utilisateur créé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/User"},"message":{"type":"string","example":"Utilisateur créé avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/users/stats":{"get":{"tags":["Users"],"summary":"Statistiques utilisateurs (Admin)","description":"Retourne les statistiques des utilisateurs.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UserStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/users/{id}":{"get":{"tags":["Users"],"summary":"Détails d'un utilisateur (Admin)","description":"Retourne les détails d'un utilisateur spécifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"Détails utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/User"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Users"],"summary":"Modifier un utilisateur (Admin)","description":"Met à jour les informations d'un utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserInput"}}}},"responses":{"200":{"description":"Utilisateur mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/User"},"message":{"type":"string","example":"Utilisateur mis à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Users"],"summary":"Supprimer un utilisateur (Admin)","description":"Supprime (soft delete) un utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"Utilisateur supprimé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Utilisateur supprimé"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/users/{id}/verify-document":{"patch":{"tags":["Users"],"summary":"Vérifier un document (Admin)","description":"Approuve ou rejette un document utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyDocumentInput"}}}},"responses":{"200":{"description":"Document vérifié","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Document vérifié"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/users/agents":{"get":{"tags":["Users"],"summary":"Liste des agents (Proprio)","description":"Retourne la liste des agents du propriétaire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des agents","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Users"],"summary":"Créer un agent (Proprio)","description":"Crée un nouvel agent pour le propriétaire.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentInput"}}}},"responses":{"201":{"description":"Agent créé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Agent"},"message":{"type":"string","example":"Agent créé avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/users/agents/{agentId}":{"get":{"tags":["Users"],"summary":"Détails d'un agent (Proprio)","description":"Retourne les détails d'un agent.","security":[{"bearerAuth":[]}],"parameters":[{"name":"agentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agent"}],"responses":{"200":{"description":"Détails de l'agent","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Agent"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Users"],"summary":"Modifier un agent (Proprio)","description":"Met à jour les informations d'un agent.","security":[{"bearerAuth":[]}],"parameters":[{"name":"agentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agent"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentInput"}}}},"responses":{"200":{"description":"Agent mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Agent"},"message":{"type":"string","example":"Agent mis à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Users"],"summary":"Supprimer un agent (Proprio)","description":"Supprime un agent.","security":[{"bearerAuth":[]}],"parameters":[{"name":"agentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agent"}],"responses":{"200":{"description":"Agent supprimé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Agent supprimé"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/users/team/stats":{"get":{"tags":["Users"],"summary":"Statistiques équipe (Proprio)","description":"Retourne les statistiques de l'équipe du propriétaire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques équipe","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TeamStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/users/profile":{"get":{"tags":["Users"],"summary":"Mon profil","description":"Retourne le profil de l'utilisateur connecté.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Profil utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/User"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"tags":["Users"],"summary":"Modifier mon profil","description":"Met à jour le profil de l'utilisateur connecté.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileInput"}}}},"responses":{"200":{"description":"Profil mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/User"},"message":{"type":"string","example":"Profil mis à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/users/profile/photo":{"post":{"tags":["Users"],"summary":"Ajouter ou modifier ma photo de profil","description":"Upload une photo de profil pour l'utilisateur connecté. Le serveur accepte les champs multipart `image` et `avatar` pour compatibilité front.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"image":{"type":"string","format":"binary","description":"Fichier image (champ recommandé)"},"avatar":{"type":"string","format":"binary","description":"Fichier image (champ alternatif)"}}}}}},"responses":{"200":{"description":"Photo de profil mise à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"message":{"type":"string","example":"Photo de profil mise a jour avec succes"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Users"],"summary":"Supprimer ma photo de profil","description":"Supprime la photo de profil de l'utilisateur connecté (met `profileImage` à `null`).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Photo de profil supprimée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"message":{"type":"string","example":"Photo de profil supprimée avec succès"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/users/complete-onboarding":{"post":{"tags":["Users"],"summary":"Compléter l'onboarding","description":"Marque l'onboarding comme complété pour le propriétaire. Optionnellement enregistre la catégorie métier choisie (dont **transport** = transport interurbain / agence, **vtc** = VTC / chauffeur privé) dans l'abonnement COMMISSION (1er service). Corps vide `{}` autorisé (reprise sans changement de catégorie).","security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"serviceType":{"type":"string","enum":["hotel","restaurant","food_order","vehicle","parking","appointment","event","rideshare","transport","vtc"],"description":"Catégorie principale à l'inscription. **transport** : lignes / bus interurbains. **vtc** : VTC (ride-hailing)."}}},"examples":{"transport":{"summary":"Agence transport","value":{"serviceType":"transport"}},"vtc":{"summary":"VTC","value":{"serviceType":"vtc"}},"empty":{"summary":"Sans catégorie (déjà choisie ou finalisation)","value":{}}}}}},"responses":{"200":{"description":"Onboarding complété","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Onboarding terminé avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/hotels":{"get":{"tags":["Hotels"],"summary":"Lister les hotels","description":"\n        Liste paginee des hotels avec filtrage par ville, statut, etc.\n\n        **Comportement selon le role:**\n        - Public/Client: Uniquement les hotels actifs\n        - Admin: Tous les hotels\n        - Owner/Agent: Uniquement leurs hotels\n      ","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom ou description"},{"name":"city","in":"query","schema":{"type":"string"},"description":"Filtrer par ville"},{"name":"commune","in":"query","schema":{"type":"string"},"description":"Filtrer par commune"},{"name":"starRating","in":"query","schema":{"type":"integer","minimum":1,"maximum":5},"description":"Filtrer par nombre d'etoiles"},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}},{"name":"minPrice","in":"query","schema":{"type":"number"},"description":"Prix minimum par nuit"},{"name":"maxPrice","in":"query","schema":{"type":"number"},"description":"Prix maximum par nuit"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","city","rating","starRating","createdAt"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des hotels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Hotel"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/hotels/search":{"get":{"tags":["Hotels"],"summary":"Rechercher des hotels (public)","description":"Recherche publique d'hotels actifs uniquement","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"checkIn","in":"query","schema":{"type":"string","format":"date"},"description":"Date d'arrivee"},{"name":"checkOut","in":"query","schema":{"type":"string","format":"date"},"description":"Date de depart"},{"name":"guests","in":"query","schema":{"type":"integer"},"description":"Nombre de personnes"}],"responses":{"200":{"description":"Resultats de recherche","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Hotel"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/hotels/{id}":{"get":{"tags":["Hotels"],"summary":"Obtenir un hotel par ID ou slug","description":"Recupere les details complets d'un hotel. Accepte UUID ou slug.","parameters":[{"name":"id","in":"path","required":true,"description":"UUID ou slug de l'hotel","schema":{"type":"string"},"examples":{"uuid":{"value":"550e8400-e29b-41d4-a716-446655440000","summary":"Format UUID"},"slug":{"value":"hotel-ivoire-cocody","summary":"Format slug"}}}],"responses":{"200":{"description":"Details de l'hotel","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Hotel"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/hotels/slug/{slug}":{"get":{"tags":["Hotels"],"summary":"Obtenir un hotel par slug","description":"Recupere un hotel par son slug SEO-friendly","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"hotel-ivoire-cocody"}],"responses":{"200":{"description":"Details de l'hotel","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Hotel"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/hotels/{id}/rooms":{"get":{"tags":["Hotels"],"summary":"Lister les chambres d'un hotel","description":"Recupere la liste des chambres disponibles d'un hotel","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"type","in":"query","schema":{"type":"string","enum":["single","double","twin","suite","family","deluxe"]}},{"name":"minCapacity","in":"query","schema":{"type":"integer"}},{"name":"maxPrice","in":"query","schema":{"type":"number"}},{"name":"available","in":"query","schema":{"type":"boolean"},"description":"Filtrer uniquement les chambres disponibles"}],"responses":{"200":{"description":"Liste des chambres","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Room"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/hotels/{id}/extras":{"get":{"tags":["Hotels"],"summary":"Lister les suppléments disponibles d'un hôtel","description":"Récupère la liste des suppléments/extras actifs disponibles pour un hôtel (petit-déjeuner, parking, etc.)","parameters":[{"name":"id","in":"path","required":true,"description":"UUID de l'hôtel","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des suppléments","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RoomExtra"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels":{"get":{"tags":["Hotels"],"summary":"Lister mes hotels (Owner)","description":"Liste tous les hotels appartenant au proprietaire connecte","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}}],"responses":{"200":{"description":"Liste des hotels du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Hotel"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Hotels"],"summary":"Creer un hotel (Owner)","description":"Cree un nouvel hotel. Supporte l'upload d'images via multipart/form-data.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHotelInput"}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"commune":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"starRating":{"type":"integer"},"checkInTime":{"type":"string"},"checkOutTime":{"type":"string"},"coverImage":{"type":"string","format":"binary"},"images":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Hotel cree avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"hotel":{"$ref":"#/components/schemas/Hotel"},"message":{"type":"string","example":"Hotel cree avec succes"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/hotels/{id}":{"patch":{"tags":["Hotels"],"summary":"Modifier un hotel (Owner)","description":"Met a jour les informations d'un hotel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHotelInput"}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"coverImage":{"type":"string","format":"binary"},"images":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"200":{"description":"Hotel mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"hotel":{"$ref":"#/components/schemas/Hotel"},"message":{"type":"string","example":"Hotel mis a jour avec succes"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Hotels"],"summary":"Supprimer un hotel (Owner)","description":"Supprime un hotel et toutes ses chambres associees","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Hotel supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Hotel supprime avec succes"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels/{id}/rooms":{"post":{"tags":["Hotels"],"summary":"Ajouter une chambre (Owner)","description":"Ajoute un nouveau type de chambre a l'hotel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoomInput"}}}},"responses":{"201":{"description":"Chambre ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"room":{"$ref":"#/components/schemas/Room"},"message":{"type":"string","example":"Chambre ajoutee avec succes"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels/{id}/rooms/{roomId}":{"patch":{"tags":["Hotels"],"summary":"Modifier une chambre (Owner)","description":"Met a jour les informations d'une chambre","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'hotel"},{"name":"roomId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la chambre"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoomInput"}}}},"responses":{"200":{"description":"Chambre mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"room":{"$ref":"#/components/schemas/Room"},"message":{"type":"string","example":"Chambre mise a jour avec succes"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Hotels"],"summary":"Supprimer une chambre (Owner)","description":"Supprime un type de chambre de l'hotel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roomId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Chambre supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Chambre supprimee avec succes"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels/{id}/extras":{"get":{"tags":["Hotels"],"summary":"Lister les suppléments d'un hôtel (Owner)","description":"Liste tous les suppléments (actifs et inactifs) d'un hôtel appartenant au propriétaire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des suppléments","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RoomExtra"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Hotels"],"summary":"Créer un supplément (Owner)","description":"Ajoute un nouveau supplément/extra à un hôtel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoomExtraInput"}}}},"responses":{"201":{"description":"Supplément créé avec succès","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RoomExtra"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels/{id}/extras/{extraId}":{"patch":{"tags":["Hotels"],"summary":"Mettre à jour un supplément (Owner)","description":"Modifie un supplément existant d'un hôtel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"extraId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoomExtraInput"}}}},"responses":{"200":{"description":"Supplément mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RoomExtra"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Hotels"],"summary":"Supprimer un supplément (Owner)","description":"Supprime un supplément d'un hôtel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"extraId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Supplément supprimé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Room extra deleted successfully"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/hotels/stats":{"get":{"tags":["Hotels"],"summary":"Statistiques hotels (Owner)","description":"Obtient les statistiques globales des hotels du proprietaire","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des hotels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/HotelStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/restaurants":{"get":{"tags":["Restaurants"],"summary":"Lister les restaurants","description":"\n        Liste paginee des restaurants avec filtrage.\n\n        **Comportement selon le role:**\n        - Public/Client: Uniquement les restaurants actifs\n        - Admin: Tous les restaurants\n        - Owner/Agent: Uniquement leurs restaurants\n      ","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"commune","in":"query","schema":{"type":"string"}},{"name":"cuisineType","in":"query","schema":{"type":"string","enum":["francaise","italienne","africaine","asiatique","libanaise","indienne","fusion","fast-food","autre"]}},{"name":"priceRange","in":"query","schema":{"type":"string","enum":["$","$$","$$$","$$$$"]}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}},{"name":"hasDelivery","in":"query","schema":{"type":"boolean"}},{"name":"hasTakeaway","in":"query","schema":{"type":"boolean"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","city","rating","averagePrice","createdAt"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des restaurants","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Restaurant"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/restaurants/search":{"get":{"tags":["Restaurants"],"summary":"Rechercher des restaurants (public)","description":"Recherche publique de restaurants actifs","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"cuisineType","in":"query","schema":{"type":"string"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"},"description":"Date de reservation"},{"name":"time","in":"query","schema":{"type":"string"},"description":"Heure souhaitee (HH:mm)"},{"name":"guests","in":"query","schema":{"type":"integer"},"description":"Nombre de convives"}],"responses":{"200":{"description":"Resultats de recherche","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Restaurant"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/restaurants/{id}":{"get":{"tags":["Restaurants"],"summary":"Obtenir un restaurant par ID ou slug","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"UUID ou slug du restaurant"}],"responses":{"200":{"description":"Details du restaurant","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Restaurant"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/restaurants/{id}/menu":{"get":{"tags":["Restaurants"],"summary":"Obtenir le menu d'un restaurant","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"category","in":"query","schema":{"type":"string","enum":["entree","plat","dessert","boisson","accompagnement","menu"]}},{"name":"available","in":"query","schema":{"type":"boolean"},"description":"Uniquement les items disponibles"}],"responses":{"200":{"description":"Menu du restaurant","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/MenuItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/restaurants/{id}/tables":{"get":{"tags":["Restaurants"],"summary":"Lister les tables d'un restaurant","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"location","in":"query","schema":{"type":"string","enum":["interieur","terrasse","prive","bar"]}},{"name":"minCapacity","in":"query","schema":{"type":"integer"}},{"name":"available","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Tables du restaurant","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Table"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants":{"get":{"tags":["Restaurants"],"summary":"Lister mes restaurants (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}}],"responses":{"200":{"description":"Liste des restaurants du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Restaurant"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Restaurants"],"summary":"Creer un restaurant (Owner)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRestaurantInput"}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"cuisineType":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"phone":{"type":"string"},"coverImage":{"type":"string","format":"binary"},"images":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Restaurant cree avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"restaurant":{"$ref":"#/components/schemas/Restaurant"},"message":{"type":"string","example":"Restaurant cree avec succes"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/restaurants/{id}":{"patch":{"tags":["Restaurants"],"summary":"Modifier un restaurant (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRestaurantInput"}}}},"responses":{"200":{"description":"Restaurant mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"restaurant":{"$ref":"#/components/schemas/Restaurant"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Restaurants"],"summary":"Supprimer un restaurant (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Restaurant supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Restaurant supprime avec succes"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants/{id}/menu":{"post":{"tags":["Restaurants"],"summary":"Ajouter un item au menu (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMenuItemInput"}}}},"responses":{"201":{"description":"Item ajoute au menu","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/MenuItem"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants/{id}/menu/{itemId}":{"patch":{"tags":["Restaurants"],"summary":"Modifier un item du menu (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMenuItemInput"}}}},"responses":{"200":{"description":"Item mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/MenuItem"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Restaurants"],"summary":"Supprimer un item du menu (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Item supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants/{id}/tables":{"post":{"tags":["Restaurants"],"summary":"Ajouter une table (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTableInput"}}}},"responses":{"201":{"description":"Table ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"table":{"$ref":"#/components/schemas/Table"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants/{id}/tables/{tableId}":{"patch":{"tags":["Restaurants"],"summary":"Modifier une table (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTableInput"}}}},"responses":{"200":{"description":"Table mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"table":{"$ref":"#/components/schemas/Table"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Restaurants"],"summary":"Supprimer une table (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Table supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/restaurants/stats":{"get":{"tags":["Restaurants"],"summary":"Statistiques restaurants (Owner)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des restaurants","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RestaurantStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/parkings":{"get":{"tags":["Parkings"],"summary":"Lister les parkings","description":"\n        Liste paginee des parkings avec filtrage.\n\n        **Comportement selon le role:**\n        - Public/Client: Uniquement les parkings actifs\n        - Admin: Tous les parkings\n        - Owner/Agent: Uniquement leurs parkings\n      ","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"commune","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["public","prive","souterrain","aerien","couvert","exterieur"]}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}},{"name":"is24Hours","in":"query","schema":{"type":"boolean"}},{"name":"hasElectricCharging","in":"query","schema":{"type":"boolean"}},{"name":"maxHourlyRate","in":"query","schema":{"type":"number"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","city","rating","hourlyRate","createdAt"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des parkings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Parking"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/parkings/{id}":{"get":{"tags":["Parkings"],"summary":"Obtenir un parking par ID ou slug","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"UUID ou slug du parking"}],"responses":{"200":{"description":"Details du parking","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Parking"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parkings/{id}/spots":{"get":{"tags":["Parkings"],"summary":"Lister les places d'un parking","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"type","in":"query","schema":{"type":"string","enum":["standard","handicap","moto","electrique","vip","camion"]}},{"name":"floor","in":"query","schema":{"type":"string"}},{"name":"available","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Liste des places","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ParkingSpot"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parkings/{id}/spots/available":{"get":{"tags":["Parkings"],"summary":"Lister les places disponibles","description":"Obtient uniquement les places disponibles pour la reservation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Places disponibles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ParkingSpot"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parkings/{id}/spots/{spotId}":{"get":{"tags":["Parkings"],"summary":"Obtenir une place specifique","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Details de la place","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ParkingSpot"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parkings/{id}/spots/{spotId}/reserve":{"post":{"tags":["Parkings"],"summary":"Reserver une place (temporaire)","description":"Reserve temporairement une place avant la creation de la reservation complete","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Place reservee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"spot":{"$ref":"#/components/schemas/ParkingSpot"},"message":{"type":"string","example":"Place reservee avec succes"}}}}}}}},"400":{"description":"Place non disponible"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parkings/{id}/spots/{spotId}/release":{"post":{"tags":["Parkings"],"summary":"Liberer une place","description":"Libere une place precedemment reservee","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Place liberee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"spot":{"$ref":"#/components/schemas/ParkingSpot"},"message":{"type":"string","example":"Place liberee avec succes"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/parkings":{"get":{"tags":["Parkings"],"summary":"Lister mes parkings (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}}],"responses":{"200":{"description":"Liste des parkings du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Parking"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Parkings"],"summary":"Creer un parking (Owner)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateParkingInput"}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"totalSpots":{"type":"integer"},"hourlyRate":{"type":"number"},"coverImage":{"type":"string","format":"binary"},"images":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Parking cree avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"parking":{"$ref":"#/components/schemas/Parking"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/parkings/{id}":{"patch":{"tags":["Parkings"],"summary":"Modifier un parking (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateParkingInput"}}}},"responses":{"200":{"description":"Parking mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"parking":{"$ref":"#/components/schemas/Parking"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Parkings"],"summary":"Supprimer un parking (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Parking supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/parkings/{id}/spots":{"post":{"tags":["Parkings"],"summary":"Ajouter une place (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpotInput"}}}},"responses":{"201":{"description":"Place ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"spot":{"$ref":"#/components/schemas/ParkingSpot"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/parkings/{id}/spots/{spotId}":{"patch":{"tags":["Parkings"],"summary":"Modifier une place (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpotInput"}}}},"responses":{"200":{"description":"Place mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"spot":{"$ref":"#/components/schemas/ParkingSpot"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Parkings"],"summary":"Supprimer une place (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Place supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/parkings/stats":{"get":{"tags":["Parkings"],"summary":"Statistiques parkings (Owner)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des parkings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ParkingStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/rental-agencies":{"get":{"tags":["Rental Agencies"],"summary":"Lister les agences de location","description":"\n        Liste paginee des agences de location avec filtrage.\n\n        **Comportement selon le role:**\n        - Public/Client: Uniquement les agences actives\n        - Admin: Toutes les agences\n        - Owner/Agent: Uniquement leurs agences\n      ","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"commune","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}},{"name":"hasDelivery","in":"query","schema":{"type":"boolean"}},{"name":"hasDriver","in":"query","schema":{"type":"boolean"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","city","rating","createdAt"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des agences","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RentalAgency"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/rental-agencies/{id}":{"get":{"tags":["Rental Agencies"],"summary":"Obtenir une agence par ID ou slug","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"UUID ou slug de l'agence"}],"responses":{"200":{"description":"Details de l'agence","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RentalAgency"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/rental-agencies/{id}/fleet":{"get":{"tags":["Rental Agencies"],"summary":"Lister la flotte d'une agence","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"category","in":"query","schema":{"type":"string","enum":["economique","compact","berline","suv","luxe","utilitaire","minibus","moto"]}},{"name":"transmission","in":"query","schema":{"type":"string","enum":["manual","automatic"]}},{"name":"seats","in":"query","schema":{"type":"integer"},"description":"Nombre minimum de places"},{"name":"maxDailyRate","in":"query","schema":{"type":"number"}},{"name":"available","in":"query","schema":{"type":"boolean"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Flotte de vehicules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Vehicle"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Rental Agencies"],"summary":"Ajouter un vehicule (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVehicleInput"}}}},"responses":{"201":{"description":"Vehicule ajoute","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"vehicle":{"$ref":"#/components/schemas/Vehicle"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/rental-agencies/{id}/fleet/{vehicleId}":{"patch":{"tags":["Rental Agencies"],"summary":"Modifier un vehicule (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"vehicleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVehicleInput"}}}},"responses":{"200":{"description":"Vehicule mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"vehicle":{"$ref":"#/components/schemas/Vehicle"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Rental Agencies"],"summary":"Supprimer un vehicule (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"vehicleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Vehicule supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/rental-agencies":{"get":{"tags":["Rental Agencies"],"summary":"Lister mes agences (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}}],"responses":{"200":{"description":"Liste des agences du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RentalAgency"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Rental Agencies"],"summary":"Creer une agence (Owner)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRentalAgencyInput"}},"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"phone":{"type":"string"},"coverImage":{"type":"string","format":"binary"},"images":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Agence creee avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"agency":{"$ref":"#/components/schemas/RentalAgency"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/rental-agencies/{id}":{"patch":{"tags":["Rental Agencies"],"summary":"Modifier une agence (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRentalAgencyInput"}}}},"responses":{"200":{"description":"Agence mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"agency":{"$ref":"#/components/schemas/RentalAgency"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Rental Agencies"],"summary":"Supprimer une agence (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Agence supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/rental-agencies/{id}/status":{"patch":{"tags":["Rental Agencies"],"summary":"Modifier le statut d'une agence (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/EstablishmentStatus"}}}}}},"responses":{"200":{"description":"Statut mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"agency":{"$ref":"#/components/schemas/RentalAgency"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/rental-agencies/stats":{"get":{"tags":["Rental Agencies"],"summary":"Statistiques agences (Owner)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des agences","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RentalAgencyStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/establishments":{"get":{"tags":["Establishments"],"summary":"Lister les etablissements","description":"\n        Liste paginee des etablissements (salons, spas, etc.) avec filtrage.\n\n        **Comportement selon le role:**\n        - Public/Client: Uniquement les etablissements actifs\n        - Admin: Tous les etablissements\n        - Owner/Agent: Uniquement leurs etablissements\n      ","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"commune","in":"query","schema":{"type":"string"}},{"name":"businessType","in":"query","schema":{"type":"string","enum":["salon_coiffure","spa","salle_sport","cabinet_medical","centre_esthetique","autre"]}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["name","city","rating","createdAt"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des etablissements","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Establishment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/establishments/{id}":{"get":{"tags":["Establishments"],"summary":"Obtenir un etablissement par ID ou slug","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"UUID ou slug de l'etablissement"}],"responses":{"200":{"description":"Details de l'etablissement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Establishment"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/establishments/{id}/services":{"get":{"tags":["Establishments"],"summary":"Lister les services d'un etablissement","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"active","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Liste des services","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Service"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/establishments/{id}/working-hours":{"get":{"tags":["Establishments"],"summary":"Obtenir les horaires d'ouverture","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Horaires d'ouverture","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/WorkingHours"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/establishments/{id}/available-slots":{"get":{"tags":["Establishments"],"summary":"Obtenir les creneaux disponibles","description":"Recupere les creneaux horaires disponibles pour un service donne","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"serviceId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du service souhaite"},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Date souhaitee"},{"name":"providerId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Prestataire specifique (optionnel)"}],"responses":{"200":{"description":"Creneaux disponibles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AvailableSlot"}}}}}}},"400":{"description":"Parametres manquants"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/establishments/{id}/schedule":{"get":{"tags":["Establishments"],"summary":"Obtenir le planning de l'etablissement","description":"Vue planning avec toutes les reservations et disponibilites","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"startDate","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"providerId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Planning","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","description":"Planning structure par jour et par prestataire"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/establishments/{id}/reservations":{"get":{"tags":["Establishments"],"summary":"Lister les reservations d'un etablissement","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Liste des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments":{"get":{"tags":["Establishments"],"summary":"Lister mes etablissements (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"businessType","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/EstablishmentStatus"}}],"responses":{"200":{"description":"Liste des etablissements du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Establishment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Establishments"],"summary":"Creer un etablissement (Owner)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEstablishmentInput"}}}},"responses":{"201":{"description":"Etablissement cree avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"establishment":{"$ref":"#/components/schemas/Establishment"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/establishments/{id}":{"patch":{"tags":["Establishments"],"summary":"Modifier un etablissement (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEstablishmentInput"}}}},"responses":{"200":{"description":"Etablissement mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"establishment":{"$ref":"#/components/schemas/Establishment"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Establishments"],"summary":"Supprimer un etablissement (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Etablissement supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments/{id}/working-hours":{"patch":{"tags":["Establishments"],"summary":"Modifier les horaires d'ouverture (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkingHoursInput"}}}},"responses":{"200":{"description":"Horaires mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"workingHours":{"$ref":"#/components/schemas/WorkingHours"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments/{id}/services":{"post":{"tags":["Establishments"],"summary":"Ajouter un service (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceInput"}}}},"responses":{"201":{"description":"Service ajoute","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"service":{"$ref":"#/components/schemas/Service"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments/{id}/services/{serviceId}":{"patch":{"tags":["Establishments"],"summary":"Modifier un service (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceInput"}}}},"responses":{"200":{"description":"Service mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"service":{"$ref":"#/components/schemas/Service"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Establishments"],"summary":"Supprimer un service (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments/stats":{"get":{"tags":["Establishments"],"summary":"Statistiques etablissements (Owner)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des etablissements","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/EstablishmentStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/reservations":{"get":{"tags":["Reservations"],"summary":"Lister mes reservations (Client)","description":"Recupere la liste des reservations du client connecte","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/ReservationType"}},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Liste des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Reservation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Reservations"],"summary":"Creer une reservation (Client)","description":"\n        Cree une nouvelle reservation. Les codes promo sont valides automatiquement.\n\n        **Validation du code promo:**\n        - Verification de la validite (dates, limite d'utilisation)\n        - Verification des restrictions d'etablissement\n        - Application de la reduction\n      ","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReservationInput"},"examples":{"hotel":{"summary":"Reservation hotel","value":{"type":"hotel","startDate":"2024-03-20T14:00:00Z","endDate":"2024-03-22T12:00:00Z","guestCount":2,"hotelId":"550e8400-e29b-41d4-a716-446655440000","items":[{"roomId":"550e8400-e29b-41d4-a716-446655440001","quantity":1}],"promoCode":"SUMMER20"}},"restaurant":{"summary":"Reservation restaurant","value":{"type":"restaurant","startDate":"2024-03-20T19:00:00Z","endDate":"2024-03-20T21:00:00Z","guestCount":4,"restaurantId":"550e8400-e29b-41d4-a716-446655440002","items":[{"tableId":"550e8400-e29b-41d4-a716-446655440003","quantity":1}]}},"appointment":{"summary":"Rendez-vous salon","value":{"type":"appointment","startDate":"2024-03-20T10:00:00Z","endDate":"2024-03-20T11:00:00Z","establishmentId":"550e8400-e29b-41d4-a716-446655440004","providerId":"550e8400-e29b-41d4-a716-446655440005","items":[{"serviceId":"550e8400-e29b-41d4-a716-446655440006","quantity":1}]}}}}}},"responses":{"201":{"description":"Reservation creee avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string","example":"Reservation creee avec succes"}}}}}}}},"400":{"description":"Code promo invalide ou element non disponible"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/reservations/my-reservations":{"get":{"tags":["Reservations"],"summary":"Mes reservations (Client)","description":"Alias pour GET /reservations","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/ReservationType"}}],"responses":{"200":{"description":"Liste des reservations du client","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Reservation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/reservations/{id}":{"get":{"tags":["Reservations"],"summary":"Obtenir une reservation par ID ou numero","description":"Accepte UUID ou numero de reservation (ex: RES-ABC12345)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"UUID ou numero de reservation","examples":{"uuid":{"value":"550e8400-e29b-41d4-a716-446655440000"},"number":{"value":"RES-ABC12345"}}}],"responses":{"200":{"description":"Details de la reservation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"}}}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reservations/{number}/confirm":{"patch":{"tags":["Reservations"],"summary":"Confirmer une reservation (Client)","description":"Confirmation par le client (si paiement en ligne effectue)","security":[{"bearerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string"},"description":"Numero de reservation"}],"responses":{"200":{"description":"Reservation confirmee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"400":{"description":"Reservation deja confirmee ou non eligible"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reservations/{number}/cancel":{"patch":{"tags":["Reservations"],"summary":"Annuler une reservation (Client)","security":[{"bearerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelReservationInput"}}}},"responses":{"200":{"description":"Reservation annulee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"400":{"description":"Annulation non autorisee"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reservations/{number}/complete":{"patch":{"tags":["Reservations"],"summary":"Marquer comme terminee (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reservation terminee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reservations/{number}/no-show":{"patch":{"tags":["Reservations"],"summary":"Marquer comme no-show (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reservation marquee no-show","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/reservations":{"get":{"tags":["Reservations"],"summary":"Lister les reservations (Owner)","description":"Reservations de tous les etablissements du proprietaire","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/ReservationType"}},{"name":"establishment","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par etablissement"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Liste des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Reservation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/reservations/stats":{"get":{"tags":["Reservations"],"summary":"Statistiques reservations (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month","year"]}},{"name":"establishmentId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statistiques des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReservationStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/reservations/{id}/confirm-item":{"post":{"tags":["Reservations"],"summary":"Confirmer un element (Owner)","description":"Confirme un element specifique de la reservation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmItemInput"}}}},"responses":{"200":{"description":"Element confirme","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/ReservationItem"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/reservations/{id}/reject-item":{"post":{"tags":["Reservations"],"summary":"Rejeter un element (Owner)","description":"Rejete un element specifique avec une raison","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectItemInput"}}}},"responses":{"200":{"description":"Element rejete","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/ReservationItem"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/reservations":{"get":{"tags":["Reservations"],"summary":"Lister toutes les reservations (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/ReservationType"}},{"name":"clientId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"ownerId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste de toutes les reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Reservation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Reservations"],"summary":"Creer une reservation pour un client (Admin)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/CreateReservationInput"},{"type":"object","properties":{"clientId":{"type":"string","format":"uuid","description":"ID du client (optionnel)"}}}]}}}},"responses":{"201":{"description":"Reservation creee"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/reservations/stats":{"get":{"tags":["Reservations"],"summary":"Statistiques globales (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month","year"]}}],"responses":{"200":{"description":"Statistiques globales","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReservationStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/reservations/{id}":{"delete":{"tags":["Reservations"],"summary":"Supprimer une reservation (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Reservation supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/provider/reservations":{"get":{"tags":["Reservations"],"summary":"Mes reservations (Provider)","description":"Reservations assignees au prestataire connecte","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationStatus"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Reservations du prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Reservation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/provider/reservations/{id}/complete":{"patch":{"tags":["Reservations"],"summary":"Terminer une reservation (Provider)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Reservation terminee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/provider/reservations/{id}/cancel":{"patch":{"tags":["Reservations"],"summary":"Annuler une reservation (Provider)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelReservationInput"}}}},"responses":{"200":{"description":"Reservation annulee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"reservation":{"$ref":"#/components/schemas/Reservation"},"message":{"type":"string"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/back/reservations/stats":{"get":{"tags":["Reservations"],"summary":"Statistiques back-office (Agent)","description":"Statistiques pour les agents du proprietaire","security":[{"bearerAuth":[]}],"parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month","year"]}}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReservationStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/reviews/my-reviews":{"get":{"tags":["Reviews"],"summary":"Mes avis (Client)","description":"Liste des avis laisses par le client connecte","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"rating","in":"query","schema":{"type":"integer","minimum":1,"maximum":5}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","rating"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des avis du client","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/reviews":{"post":{"tags":["Reviews"],"summary":"Creer un avis (Client)","description":"Laisser un avis apres une reservation completee","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewInput"},"example":{"reservationId":"550e8400-e29b-41d4-a716-446655440000","establishmentId":"550e8400-e29b-41d4-a716-446655440001","rating":5,"title":"Service exceptionnel","comment":"Accueil chaleureux et prestation de qualite. Je recommande vivement!","pros":["Proprete","Personnel professionnel","Rapport qualite-prix"],"cons":[]}}}},"responses":{"201":{"description":"Avis cree avec succes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Review"},"message":{"type":"string","example":"Avis cree avec succes"}}}}}},"400":{"description":"Reservation non completee ou avis deja laisse"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/{id}":{"get":{"tags":["Reviews"],"summary":"Obtenir un avis par ID","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Details de l'avis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Review"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Reviews"],"summary":"Modifier un avis (Client)","description":"Le client peut modifier son avis dans les 48h suivant la creation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviewInput"}}}},"responses":{"200":{"description":"Avis modifie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Review"},"message":{"type":"string"}}}}}},"400":{"description":"Modification non autorisee (delai depasse)"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Reviews"],"summary":"Supprimer un avis (Client)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Avis supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Avis supprime avec succes"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/reviews":{"get":{"tags":["Reviews"],"summary":"Avis de mes etablissements (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"establishmentId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"rating","in":"query","schema":{"type":"integer","minimum":1,"maximum":5}},{"name":"responded","in":"query","schema":{"type":"boolean"},"description":"Filtrer par repondu/non repondu"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","rating"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Liste des avis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/reviews/{id}/respond":{"post":{"tags":["Reviews"],"summary":"Repondre a un avis (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RespondToReviewInput"}}}},"responses":{"200":{"description":"Reponse ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Review"},"message":{"type":"string","example":"Reponse ajoutee avec succes"}}}}}},"400":{"description":"Avis deja repondu"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/establishments/{establishmentId}":{"get":{"tags":["Reviews"],"summary":"Avis d'un etablissement (Public)","parameters":[{"name":"establishmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"rating","in":"query","schema":{"type":"integer","minimum":1,"maximum":5}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","rating","helpful"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Avis de l'etablissement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/establishments/{establishmentId}/stats":{"get":{"tags":["Reviews"],"summary":"Statistiques avis d'un etablissement (Public)","parameters":[{"name":"establishmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statistiques des avis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReviewStats"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/providers/{providerId}":{"get":{"tags":["Reviews"],"summary":"Avis d'un prestataire (Public)","parameters":[{"name":"providerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Avis du prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/providers/{providerId}/stats":{"get":{"tags":["Reviews"],"summary":"Statistiques avis d'un prestataire (Public)","parameters":[{"name":"providerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statistiques des avis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReviewStats"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/services/{serviceId}":{"get":{"tags":["Reviews"],"summary":"Avis d'un service (Public)","parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Avis du service","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Review"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reviews/services/{serviceId}/stats":{"get":{"tags":["Reviews"],"summary":"Statistiques avis d'un service (Public)","parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statistiques des avis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReviewStats"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/establishments/{id}/providers":{"get":{"tags":["Providers"],"summary":"Lister les prestataires (Owner/Admin/SuperAdmin)","description":"Liste les prestataires d'un etablissement. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'etablissement"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"available","in":"query","schema":{"type":"boolean"}},{"name":"serviceId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des prestataires","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Providers"],"summary":"Creer un prestataire (Owner/Admin/SuperAdmin)","description":"Cree un nouveau prestataire ou lie un compte prestataire existant (email deja present) a l'etablissement. Mode liaison active avec linkExistingUser=true ou password omis.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderInput"}}}},"responses":{"201":{"description":"Prestataire cree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"},"message":{"type":"string","example":"Provider created successfully"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Email existant mais compte non prestataire"}}}},"/owner/establishments/{id}/providers/{userId}":{"get":{"tags":["Providers"],"summary":"Obtenir un prestataire (Owner/Admin/SuperAdmin)","description":"Recupere les details d'un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID utilisateur du prestataire"}],"responses":{"200":{"description":"Details du prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Providers"],"summary":"Modifier un prestataire (Owner/Admin/SuperAdmin)","description":"Modifie les informations d'un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderInput"}}}},"responses":{"200":{"description":"Prestataire mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Providers"],"summary":"Supprimer un prestataire (Owner/Admin/SuperAdmin)","description":"Supprime un prestataire de l'etablissement. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Prestataire supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/providers/{userId}/services":{"get":{"tags":["Providers"],"summary":"Services d'un prestataire (Owner/Admin/SuperAdmin)","description":"Liste les services assignes a un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Services assignes au prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ProviderService"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Providers"],"summary":"Assigner un service (Owner/Admin/SuperAdmin)","description":"Assigne un service a un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignServiceInput"}}}},"responses":{"201":{"description":"Service assigne","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ProviderService"},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Service deja assigne"}}}},"/owner/providers/{userId}/services/{serviceId}":{"delete":{"tags":["Providers"],"summary":"Retirer un service (Owner/Admin/SuperAdmin)","description":"Retire un service assigne a un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service retire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/providers/{userId}/availability":{"get":{"tags":["Providers"],"summary":"Disponibilite d'un prestataire (Owner/Admin/SuperAdmin)","description":"Recupere le statut de disponibilite d'un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statut de disponibilite","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"isAvailable":{"type":"boolean"},"unavailableUntil":{"type":"string","format":"date-time","nullable":true}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Providers"],"summary":"Modifier disponibilite (Owner/Admin/SuperAdmin)","description":"Modifie la disponibilite d'un prestataire. Accessible par les proprietaires, admins et super admins.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityInput"}}}},"responses":{"200":{"description":"Disponibilite mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/providers/available":{"get":{"tags":["Providers"],"summary":"Prestataires disponibles (Public)","description":"Liste les prestataires disponibles pour un service a une date donnee","parameters":[{"name":"establishmentId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"serviceId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}},{"name":"time","in":"query","schema":{"type":"string"},"description":"Heure souhaitee (HH:mm)"}],"responses":{"200":{"description":"Prestataires disponibles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}}}}}}}}}},"/provider/profile":{"get":{"tags":["Providers"],"summary":"Mon profil (Provider)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Profil du prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["Providers"],"summary":"Modifier mon profil (Provider)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderInput"}}}},"responses":{"200":{"description":"Profil mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/provider/availability":{"patch":{"tags":["Providers"],"summary":"Ma disponibilite (Provider)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityInput"}}}},"responses":{"200":{"description":"Disponibilite mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Provider"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/provider/stats":{"get":{"tags":["Providers"],"summary":"Mes statistiques (Provider)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques du prestataire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ProviderStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/search":{"get":{"tags":["Search"],"summary":"Recherche globale","description":"\n        Recherche unifiee dans tous les types d'etablissements et services.\n\n        **Fonctionnalites:**\n        - Recherche textuelle full-text\n        - Filtrage par type, ville, prix, note\n        - Recherche geographique avec distance\n        - Tri par pertinence, distance, prix ou note\n      ","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2},"description":"Terme de recherche"},{"name":"type","in":"query","schema":{"type":"string","enum":["hotel","restaurant","rental_agency","parking","establishment","service"]},"description":"Type de resultat"},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"commune","in":"query","schema":{"type":"string"}},{"name":"minPrice","in":"query","schema":{"type":"number"}},{"name":"maxPrice","in":"query","schema":{"type":"number"}},{"name":"minRating","in":"query","schema":{"type":"number","minimum":0,"maximum":5}},{"name":"lat","in":"query","schema":{"type":"number","format":"double"},"description":"Latitude pour recherche geographique"},{"name":"lng","in":"query","schema":{"type":"number","format":"double"},"description":"Longitude pour recherche geographique"},{"name":"radius","in":"query","schema":{"type":"number","default":10},"description":"Rayon de recherche en km"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["relevance","distance","price","rating","reviewCount"]}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Resultats de recherche","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"filters":{"$ref":"#/components/schemas/SearchFilters"}}}}}},"400":{"description":"Terme de recherche trop court"}}}},"/search/suggestions":{"get":{"tags":["Search"],"summary":"Suggestions d'autocompletion","description":"Obtient des suggestions de recherche pendant la saisie","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2},"description":"Terme partiel"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":20}}],"responses":{"200":{"description":"Suggestions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchSuggestion"}}}},"example":{"success":true,"data":[{"id":"1","type":"hotel","text":"Hotel Ivoire","category":"Hotels","image":"https://..."},{"id":"2","type":"city","text":"Abidjan","category":"Villes","image":null},{"id":"3","type":"service","text":"Coupe homme","category":"Services","image":null}]}}}}}}},"/search/top-destinations":{"get":{"tags":["Search"],"summary":"Meilleures destinations","description":"\n        Retourne les meilleures destinations toutes entites confondues (hotels, restaurants, parkings, salons, evenements, agences de location).\n\n        **Modes de tri:**\n        - `top_rated` : Par note moyenne decroissante (tiebreak: nombre d'avis)\n        - `most_booked` : Par nombre de reservations completees (tiebreak: note)\n\n        **Filtres disponibles:**\n        - Type d'entite (hotel, restaurant, parking, etc.)\n        - Ville (recherche partielle, insensible a la casse)\n        - Pagination (page + limit)\n      ","parameters":[{"name":"sort","in":"query","schema":{"type":"string","enum":["top_rated","most_booked"],"default":"top_rated"},"description":"Mode de classement"},{"name":"type","in":"query","schema":{"type":"string","enum":["hotel","restaurant","parking","establishment","event","rental_agency","all"],"default":"all"},"description":"Filtrer par type d'entite (all = toutes)"},{"name":"city","in":"query","schema":{"type":"string"},"description":"Filtrer par ville (ex: Cocody, Abidjan)"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Nombre de resultats par page"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"}],"responses":{"200":{"description":"Liste des meilleures destinations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TopDestinationItem"}},"meta":{"type":"object","properties":{"total":{"type":"integer","example":85},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":20},"totalPages":{"type":"integer","example":5},"sort":{"type":"string","example":"top_rated"}}}}},"example":{"success":true,"data":[{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Hotel Ivoire","slug":"hotel-ivoire","entityType":"hotel","coverImage":"https://images.reservababi.com/hotels/ivoire.jpg","city":"Cocody","address":"Boulevard de France","latitude":5.345,"longitude":-3.998,"rating":4.8,"reviewCount":120,"reservationCount":350,"price":45000,"priceLabel":"45 000 XOF / nuit"},{"id":"660e8400-e29b-41d4-a716-446655440001","name":"Le Jardin des Saveurs","slug":"jardin-des-saveurs","entityType":"restaurant","coverImage":"https://images.reservababi.com/restaurants/jardin.jpg","city":"Plateau","address":"Rue du Commerce","latitude":5.318,"longitude":-4.017,"rating":4.6,"reviewCount":89,"reservationCount":210,"price":5000,"priceLabel":"5 000 XOF / heure"}],"meta":{"total":85,"page":1,"limit":20,"totalPages":5,"sort":"top_rated"}}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/search/popular-cities":{"get":{"tags":["Search"],"summary":"Villes les plus populaires","description":"\n        Retourne les villes classees par popularite, basee sur les entites presentes (hotels, restaurants, parkings, salons, evenements, agences de location).\n\n        **Modes de tri:**\n        - `most_booked` : Par nombre total de reservations completees\n        - `top_rated` : Par note moyenne des entites\n        - `most_entities` : Par nombre total d'entites\n\n        Chaque ville inclut le nombre d'entites par type, la note moyenne, et une image representative.\n      ","parameters":[{"name":"sort","in":"query","schema":{"type":"string","enum":["top_rated","most_booked","most_entities"],"default":"most_booked"},"description":"Mode de classement"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Nombre de villes par page"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"}],"responses":{"200":{"description":"Liste des villes populaires","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/PopularCityItem"}},"meta":{"type":"object","properties":{"total":{"type":"integer","example":15},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":20},"totalPages":{"type":"integer","example":1},"sort":{"type":"string","example":"most_booked"}}}}}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/search/reindex":{"post":{"tags":["Search"],"summary":"Reindexer tous les services (Admin)","description":"Reconstruit l'index de recherche complet. Operation longue.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reindexation terminee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ReindexResult"},"message":{"type":"string","example":"Reindex complete: 150 indexed, 2 failed"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/search/index/{serviceId}":{"post":{"tags":["Search"],"summary":"Indexer un service (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service indexe","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Service 123 indexed successfully"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Search"],"summary":"Supprimer un service de l'index (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Service retire de l'index","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Service 123 removed from index"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/location/geocode":{"post":{"tags":["Location"],"summary":"Geocoder une adresse","description":"Convertit une adresse textuelle en coordonnees GPS","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodeAddressInput"},"example":{"address":"Boulevard de France, Cocody","city":"Abidjan","country":"Cote d'Ivoire"}}}},"responses":{"200":{"description":"Adresse geocodee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GeocodedAddress"}}}}}},"400":{"description":"Adresse introuvable"}}}},"/location/reverse-geocode":{"post":{"tags":["Location"],"summary":"Reverse geocoding","description":"Convertit des coordonnees GPS en adresse textuelle","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseGeocodeInput"},"example":{"lat":5.3599,"lng":-4.0083}}}},"responses":{"200":{"description":"Adresse trouvee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GeocodedAddress"}}}}}},"400":{"description":"Coordonnees invalides ou non trouvees"}}}},"/location/calculate-distance":{"post":{"tags":["Location"],"summary":"Calculer la distance entre deux points","description":"Calcule la distance et le temps de trajet entre deux coordonnees","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculateDistanceInput"},"example":{"origin":{"lat":5.3599,"lng":-4.0083},"destination":{"lat":5.3167,"lng":-4.0167},"mode":"driving"}}}},"responses":{"200":{"description":"Distance calculee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/DistanceResult"}}}}}},"400":{"description":"Coordonnees invalides"}}}},"/location/calculate-distances":{"post":{"tags":["Location"],"summary":"Calculer les distances vers plusieurs etablissements","description":"Calcule la distance de l'utilisateur vers plusieurs etablissements (max 25)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculateDistancesInput"},"example":{"userLocation":{"lat":5.3599,"lng":-4.0083},"establishmentIds":["550e8400-e29b-41d4-a716-446655440001","550e8400-e29b-41d4-a716-446655440002"],"mode":"driving"}}}},"responses":{"200":{"description":"Distances calculees","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"establishmentId":{"type":"string","format":"uuid"},"distance":{"$ref":"#/components/schemas/DistanceResult"}}}}}}}}},"400":{"description":"Trop d'etablissements (max 25)"}}}},"/location/nearby":{"get":{"tags":["Location"],"summary":"Etablissements a proximite","description":"Trouve les etablissements dans un rayon autour d'un point","parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","format":"double"},"description":"Latitude"},{"name":"lng","in":"query","required":true,"schema":{"type":"number","format":"double"},"description":"Longitude"},{"name":"radius","in":"query","schema":{"type":"number","default":10,"maximum":50},"description":"Rayon en km"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"type","in":"query","schema":{"type":"string","enum":["hotel","restaurant","rental_agency","parking","establishment"]}}],"responses":{"200":{"description":"Etablissements proches","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/NearbyEstablishment"}},"meta":{"type":"object","properties":{"count":{"type":"integer","example":15},"radius":{"type":"number","example":10},"center":{"$ref":"#/components/schemas/Coordinates"}}}}}}}},"400":{"description":"Coordonnees invalides"}}}},"/api/owner/wallet":{"get":{"tags":["Finance - Owner"],"summary":"Get owner wallet","description":"Retrieve the wallet information for the authenticated owner","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Wallet retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Wallet"}}}}}}}}},"/api/owner/wallet/stats":{"get":{"tags":["Finance - Owner"],"summary":"Get wallet statistics","description":"Retrieve financial statistics for the owner","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistics retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/WalletStats"}}}}}}}}},"/api/owner/wallet/transactions":{"get":{"tags":["Finance - Owner"],"summary":"List wallet transactions","description":"Get paginated list of wallet transactions","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"type","in":"query","schema":{"type":"string","enum":["CREDIT","DEBIT","COMMISSION","PAYOUT","REFUND","MONTHLY_FEE"]}}],"responses":{"200":{"description":"Transactions retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/WalletTransaction"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}}}}},"/api/owner/payouts":{"get":{"tags":["Finance - Owner"],"summary":"List payouts","description":"Get list of payout requests","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Payouts retrieved successfully"}}},"post":{"tags":["Finance - Owner"],"summary":"Request payout","description":"Create a new payout request","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","paymentMethod","accountDetails"],"properties":{"amount":{"type":"number","minimum":5000},"paymentMethod":{"type":"string","enum":["MOBILE_MONEY","BANK_TRANSFER"]},"accountDetails":{"type":"object","properties":{"accountNumber":{"type":"string"},"accountName":{"type":"string"},"provider":{"type":"string"}}}}}}}},"responses":{"201":{"description":"Payout request created successfully"}}}},"/api/owner/revenue/by-establishment":{"get":{"tags":["Finance - Owner"],"summary":"Revenue by establishment","description":"Get revenue breakdown by establishment","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Revenue data retrieved successfully"}}}},"/api/owner/revenue/by-period":{"get":{"tags":["Finance - Owner"],"summary":"Revenue by period","description":"Get revenue over time periods","security":[{"bearerAuth":[]}],"parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month"],"default":"month"}},{"name":"months","in":"query","schema":{"type":"integer","default":6}}],"responses":{"200":{"description":"Revenue data retrieved successfully"}}}},"/api/admin/finance/overview":{"get":{"tags":["Finance - Admin"],"summary":"Finance overview","description":"Get global financial overview (admin/superAdmin only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Overview retrieved successfully"}}}},"/api/admin/finance/transactions":{"get":{"tags":["Finance - Admin"],"summary":"List all transactions","description":"Get all platform transactions (admin/superAdmin only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Transactions retrieved successfully"}}}},"/api/admin/finance/payouts":{"get":{"tags":["Finance - Admin"],"summary":"List all payouts","description":"Get all payout requests (admin/superAdmin only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Payouts retrieved successfully"}}}},"/api/admin/finance/payouts/{payoutId}/process":{"put":{"tags":["Finance - Admin"],"summary":"Process payout","description":"Approve or reject a payout request (admin/superAdmin only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"payoutId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["approve","reject"]},"note":{"type":"string"}}}}}},"responses":{"200":{"description":"Payout processed successfully"}}}},"/api/admin/system-account":{"get":{"tags":["Finance - Admin"],"summary":"Get system account","description":"Retrieve platform system account information (admin/superAdmin only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"System account retrieved successfully"}}}},"/api/admin/commissions":{"get":{"tags":["Finance - Admin"],"summary":"List commission tiers","description":"Get all commission tier configurations (superAdmin only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Commission tiers retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CommissionTier"}}}}}}}}},"post":{"tags":["Finance - Admin"],"summary":"Create commission tier","description":"Create a new commission tier (superAdmin only)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["minAmount","type","value","priority"],"properties":{"minAmount":{"type":"number"},"maxAmount":{"type":"number","nullable":true},"type":{"type":"string","enum":["PERCENTAGE","FIXED"]},"value":{"type":"number"},"priority":{"type":"integer"}}}}}},"responses":{"201":{"description":"Commission tier created successfully"}}}},"/api/admin/commissions/{id}":{"get":{"tags":["Finance - Admin"],"summary":"Get commission tier","description":"Get a specific commission tier (superAdmin only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commission tier retrieved successfully"}}},"put":{"tags":["Finance - Admin"],"summary":"Update commission tier","description":"Update an existing commission tier (superAdmin only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"minAmount":{"type":"number"},"maxAmount":{"type":"number","nullable":true},"type":{"type":"string","enum":["PERCENTAGE","FIXED"]},"value":{"type":"number"},"priority":{"type":"integer"},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Commission tier updated successfully"}}},"delete":{"tags":["Finance - Admin"],"summary":"Delete commission tier","description":"Delete a commission tier (superAdmin only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commission tier deleted successfully"}}}},"/api/admin/monthly-fees/enable":{"post":{"tags":["Finance - Admin"],"summary":"Enable monthly fee","description":"Enable monthly fixed fee for a wallet with revenue threshold (superAdmin only)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["walletId","amount","threshold"],"properties":{"walletId":{"type":"string","description":"Wallet ID to enable monthly fee for"},"amount":{"type":"number","description":"Monthly fee amount in XOF","example":5000},"threshold":{"type":"number","description":"Minimum revenue threshold in XOF. Fee is charged if monthly revenue is below this amount","example":50000}}}}}},"responses":{"200":{"description":"Monthly fee enabled successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/api/admin/monthly-fees/disable":{"post":{"tags":["Finance - Admin"],"summary":"Disable monthly fee","description":"Disable monthly fixed fee for a wallet (superAdmin only)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["walletId"],"properties":{"walletId":{"type":"string","description":"Wallet ID to disable monthly fee for"}}}}}},"responses":{"200":{"description":"Monthly fee disabled successfully"}}}},"/api/admin/monthly-fees/settings":{"put":{"tags":["Finance - Admin"],"summary":"Update monthly fee settings","description":"Update monthly fee amount and/or revenue threshold (superAdmin only)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["walletId"],"properties":{"walletId":{"type":"string","description":"Wallet ID to update settings for"},"amount":{"type":"number","description":"New monthly fee amount in XOF (optional)"},"threshold":{"type":"number","description":"New revenue threshold in XOF (optional)"}}}}}},"responses":{"200":{"description":"Monthly fee settings updated successfully"}}}},"/api/admin/monthly-fees/process":{"post":{"tags":["Finance - Admin"],"summary":"Process monthly fees manually","description":"Manually trigger monthly fee processing for all eligible wallets (superAdmin only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Monthly fees processed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"processed":{"type":"integer"},"errors":{"type":"integer"}}}}}}}}}}},"/api/promo-codes/validate":{"post":{"tags":["Promo Codes"],"summary":"Validate promo code","description":"Validate a promo code for a specific reservation","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidatePromoCodeInput"}}}},"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ValidatePromoCodeResult"},"message":{"type":"string"}}}}}}}}},"/api/owner/promo-codes":{"get":{"tags":["Promo Codes"],"summary":"List owner's promo codes","description":"Get paginated list of promo codes for the authenticated owner","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["percentage","fixed"]}},{"name":"isActive","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of promo codes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PromoCode"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Promo Codes"],"summary":"Create promo code","description":"Create a new promo code for owner's establishments","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePromoCodeInput"}}}},"responses":{"201":{"description":"Promo code created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PromoCode"},"message":{"type":"string"}}}}}},"409":{"description":"Code already exists"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/owner/promo-codes/stats/owner":{"get":{"tags":["Promo Codes"],"summary":"Owner statistics","description":"Get aggregated statistics for all owner's promo codes","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Owner statistics","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"totalPromoCodes":{"type":"integer"},"activePromoCodes":{"type":"integer"},"totalUsage":{"type":"integer"},"totalDiscountGiven":{"type":"number"},"averageDiscountPerUse":{"type":"number"}}}}}}}}}}},"/api/owner/promo-codes/{id}":{"get":{"tags":["Promo Codes"],"summary":"Get promo code","description":"Get details of a specific promo code","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Promo code details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PromoCode"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Promo Codes"],"summary":"Update promo code","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePromoCodeInput"}}}},"responses":{"200":{"description":"Promo code updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PromoCode"},"message":{"type":"string"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Promo Codes"],"summary":"Delete promo code","description":"Delete a promo code (only if not used)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Promo code deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Cannot delete used promo code"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/owner/promo-codes/{id}/stats":{"get":{"tags":["Promo Codes"],"summary":"Promo code statistics","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Promo code statistics","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PromoCodeStats"}}}}}}}}},"/api/owner/promo-codes/{id}/activate":{"patch":{"tags":["Promo Codes"],"summary":"Activate promo code","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Promo code activated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PromoCode"},"message":{"type":"string"}}}}}}}}},"/api/owner/promo-codes/{id}/deactivate":{"patch":{"tags":["Promo Codes"],"summary":"Deactivate promo code","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Promo code deactivated"}}}},"/api/admin/promo-codes":{"get":{"tags":["Promo Codes - Admin"],"summary":"List all promo codes (Admin)","description":"Get all promo codes including owner and global codes","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["percentage","fixed"]}},{"name":"isActive","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of all promo codes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PromoCode"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/admin/promo-codes/global":{"get":{"tags":["Promo Codes - Admin"],"summary":"List global promo codes (Admin)","description":"Get only global promo codes created by admins","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of global promo codes"}}},"post":{"tags":["Promo Codes - Admin"],"summary":"Create global promo code (Admin)","description":"Create a global promo code applicable to all establishments","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePromoCodeInput"}}}},"responses":{"201":{"description":"Global promo code created"}}}},"/carpool/trips":{"get":{"tags":["Carpool"],"summary":"Rechercher des trajets de covoiturage","parameters":[{"name":"from","in":"query","schema":{"type":"string"},"description":"Ville de départ"},{"name":"to","in":"query","schema":{"type":"string"},"description":"Ville d'arrivée"},{"name":"date","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"seats","in":"query","schema":{"type":"integer","minimum":1}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"Liste paginée des trajets publiés et non-complets","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CarpoolTrip"}}}}}}}}},"post":{"tags":["Carpool"],"summary":"Publier un trajet (débite 1 crédit)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishCarpoolTripInput"}}}},"responses":{"201":{"description":"Trajet créé"},"400":{"description":"Données invalides ou solde de crédits insuffisant"}}}},"/carpool/trips/{id}":{"get":{"tags":["Carpool"],"summary":"Détail d'un trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détail du trajet avec réservations et waypoints","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CarpoolTrip"}}}}}}},"/carpool/trips/{id}/reservations":{"post":{"tags":["Carpool"],"summary":"Réserver des places (débite N crédits, N = seatsBooked)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReserveCarpoolSeatsInput"}}}},"responses":{"201":{"description":"Réservation créée (paiement cash au publisher)"}}}},"/carpool/reservations/{id}/cancel":{"post":{"tags":["Carpool"],"summary":"Annuler une réservation (crédits non remboursés)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Réservation annulée"}}}},"/carpool/trips/{id}/start":{"post":{"tags":["Carpool"],"summary":"Démarrer le trajet (publisher uniquement, active le tracking)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trajet démarré, statut = inProgress"}}}},"/carpool/trips/{id}/complete":{"post":{"tags":["Carpool"],"summary":"Terminer le trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trajet terminé"}}}},"/carpool/me/trips":{"get":{"tags":["Carpool"],"summary":"Mes publications","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste paginée"}}}},"/carpool/me/reservations":{"get":{"tags":["Carpool"],"summary":"Mes réservations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste paginée"}}}},"/carpool/trips/{id}/ratings":{"post":{"tags":["Carpool"],"summary":"Noter un participant après le trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/carpool/trips/{id}/surveys":{"post":{"tags":["Carpool"],"summary":"Soumettre le questionnaire post-trajet (garde-fou anti-abus)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CarpoolSurveyInput"}}}}}},"/carpool/trips/{id}/location":{"post":{"tags":["Carpool"],"summary":"Envoyer un ping GPS (fallback REST — préférer Socket.IO 'carpool:location:update')","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["latitude","longitude"],"properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"accuracy":{"type":"number"},"speed":{"type":"number"},"heading":{"type":"number"},"altitude":{"type":"number"}}}}}}}},"/admin/carpool/trips":{"get":{"tags":["Carpool Admin"],"summary":"Lister tous les trajets (filtres)","security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/CarpoolTripStatus"}},{"name":"from","in":"query","schema":{"type":"string"}},{"name":"to","in":"query","schema":{"type":"string"}},{"name":"publisherUserId","in":"query","schema":{"type":"string","format":"uuid"}}]}},"/admin/carpool/stats":{"get":{"tags":["Carpool Admin"],"summary":"Stats globales (trajets, crédits dépensés, revenu XOF)","security":[{"bearerAuth":[]}]}},"/admin/carpool/trips/{id}/live":{"get":{"tags":["Carpool Admin"],"summary":"Positions temps réel (dernier ping par participant, fenêtre 5min)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/admin/carpool/trips/{id}/cancel":{"post":{"tags":["Carpool Admin"],"summary":"Annuler un trajet (admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/credits/me/wallet":{"get":{"tags":["Credits"],"summary":"Mon portefeuille de crédits","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Solde actuel + unitPriceXof","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditWallet"}}}}}}},"/credits/me/transactions":{"get":{"tags":["Credits"],"summary":"Historique des transactions crédits","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}}]}},"/credits/packages":{"get":{"tags":["Credits"],"summary":"Packs d'achat actifs","responses":{"200":{"description":"Packs + prix unitaire de référence","content":{"application/json":{"schema":{"type":"object","properties":{"packages":{"type":"array","items":{"$ref":"#/components/schemas/CreditPackage"}},"unitPriceXof":{"type":"number"}}}}}}}}},"/credits/purchases":{"post":{"tags":["Credits"],"summary":"Initier un achat de crédits","description":"Crée un CreditPurchase en statut PENDING avec référence CRD-. Utilise la même factory multi-provider que les paniers (mobile_money / card / bank_transfer → CinetPay / Stripe / MoneyFusion / Wave / MTN / PayPal). Le webhook confirme et crédite automatiquement le wallet.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateCreditPurchaseInput"}}}},"responses":{"201":{"description":"Paiement initié, redirection vers le provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateCreditPurchaseResponse"}}}}}}},"/admin/credits/packages":{"get":{"tags":["Credits Admin"],"summary":"Lister tous les packs (actifs + inactifs)","security":[{"bearerAuth":[]}]},"post":{"tags":["Credits Admin"],"summary":"Créer un pack","security":[{"bearerAuth":[]}]}},"/admin/credits/packages/{id}":{"patch":{"tags":["Credits Admin"],"summary":"Mettre à jour un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"delete":{"tags":["Credits Admin"],"summary":"Supprimer un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/admin/credits/wallets/adjust":{"post":{"tags":["Credits Admin"],"summary":"Ajuster manuellement un wallet (compensation, correction)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId","amount","reason"],"properties":{"userId":{"type":"string","format":"uuid"},"amount":{"type":"integer","description":"Positif = crédit, négatif = débit"},"reason":{"type":"string"}}}}}}}},"/api/events":{"get":{"tags":["Events - Public"],"summary":"Rechercher des événements","description":"Recherche publique d'événements avec filtres géographiques et par catégorie","parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"search","schema":{"type":"string"}},{"in":"query","name":"category","schema":{"type":"string","enum":["music","sport","conference","exhibition","workshop","party","other"]}},{"in":"query","name":"lat","schema":{"type":"number"}},{"in":"query","name":"lng","schema":{"type":"number"}},{"in":"query","name":"radius","schema":{"type":"number","default":50}},{"in":"query","name":"startDate","schema":{"type":"string","format":"date"}},{"in":"query","name":"endDate","schema":{"type":"string","format":"date"}},{"in":"query","name":"minPrice","schema":{"type":"number"}},{"in":"query","name":"maxPrice","schema":{"type":"number"}}],"responses":{"200":{"description":"Liste des événements trouvés"}}}},"/api/events/featured":{"get":{"tags":["Events - Public"],"summary":"Événements mis en avant","description":"Liste des événements featured par les admins","responses":{"200":{"description":"Liste des événements featured"}}}},"/api/events/{id}":{"get":{"tags":["Events - Public"],"summary":"Détails d'un événement","description":"Récupère les détails complets d'un événement","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de l'événement"},"404":{"description":"Événement non trouvé"}}}},"/api/client/events/tickets/my-tickets":{"get":{"tags":["Events - Client"],"summary":"Mes billets","description":"Liste de tous mes billets d'événements (passés et à venir)","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"status","schema":{"type":"string","enum":["pending","confirmed","cancelled"]}}],"responses":{"200":{"description":"Liste de mes billets"},"401":{"description":"Non authentifié"}}}},"/api/client/events/tickets":{"post":{"tags":["Events - Client"],"summary":"Acheter des billets","description":"Achète des billets pour un événement avec support des promo codes","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseTicketInput"}}}},"responses":{"201":{"description":"Billets achetés avec succès"},"400":{"description":"Validation échouée ou événement complet"},"401":{"description":"Non authentifié"},"404":{"description":"Événement non trouvé"}}}},"/api/client/events/tickets/{id}":{"get":{"tags":["Events - Client"],"summary":"Détails d'un billet","description":"Récupère les détails d'un de mes billets (avec QR code)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails du billet"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Billet non trouvé"}}}},"/api/client/events/reviews":{"post":{"tags":["Events - Client"],"summary":"Créer un avis","description":"Créer un avis pour un événement auquel j'ai assisté","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventReviewInput"}}}},"responses":{"201":{"description":"Avis créé avec succès"},"400":{"description":"Validation échouée ou avis déjà existant"},"401":{"description":"Non authentifié"},"404":{"description":"Événement non trouvé"}}}},"/api/client/events/reviews/my-reviews":{"get":{"tags":["Events - Client"],"summary":"Mes avis","description":"Liste de tous les avis que j'ai écrits","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste de mes avis"},"401":{"description":"Non authentifié"}}}},"/api/owner/events":{"get":{"tags":["Events - Owner"],"summary":"Mes événements","description":"Liste de tous mes événements créés","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","published","completed","cancelled"]}}],"responses":{"200":{"description":"Liste de mes événements"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé (rôle owner/admin requis)"}}},"post":{"tags":["Events - Owner"],"summary":"Créer un événement","description":"Créer un nouvel événement","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventInput"}}}},"responses":{"201":{"description":"Événement créé avec succès"},"400":{"description":"Validation échouée"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"}}}},"/api/owner/events/stats":{"get":{"tags":["Events - Owner"],"summary":"Statistiques de mes événements","description":"Récupère les statistiques globales de mes événements","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"}}}},"/api/owner/events/{id}":{"get":{"tags":["Events - Owner"],"summary":"Détails d'un de mes événements","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de l'événement"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}},"patch":{"tags":["Events - Owner"],"summary":"Modifier mon événement","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventInput"}}}},"responses":{"200":{"description":"Événement mis à jour"},"400":{"description":"Validation échouée"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}},"delete":{"tags":["Events - Owner"],"summary":"Supprimer mon événement","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement supprimé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/owner/events/{id}/publish":{"patch":{"tags":["Events - Owner"],"summary":"Publier mon événement","description":"Change le statut de draft à published","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement publié"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/owner/events/{id}/cover-image":{"post":{"tags":["Events - Owner"],"summary":"Uploader/remplacer l'image de couverture d'un événement","description":"Upload multipart/form-data d'une image (champ `image`) et mise a jour du coverImage de l'événement","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["image"],"properties":{"image":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Image de couverture mise à jour"},"400":{"description":"Image manquante ou invalide"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/owner/events/{id}/cancel":{"patch":{"tags":["Events - Owner"],"summary":"Annuler mon événement","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement annulé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/owner/events/{eventId}/attendees":{"get":{"tags":["Events - Owner"],"summary":"Liste des participants","description":"Liste de tous les participants à mon événement","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"eventId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Liste des participants"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/owner/events/{eventId}/check-in":{"post":{"tags":["Events - Owner"],"summary":"Check-in d'un participant","description":"Valider l'entrée d'un participant via QR code","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"eventId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckInInput"}}}},"responses":{"200":{"description":"Check-in effectué avec succès"},"400":{"description":"QR code invalide ou déjà utilisé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/admin/events":{"get":{"tags":["Events - Admin"],"summary":"Tous les événements","description":"Liste de tous les événements sur la plateforme","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","published","completed","cancelled"]}},{"in":"query","name":"isVerified","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Liste de tous les événements"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé (rôle admin requis)"}}}},"/api/admin/events/{id}":{"get":{"tags":["Events - Admin"],"summary":"Détails d'un événement (admin)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de l'événement"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}},"delete":{"tags":["Events - Admin"],"summary":"Supprimer un événement (modération)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement supprimé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/admin/events/{id}/verify":{"patch":{"tags":["Events - Admin"],"summary":"Vérifier un événement","description":"Marque un événement comme vérifié (badge vérifié)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement vérifié"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/admin/events/{id}/feature":{"patch":{"tags":["Events - Admin"],"summary":"Mettre en avant un événement","description":"Marque un événement comme featured","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement mis en avant"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/admin/events/{id}/cancel":{"patch":{"tags":["Events - Admin"],"summary":"Annuler un événement (modération)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Événement annulé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Événement non trouvé"}}}},"/api/admin/events/reviews":{"get":{"tags":["Events - Admin"],"summary":"Tous les avis","description":"Liste de tous les avis d'événements","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"minRating","schema":{"type":"integer","minimum":1,"maximum":5}}],"responses":{"200":{"description":"Liste de tous les avis"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"}}}},"/api/admin/events/reviews/{id}":{"get":{"tags":["Events - Admin"],"summary":"Détails d'un avis (admin)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de l'avis"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Avis non trouvé"}}},"delete":{"tags":["Events - Admin"],"summary":"Supprimer un avis (modération)","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Avis supprimé"},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé"},"404":{"description":"Avis non trouvé"}}}},"/admin/archive/config":{"get":{"tags":["Archive - Admin"],"summary":"Get archive configuration","description":"Recupere la configuration actuelle de l'archivage automatique","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuration recuperee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ArchiveConfig"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"patch":{"tags":["Archive - Admin"],"summary":"Update archive configuration","description":"Met a jour la configuration de l'archivage automatique","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateArchiveConfigInput"}}}},"responses":{"200":{"description":"Configuration mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ArchiveConfig"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/archive/stats":{"get":{"tags":["Archive - Admin"],"summary":"Get archive statistics","description":"Recupere les statistiques globales des archives","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques recuperees","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ArchiveStats"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/archive":{"get":{"tags":["Archive - Admin"],"summary":"List archives","description":"Liste paginee des archives avec filtres","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"type","in":"query","schema":{"type":"string","enum":["full","database","files","incremental"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","in_progress","completed","failed","verified"]}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","sizeBytes","filename"],"default":"createdAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Liste des archives","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Archive"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Archive - Admin"],"summary":"Create archive","description":"Lance la creation d'une nouvelle archive (processus asynchrone)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateArchiveInput"}}}},"responses":{"201":{"description":"Archivage lance","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Archive"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/archive/cleanup":{"post":{"tags":["Archive - Admin"],"summary":"Cleanup expired archives","description":"Supprime les archives expirees et non protegees","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Nettoyage termine","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CleanupResult"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/archive/{id}":{"get":{"tags":["Archive - Admin"],"summary":"Get archive details","description":"Recupere les details d'une archive specifique","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Details de l'archive","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Archive"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Archive - Admin"],"summary":"Delete archive","description":"Supprime une archive (echoue si protegee)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Archive supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"400":{"description":"Cannot delete protected archive"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/archive/{id}/progress":{"get":{"tags":["Archive - Admin"],"summary":"Get archive progress","description":"Recupere la progression d'un archivage en cours","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Progression de l'archive","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ArchiveProgress"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/archive/{id}/download":{"get":{"tags":["Archive - Admin"],"summary":"Download archive","description":"Telecharge le fichier archive (tar.gz)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Fichier archive","content":{"application/gzip":{"schema":{"type":"string","format":"binary"}}},"headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"attachment; filename=\"archive_xxx.tar.gz\""}}},"400":{"description":"Archive not available for download"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/archive/{id}/protect":{"patch":{"tags":["Archive - Admin"],"summary":"Protect/unprotect archive","description":"Active ou desactive la protection contre la suppression automatique","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtectArchiveInput"}}}},"responses":{"200":{"description":"Protection mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Archive"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/archive/{id}/verify":{"post":{"tags":["Archive - Admin"],"summary":"Verify archive integrity","description":"Verifie l'integrite de l'archive (checksum et taille)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Resultat de verification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/VerifyResult"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/amenities":{"get":{"tags":["Amenities"],"summary":"Liste des commodités (Admin)","description":"Retourne la liste de toutes les commodités.","security":[{"bearerAuth":[]}],"parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["general","comfort","service","food","business","entertainment","accessibility","safety"]},"description":"Filtrer par catégorie"},{"name":"isFree","in":"query","schema":{"type":"boolean"},"description":"Filtrer par gratuité"},{"name":"isActive","in":"query","schema":{"type":"boolean"},"description":"Filtrer par statut actif"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":50},"description":"Éléments par page"}],"responses":{"200":{"description":"Liste des commodités","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Amenities"],"summary":"Créer une commodité (Admin)","description":"Crée une nouvelle commodité.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAmenityInput"}}}},"responses":{"201":{"description":"Commodité créée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Amenity"},"message":{"type":"string","example":"Commodité créée avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/amenities/{id}":{"get":{"tags":["Amenities"],"summary":"Détails d'une commodité (Admin)","description":"Retourne les détails d'une commodité.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la commodité"}],"responses":{"200":{"description":"Détails de la commodité","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Amenity"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Amenities"],"summary":"Modifier une commodité (Admin)","description":"Met à jour une commodité.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la commodité"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAmenityInput"}}}},"responses":{"200":{"description":"Commodité mise à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Amenity"},"message":{"type":"string","example":"Commodité mise à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Amenities"],"summary":"Supprimer une commodité (Admin)","description":"Supprime une commodité.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la commodité"}],"responses":{"200":{"description":"Commodité supprimée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Commodité supprimée"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/amenities":{"get":{"tags":["Amenities"],"summary":"Liste des commodités (Proprio)","description":"Retourne la liste des commodités disponibles.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des commodités","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/amenities/hotels/{hotelId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un hôtel (Proprio)","description":"Retourne les commodités assignées à un hôtel.","security":[{"bearerAuth":[]}],"parameters":[{"name":"hotelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'hôtel"}],"responses":{"200":{"description":"Commodités de l'hôtel","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Amenities"],"summary":"Assigner commodités à un hôtel (Proprio)","description":"Assigne des commodités à un hôtel.","security":[{"bearerAuth":[]}],"parameters":[{"name":"hotelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'hôtel"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignAmenitiesToEstablishmentInput"}}}},"responses":{"200":{"description":"Commodités assignées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Commodités assignées à l'hôtel"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/amenities/restaurants/{restaurantId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un restaurant (Proprio)","description":"Retourne les commodités assignées à un restaurant.","security":[{"bearerAuth":[]}],"parameters":[{"name":"restaurantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du restaurant"}],"responses":{"200":{"description":"Commodités du restaurant","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Amenities"],"summary":"Assigner commodités à un restaurant (Proprio)","description":"Assigne des commodités à un restaurant.","security":[{"bearerAuth":[]}],"parameters":[{"name":"restaurantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du restaurant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignAmenitiesToEstablishmentInput"}}}},"responses":{"200":{"description":"Commodités assignées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Commodités assignées au restaurant"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/amenities/establishments/{establishmentId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un établissement (Proprio)","description":"Retourne les commodités assignées à un établissement (salon, spa, etc.).","security":[{"bearerAuth":[]}],"parameters":[{"name":"establishmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'établissement"}],"responses":{"200":{"description":"Commodités de l'établissement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Amenities"],"summary":"Assigner commodités à un établissement (Proprio)","description":"Assigne des commodités à un établissement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"establishmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'établissement"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignAmenitiesToEstablishmentInput"}}}},"responses":{"200":{"description":"Commodités assignées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Commodités assignées à l'établissement"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/amenities/rental-agencies/{rentalAgencyId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'une agence de location (Proprio)","description":"Retourne les commodités assignées à une agence de location.","security":[{"bearerAuth":[]}],"parameters":[{"name":"rentalAgencyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agence de location"}],"responses":{"200":{"description":"Commodités de l'agence","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Amenities"],"summary":"Assigner commodités à une agence de location (Proprio)","description":"Assigne des commodités à une agence de location.","security":[{"bearerAuth":[]}],"parameters":[{"name":"rentalAgencyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agence de location"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignAmenitiesToEstablishmentInput"}}}},"responses":{"200":{"description":"Commodités assignées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Commodités assignées à l'agence de location"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/amenities/hotels/{hotelId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un hôtel (Public)","description":"Retourne les commodités d'un hôtel (accessible publiquement).","parameters":[{"name":"hotelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'hôtel"}],"responses":{"200":{"description":"Commodités de l'hôtel","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/amenities/restaurants/{restaurantId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un restaurant (Public)","description":"Retourne les commodités d'un restaurant (accessible publiquement).","parameters":[{"name":"restaurantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du restaurant"}],"responses":{"200":{"description":"Commodités du restaurant","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/amenities/establishments/{establishmentId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'un établissement (Public)","description":"Retourne les commodités d'un établissement (accessible publiquement).","parameters":[{"name":"establishmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'établissement"}],"responses":{"200":{"description":"Commodités de l'établissement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/amenities/rental-agencies/{rentalAgencyId}":{"get":{"tags":["Amenities"],"summary":"Commodités d'une agence de location (Public)","description":"Retourne les commodités d'une agence de location (accessible publiquement).","parameters":[{"name":"rentalAgencyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'agence de location"}],"responses":{"200":{"description":"Commodités de l'agence","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Amenity"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/calendar/reservations":{"get":{"tags":["Calendar"],"summary":"Vue calendrier des réservations","description":"Retourne les réservations dans un format calendrier pour une période donnée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"view","in":"query","schema":{"type":"string","enum":["day","week","month"],"default":"month"},"description":"Type de vue calendrier"},{"name":"date","in":"query","schema":{"type":"string","format":"date-time"},"description":"Date de référence (ISO 8601). Par défaut: aujourd'hui"},{"name":"establishmentId","in":"query","schema":{"type":"string","format":"uuid"},"description":"ID de l'établissement (optionnel pour filtrer)"},{"name":"establishmentType","in":"query","schema":{"type":"string","enum":["hotel","restaurant","appointment","rentalAgency","parking","all"],"default":"all"},"description":"Type d'établissement à filtrer"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","confirmed","completed","cancelled","all"],"default":"all"},"description":"Statut des réservations à filtrer"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100},"description":"Nombre de résultats par page"}],"responses":{"200":{"description":"Réservations du calendrier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/upload/image":{"post":{"tags":["Upload"],"summary":"Upload une image","description":"Upload une seule image. Champ `image`. Formats: JPEG, PNG, WebP, GIF, HEIC/HEIF. Taille max: 20MB.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["image"],"properties":{"image":{"type":"string","format":"binary","description":"Fichier image à uploader"}}}}}},"responses":{"200":{"description":"Image uploadée","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResponse"}}}},"400":{"description":"Format de fichier invalide ou taille dépassée","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/upload/images":{"post":{"tags":["Upload"],"summary":"Upload multiple images (batch)","description":"Multipart `images` (répété, max 10). JPEG, PNG, WebP, GIF, HEIC/HEIF. Max 20 Mo par fichier. Rôles: client, marketing, proprio, admin, superAdmin.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["images"],"properties":{"images":{"type":"array","items":{"type":"string","format":"binary"},"description":"Fichiers images (champ répété, max 10)"}}}}}},"responses":{"200":{"description":"URLs relatives des fichiers enregistrés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBatchUrlsResponse"}}}},"400":{"description":"Aucun fichier, type MIME non autorisé ou erreur de filtre","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"description":"Fichier trop volumineux (limite Multer, typ. 20 Mo)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/upload/documents":{"post":{"tags":["Upload"],"summary":"Upload multiple documents (batch)","description":"Multipart `documents` (répété, max 10). PDF, Word (.doc, .docx). Max 20 Mo par fichier. Mêmes rôles que /upload/images.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["documents"],"properties":{"documents":{"type":"array","items":{"type":"string","format":"binary"},"description":"Fichiers documents (champ répété, max 10)"}}}}}},"responses":{"200":{"description":"URLs relatives des fichiers enregistrés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBatchUrlsResponse"}}}},"400":{"description":"Aucun fichier ou type non autorisé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"description":"Fichier trop volumineux","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/upload/images":{"post":{"tags":["Upload"],"summary":"Upload multiple images (batch)","description":"Multipart `images` (répété, max 10). JPEG, PNG, WebP, GIF, HEIC/HEIF. Max 20 Mo par fichier. Rôles: client, marketing, proprio, admin, superAdmin.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["images"],"properties":{"images":{"type":"array","items":{"type":"string","format":"binary"},"description":"Fichiers images (champ répété, max 10)"}}}}}},"responses":{"200":{"description":"URLs relatives des fichiers enregistrés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBatchUrlsResponse"}}}},"400":{"description":"Aucun fichier, type MIME non autorisé ou erreur de filtre","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"description":"Fichier trop volumineux (limite Multer, typ. 20 Mo)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/upload/documents":{"post":{"tags":["Upload"],"summary":"Upload multiple documents (batch)","description":"Multipart `documents` (répété, max 10). PDF, Word (.doc, .docx). Max 20 Mo par fichier. Mêmes rôles que /upload/images.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["documents"],"properties":{"documents":{"type":"array","items":{"type":"string","format":"binary"},"description":"Fichiers documents (champ répété, max 10)"}}}}}},"responses":{"200":{"description":"URLs relatives des fichiers enregistrés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadBatchUrlsResponse"}}}},"400":{"description":"Aucun fichier ou type non autorisé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"description":"Fichier trop volumineux","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/audit-logs":{"get":{"tags":["Audit Logs"],"summary":"Liste des logs d'audit (Admin)","description":"Retourne la liste paginée de tous les logs d'audit.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100},"description":"Éléments par page"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche textuelle"},{"name":"action","in":"query","schema":{"type":"string"},"description":"Filtrer par action"},{"name":"resourceType","in":"query","schema":{"type":"string"},"description":"Filtrer par type de ressource"},{"name":"resourceId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par ID de ressource"},{"name":"userId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par utilisateur"},{"name":"userRole","in":"query","schema":{"type":"string"},"description":"Filtrer par rôle utilisateur"},{"name":"visibility","in":"query","schema":{"type":"string","enum":["admin","owner","self","system"]},"description":"Filtrer par visibilité"},{"name":"isSystemAction","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filtrer actions système"},{"name":"severity","in":"query","schema":{"type":"string","enum":["info","warning","error","critical"]},"description":"Filtrer par sévérité"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Date de début (YYYY-MM-DD)"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin (YYYY-MM-DD)"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["createdAt","action","resourceType","severity"],"default":"createdAt"},"description":"Champ de tri"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Ordre de tri"}],"responses":{"200":{"description":"Liste des logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/audit-logs/stats":{"get":{"tags":["Audit Logs"],"summary":"Statistiques des logs (Admin)","description":"Retourne les statistiques des logs d'audit.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AuditLogStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/audit-logs/export":{"get":{"tags":["Audit Logs"],"summary":"Exporter les logs (Admin)","description":"Exporte les logs d'audit au format CSV ou JSON.","security":[{"bearerAuth":[]}],"parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["csv","json"],"default":"csv"},"description":"Format d'export"},{"name":"action","in":"query","schema":{"type":"string"},"description":"Filtrer par action"},{"name":"resourceType","in":"query","schema":{"type":"string"},"description":"Filtrer par type de ressource"},{"name":"userId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par utilisateur"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Date de début"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin"},{"name":"severity","in":"query","schema":{"type":"string","enum":["info","warning","error","critical"]},"description":"Filtrer par sévérité"},{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":10000},"description":"Nombre max de logs à exporter"}],"responses":{"200":{"description":"Fichier exporté","content":{"text/csv":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/audit-logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Détails d'un log (Admin)","description":"Retourne les détails complets d'un log d'audit.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du log"}],"responses":{"200":{"description":"Détails du log","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AuditLog"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/audit-logs":{"get":{"tags":["Audit Logs"],"summary":"Mes logs d'audit (Proprio)","description":"Retourne les logs d'audit des établissements du propriétaire.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Éléments par page"},{"name":"action","in":"query","schema":{"type":"string"},"description":"Filtrer par action"},{"name":"resourceType","in":"query","schema":{"type":"string"},"description":"Filtrer par type de ressource"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Date de début"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin"},{"name":"sortBy","in":"query","schema":{"type":"string","default":"createdAt"},"description":"Champ de tri"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Ordre de tri"}],"responses":{"200":{"description":"Liste des logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/audit-logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Détails d'un de mes logs (Proprio)","description":"Retourne les détails d'un log d'audit appartenant au propriétaire.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du log"}],"responses":{"200":{"description":"Détails du log","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AuditLog"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/me/audit-logs":{"get":{"tags":["Audit Logs"],"summary":"Mes logs personnels","description":"Retourne les logs d'audit de l'utilisateur connecté.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Éléments par page"},{"name":"action","in":"query","schema":{"type":"string"},"description":"Filtrer par action"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Date de début"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Ordre de tri"}],"responses":{"200":{"description":"Liste des logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/me/audit-logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Détails d'un de mes logs","description":"Retourne les détails d'un de mes logs d'audit.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du log"}],"responses":{"200":{"description":"Détails du log","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AuditLog"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/kyc":{"get":{"tags":["KYC"],"summary":"Mon statut KYC","description":"Retourne le statut de vérification KYC du propriétaire connecté.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statut KYC","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/kyc/documents":{"get":{"tags":["KYC"],"summary":"Mes documents KYC","description":"Retourne la liste des documents KYC du propriétaire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des documents","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/KycDocument"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["KYC"],"summary":"Uploader un document KYC","description":"Upload un document pour la vérification KYC. Formats acceptés: JPEG, PNG, WebP, PDF. Taille max: 10MB.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","documentType"],"properties":{"file":{"type":"string","format":"binary","description":"Fichier document (image ou PDF)"},"documentType":{"type":"string","enum":["identity_document","establishment_proof","business_registration","selfie_photo"],"description":"Type de document"},"documentNumber":{"type":"string","description":"Numéro du document (optionnel)"}}}}}},"responses":{"201":{"description":"Document uploadé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycDocument"},"message":{"type":"string","example":"Document uploadé avec succès"}}}}}},"400":{"description":"Format de fichier invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/kyc/documents/{documentId}":{"delete":{"tags":["KYC"],"summary":"Supprimer un document KYC","description":"Supprime un document KYC non encore approuvé.","security":[{"bearerAuth":[]}],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du document"}],"responses":{"200":{"description":"Document supprimé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Document supprimé"}}}}}},"400":{"description":"Impossible de supprimer un document déjà approuvé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/kyc/submit":{"post":{"tags":["KYC"],"summary":"Soumettre le KYC pour vérification","description":"Soumet les documents KYC pour vérification par un administrateur.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"KYC soumis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycStatus"},"message":{"type":"string","example":"KYC soumis pour vérification"}}}}}},"400":{"description":"Documents manquants ou KYC déjà soumis","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/kyc":{"get":{"tags":["KYC"],"summary":"Liste des soumissions KYC (Admin)","description":"Retourne la liste paginée de toutes les soumissions KYC.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":100},"description":"Éléments par page"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","rejected"]},"description":"Filtrer par statut"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom ou email"}],"responses":{"200":{"description":"Liste des soumissions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/KycSubmission"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/kyc/stats":{"get":{"tags":["KYC"],"summary":"Statistiques KYC (Admin)","description":"Retourne les statistiques des soumissions KYC.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/kyc/pending":{"get":{"tags":["KYC"],"summary":"Soumissions en attente (Admin)","description":"Retourne la liste des soumissions KYC en attente de vérification.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10},"description":"Éléments par page"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom ou email"}],"responses":{"200":{"description":"Liste des soumissions en attente","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/KycSubmission"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/kyc/{userId}":{"get":{"tags":["KYC"],"summary":"Détails d'une soumission KYC (Admin)","description":"Retourne les détails complets d'une soumission KYC.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"Détails de la soumission","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycSubmission"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/kyc/{userId}/approve":{"post":{"tags":["KYC"],"summary":"Approuver le KYC (Admin)","description":"Approuve la soumission KYC d'un utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"KYC approuvé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycSubmission"},"message":{"type":"string","example":"KYC approuvé avec succès"}}}}}},"400":{"description":"KYC déjà traité ou pas en attente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/kyc/{userId}/reject":{"post":{"tags":["KYC"],"summary":"Rejeter le KYC (Admin)","description":"Rejette la soumission KYC d'un utilisateur avec une raison.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectKycInput"}}}},"responses":{"200":{"description":"KYC rejeté","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/KycSubmission"},"message":{"type":"string","example":"KYC rejeté"}}}}}},"400":{"description":"KYC déjà traité ou pas en attente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/gift-cards/balance/{code}":{"get":{"tags":["Gift Cards - Client"],"summary":"Vérifier le solde (Public)","description":"Vérifie le solde d'une carte cadeau. Accessible sans authentification.","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Code de la carte cadeau"}],"responses":{"200":{"description":"Solde de la carte","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BalanceResponse"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/gift-cards/purchase":{"post":{"tags":["Gift Cards - Client"],"summary":"Acheter une carte cadeau","description":"Initie l'achat d'une carte cadeau. La carte est créée en statut 'pending' jusqu'à confirmation du paiement.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseGiftCardInput"}}}},"responses":{"201":{"description":"Carte cadeau créée (en attente de paiement)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Carte cadeau créée, en attente de paiement"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/gift-cards/confirm-payment":{"post":{"tags":["Gift Cards - Client"],"summary":"Confirmer le paiement","description":"Confirme le paiement d'une carte cadeau et l'active. L'argent est crédité au compte système.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmPaymentInput"}}}},"responses":{"200":{"description":"Paiement confirmé, carte activée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Paiement confirmé, carte cadeau activée"}}}}}},"400":{"description":"Carte non trouvée ou non en attente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/gift-cards/purchase/{id}":{"delete":{"tags":["Gift Cards - Client"],"summary":"Annuler un achat en attente","description":"Annule un achat de carte cadeau en attente de paiement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la carte cadeau"}],"responses":{"200":{"description":"Achat annulé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Achat annulé"}}}}}},"400":{"description":"Seules les cartes en attente peuvent être annulées","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/gift-cards/validate":{"post":{"tags":["Gift Cards - Client"],"summary":"Valider un code carte cadeau","description":"Vérifie si un code de carte cadeau est valide pour une utilisation.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateCodeInput"}}}},"responses":{"200":{"description":"Résultat de la validation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ValidateCodeResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/gift-cards/redeem":{"post":{"tags":["Gift Cards - Client"],"summary":"Utiliser une carte cadeau","description":"Utilise une carte cadeau sur une réservation. L'argent est distribué au propriétaire (moins commission).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemInput"}}}},"responses":{"200":{"description":"Carte utilisée avec succès","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RedeemResponse"},"message":{"type":"string","example":"25000 XOF appliqués"}}}}}},"400":{"description":"Carte invalide, expirée, annulée ou solde insuffisant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/gift-cards/mine":{"get":{"tags":["Gift Cards - Client"],"summary":"Mes cartes cadeaux","description":"Retourne les cartes cadeaux achetées par l'utilisateur ou reçues.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des cartes cadeaux","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/GiftCard"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/gift-cards":{"get":{"tags":["Gift Cards - Admin"],"summary":"Liste des cartes cadeaux (Admin)","description":"Retourne la liste paginée de toutes les cartes cadeaux.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","active","redeemed","expired","cancelled"]}},{"name":"recipientEmail","in":"query","schema":{"type":"string","format":"email"}},{"name":"purchasedById","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par acheteur"},{"name":"isPromoCard","in":"query","schema":{"type":"boolean"},"description":"Filtrer cartes promo vs achetées"},{"name":"minValue","in":"query","schema":{"type":"number"}},{"name":"maxValue","in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"Liste des cartes cadeaux","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/GiftCard"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/gift-cards/stats":{"get":{"tags":["Gift Cards - Admin"],"summary":"Statistiques des cartes cadeaux (Admin)","description":"Retourne les statistiques complètes des cartes cadeaux.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCardStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/gift-cards/promo":{"post":{"tags":["Gift Cards - Admin"],"summary":"Créer une carte promo (Admin)","description":"Crée une carte cadeau promo gratuite (pour promotions, cadeaux, etc.).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePromoCardInput"}}}},"responses":{"201":{"description":"Carte promo créée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Carte promo créée avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/gift-cards/promo/bulk":{"post":{"tags":["Gift Cards - Admin"],"summary":"Créer des cartes promo en masse (Admin)","description":"Crée plusieurs cartes promo en une seule opération (max 100).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBulkPromoCardsInput"}}}},"responses":{"201":{"description":"Cartes promo créées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/GiftCard"}},"message":{"type":"string","example":"10 cartes promo créées avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/gift-cards/{id}":{"get":{"tags":["Gift Cards - Admin"],"summary":"Détails d'une carte cadeau (Admin)","description":"Retourne les détails complets d'une carte cadeau avec historique des utilisations.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de la carte","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"allOf":[{"$ref":"#/components/schemas/GiftCard"},{"type":"object","properties":{"redemptions":{"type":"array","items":{"$ref":"#/components/schemas/GiftCardRedemption"}}}}]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Gift Cards - Admin"],"summary":"Modifier une carte cadeau (Admin)","description":"Met à jour une carte cadeau.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGiftCardInput"}}}},"responses":{"200":{"description":"Carte mise à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Carte cadeau mise à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Gift Cards - Admin"],"summary":"Annuler/Rembourser une carte (Admin)","description":"Annule une carte cadeau. Si la carte a un solde et a été payée, le système prépare un remboursement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Carte annulée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/GiftCard"},"message":{"type":"string","example":"Carte cadeau annulée"}}}}}},"400":{"description":"Impossible d'annuler cette carte","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/loyalty/balance":{"get":{"tags":["Loyalty - Client"],"summary":"Mon solde de points","description":"Retourne le solde de points et le niveau de fidélité de l'utilisateur.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Solde de points","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/LoyaltyBalance"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/loyalty/transactions":{"get":{"tags":["Loyalty - Client"],"summary":"Mes transactions de points","description":"Retourne l'historique des transactions de points.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Éléments par page"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Date de début"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin"}],"responses":{"200":{"description":"Historique des transactions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyTransaction"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/loyalty/reward-tiers":{"get":{"tags":["Loyalty - Client"],"summary":"Mes paliers de récompenses disponibles","description":"Retourne les paliers de récompenses accessibles avec mes points.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Paliers disponibles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RewardTier"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/loyalty/tiers-info":{"get":{"tags":["Loyalty - Client"],"summary":"Informations sur les niveaux","description":"Retourne les informations sur les niveaux Bronze, Silver, Gold, Platinum.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Informations sur les niveaux","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TiersInfo"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/loyalty/validate-redemption":{"post":{"tags":["Loyalty - Client"],"summary":"Valider une utilisation de points","description":"Vérifie si l'utilisateur peut utiliser un palier de récompense.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRedemptionInput"}}}},"responses":{"200":{"description":"Validation réussie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"isValid":{"type":"boolean"},"discountAmount":{"type":"number"},"pointsRequired":{"type":"integer"},"message":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/loyalty/redeem":{"post":{"tags":["Loyalty - Client"],"summary":"Utiliser mes points","description":"Utilise un palier de récompense sur une réservation.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemLoyaltyInput"}}}},"responses":{"200":{"description":"Points utilisés","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"transaction":{"$ref":"#/components/schemas/LoyaltyTransaction"},"newBalance":{"type":"integer"},"discountApplied":{"type":"number"}}},"message":{"type":"string","example":"5000 XOF de réduction appliqués"}}}}}},"400":{"description":"Points insuffisants ou palier invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/loyalty/config":{"get":{"tags":["Loyalty - Admin"],"summary":"Configuration du programme (Admin)","description":"Retourne la configuration du programme de fidélité.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuration","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/LoyaltyConfig"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"patch":{"tags":["Loyalty - Admin"],"summary":"Modifier la configuration (Admin)","description":"Met à jour la configuration du programme de fidélité.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLoyaltyConfigInput"}}}},"responses":{"200":{"description":"Configuration mise à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/LoyaltyConfig"},"message":{"type":"string","example":"Configuration mise à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/loyalty/reward-tiers":{"get":{"tags":["Loyalty - Admin"],"summary":"Liste des paliers de récompenses (Admin)","description":"Retourne tous les paliers de récompenses.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des paliers","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RewardTier"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Loyalty - Admin"],"summary":"Créer un palier de récompense (Admin)","description":"Crée un nouveau palier de récompense.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRewardTierInput"}}}},"responses":{"201":{"description":"Palier créé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RewardTier"},"message":{"type":"string","example":"Palier créé avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/loyalty/reward-tiers/{tierId}":{"patch":{"tags":["Loyalty - Admin"],"summary":"Modifier un palier (Admin)","description":"Met à jour un palier de récompense.","security":[{"bearerAuth":[]}],"parameters":[{"name":"tierId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du palier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRewardTierInput"}}}},"responses":{"200":{"description":"Palier mis à jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RewardTier"},"message":{"type":"string","example":"Palier mis à jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Loyalty - Admin"],"summary":"Supprimer un palier (Admin)","description":"Supprime un palier de récompense.","security":[{"bearerAuth":[]}],"parameters":[{"name":"tierId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du palier"}],"responses":{"200":{"description":"Palier supprimé","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Palier supprimé"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/loyalty/stats":{"get":{"tags":["Loyalty - Admin"],"summary":"Statistiques du programme (Admin)","description":"Retourne les statistiques du programme de fidélité.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/LoyaltyStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/loyalty/top-members":{"get":{"tags":["Loyalty - Admin"],"summary":"Top membres (Admin)","description":"Retourne les membres avec le plus de points.","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":100},"description":"Nombre de membres"}],"responses":{"200":{"description":"Top membres","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TopMember"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/loyalty/users/{userId}/balance":{"get":{"tags":["Loyalty - Admin"],"summary":"Solde d'un utilisateur (Admin)","description":"Retourne le solde de points d'un utilisateur spécifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"Solde de l'utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/LoyaltyBalance"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/loyalty/users/{userId}/transactions":{"get":{"tags":["Loyalty - Admin"],"summary":"Transactions d'un utilisateur (Admin)","description":"Retourne l'historique des transactions d'un utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Éléments par page"}],"responses":{"200":{"description":"Transactions de l'utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/LoyaltyTransaction"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/loyalty/adjust/{userId}":{"post":{"tags":["Loyalty - Admin"],"summary":"Ajuster les points d'un utilisateur (Admin)","description":"Ajoute ou retire des points manuellement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustPointsInput"}}}},"responses":{"200":{"description":"Points ajustés","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"transaction":{"$ref":"#/components/schemas/LoyaltyTransaction"},"newBalance":{"type":"integer"}}},"message":{"type":"string","example":"Points ajustés avec succès"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/reservation-attempts":{"post":{"tags":["Reservation Attempts"],"summary":"Enregistrer une tentative de reservation","description":"Enregistre une tentative de reservation sur une entite sans proprietaire (public)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReservationAttemptDto"}}}},"responses":{"201":{"description":"Tentative enregistree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ReservationAttempt"}}}}}},"404":{"description":"Entite non trouvee ou deja revendiquee"}}},"get":{"tags":["Reservation Attempts"],"summary":"Lister les tentatives","description":"Liste paginee des tentatives de reservation (admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ReservationAttemptStatus"}},{"name":"entityId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Liste des tentatives","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReservationAttempt"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/api/reservation-attempts/stats":{"get":{"tags":["Reservation Attempts"],"summary":"Statistiques des tentatives","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AttemptStats"}}}}}}}}},"/api/reservation-attempts/{id}":{"get":{"tags":["Reservation Attempts"],"summary":"Details d'une tentative","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Details de la tentative","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReservationAttempt"}}}}}},"404":{"description":"Tentative non trouvee"}}}},"/api/reservation-attempts/{id}/status":{"patch":{"tags":["Reservation Attempts"],"summary":"Mettre a jour le statut","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/ReservationAttemptStatus"}}}}}},"responses":{"200":{"description":"Statut mis a jour"},"404":{"description":"Tentative non trouvee"}}}},"/api/reservation-attempts/entity/{entityType}/{entityId}":{"get":{"tags":["Reservation Attempts"],"summary":"Tentatives pour une entite","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des tentatives","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReservationAttempt"}}}}}}}}}},"/api/reservation-attempts/possible-owners":{"post":{"tags":["Possible Owners"],"summary":"Creer un possible owner","description":"Ajoute un contact potentiel pour une entite (admin)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePossibleOwnerDto"}}}},"responses":{"201":{"description":"Possible owner cree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"$ref":"#/components/schemas/PossibleOwner"}}}}}},"400":{"description":"Contact deja existant pour cette entite"},"404":{"description":"Entite non trouvee"}}},"get":{"tags":["Possible Owners"],"summary":"Lister les possible owners","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"entityId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"responseStatus","in":"query","schema":{"$ref":"#/components/schemas/PossibleOwnerResponse"}},{"name":"isContacted","in":"query","schema":{"type":"boolean"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste des possible owners","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PossibleOwner"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/api/reservation-attempts/possible-owners/stats":{"get":{"tags":["Possible Owners"],"summary":"Statistiques des possible owners","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PossibleOwnerStats"}}}}}}}}},"/api/reservation-attempts/possible-owners/{id}":{"get":{"tags":["Possible Owners"],"summary":"Details d'un possible owner","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PossibleOwner"}}}}}},"404":{"description":"Non trouve"}}},"patch":{"tags":["Possible Owners"],"summary":"Mettre a jour un possible owner","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePossibleOwnerDto"}}}},"responses":{"200":{"description":"Mis a jour"},"404":{"description":"Non trouve"}}}},"/api/reservation-attempts/possible-owners/{id}/response":{"patch":{"tags":["Possible Owners"],"summary":"Mettre a jour la reponse","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePossibleOwnerResponseDto"}}}},"responses":{"200":{"description":"Reponse mise a jour"},"404":{"description":"Non trouve"}}}},"/api/reservation-attempts/possible-owners/{id}/claim":{"post":{"tags":["Possible Owners"],"summary":"Marquer comme proprietaire verifie","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Marque comme proprietaire"},"404":{"description":"Non trouve"}}}},"/api/reservation-attempts/possible-owners/entity/{entityType}/{entityId}":{"get":{"tags":["Possible Owners"],"summary":"Possible owners pour une entite","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des possible owners","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PossibleOwner"}}}}}}}}}},"/api/reservation-attempts/notifications/send":{"post":{"tags":["Possible Owner Notifications"],"summary":"Envoyer une notification","description":"Envoie une notification multi-canal a un possible owner","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendNotificationDto"}}}},"responses":{"200":{"description":"Resultats d'envoi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationResult"}}}}}}},"404":{"description":"Possible owner non trouve"}}}},"/api/reservation-attempts/notifications/send-bulk":{"post":{"tags":["Possible Owner Notifications"],"summary":"Envoyer des notifications en masse","description":"Envoie des notifications a plusieurs possible owners","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBulkNotificationsDto"}}}},"responses":{"200":{"description":"Resultats d'envoi en masse","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"possibleOwnerId":{"type":"string","format":"uuid"},"results":{"type":"array","items":{"$ref":"#/components/schemas/NotificationResult"}}}}}}}}}}}}},"/admin/trash":{"get":{"tags":["Trash - Admin"],"summary":"Lister tous les éléments en corbeille","description":"Récupère tous les éléments supprimés de toutes les entités avec pagination et filtres.","operationId":"listTrash","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100},"description":"Éléments par page"},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/TrashableEntityType"},"description":"Filtrer par type d'entité"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["deletedAt","name","entityType"],"default":"deletedAt"},"description":"Champ de tri"},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Ordre de tri"}],"responses":{"200":{"description":"Liste des éléments en corbeille","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrashListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/trash/stats":{"get":{"tags":["Trash - Admin"],"summary":"Statistiques de la corbeille","description":"Récupère les statistiques globales de la corbeille: nombre total, par type d'entité, et éléments expirant bientôt.","operationId":"getTrashStats","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques de la corbeille","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrashStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/trash/{entityType}":{"get":{"tags":["Trash - Admin"],"summary":"Lister les éléments par type","description":"Récupère tous les éléments supprimés d'un type d'entité spécifique.","operationId":"listTrashByType","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"},"description":"Type d'entité"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["deletedAt","name"],"default":"deletedAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Liste des éléments du type spécifié","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrashListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/trash/restore-bulk":{"post":{"tags":["Trash - Admin"],"summary":"Restaurer plusieurs éléments","description":"Restaure plusieurs éléments de la corbeille en une seule opération. Les éléments enfants sont automatiquement restaurés.","operationId":"restoreBulk","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkRestoreInput"}}}},"responses":{"200":{"description":"Résultat de la restauration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkRestoreResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/trash/restore/{entityType}/{id}":{"post":{"tags":["Trash - Admin"],"summary":"Restaurer un élément","description":"Restaure un élément unique de la corbeille. Pour les entités parentes (hotel, restaurant, etc.), les éléments enfants supprimés en même temps sont aussi restaurés.","operationId":"restoreItem","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'élément à restaurer"}],"responses":{"200":{"description":"Élément restauré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/trash/purge-all":{"delete":{"tags":["Trash - Admin"],"summary":"Vider toute la corbeille","description":"Supprime définitivement TOUS les éléments de la corbeille. Cette action est irréversible.","operationId":"purgeAll","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Corbeille vidée","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/trash/purge/{entityType}":{"delete":{"tags":["Trash - Admin"],"summary":"Vider par type d'entité","description":"Supprime définitivement tous les éléments d'un type spécifique de la corbeille.","operationId":"purgeByType","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"}}],"responses":{"200":{"description":"Éléments du type supprimés","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/trash/{entityType}/{id}":{"delete":{"tags":["Trash - Admin"],"summary":"Supprimer définitivement un élément","description":"Supprime définitivement un élément spécifique de la corbeille. Cette action est irréversible.","operationId":"permanentDelete","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Élément supprimé définitivement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/trash":{"get":{"tags":["Trash - Owner"],"summary":"Lister ma corbeille","description":"Récupère tous les éléments supprimés appartenant au propriétaire connecté.","operationId":"listOwnerTrash","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/TrashableEntityType"}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["deletedAt","name","entityType"],"default":"deletedAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Liste des éléments en corbeille du propriétaire","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrashListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/trash/stats":{"get":{"tags":["Trash - Owner"],"summary":"Statistiques de ma corbeille","description":"Récupère les statistiques de la corbeille du propriétaire connecté.","operationId":"getOwnerTrashStats","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques de la corbeille du propriétaire","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrashStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/trash/restore/{entityType}/{id}":{"post":{"tags":["Trash - Owner"],"summary":"Restaurer un de mes éléments","description":"Restaure un élément appartenant au propriétaire depuis sa corbeille.","operationId":"restoreOwnerItem","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Élément restauré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/trash/{entityType}/{id}":{"delete":{"tags":["Trash - Owner"],"summary":"Supprimer définitivement un de mes éléments","description":"Supprime définitivement un élément appartenant au propriétaire. Cette action est irréversible.","operationId":"permanentDeleteOwnerItem","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/TrashableEntityType"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Élément supprimé définitivement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/external/hotels":{"post":{"tags":["External API"],"summary":"Créer un hôtel non réclamé(e)","description":"\nCrée un hôtel sans propriétaire (statut: awaitingOwner).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- L'entité est créée avec `ownerId = null` et `status = awaitingOwner`\n- Elle apparaît dans la liste des entités à revendiquer\n- Un possible owner (contact potentiel) peut être ajouté pour le suivi\n- Quand un propriétaire revendique l'entité, le processus de claim démarre\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnclaimedHotelInput"}}}},"responses":{"201":{"description":"Entité créée avec succès","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/hotels/bulk":{"post":{"tags":["External API"],"summary":"Créer plusieurs hotels non réclamés","description":"\nCrée plusieurs hotels en une seule requête (max 100).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- Chaque entité est traitée individuellement\n- Les succès et échecs sont retournés séparément\n- Un échec n'empêche pas les autres créations\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateUnclaimedHotelInput"},"minItems":1,"maxItems":100}}}}}},"responses":{"201":{"description":"Résultat de la création en masse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/restaurants":{"post":{"tags":["External API"],"summary":"Créer un restaurant non réclamé(e)","description":"\nCrée un restaurant sans propriétaire (statut: awaitingOwner).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- L'entité est créée avec `ownerId = null` et `status = awaitingOwner`\n- Elle apparaît dans la liste des entités à revendiquer\n- Un possible owner (contact potentiel) peut être ajouté pour le suivi\n- Quand un propriétaire revendique l'entité, le processus de claim démarre\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnclaimedRestaurantInput"}}}},"responses":{"201":{"description":"Entité créée avec succès","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/restaurants/bulk":{"post":{"tags":["External API"],"summary":"Créer plusieurs restaurants non réclamés","description":"\nCrée plusieurs restaurants en une seule requête (max 100).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- Chaque entité est traitée individuellement\n- Les succès et échecs sont retournés séparément\n- Un échec n'empêche pas les autres créations\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateUnclaimedRestaurantInput"},"minItems":1,"maxItems":100}}}}}},"responses":{"201":{"description":"Résultat de la création en masse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/parkings":{"post":{"tags":["External API"],"summary":"Créer un parking non réclamé(e)","description":"\nCrée un parking sans propriétaire (statut: awaitingOwner).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- L'entité est créée avec `ownerId = null` et `status = awaitingOwner`\n- Elle apparaît dans la liste des entités à revendiquer\n- Un possible owner (contact potentiel) peut être ajouté pour le suivi\n- Quand un propriétaire revendique l'entité, le processus de claim démarre\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnclaimedParkingInput"}}}},"responses":{"201":{"description":"Entité créée avec succès","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/parkings/bulk":{"post":{"tags":["External API"],"summary":"Créer plusieurs parkings non réclamés","description":"\nCrée plusieurs parkings en une seule requête (max 100).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- Chaque entité est traitée individuellement\n- Les succès et échecs sont retournés séparément\n- Un échec n'empêche pas les autres créations\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateUnclaimedParkingInput"},"minItems":1,"maxItems":100}}}}}},"responses":{"201":{"description":"Résultat de la création en masse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/rental-agencies":{"post":{"tags":["External API"],"summary":"Créer une agence de location non réclamé(e)","description":"\nCrée une agence de location sans propriétaire (statut: awaitingOwner).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- L'entité est créée avec `ownerId = null` et `status = awaitingOwner`\n- Elle apparaît dans la liste des entités à revendiquer\n- Un possible owner (contact potentiel) peut être ajouté pour le suivi\n- Quand un propriétaire revendique l'entité, le processus de claim démarre\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnclaimedRentalAgencyInput"}}}},"responses":{"201":{"description":"Entité créée avec succès","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/rental-agencies/bulk":{"post":{"tags":["External API"],"summary":"Créer plusieurs rental-agencies non réclamés","description":"\nCrée plusieurs rental-agencies en une seule requête (max 100).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- Chaque entité est traitée individuellement\n- Les succès et échecs sont retournés séparément\n- Un échec n'empêche pas les autres créations\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateUnclaimedRentalAgencyInput"},"minItems":1,"maxItems":100}}}}}},"responses":{"201":{"description":"Résultat de la création en masse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/establishments":{"post":{"tags":["External API"],"summary":"Créer un établissement non réclamé(e)","description":"\nCrée un établissement sans propriétaire (statut: awaitingOwner).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- L'entité est créée avec `ownerId = null` et `status = awaitingOwner`\n- Elle apparaît dans la liste des entités à revendiquer\n- Un possible owner (contact potentiel) peut être ajouté pour le suivi\n- Quand un propriétaire revendique l'entité, le processus de claim démarre\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnclaimedEstablishmentInput"}}}},"responses":{"201":{"description":"Entité créée avec succès","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/external/establishments/bulk":{"post":{"tags":["External API"],"summary":"Créer plusieurs establishments non réclamés","description":"\nCrée plusieurs establishments en une seule requête (max 100).\n\n**Authentification:** Clé API requise dans le header `X-API-Key`\n\n**Comportement:**\n- Chaque entité est traitée individuellement\n- Les succès et échecs sont retournés séparément\n- Un échec n'empêche pas les autres créations\n      ","security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateUnclaimedEstablishmentInput"},"minItems":1,"maxItems":100}}}}}},"responses":{"201":{"description":"Résultat de la création en masse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUnclaimedEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/ai/chat":{"post":{"tags":["AI Chatbot"],"summary":"Envoyer un message au chatbot (SSE streaming)","description":"Endpoint principal du chatbot IA. Retourne une reponse en streaming via Server-Sent Events (SSE).\n\nLes evenements SSE possibles sont:\n- `text_delta` - Fragment de texte de la reponse\n- `tool_call` - Appel d'un outil (recherche, reservation, etc.)\n- `tool_result` - Resultat d'un appel d'outil\n- `action` - Action de navigation ou ouverture du panier\n- `quick_reply` - Boutons de reponse rapide\n- `request_feedback` - Demande de satisfaction\n- `error` - Erreur pendant le traitement\n- `done` - Fin du stream\n\nAccessible aux visiteurs (sans token) et aux utilisateurs connectes.","security":[{"bearerAuth":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequestInput"}}}},"responses":{"200":{"description":"Stream SSE de la reponse du chatbot","content":{"text/event-stream":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SSEEvent"},"description":"Flux d'evenements SSE (data: JSON\\n\\n)"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/ai/chat/sessions":{"get":{"tags":["AI Chatbot"],"summary":"Lister mes sessions de chat","description":"Retourne la liste des sessions de chat de l'utilisateur connecte.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des sessions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/ChatSession"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/ai/chat/history/{sessionId}":{"get":{"tags":["AI Chatbot"],"summary":"Historique d'une session de chat","description":"Recupere l'historique complet des messages d'une session specifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de chat"}],"responses":{"200":{"description":"Historique de la session","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ChatHistoryResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["AI Chatbot"],"summary":"Supprimer une session de chat","description":"Supprime definitivement une session de chat et tous ses messages.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de chat"}],"responses":{"200":{"description":"Session supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Session supprimee."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/ai/chat/sessions/{sessionId}/feedback":{"post":{"tags":["AI Chatbot"],"summary":"Soumettre un feedback pour une session","description":"Permet a un visiteur ou un utilisateur connecte de noter et commenter une session de chat.","security":[{"bearerAuth":[]},{}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de chat"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackInput"}}}},"responses":{"200":{"description":"Feedback enregistre","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Merci pour votre retour !"}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/ai/admin/sessions":{"get":{"tags":["AI Chatbot - Admin"],"summary":"Lister toutes les sessions de chat (Admin)","description":"Retourne la liste paginee de toutes les sessions de chat avec les details utilisateur. Reserve aux superAdmin et admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":30},"description":"Elements par page"},{"name":"hasOrdered","in":"query","schema":{"type":"boolean"},"description":"Filtrer par sessions ayant mene a une commande"},{"name":"minRating","in":"query","schema":{"type":"integer","minimum":1,"maximum":5},"description":"Note de satisfaction minimale"}],"responses":{"200":{"description":"Liste paginee des sessions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/AdminChatSession"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/ai/admin/sessions/{sessionId}":{"get":{"tags":["AI Chatbot - Admin"],"summary":"Voir une session complete (Admin)","description":"Retourne le detail complet d'une session de chat avec tous les messages. Reserve aux superAdmin et admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de chat"}],"responses":{"200":{"description":"Detail de la session","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AdminChatSessionDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/ai/generate-description":{"post":{"tags":["Content Generation"],"summary":"Generer une description d'etablissement","description":"Utilise l'IA pour generer une description marketing a partir de mots-cles et du type d'etablissement. Accessible aux roles proprio, admin, superAdmin et marketing.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDescriptionInput"}}}},"responses":{"200":{"description":"Description generee avec succes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratedDescription"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"Erreur lors de la generation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Erreur lors de la generation de description"}}}}}}}}},"/ai/generate-menu-description":{"post":{"tags":["Content Generation"],"summary":"Generer une description de plat","description":"Utilise l'IA pour generer une description appetissante d'un plat a partir de son nom et de mots-cles. Accessible aux roles proprio, admin, superAdmin et marketing.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateMenuDescriptionInput"}}}},"responses":{"200":{"description":"Description de plat generee avec succes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratedDescription"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"Erreur lors de la generation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Erreur lors de la generation de description menu"}}}}}}}}},"/ai/generate-alt-text":{"post":{"tags":["Content Generation"],"summary":"Generer un texte alternatif pour une image","description":"Utilise l'IA pour generer un texte alternatif (alt-text) accessible a partir d'une description d'image. Accessible aux roles proprio, admin, superAdmin et marketing.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateAltTextInput"}}}},"responses":{"200":{"description":"Texte alternatif genere avec succes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratedAltText"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"Erreur lors de la generation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Erreur lors de la generation de alt-text"}}}}}}}}},"/proprio/vehicle-tracking":{"post":{"tags":["Vehicle Tracking - Proprio"],"summary":"Créer une session de suivi","description":"Crée une nouvelle session de suivi véhicule pour un trajet covoiturage ou une réservation de location. Nécessite l'addon 'Suivi véhicule' activé.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTrackingSessionInput"}}}},"responses":{"201":{"description":"Session de suivi créée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TrackingSession"}}}}}},"400":{"description":"Données invalides","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Addon non activé ou non propriétaire du trajet/agence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Trajet ou réservation non trouvé(e)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Une session de suivi est déjà active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}},"get":{"tags":["Vehicle Tracking - Proprio"],"summary":"Lister mes sessions de suivi","description":"Retourne la liste paginée des sessions de suivi du proprio connecté.","security":[{"bearerAuth":[]}],"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["rental"]},"description":"Filtrer par type de session"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","paused","completed","cancelled"]},"description":"Filtrer par statut"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Éléments par page"}],"responses":{"200":{"description":"Liste des sessions de suivi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TrackingSessionListItem"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Addon non activé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/proprio/vehicle-tracking/{sessionId}":{"get":{"tags":["Vehicle Tracking - Proprio"],"summary":"Détail d'une session de suivi","description":"Retourne le détail complet d'une session de suivi incluant les participants et leurs dernières positions.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"}],"responses":{"200":{"description":"Détail de la session","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TrackingSession"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/proprio/vehicle-tracking/{sessionId}/end":{"patch":{"tags":["Vehicle Tracking - Proprio"],"summary":"Terminer une session de suivi","description":"Termine une session de suivi active. Seul le propriétaire de la session peut la terminer.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"}],"responses":{"200":{"description":"Session terminée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Session de suivi terminée"}}}}}},"400":{"description":"La session n'est pas active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/proprio/vehicle-tracking/{sessionId}/history":{"get":{"tags":["Vehicle Tracking - Proprio"],"summary":"Historique des positions","description":"Retourne l'historique paginé des positions GPS enregistrées pour une session de suivi.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":200},"description":"Éléments par page (max 200)"}],"responses":{"200":{"description":"Historique des positions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TrackingLocationLog"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/client/vehicle-tracking/trip/{tripId}":{"get":{"tags":["Vehicle Tracking - Client"],"summary":"Session de suivi d'un trajet","description":"Retourne la session de suivi active associée à un trajet covoiturage. Retourne null si aucune session active.","security":[{"bearerAuth":[]}],"parameters":[{"name":"tripId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du trajet covoiturage"}],"responses":{"200":{"description":"Session de suivi du trajet (ou null)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"oneOf":[{"$ref":"#/components/schemas/TrackingSession"},{"type":"null"}],"nullable":true,"description":"Session de suivi ou null si aucune session active"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/client/vehicle-tracking/{sessionId}":{"get":{"tags":["Vehicle Tracking - Client"],"summary":"Détail d'une session de suivi (Client)","description":"Retourne le détail d'une session de suivi. Le client doit être un participant de la session (passager ou locataire).","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"}],"responses":{"200":{"description":"Détail de la session","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TrackingSession"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/vehicle-tracking":{"get":{"tags":["Vehicle Tracking - Admin"],"summary":"Lister toutes les sessions (Admin)","description":"Retourne la liste paginée de toutes les sessions de suivi. Réservé aux admin/superAdmin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["rental"]},"description":"Filtrer par type de session"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","paused","completed","cancelled"]},"description":"Filtrer par statut"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Éléments par page"}],"responses":{"200":{"description":"Liste de toutes les sessions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TrackingSessionListItem"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/vehicle-tracking/{sessionId}":{"get":{"tags":["Vehicle Tracking - Admin"],"summary":"Détail d'une session (Admin)","description":"Retourne le détail complet d'une session de suivi. Réservé aux admin/superAdmin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"}],"responses":{"200":{"description":"Détail de la session","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TrackingSession"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/vehicle-tracking/{sessionId}/force-end":{"patch":{"tags":["Vehicle Tracking - Admin"],"summary":"Forcer la fin d'une session (Admin)","description":"Permet à un admin/superAdmin de forcer la fin d'une session de suivi active, même si le proprio ne l'a pas terminée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"}],"responses":{"200":{"description":"Session forcée à terminer","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Session forcée à terminer"}}}}}},"400":{"description":"La session n'est pas active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/vehicle-tracking/{sessionId}/history":{"get":{"tags":["Vehicle Tracking - Admin"],"summary":"Historique des positions (Admin)","description":"Retourne l'historique paginé des positions GPS d'une session. Réservé aux admin/superAdmin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la session de suivi"},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numéro de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":200},"description":"Éléments par page (max 200)"}],"responses":{"200":{"description":"Historique des positions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/TrackingLocationLog"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/addons":{"get":{"tags":["Addon Services - Owner"],"summary":"Lister les services disponibles","description":"Retourne tous les services supplementaires actifs avec le statut d'abonnement du proprietaire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des services disponibles","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AddonWithSubscription"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/addons/subscribe":{"post":{"tags":["Addon Services - Owner"],"summary":"S'abonner a un service","description":"Souscrit a un service supplementaire. Le paiement est debite du portefeuille si le solde est suffisant, sinon un paiement externe via CinetPay est initie.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeAddonInput"}}}},"responses":{"200":{"description":"Abonnement reussi ou paiement externe initie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SubscribePaymentResult"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Service introuvable ou inactif","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Deja abonne a ce service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/addons/unsubscribe":{"post":{"tags":["Addon Services - Owner"],"summary":"Se desabonner d'un service","description":"Annule l'abonnement a un service supplementaire. Le service reste actif jusqu'a la fin de la periode payee.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeAddonInput"}}}},"responses":{"200":{"description":"Desabonnement reussi","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UnsubscribeResult"}}}}}},"400":{"description":"Non abonne a ce service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Service introuvable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/addons/check/{slug}":{"get":{"tags":["Addon Services - Owner"],"summary":"Verifier l'acces a un service","description":"Verifie si le proprietaire a acces a un service supplementaire. Si non, retourne aussi le prix et le nom du service (pour l'affichage verrouille).","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug du service","example":"ai-insights"}],"responses":{"200":{"description":"Resultat de la verification d'acces","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AddonAccessResult"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/addons":{"get":{"tags":["Addon Services - Admin"],"summary":"Lister les definitions d'addons (Admin)","description":"Retourne toutes les definitions d'addons avec le nombre d'abonnes. Par defaut, seuls les addons actifs sont retournes.","security":[{"bearerAuth":[]}],"parameters":[{"name":"includeInactive","in":"query","schema":{"type":"boolean","default":false},"description":"Inclure les addons inactifs"}],"responses":{"200":{"description":"Liste des definitions d'addons","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AddonDefinitionWithCount"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Addon Services - Admin"],"summary":"Creer une definition d'addon (Admin)","description":"Cree une nouvelle definition de service supplementaire. Le slug doit etre unique.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAddonDefinitionInput"}}}},"responses":{"201":{"description":"Addon cree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AddonDefinition"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Un addon avec ce slug existe deja","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/addons/registry":{"get":{"tags":["Addon Services - Admin"],"summary":"Registre des addons systeme (Admin)","description":"Retourne le registre des addons enregistres dans le code (source of truth). Indique si chaque addon existe deja en base de donnees.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Registre des addons systeme","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AddonRegistryEntry"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/addons/{addonId}":{"put":{"tags":["Addon Services - Admin"],"summary":"Modifier une definition d'addon (Admin)","description":"Met a jour une definition d'addon. Le slug des addons systeme ne peut pas etre modifie.","security":[{"bearerAuth":[]}],"parameters":[{"name":"addonId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'addon"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAddonDefinitionInput"}}}},"responses":{"200":{"description":"Addon mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AddonDefinition"}}}}}},"400":{"description":"Impossible de modifier le slug d'un addon systeme","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Un addon avec ce slug existe deja","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Addon Services - Admin"],"summary":"Supprimer une definition d'addon (Admin)","description":"Supprime (desactive) une definition d'addon. Les addons systeme sont desactives en soft-delete.","security":[{"bearerAuth":[]}],"parameters":[{"name":"addonId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'addon"}],"responses":{"200":{"description":"Addon desactive","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Addon desactive"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/addons/{addonId}/stats":{"get":{"tags":["Addon Services - Admin"],"summary":"Statistiques d'un addon (Admin)","description":"Retourne les statistiques d'un addon: nombre d'abonnes, revenu mensuel et liste des abonnes actifs.","security":[{"bearerAuth":[]}],"parameters":[{"name":"addonId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'addon"}],"responses":{"200":{"description":"Statistiques de l'addon","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AddonStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/messaging/conversations":{"get":{"tags":["Messaging"],"summary":"Liste des conversations","description":"Retourne les conversations de l'utilisateur authentifie avec pagination.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":50},"description":"Elements par page"},{"name":"type","in":"query","schema":{"type":"string","enum":["establishment_support","platform_support"]},"description":"Filtrer par type de conversation"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","archived","closed"]},"description":"Filtrer par statut"},{"name":"category","in":"query","schema":{"$ref":"#/components/schemas/SupportTicketCategory"},"description":"Filtrer par categorie de ticket (platform_support)"}],"responses":{"200":{"description":"Liste des conversations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"conversations":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Messaging"],"summary":"Creer une conversation","description":"Cree une nouvelle conversation ou recupere une existante entre les memes participants.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationInput"}}}},"responses":{"201":{"description":"Conversation creee ou existante retournee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ConversationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Etablissement non trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/messaging/conversations/{id}":{"get":{"tags":["Messaging"],"summary":"Details d'une conversation","description":"Retourne les details d'une conversation specifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la conversation"}],"responses":{"200":{"description":"Details de la conversation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ConversationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/messaging/conversations/{id}/messages":{"get":{"tags":["Messaging"],"summary":"Liste des messages","description":"Retourne les messages d'une conversation avec pagination.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la conversation"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":30,"maximum":100},"description":"Elements par page"}],"responses":{"200":{"description":"Liste des messages","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Messaging"],"summary":"Envoyer un message","description":"Envoie un message dans une conversation. Au moins le contenu ou une piece jointe est requis.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la conversation"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageInput"}}}},"responses":{"201":{"description":"Message envoye","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/MessageResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/messaging/conversations/{id}/status":{"patch":{"tags":["Messaging"],"summary":"Mettre a jour le statut","description":"Change le statut (active / archived / closed) d'une conversation. Reserve aux admins / support staff (sauf archived qui est aussi accessible aux participants). Pour un ticket platform_support, **closed** correspond a un ticket **resolu** : le client recoit une notification plateforme (`platform_support_ticket_resolved`, canaux in-app + push) et un evenement temps reel `conversation:update` sur la room de la conversation (ainsi que `support:conversation:update` pour le back-office).","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConversationStatusInput"}}}},"responses":{"200":{"description":"Statut mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ConversationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/messaging/conversations/{id}/category":{"patch":{"tags":["Messaging"],"summary":"Mettre a jour la categorie","description":"Change la categorie d'un ticket de support (platform_support). Reserve aux admins / support staff.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConversationCategoryInput"}}}},"responses":{"200":{"description":"Categorie mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ConversationResponse"}}}}}},"400":{"description":"Categorie inapplicable (conversation non-support)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/messaging/conversations/{id}/read":{"put":{"tags":["Messaging"],"summary":"Marquer comme lu","description":"Marque tous les messages d'une conversation comme lus pour l'utilisateur authentifie.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la conversation"}],"responses":{"200":{"description":"Messages marques comme lus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Messages marques comme lus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/messaging/unread-count":{"get":{"tags":["Messaging"],"summary":"Nombre de messages non lus","description":"Retourne le nombre total de messages non lus pour l'utilisateur authentifie.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Nombre de messages non lus","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"count":{"type":"integer","description":"Nombre de messages non lus"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/messaging/push-token":{"post":{"tags":["Messaging"],"summary":"Enregistrer un token push","description":"Enregistre un token de notification push pour l'utilisateur authentifie.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterPushTokenInput"}}}},"responses":{"200":{"description":"Token enregistre","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Token enregistre"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Messaging"],"summary":"Supprimer un token push","description":"Supprime un token de notification push.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemovePushTokenInput"}}}},"responses":{"200":{"description":"Token supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Token supprime"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/messaging/push-token/remove":{"post":{"tags":["Messaging"],"summary":"Supprimer un token push (alternative)","description":"Supprime un token de notification push. Alternative POST pour les clients ne supportant pas DELETE avec body.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemovePushTokenInput"}}}},"responses":{"200":{"description":"Token supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Token supprime"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/ai-insights":{"get":{"tags":["AI Insights - Owner"],"summary":"Obtenir les insights IA","description":"Retourne les insights IA générés pour le propriétaire connecté. Utilise le cache si disponible, sinon génère de nouveaux insights via OpenAI.","security":[{"bearerAuth":[]}],"parameters":[{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement des insights (ignorer le cache)"}],"responses":{"200":{"description":"Insights IA générés","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/InsightsResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Abonnement AI Insights requis","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/owner/ai-insights/access":{"get":{"tags":["AI Insights - Owner"],"summary":"Vérifier l'accès aux insights IA","description":"Vérifie si le propriétaire a accès à l'addon AI Insights. Retourne le prix et le nom de l'addon si pas d'accès.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statut d'accès","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AiInsightsAccessResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/ai-insights/pricing/{entityType}/{entityId}":{"get":{"tags":["AI Insights - Owner"],"summary":"Suggestions de tarification dynamique","description":"Retourne les suggestions d'optimisation tarifaire pour une entité spécifique, incluant les prédictions de demande et les suggestions de promotions.","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"type":"string","enum":["hotel","restaurant","parking","event"]},"description":"Type d'entité"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'entité"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement (ignorer le cache)"}],"responses":{"200":{"description":"Suggestions de tarification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PricingOptimizationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Abonnement AI Insights requis","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/owner/ai-insights/pricing/suggestions/{suggestionId}/accept":{"put":{"tags":["AI Insights - Owner"],"summary":"Accepter une suggestion de tarification","description":"Marque une suggestion de tarification comme acceptée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la suggestion"}],"responses":{"200":{"description":"Suggestion acceptée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Suggestion acceptee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/ai-insights/pricing/suggestions/{suggestionId}/reject":{"put":{"tags":["AI Insights - Owner"],"summary":"Rejeter une suggestion de tarification","description":"Marque une suggestion de tarification comme rejetée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la suggestion"}],"responses":{"200":{"description":"Suggestion rejetée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Suggestion rejetee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/ai-insights/slots/{entityType}/{entityId}":{"get":{"tags":["AI Insights - Owner"],"summary":"Optimisation des créneaux","description":"Retourne les suggestions d'optimisation des créneaux pour une entité spécifique, incluant les statistiques de no-show, les alertes de pic de demande et les recommandations de planning.","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"type":"string","enum":["establishment","restaurant","hotel"]},"description":"Type d'entité"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'entité"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement (ignorer le cache)"}],"responses":{"200":{"description":"Suggestions d'optimisation des créneaux","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SlotOptimizationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Abonnement AI Insights requis","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/owner/ai-insights/slots/suggestions/{suggestionId}/accept":{"put":{"tags":["AI Insights - Owner"],"summary":"Accepter une suggestion de créneau","description":"Marque une suggestion d'optimisation de créneau comme acceptée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la suggestion"}],"responses":{"200":{"description":"Suggestion acceptée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Suggestion acceptee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/ai-insights/slots/suggestions/{suggestionId}/reject":{"put":{"tags":["AI Insights - Owner"],"summary":"Rejeter une suggestion de créneau","description":"Marque une suggestion d'optimisation de créneau comme rejetée.","security":[{"bearerAuth":[]}],"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la suggestion"}],"responses":{"200":{"description":"Suggestion rejetée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Suggestion rejetee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/ai-insights/{ownerId}":{"get":{"tags":["AI Insights - Admin"],"summary":"Insights IA d'un propriétaire (Admin)","description":"Retourne les insights IA générés pour un propriétaire spécifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"ownerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du propriétaire"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement des insights"}],"responses":{"200":{"description":"Insights IA du propriétaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/InsightsResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/ai-insights/{ownerId}/access":{"get":{"tags":["AI Insights - Admin"],"summary":"Vérifier l'accès IA d'un propriétaire (Admin)","description":"Vérifie si un propriétaire spécifique a accès à l'addon AI Insights.","security":[{"bearerAuth":[]}],"parameters":[{"name":"ownerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du propriétaire"}],"responses":{"200":{"description":"Statut d'accès du propriétaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/AiInsightsAccessResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/ai-insights/{ownerId}/pricing/{entityType}/{entityId}":{"get":{"tags":["AI Insights - Admin"],"summary":"Suggestions tarifaires d'un propriétaire (Admin)","description":"Retourne les suggestions d'optimisation tarifaire pour une entité d'un propriétaire spécifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"ownerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du propriétaire"},{"name":"entityType","in":"path","required":true,"schema":{"type":"string","enum":["hotel","restaurant","parking","event"]},"description":"Type d'entité"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'entité"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement"}],"responses":{"200":{"description":"Suggestions de tarification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PricingOptimizationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/ai-insights/{ownerId}/slots/{entityType}/{entityId}":{"get":{"tags":["AI Insights - Admin"],"summary":"Optimisation créneaux d'un propriétaire (Admin)","description":"Retourne les suggestions d'optimisation des créneaux pour une entité d'un propriétaire spécifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"ownerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du propriétaire"},{"name":"entityType","in":"path","required":true,"schema":{"type":"string","enum":["establishment","restaurant","hotel"]},"description":"Type d'entité"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'entité"},{"name":"refresh","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Forcer le rafraîchissement"}],"responses":{"200":{"description":"Suggestions d'optimisation des créneaux","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SlotOptimizationResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/blog/articles":{"get":{"tags":["Blog - Public"],"summary":"Liste des articles publies","description":"Retourne la liste paginee des articles publies. Supporte le filtrage par categorie et la recherche textuelle.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"minimum":1,"maximum":50},"description":"Elements par page"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filtrer par categorie"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche textuelle (titre, resume, tags)"}],"responses":{"200":{"description":"Liste des articles publies","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BlogArticle"}},"pagination":{"$ref":"#/components/schemas/BlogPagination"}}}}}},"500":{"description":"Erreur serveur","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Blog - Admin"],"summary":"Creer un article","description":"Cree un nouvel article de blog en tant que brouillon. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBlogArticleInput"}}}},"responses":{"201":{"description":"Article cree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/blog/articles/categories":{"get":{"tags":["Blog - Public"],"summary":"Liste des categories","description":"Retourne la liste des categories ayant au moins un article publie.","responses":{"200":{"description":"Liste des categories","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"example":["Tourisme","Gastronomie","Evenements","Hotellerie"]}}}},"500":{"description":"Erreur serveur","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/blog/articles/by-slug/{slug}":{"get":{"tags":["Blog - Public"],"summary":"Article par slug","description":"Retourne un article publie par son slug unique.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug unique de l'article"}],"responses":{"200":{"description":"Article trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"404":{"description":"Article non trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Erreur serveur","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/blog/articles/admin":{"get":{"tags":["Blog - Admin"],"summary":"Liste de tous les articles (Admin)","description":"Retourne la liste paginee de tous les articles, quel que soit leur statut. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"minimum":1,"maximum":50},"description":"Elements par page"},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","pending_review","published","archived"]},"description":"Filtrer par statut"},{"name":"category","in":"query","schema":{"type":"string"},"description":"Filtrer par categorie"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche textuelle (titre, resume)"}],"responses":{"200":{"description":"Liste de tous les articles","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BlogArticle"}},"pagination":{"$ref":"#/components/schemas/BlogPagination"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/blog/articles/admin/stats":{"get":{"tags":["Blog - Admin"],"summary":"Statistiques du blog (Admin)","description":"Retourne les statistiques globales du blog (total, publies, en attente, brouillons). Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques du blog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogStats"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/blog/articles/admin/{id}":{"get":{"tags":["Blog - Admin"],"summary":"Detail d'un article par ID (Admin)","description":"Retourne un article par son ID, quel que soit son statut. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"responses":{"200":{"description":"Detail de l'article","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Article non trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/blog/articles/generate":{"post":{"tags":["Blog - Admin"],"summary":"Generer un article par IA","description":"Genere un article de blog complet via l'IA a partir d'un sujet et de mots-cles. L'article est cree en tant que brouillon. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateArticleInput"}}}},"responses":{"201":{"description":"Article genere et cree en brouillon","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"Erreur lors de la generation de l'article","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/blog/articles/{id}":{"put":{"tags":["Blog - Admin"],"summary":"Modifier un article","description":"Met a jour un article existant. Les non-admins ne peuvent modifier que leurs propres articles. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlogArticleInput"}}}},"responses":{"200":{"description":"Article mis a jour","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Blog - Admin"],"summary":"Supprimer un article","description":"Supprime un article. Les non-admins ne peuvent supprimer que leurs propres articles. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"responses":{"200":{"description":"Article supprime","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Article supprime"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/blog/articles/{id}/submit":{"post":{"tags":["Blog - Admin"],"summary":"Soumettre un article pour validation","description":"Soumet un article brouillon pour validation par un admin. Seul l'auteur peut soumettre son article. Roles requis: superAdmin, admin, marketing.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"responses":{"200":{"description":"Article soumis pour validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"400":{"description":"Article non valide pour soumission (pas un brouillon ou pas l'auteur)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/blog/articles/{id}/review":{"patch":{"tags":["Blog - Admin"],"summary":"Valider ou rejeter un article (Admin only)","description":"Approuve ou rejette un article en attente de validation. Approbation immediate ou planifiee via publishAt. Roles requis: superAdmin, admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewArticleInput"}}}},"responses":{"200":{"description":"Article valide ou rejete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"400":{"description":"Article non en attente de validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/blog/articles/{id}/unpublish":{"patch":{"tags":["Blog - Admin"],"summary":"Depublier un article","description":"Retire l'article du site public (statut archived, publishedAt efface). Article doit etre publie ou planifie (statut published). Roles requis: superAdmin, admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"responses":{"200":{"description":"Article depublie","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"400":{"description":"Article non eligible","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/blog/articles/{id}/schedule":{"patch":{"tags":["Blog - Admin"],"summary":"Planifier la publication","description":"Definit status=published et publishedAt dans le futur (visible sur le site a cette date). Roles requis: superAdmin, admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchedulePublicationInput"}}}},"responses":{"200":{"description":"Publication planifiee","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogArticle"}}}},"400":{"description":"Date invalide ou article introuvable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/claims/unclaimed":{"get":{"tags":["Claims"],"summary":"Liste des entités non revendiquées","description":"Récupère la liste des entités sans propriétaire disponibles pour revendication","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":10}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"city","in":"query","schema":{"type":"string"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste des entités non revendiquées","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/UnclaimedEntity"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé - Proprio requis"}}}},"/owner/claims/unclaimed/{entityType}/{entityId}":{"get":{"tags":["Claims"],"summary":"Détail d'une entité non revendiquée","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de l'entité","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UnclaimedEntity"}}}}}},"404":{"description":"Entité non trouvée ou déjà revendiquée"}}}},"/owner/claims":{"post":{"tags":["Claims"],"summary":"Soumettre une demande de revendication","description":"Soumet une demande pour revendiquer une entité sans propriétaire","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClaimRequestInput"}}}},"responses":{"201":{"description":"Demande de revendication créée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"},"message":{"type":"string"}}}}}},"400":{"description":"Entité déjà revendiquée ou demande existante"},"404":{"description":"Entité non trouvée"}}}},"/owner/claims/bulk":{"post":{"tags":["Claims"],"summary":"Soumettre plusieurs revendications","description":"Soumet plusieurs demandes de revendication en lot (max 10)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBulkClaimInput"}}}},"responses":{"201":{"description":"Résultat du traitement en lot","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BulkClaimResult"}}}}}},"400":{"description":"Données invalides"}}}},"/owner/claims/removal":{"post":{"tags":["Claims"],"summary":"Demander la suppression d'une entité","description":"Soumet une demande pour supprimer une entité que vous possédez","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRemovalRequestInput"}}}},"responses":{"201":{"description":"Demande de suppression créée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"},"message":{"type":"string"}}}}}},"400":{"description":"Vous n'êtes pas propriétaire de cette entité"},"404":{"description":"Entité non trouvée"}}}},"/owner/claims/my-requests":{"get":{"tags":["Claims"],"summary":"Liste de mes demandes","description":"Récupère la liste de mes demandes de revendication et suppression","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":10}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/OwnershipRequestType"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/OwnershipRequestStatus"}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste de mes demandes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/OwnershipRequest"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}}}},"/owner/claims/my-requests/{id}":{"get":{"tags":["Claims"],"summary":"Détail d'une de mes demandes","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de la demande","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"}}}}}},"404":{"description":"Demande non trouvée"}}}},"/owner/claims/my-requests/{id}/cancel":{"post":{"tags":["Claims"],"summary":"Annuler ma demande","description":"Annule une de mes demandes en attente","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Demande annulée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"400":{"description":"La demande n'est plus en attente"},"404":{"description":"Demande non trouvée"}}}},"/admin/claims":{"get":{"tags":["Claims"],"summary":"Liste toutes les demandes (Admin)","description":"Récupère toutes les demandes de revendication et suppression","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":10}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/OwnershipRequestType"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/OwnershipRequestStatus"}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/ClaimableEntityType"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste de toutes les demandes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/OwnershipRequest"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Non authentifié"},"403":{"description":"Accès refusé - Admin requis"}}}},"/admin/claims/stats":{"get":{"tags":["Claims"],"summary":"Statistiques des demandes (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des demandes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ClaimStats"}}}}}}}}},"/admin/claims/{id}":{"get":{"tags":["Claims"],"summary":"Détail d'une demande (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Détails de la demande","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"}}}}}},"404":{"description":"Demande non trouvée"}}}},"/admin/claims/{id}/approve":{"post":{"tags":["Claims"],"summary":"Approuver une demande (Admin)","description":"Approuve une demande de revendication ou suppression. Pour une revendication, transfère la propriété. Pour une suppression, archive l'entité.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessRequestInput"}}}},"responses":{"200":{"description":"Demande approuvée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"},"message":{"type":"string"}}}}}},"400":{"description":"La demande n'est plus en attente ou l'entité est déjà revendiquée"},"404":{"description":"Demande non trouvée"}}}},"/admin/claims/{id}/reject":{"post":{"tags":["Claims"],"summary":"Rejeter une demande (Admin)","description":"Rejette une demande de revendication ou suppression avec une raison","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reviewNote"],"properties":{"reviewNote":{"type":"string","minLength":1,"maxLength":1000}}}}}},"responses":{"200":{"description":"Demande rejetée","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/OwnershipRequest"},"message":{"type":"string"}}}}}},"400":{"description":"La demande n'est plus en attente ou raison manquante"},"404":{"description":"Demande non trouvée"}}}},"/admin/claims/bulk-approve":{"post":{"tags":["Claims"],"summary":"Approuver plusieurs demandes (Admin)","description":"Approuve plusieurs demandes en lot","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requestIds"],"properties":{"requestIds":{"type":"array","minItems":1,"items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"Résultat du traitement en lot","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BulkProcessResult"}}}}}}}}},"/admin/claims/bulk-reject":{"post":{"tags":["Claims"],"summary":"Rejeter plusieurs demandes (Admin)","description":"Rejette plusieurs demandes en lot avec une raison commune","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkProcessInput"}}}},"responses":{"200":{"description":"Résultat du traitement en lot","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BulkProcessResult"}}}}}}}}},"/admin/email-logs":{"get":{"tags":["Email Logs"],"summary":"Liste des emails envoyes (Admin)","description":"Retourne l'historique pagine et filtre de tous les emails envoyes par la plateforme.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche dans destinataire et sujet"},{"name":"templateType","in":"query","schema":{"type":"string"},"description":"Filtrer par type de template (welcome, password_reset, 2fa_code, etc.)"},{"name":"status","in":"query","schema":{"type":"string","enum":["sent","failed"]},"description":"Filtrer par statut"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"Date de debut"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"},"description":"Date de fin"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["sentAt","to","subject","templateType","status"],"default":"sentAt"}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Liste des emails","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailLog"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/email-logs/stats":{"get":{"tags":["Email Logs"],"summary":"Statistiques des emails (Admin)","description":"Retourne les statistiques globales des emails envoyes.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/EmailLogStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/email-logs/{id}":{"get":{"tags":["Email Logs"],"summary":"Detail d'un email (Admin)","description":"Retourne le detail complet d'un email envoye, incluant le contenu HTML.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail de l'email","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/EmailLog"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/notifications":{"get":{"tags":["Notifications"],"summary":"Liste mes notifications","description":"Récupère la liste de mes notifications plateforme","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"isRead","in":"query","schema":{"type":"boolean"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/PlatformNotificationType"}}],"responses":{"200":{"description":"Liste des notifications","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/PlatformNotification"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Non authentifié"}}}},"/notifications/unread-count":{"get":{"tags":["Notifications"],"summary":"Nombre de notifications non lues","description":"Retourne le nombre de notifications non lues","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Nombre de notifications non lues","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UnreadCountResponse"}}}}}},"401":{"description":"Non authentifié"}}}},"/notifications/{id}/read":{"post":{"tags":["Notifications"],"summary":"Marquer une notification comme lue","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Notification marquée comme lue","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/MarkReadResponse"}}}}}},"404":{"description":"Notification non trouvée"}}}},"/notifications/read-all":{"post":{"tags":["Notifications"],"summary":"Marquer toutes les notifications comme lues","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Toutes les notifications marquées comme lues","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/MarkAllReadResponse"}}}}}}}}},"/payments/initiate":{"post":{"tags":["Payments"],"summary":"Initier un paiement","description":"Initie un nouveau paiement pour une reservation. Inclut une verification anti-fraude.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiatePaymentInput"}}}},"responses":{"201":{"description":"Session de paiement creee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PaymentSession"}}}}}},"400":{"description":"Reservation deja payee ou paiement deja complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Reservation non trouvee","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/payments/verify/{reference}":{"get":{"tags":["Payments"],"summary":"Verifier le statut d'un paiement","description":"Verifie le statut d'un paiement aupres du fournisseur de paiement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string"},"description":"Reference du paiement (PMT-xxx)","example":"PMT-ABC123DEF456"}],"responses":{"200":{"description":"Statut du paiement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/VerifyPaymentResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Paiement non trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payments/reservation/{reservationId}":{"get":{"tags":["Payments"],"summary":"Obtenir le paiement d'une reservation","description":"Retourne le paiement associe a une reservation.","security":[{"bearerAuth":[]}],"parameters":[{"name":"reservationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la reservation"}],"responses":{"200":{"description":"Paiement de la reservation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Payment"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/payments/history":{"get":{"tags":["Payments"],"summary":"Historique de paiements","description":"Retourne l'historique des paiements de l'utilisateur connecte (pagine).","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"minimum":1,"maximum":100},"description":"Elements par page"}],"responses":{"200":{"description":"Historique des paiements","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentWithReservation"}},"pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":10},"total":{"type":"integer","example":25},"totalPages":{"type":"integer","example":3}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/payments/{paymentId}/refund":{"post":{"tags":["Payments"],"summary":"Demander un remboursement","description":"Demande le remboursement d'un paiement complete. Le montant peut etre partiel.","security":[{"bearerAuth":[]}],"parameters":[{"name":"paymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du paiement"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundInput"}}}},"responses":{"200":{"description":"Resultat du remboursement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundResult"}}}}}},"400":{"description":"Seuls les paiements completes peuvent etre rembourses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Paiement non trouve","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/webhooks/cinetpay":{"post":{"tags":["Payments — Webhooks"],"summary":"CinetPay payment webhook (collect)","description":"Receives notifications when a CinetPay payment is accepted or refused.\n\n**Signature** — `x-token` or `x-cinetpay-signature` header (HMAC SHA256).\n\n**Production payload**: `cpm_trans_id` is the internal reference (`PMT-`, `CART-`, `GFT-`, `CRD-`, `VC-`...). Status is in `cpm_payment_status` (`ACCEPTED` | `REFUSED`).\n\n**Sandbox payload**: `merchant_transaction_id` carries the reference. The webhook does **not** include the final status — the server calls back the verify API to determine `code: 100 SUCCESS` (→ completed) or other error codes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","description":"Production payload","properties":{"cpm_site_id":{"type":"string"},"cpm_trans_id":{"type":"string","description":"= internal reference (e.g. PMT-XXXX, GFT-XXXX)"},"cpm_trans_date":{"type":"string"},"cpm_amount":{"type":"string"},"cpm_currency":{"type":"string","example":"XOF"},"cpm_payid":{"type":"string"},"cpm_payment_status":{"type":"string","enum":["ACCEPTED","REFUSED"]},"signature":{"type":"string","description":"HMAC sha256(cpm_trans_id + siteId)"},"cpm_custom":{"type":"string","nullable":true}},"required":["cpm_trans_id","cpm_payment_status"]},{"type":"object","description":"Sandbox payload (status fetched via verify API)","properties":{"merchant_transaction_id":{"type":"string"},"notify_token":{"type":"string"},"transaction_id":{"type":"string"},"code":{"type":"integer","example":100,"description":"100 = ok, 404 = NOT_FOUND (still pending)"},"status":{"type":"integer","example":200},"currency":{"type":"string"},"country":{"type":"string"},"payment_method":{"type":"string"}},"required":["merchant_transaction_id"]}]}}}},"responses":{"200":{"description":"Webhook accepted (always returned, even on validation errors)"},"400":{"description":"Invalid signature"}}}},"/webhooks/stripe":{"post":{"tags":["Payments — Webhooks"],"summary":"Stripe payment webhook","description":"Stripe Events for hosted payment intents. Body must be the raw bytes (`application/json` with raw body kept) so the `stripe-signature` header can be validated.\n\nThe internal reference is read from `data.object.metadata.reference`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","example":"evt_xxx"},"object":{"type":"string","example":"event"},"type":{"type":"string","example":"payment_intent.succeeded"},"data":{"type":"object","properties":{"object":{"type":"object","description":"PaymentIntent or Charge object","properties":{"metadata":{"type":"object","properties":{"reference":{"type":"string","description":"= internal payment reference"}}}}}}}},"required":["id","type","data"]}}}},"parameters":[{"name":"stripe-signature","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook accepted"},"400":{"description":"Invalid signature"}}}},"/webhooks/paypal":{"post":{"tags":["Payments — Webhooks"],"summary":"PayPal payment webhook","description":"PayPal event notifications. Internal reference is read from `resource.custom_id`.\n\nSignature headers used for verification: `paypal-auth-algo`, `paypal-cert-url`, `paypal-transmission-id`, `paypal-transmission-sig`, `paypal-transmission-time`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Event id"},"event_type":{"type":"string","example":"PAYMENT.CAPTURE.COMPLETED"},"resource":{"type":"object","properties":{"id":{"type":"string"},"custom_id":{"type":"string","description":"= internal reference"},"status":{"type":"string","enum":["COMPLETED","DECLINED","PENDING"]}}}}}}}},"responses":{"200":{"description":"Webhook accepted"},"400":{"description":"Invalid signature"}}}},"/webhooks/moneyfusion":{"post":{"tags":["Payments — Webhooks"],"summary":"MoneyFusion payment webhook (collect)","description":"MoneyFusion notification for payments. Verified via `x-moneyfusion-signature`. The internal reference is read from `reference`; the provider transaction token is `tokenPay` (also stored as `Payment.externalId`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tokenPay":{"type":"string","description":"Provider token = Payment.externalId"},"personal_Info":{"type":"object","nullable":true},"paymentStatus":{"type":"string","enum":["paid","failure","pending","completed"]},"transactionId":{"type":"string","nullable":true},"reference":{"type":"string","description":"= internal reference (PMT-, CART-, GFT-, CRD-, VC-)"},"amount":{"type":"number","nullable":true}}}}}},"responses":{"200":{"description":"Webhook accepted"},"400":{"description":"Invalid signature"}}}},"/webhooks/moneyfusion/transfer":{"post":{"tags":["Payments — Webhooks"],"summary":"MoneyFusion transfer (payout) webhook","description":"Notifications for owner cashouts via MoneyFusion. Maps `payout.session.completed` → cashout `VAL`, `payout.session.cancelled` → `rejected`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","enum":["payout.session.completed","payout.session.cancelled"]},"tokenPay":{"type":"string"},"reference":{"type":"string","description":"= cashout reference","nullable":true},"amount":{"type":"number","nullable":true}}}}}},"responses":{"200":{"description":"Webhook accepted"}}}},"/webhooks/cinetpay/transfer":{"post":{"tags":["Payments — Webhooks"],"summary":"CinetPay transfer (payout) webhook","description":"Notifications for owner cashouts via CinetPay Transfer.\n\n**Production payload**: `{ client_transaction_id, treatment_status: 'VAL' | 'rejected' | 'PENDING' }`.\n\n**Sandbox payload**: `{ notify_token, merchant_transaction_id, transaction_id, user }` — the server queries the transfer-check API to map the status.","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","description":"Production","properties":{"client_transaction_id":{"type":"string"},"treatment_status":{"type":"string","enum":["VAL","rejected","PENDING"]}}},{"type":"object","description":"Sandbox","properties":{"notify_token":{"type":"string"},"merchant_transaction_id":{"type":"string"},"transaction_id":{"type":"string"},"user":{"type":"object"}}}]}}}},"responses":{"200":{"description":"Webhook accepted"}}}},"/webhooks/mtn-momo/collection":{"post":{"tags":["Payments — Webhooks"],"summary":"MTN MoMo collection webhook (RequestToPay callback)","description":"Callback from MTN MoMo Collection API after a `RequestToPay`. Both `POST` and `PUT` are accepted (MTN sends `PUT`). `externalId` is the internal payment reference; `status` is `SUCCESSFUL` | `FAILED` | `PENDING`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"referenceId":{"type":"string","format":"uuid","description":"MoMo request id"},"externalId":{"type":"string","description":"= internal payment reference"},"status":{"type":"string","enum":["SUCCESSFUL","FAILED","PENDING"]},"amount":{"type":"string"},"currency":{"type":"string"},"payer":{"type":"object","properties":{"partyIdType":{"type":"string","example":"MSISDN"},"partyId":{"type":"string"}}},"reason":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Webhook accepted"}}},"put":{"$ref":"#/paths/~1webhooks~1mtn-momo~1collection/post"}},"/webhooks/mtn-momo/disbursement":{"post":{"tags":["Payments — Webhooks"],"summary":"MTN MoMo disbursement webhook (transfer payout callback)","description":"Callback from MTN MoMo Disbursement API. `externalId` is the internal cashout reference. `SUCCESSFUL` → cashout `VAL`, anything else → `rejected`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"referenceId":{"type":"string","format":"uuid"},"externalId":{"type":"string","description":"= cashout reference"},"status":{"type":"string","enum":["SUCCESSFUL","FAILED","PENDING"]},"amount":{"type":"string"},"currency":{"type":"string"},"payee":{"type":"object","properties":{"partyIdType":{"type":"string","example":"MSISDN"},"partyId":{"type":"string"}}},"reason":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Webhook accepted"}}},"put":{"$ref":"#/paths/~1webhooks~1mtn-momo~1disbursement/post"}},"/webhooks/wave":{"post":{"tags":["Payments — Webhooks"],"summary":"Wave checkout webhook","description":"Wave checkout session events. Verified via `wave-signature`. The internal reference is `data.client_reference`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Event id"},"type":{"type":"string","enum":["checkout.session.completed","checkout.session.payment_failed"]},"data":{"type":"object","properties":{"id":{"type":"string","description":"Wave session id"},"client_reference":{"type":"string","description":"= internal payment reference"},"amount":{"type":"string"},"currency":{"type":"string","example":"XOF"},"payment_status":{"type":"string","enum":["succeeded","failed"]},"when_completed":{"type":"string","format":"date-time"}}}}}}}},"responses":{"200":{"description":"Webhook accepted"}}}},"/webhooks/mock":{"post":{"tags":["Payments — Webhooks"],"summary":"Mock webhook (development only)","description":"Local-only endpoint to simulate provider callbacks. Returns 403 outside `NODE_ENV=development`.\n\nUseful for end-to-end testing of cart/gift-card/credit/video-call activation flows without hitting a real PSP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reference":{"type":"string","description":"= internal reference (PMT-, CART-, GFT-, CRD-, VC-)"},"status":{"type":"string","enum":["completed","failed","pending"]},"amount":{"type":"number","nullable":true}},"required":["reference","status"]}}}},"responses":{"200":{"description":"Mock webhook processed"},"403":{"description":"Mock webhook only available in development"}}}},"/users/payment-methods":{"get":{"tags":["Saved Payment Methods"],"summary":"Lister mes methodes de paiement","description":"Retourne la liste des methodes de paiement enregistrees de l'utilisateur connecte.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des methodes de paiement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/SavedPaymentMethod"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Saved Payment Methods"],"summary":"Ajouter une methode de paiement","description":"Enregistre une nouvelle methode de paiement pour l'utilisateur connecte.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSavedPaymentMethodInput"}}}},"responses":{"201":{"description":"Methode de paiement ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement ajoutee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/users/payment-methods/{id}":{"put":{"tags":["Saved Payment Methods"],"summary":"Modifier une methode de paiement","description":"Met a jour une methode de paiement enregistree de l'utilisateur connecte.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSavedPaymentMethodInput"}}}},"responses":{"200":{"description":"Methode de paiement mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement mise a jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Saved Payment Methods"],"summary":"Supprimer une methode de paiement","description":"Supprime une methode de paiement enregistree de l'utilisateur connecte.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"responses":{"200":{"description":"Methode de paiement supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Methode de paiement supprimee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/users/payment-methods/{id}/default":{"patch":{"tags":["Saved Payment Methods"],"summary":"Definir une methode par defaut","description":"Definit une methode de paiement comme methode par defaut pour l'utilisateur connecte.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"responses":{"200":{"description":"Methode de paiement definie par defaut","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement definie par defaut"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/payment-methods":{"get":{"tags":["Saved Payment Methods"],"summary":"Lister les methodes de paiement (proprio)","description":"Retourne la liste des methodes de paiement enregistrees du proprietaire connecte. Necessite le role 'proprio'.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des methodes de paiement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/SavedPaymentMethod"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Saved Payment Methods"],"summary":"Ajouter une methode de paiement (proprio)","description":"Enregistre une nouvelle methode de paiement pour le proprietaire connecte. Necessite le role 'proprio'.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSavedPaymentMethodInput"}}}},"responses":{"201":{"description":"Methode de paiement ajoutee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement ajoutee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/payment-methods/{id}":{"put":{"tags":["Saved Payment Methods"],"summary":"Modifier une methode de paiement (proprio)","description":"Met a jour une methode de paiement enregistree du proprietaire. Necessite le role 'proprio'.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSavedPaymentMethodInput"}}}},"responses":{"200":{"description":"Methode de paiement mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement mise a jour"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Saved Payment Methods"],"summary":"Supprimer une methode de paiement (proprio)","description":"Supprime une methode de paiement enregistree du proprietaire. Necessite le role 'proprio'.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"responses":{"200":{"description":"Methode de paiement supprimee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Methode de paiement supprimee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/payment-methods/{id}/default":{"patch":{"tags":["Saved Payment Methods"],"summary":"Definir une methode par defaut (proprio)","description":"Definit une methode de paiement comme methode par defaut pour le proprietaire. Necessite le role 'proprio'.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la methode de paiement"}],"responses":{"200":{"description":"Methode de paiement definie par defaut","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SavedPaymentMethod"},"message":{"type":"string","example":"Methode de paiement definie par defaut"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/favorites":{"get":{"tags":["Favorites"],"summary":"Lister mes favoris","description":"Retourne la liste des favoris de l'utilisateur connecte avec pagination.","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"query","schema":{"type":"string","enum":["hotel","restaurant","establishment","parking","rental_agency","event"]},"description":"Filtrer par type d'entite"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Elements par page"}],"responses":{"200":{"description":"Liste des favoris","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Favorite"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Favorites"],"summary":"Ajouter un favori","description":"Ajoute une entite aux favoris de l'utilisateur.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddFavoriteInput"}}}},"responses":{"201":{"description":"Favori ajoute","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Favorite"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"Deja en favori","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/favorites/stats":{"get":{"tags":["Favorites"],"summary":"Statistiques des favoris","description":"Retourne les statistiques des favoris de l'utilisateur.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/FavoriteStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/favorites/check/{entityType}/{entityId}":{"get":{"tags":["Favorites"],"summary":"Verifier si une entite est en favori","description":"Verifie si une entite specifique est dans les favoris de l'utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"type":"string","enum":["hotel","restaurant","establishment","parking","rental_agency","event"]},"description":"Type d'entite"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'entite"}],"responses":{"200":{"description":"Resultat de la verification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/FavoriteCheck"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/favorites/{id}":{"delete":{"tags":["Favorites"],"summary":"Supprimer un favori","description":"Retire une entite des favoris de l'utilisateur.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du favori"}],"responses":{"200":{"description":"Favori supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Favori supprime"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/shops":{"get":{"tags":["Shops - Public"],"summary":"Lister les boutiques publiques","description":"Retourne la liste des boutiques publiques avec recherche et pagination.","parameters":[{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche par nom"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20},"description":"Elements par page"}],"responses":{"200":{"description":"Liste des boutiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Shop"}}}}}}}}}},"/shops/{slug}":{"get":{"tags":["Shops - Public"],"summary":"Obtenir une boutique par slug","description":"Retourne les details d'une boutique publique via son slug.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug de la boutique"}],"responses":{"200":{"description":"Details de la boutique","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Shop"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/shops/{slug}/services":{"get":{"tags":["Shops - Public"],"summary":"Services d'une boutique","description":"Retourne tous les services (hotels, restaurants, parkings, etc.) d'une boutique.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"Slug de la boutique"}],"responses":{"200":{"description":"Services de la boutique","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ShopServices"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/shop":{"get":{"tags":["Shops - Owner"],"summary":"Ma boutique","description":"Retourne la boutique du proprietaire connecte avec le nombre de services.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Boutique du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","nullable":true,"properties":{"shop":{"$ref":"#/components/schemas/Shop"},"servicesCount":{"$ref":"#/components/schemas/ShopServicesCount"}}},"message":{"type":"string","nullable":true,"example":"Aucune boutique configuree"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Shops - Owner"],"summary":"Creer ma boutique","description":"Cree une nouvelle boutique pour le proprietaire connecte.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShopInput"}}}},"responses":{"201":{"description":"Boutique creee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Shop"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Boutique deja existante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}},"patch":{"tags":["Shops - Owner"],"summary":"Modifier ma boutique","description":"Met a jour la boutique du proprietaire connecte.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateShopInput"}}}},"responses":{"200":{"description":"Boutique mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Shop"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/owner/shop/regenerate-qr":{"post":{"tags":["Shops - Owner"],"summary":"Regenerer le QR code","description":"Regenere le QR code de la boutique du proprietaire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"QR code regenere","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"qrCodeData":{"type":"string","description":"Donnees du QR code"},"deepLink":{"type":"string","description":"Lien profond vers la boutique","example":"reservababi://shop/ma-boutique"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/shop/visibility":{"patch":{"tags":["Shops - Owner"],"summary":"Changer la visibilite","description":"Active ou desactive la visibilite publique de la boutique.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleVisibilityInput"}}}},"responses":{"200":{"description":"Visibilite mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"isPublic":{"type":"boolean","description":"Nouvelle valeur de visibilite"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/shop/services":{"get":{"tags":["Shops - Owner"],"summary":"Mes services","description":"Retourne tous les services du proprietaire (hotels, restaurants, parkings, etc.).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Services du proprietaire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ShopServices"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/carts":{"get":{"tags":["Carts"],"summary":"Mon panier","description":"Retourne le panier de l'utilisateur connecte.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Panier de l'utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Carts"],"summary":"Vider mon panier","description":"Supprime tous les articles du panier.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Panier vide","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/carts/items":{"post":{"tags":["Carts"],"summary":"Ajouter un article au panier","description":"Ajoute un article (hotel, restaurant, parking, etc.) au panier.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCartItemInput"}}}},"responses":{"201":{"description":"Article ajoute","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/carts/items/{itemId}":{"put":{"tags":["Carts"],"summary":"Modifier un article du panier","description":"Met a jour la quantite ou les options d'un article du panier.","security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article dans le panier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCartItemInput"}}}},"responses":{"200":{"description":"Article mis a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Carts"],"summary":"Retirer un article du panier","description":"Supprime un article specifique du panier.","security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'article dans le panier"}],"responses":{"200":{"description":"Article retire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/carts/promo-code":{"post":{"tags":["Carts"],"summary":"Appliquer un code promo","description":"Applique un code promotionnel au panier.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyPromoCodeInput"}}}},"responses":{"200":{"description":"Code promo applique","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"400":{"description":"Code promo invalide ou expire","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"tags":["Carts"],"summary":"Retirer le code promo","description":"Retire le code promotionnel applique au panier.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Code promo retire","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Cart"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/carts/checkout":{"post":{"tags":["Carts"],"summary":"Valider le panier","description":"Valide le panier et prepare les reservations pour le paiement.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Panier valide, reservations preparees","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/CheckoutResult"}}}}}},"400":{"description":"Panier vide ou articles invalides","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/carts/payment/initiate":{"post":{"tags":["Carts"],"summary":"Initier le paiement","description":"Initie le processus de paiement pour le panier (CinetPay, Stripe, PayPal).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateCartPaymentInput"}}}},"responses":{"201":{"description":"Session de paiement creee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PaymentSession"}}}}}},"400":{"description":"Panier non valide pour le paiement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/carts/payment/verify/{reference}":{"get":{"tags":["Carts"],"summary":"Verifier le paiement","description":"Verifie le statut d'un paiement par sa reference.","security":[{"bearerAuth":[]}],"parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string"},"description":"Reference du paiement"}],"responses":{"200":{"description":"Statut du paiement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PaymentVerification"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/invoices/{reservationId}/download":{"get":{"tags":["Invoices"],"summary":"Telecharger la facture d'une reservation","description":"Telecharge la facture PDF pour une reservation specifique (legacy).","security":[{"bearerAuth":[]}],"parameters":[{"name":"reservationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la reservation"}],"responses":{"200":{"description":"Fichier PDF de la facture","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}},"headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"attachment; filename=\"invoice-xxx.pdf\""}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/invoices/checkout/{checkoutGroupId}":{"get":{"tags":["Invoices"],"summary":"Lister les factures d'un checkout","description":"Retourne toutes les factures (globale et par proprietaire) pour un groupe de checkout.","security":[{"bearerAuth":[]}],"parameters":[{"name":"checkoutGroupId","in":"path","required":true,"schema":{"type":"string"},"description":"ID du groupe de checkout"}],"responses":{"200":{"description":"Liste des factures","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceSummary"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/invoices/checkout/{checkoutGroupId}/global":{"get":{"tags":["Invoices"],"summary":"Telecharger la facture globale","description":"Telecharge la facture PDF globale pour un groupe de checkout.","security":[{"bearerAuth":[]}],"parameters":[{"name":"checkoutGroupId","in":"path","required":true,"schema":{"type":"string"},"description":"ID du groupe de checkout"}],"responses":{"200":{"description":"Fichier PDF de la facture globale","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}},"headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"attachment; filename=\"invoice-global-xxx.pdf\""}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/invoices/checkout/{checkoutGroupId}/owner/{ownerId}":{"get":{"tags":["Invoices"],"summary":"Telecharger la facture d'un proprietaire","description":"Telecharge la facture PDF specifique a un proprietaire pour un groupe de checkout.","security":[{"bearerAuth":[]}],"parameters":[{"name":"checkoutGroupId","in":"path","required":true,"schema":{"type":"string"},"description":"ID du groupe de checkout"},{"name":"ownerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID du proprietaire"}],"responses":{"200":{"description":"Fichier PDF de la facture proprietaire","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}},"headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"attachment; filename=\"invoice-owner-xxx.pdf\""}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/invoices/scan-qr":{"post":{"tags":["Invoices"],"summary":"Scanner un QR code de facture","description":"Traite un QR code scanne depuis une facture proprietaire pour verifier les informations.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanInvoiceQRInput"}}}},"responses":{"200":{"description":"Resultat du scan QR","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ScanInvoiceQRResult"}}}}}},"400":{"description":"QR code invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/countries":{"get":{"tags":["Countries"],"summary":"Lister tous les pays","description":"Retourne la liste de tous les pays disponibles dans l'application.","responses":{"200":{"description":"Liste des pays","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}}}}}}}}},"/countries/dial-codes":{"get":{"tags":["Countries"],"summary":"Lister les indicatifs telephoniques","description":"Retourne la liste des indicatifs telephoniques avec les pays associes.","responses":{"200":{"description":"Liste des indicatifs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialCodeEntry"}}}}}}}}}},"/countries/by-dial-code/{dialCode}":{"get":{"tags":["Countries"],"summary":"Trouver un pays par indicatif","description":"Recherche un pays par son indicatif telephonique.","parameters":[{"name":"dialCode","in":"path","required":true,"schema":{"type":"string"},"description":"Indicatif telephonique (ex: +221)","example":"+221"}],"responses":{"200":{"description":"Pays trouve","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Country"}}}}}},"404":{"description":"Pays non trouve","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"COUNTRY_NOT_FOUND"},"message":{"type":"string","example":"Country not found"}}}}}}}}}}},"/countries/by-iso/{isoAlpha2}":{"get":{"tags":["Countries"],"summary":"Trouver un pays par code ISO","description":"Recherche un pays par son code ISO alpha-2.","parameters":[{"name":"isoAlpha2","in":"path","required":true,"schema":{"type":"string","minLength":2,"maxLength":2},"description":"Code ISO alpha-2 du pays (ex: SN, FR, US)","example":"SN"}],"responses":{"200":{"description":"Pays trouve","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Country"}}}}}},"404":{"description":"Pays non trouve","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"COUNTRY_NOT_FOUND"},"message":{"type":"string","example":"Country not found"}}}}}}}}}}},"/admin/permissions":{"get":{"tags":["Permissions - Admin"],"summary":"Liste de toutes les permissions (superAdmin)","description":"Retourne toutes les permissions groupees par module. Accessible uniquement aux superAdmin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Permissions groupees par module","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"permissions":{"$ref":"#/components/schemas/GroupedPermissions"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/permissions/matrix":{"get":{"tags":["Permissions - Admin"],"summary":"Matrice role-permission (superAdmin)","description":"Retourne la matrice complete des permissions par role. Permet de visualiser quelles permissions sont attribuees a chaque role.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Matrice des permissions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PermissionMatrix"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/permissions/roles/{role}":{"get":{"tags":["Permissions - Admin"],"summary":"Permissions d'un role (superAdmin)","description":"Retourne les permissions attribuees a un role specifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"role","in":"path","required":true,"schema":{"type":"string"},"description":"Nom du role (ex: admin, proprio, agent, organisateur, prestataire)"}],"responses":{"200":{"description":"Permissions du role","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RolePermissions"}}}}}},"400":{"description":"Role invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"tags":["Permissions - Admin"],"summary":"Definir les permissions d'un role (superAdmin)","description":"Remplace toutes les permissions d'un role par la liste fournie.","security":[{"bearerAuth":[]}],"parameters":[{"name":"role","in":"path","required":true,"schema":{"type":"string"},"description":"Nom du role"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPermissionsInput"}}}},"responses":{"200":{"description":"Permissions mises a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Permissions updated for role admin"}}}}}},"400":{"description":"Role invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/permissions/roles/{role}/toggle":{"patch":{"tags":["Permissions - Admin"],"summary":"Activer/desactiver une permission pour un role (superAdmin)","description":"Active ou desactive une permission specifique pour un role donne.","security":[{"bearerAuth":[]}],"parameters":[{"name":"role","in":"path","required":true,"schema":{"type":"string"},"description":"Nom du role"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TogglePermissionInput"}}}},"responses":{"200":{"description":"Permission activee ou desactivee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/TogglePermissionResult"},"message":{"type":"string","example":"Permission granted for role admin"}}}}}},"400":{"description":"Role invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/permissions/reset-defaults/{role}":{"post":{"tags":["Permissions - Admin"],"summary":"Reinitialiser les permissions par defaut (superAdmin)","description":"Reinitialise les permissions d'un role a ses valeurs par defaut definies dans le seed.","security":[{"bearerAuth":[]}],"parameters":[{"name":"role","in":"path","required":true,"schema":{"type":"string"},"description":"Nom du role"}],"responses":{"200":{"description":"Permissions reinitialisees","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Permissions reset to defaults for role admin"}}}}}},"400":{"description":"Role invalide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/users/my-permissions":{"get":{"tags":["Permissions - User"],"summary":"Mes permissions","description":"Retourne les permissions de l'utilisateur authentifie en fonction de son role.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Permissions de l'utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/Permission"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/refunds":{"post":{"tags":["Refunds - Client"],"summary":"Creer une demande de remboursement","description":"Cree une nouvelle demande de remboursement pour une reservation. Une detection de fraude est effectuee automatiquement.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRefundRequestInput"}}}},"responses":{"201":{"description":"Demande de remboursement creee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundRequest"},"message":{"type":"string","example":"Demande de remboursement creee avec succes"}}}}}},"400":{"description":"Donnees invalides ou reservation non eligible","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/refunds/my-requests":{"get":{"tags":["Refunds - Client"],"summary":"Mes demandes de remboursement","description":"Retourne la liste des demandes de remboursement de l'utilisateur authentifie.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":100},"description":"Elements par page"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","rejected","refunded","cancelled"]},"description":"Filtrer par statut"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche textuelle"}],"responses":{"200":{"description":"Liste des demandes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RefundRequest"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/refunds":{"get":{"tags":["Refunds - Admin"],"summary":"Liste de toutes les demandes de remboursement (Admin)","description":"Retourne toutes les demandes de remboursement avec filtres et pagination.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":100},"description":"Elements par page"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","rejected","refunded","cancelled"]},"description":"Filtrer par statut"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Recherche textuelle"}],"responses":{"200":{"description":"Liste des demandes de remboursement","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RefundRequest"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/refunds/stats":{"get":{"tags":["Refunds - Admin"],"summary":"Statistiques des remboursements (Admin)","description":"Retourne les statistiques globales des demandes de remboursement.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques des remboursements","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/refunds/{id}":{"get":{"tags":["Refunds - Admin"],"summary":"Detail d'une demande de remboursement (Admin)","description":"Retourne les details complets d'une demande de remboursement.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la demande de remboursement"}],"responses":{"200":{"description":"Detail de la demande","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundRequest"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/refunds/{id}/approve":{"post":{"tags":["Refunds - Admin"],"summary":"Approuver une demande de remboursement (Admin)","description":"Approuve une demande de remboursement en attente.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la demande de remboursement"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveRefundInput"}}}},"responses":{"200":{"description":"Demande approuvee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundRequest"},"message":{"type":"string","example":"Remboursement approuve"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/refunds/{id}/reject":{"post":{"tags":["Refunds - Admin"],"summary":"Rejeter une demande de remboursement (Admin)","description":"Rejette une demande de remboursement en attente. La note de rejet est obligatoire.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de la demande de remboursement"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectRefundInput"}}}},"responses":{"200":{"description":"Demande rejetee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RefundRequest"},"message":{"type":"string","example":"Remboursement rejete"}}}}}},"400":{"description":"Note de rejet manquante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/fraud/alerts":{"get":{"tags":["Fraud - Admin"],"summary":"Liste des alertes de fraude (Admin)","description":"Retourne les alertes de fraude avec filtres et pagination. Accessible aux admin et superAdmin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Elements par page"},{"name":"status","in":"query","schema":{"type":"string","enum":["open","investigating","resolved","false_positive"]},"description":"Filtrer par statut"},{"name":"severity","in":"query","schema":{"type":"string","enum":["warning","error","critical"]},"description":"Filtrer par severite"},{"name":"type","in":"query","schema":{"type":"string","enum":["rapid_cancellations","excessive_refunds","repeated_payment_failures","suspicious_account","high_value_anomaly","velocity_abuse"]},"description":"Filtrer par type de fraude"},{"name":"userId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer par utilisateur"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date-time"},"description":"Date de debut"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date-time"},"description":"Date de fin"}],"responses":{"200":{"description":"Liste des alertes de fraude","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/FraudAlert"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/fraud/stats":{"get":{"tags":["Fraud - Admin"],"summary":"Statistiques de fraude (Admin)","description":"Retourne les statistiques de fraude sur une periode donnee.","security":[{"bearerAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":365},"description":"Nombre de jours a analyser"}],"responses":{"200":{"description":"Statistiques de fraude","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/FraudStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/fraud/alerts/{id}":{"get":{"tags":["Fraud - Admin"],"summary":"Detail d'une alerte de fraude (Admin)","description":"Retourne les details complets d'une alerte de fraude.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'alerte"}],"responses":{"200":{"description":"Detail de l'alerte","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/FraudAlert"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Fraud - Admin"],"summary":"Mettre a jour une alerte de fraude (Admin)","description":"Met a jour le statut et les notes d'une alerte de fraude.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'alerte"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FraudAlertActionInput"}}}},"responses":{"200":{"description":"Alerte mise a jour","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/FraudAlert"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/fraud/users/{userId}":{"get":{"tags":["Fraud - Admin"],"summary":"Historique de fraude d'un utilisateur (Admin)","description":"Retourne l'historique complet de fraude d'un utilisateur, incluant les alertes, paiements recents, remboursements et annulations.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'utilisateur"}],"responses":{"200":{"description":"Historique de fraude de l'utilisateur","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/UserFraudHistory"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/moderation":{"get":{"tags":["Content Moderation - Admin"],"summary":"File d'attente de moderation (Admin)","description":"Retourne la file d'attente de moderation avec filtres et pagination. Accessible aux admin et superAdmin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Numero de page"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Elements par page"},{"name":"contentType","in":"query","schema":{"type":"string","enum":["REVIEW","MESSAGE","IMAGE"]},"description":"Filtrer par type de contenu"},{"name":"status","in":"query","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","AUTO_APPROVED","AUTO_REJECTED"]},"description":"Filtrer par statut"},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"},"description":"Date de debut"},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"},"description":"Date de fin"}],"responses":{"200":{"description":"File d'attente de moderation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModerationItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/moderation/stats":{"get":{"tags":["Content Moderation - Admin"],"summary":"Statistiques de moderation (Admin)","description":"Retourne les statistiques de moderation sur une periode donnee.","security":[{"bearerAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":365},"description":"Nombre de jours a analyser"}],"responses":{"200":{"description":"Statistiques de moderation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ModerationStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/moderation/{id}":{"get":{"tags":["Content Moderation - Admin"],"summary":"Detail d'un element de moderation (Admin)","description":"Retourne les details complets d'un element de moderation avec un apercu du contenu original.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'element de moderation"}],"responses":{"200":{"description":"Detail de l'element","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ModerationDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/moderation/{id}/approve":{"put":{"tags":["Content Moderation - Admin"],"summary":"Approuver un contenu signale (Admin)","description":"Approuve un contenu signale et le rend visible.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'element de moderation"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionInput"}}}},"responses":{"200":{"description":"Contenu approuve","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ModerationItem"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/moderation/{id}/reject":{"put":{"tags":["Content Moderation - Admin"],"summary":"Rejeter un contenu signale (Admin)","description":"Rejette un contenu signale et le masque.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID de l'element de moderation"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationActionInput"}}}},"responses":{"200":{"description":"Contenu rejete","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ModerationItem"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/brevo/sync-status":{"get":{"tags":["Brevo - Admin"],"summary":"Statut de synchronisation Brevo (Admin)","description":"Retourne le statut actuel de la synchronisation des contacts avec Brevo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statut de synchronisation","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BrevoSyncStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/brevo/sync-all":{"post":{"tags":["Brevo - Admin"],"summary":"Synchroniser tous les contacts (Admin)","description":"Declenche une synchronisation complete de tous les utilisateurs vers Brevo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Synchronisation lancee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Synchronisation lancée"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/brevo/track-view":{"post":{"tags":["Brevo"],"summary":"Tracker une vue d'entite","description":"Enregistre un evenement de vue repetee pour le workflow d'automatisation Brevo (WF14).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrevoTrackViewInput"}}}},"responses":{"200":{"description":"Vue trackee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/webhooks/brevo/{type}":{"post":{"tags":["Brevo"],"summary":"Webhook Brevo","description":"Endpoint de reception des webhooks Brevo pour les workflows d'automatisation (proprio-inactif, upsell, etc.).","parameters":[{"name":"type","in":"path","required":true,"schema":{"type":"string","example":"proprio-inactif"},"description":"Type de webhook (proprio-inactif, upsell, etc.)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Payload Brevo (variable selon le type de webhook)"}}}},"responses":{"200":{"description":"Webhook traite avec succes"},"400":{"description":"Type de webhook invalide"}}}},"/owner/byc/config/{serviceType}":{"get":{"tags":["BYC - Owner"],"summary":"Configuration des documents requis","description":"Retourne la liste des documents requis pour un type de service donne.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string","example":"hotel"}}],"responses":{"200":{"description":"Configuration des documents","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BycDocumentConfig"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/byc/{serviceType}/{entityId}":{"get":{"tags":["BYC - Owner"],"summary":"Statut BYC d'une entite","description":"Retourne le statut de verification BYC et les documents soumis pour une entite.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statut BYC","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BycSubmission"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/byc/{serviceType}/{entityId}/documents":{"post":{"tags":["BYC - Owner"],"summary":"Upload un document BYC","description":"Upload un document de verification pour une entite.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["documentType","file"],"properties":{"documentType":{"$ref":"#/components/schemas/BycDocumentType"},"documentNumber":{"type":"string"},"comment":{"type":"string"},"file":{"type":"string","format":"binary"}}}}}},"responses":{"201":{"description":"Document uploade","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BycDocument"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/byc/documents/{documentId}":{"delete":{"tags":["BYC - Owner"],"summary":"Supprimer un document BYC","security":[{"bearerAuth":[]}],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Document supprime","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/byc/{serviceType}/{entityId}/submit":{"post":{"tags":["BYC - Owner"],"summary":"Soumettre la verification BYC","description":"Soumet tous les documents de l'entite pour verification par l'admin.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Verification soumise","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verification soumise avec succes"}}}}}},"400":{"description":"Documents requis manquants"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/byc/stats":{"get":{"tags":["BYC - Admin"],"summary":"Statistiques BYC (Admin)","description":"Retourne les statistiques globales des verifications BYC.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BycStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/byc":{"get":{"tags":["BYC - Admin"],"summary":"Liste des soumissions BYC (Admin)","description":"Retourne la liste paginee de toutes les soumissions BYC.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","submitted","approved","rejected"]}},{"name":"serviceType","in":"query","schema":{"type":"string"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste des soumissions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/BycSubmission"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/byc/{serviceType}/{entityId}":{"get":{"tags":["BYC - Admin"],"summary":"Detail d'une soumission BYC (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail de la soumission","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/BycSubmission"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/byc/{serviceType}/{entityId}/approve":{"post":{"tags":["BYC - Admin"],"summary":"Approuver une verification BYC (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Verification approuvee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verification approuvee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/byc/{serviceType}/{entityId}/reject":{"post":{"tags":["BYC - Admin"],"summary":"Rejeter une verification BYC (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","example":"Document illisible"},"rejectedDocuments":{"type":"array","items":{"type":"string","format":"uuid"},"description":"IDs des documents rejetes"}}}}}},"responses":{"200":{"description":"Verification rejetee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verification rejetee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/file-banks":{"post":{"tags":["File Bank - Owner"],"summary":"Creer un FileBank","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileBankCreateInput"}}}},"responses":{"201":{"description":"FileBank cree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FileBank"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"get":{"tags":["File Bank - Owner"],"summary":"Lister mes FileBanks","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des FileBanks","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FileBank"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/file-banks/{id}":{"get":{"tags":["File Bank - Owner"],"summary":"Detail d'un FileBank (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail du FileBank","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FileBank"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["File Bank - Owner"],"summary":"Modifier un FileBank","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileBankCreateInput"}}}},"responses":{"200":{"description":"FileBank modifie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FileBank"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["File Bank - Owner"],"summary":"Supprimer un FileBank","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"FileBank supprime"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/owner/file-banks/upload":{"post":{"tags":["File Bank - Owner"],"summary":"Upload un fichier","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Fichier uploade","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"fileUrl":{"type":"string"},"fileName":{"type":"string"},"fileSize":{"type":"integer"},"mimeType":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/file-banks/{id}/items":{"post":{"tags":["File Bank - Owner"],"summary":"Ajouter un item au FileBank","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileBankItemInput"}}}},"responses":{"201":{"description":"Item ajoute","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FileBankItem"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/file-banks/{id}/items/{itemId}":{"put":{"tags":["File Bank - Owner"],"summary":"Modifier un item","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"},"isFree":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Item modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["File Bank - Owner"],"summary":"Supprimer un item","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Item supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/file-banks/{id}/packs":{"post":{"tags":["File Bank - Owner"],"summary":"Creer un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","price","itemIds"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"},"itemIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"201":{"description":"Pack cree"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/file-banks/{id}/packs/{packId}":{"put":{"tags":["File Bank - Owner"],"summary":"Modifier un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"packId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"}}}}}},"responses":{"200":{"description":"Pack modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["File Bank - Owner"],"summary":"Supprimer un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"packId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pack supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/my-purchases":{"get":{"tags":["File Bank - Client"],"summary":"Mes achats de fichiers","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des achats","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FileBankPurchase"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/{id}/items/me":{"get":{"tags":["File Bank - Client"],"summary":"Items avec statut d'achat","description":"Retourne les items d'un FileBank avec un flag isPurchased pour l'utilisateur connecte.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Items avec statut"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/items/{itemId}/purchase":{"post":{"tags":["File Bank - Client"],"summary":"Acheter un item","security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Item achete"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/packs/{packId}/purchase":{"post":{"tags":["File Bank - Client"],"summary":"Acheter un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"packId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pack achete"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/items/{itemId}/download":{"get":{"tags":["File Bank - Client"],"summary":"Telecharger un item achete","security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Fichier telecharge","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Item non achete"}}}},"/file-banks/items/{itemId}/initiate-payment":{"post":{"tags":["File Bank - Client"],"summary":"Initier le paiement d'un item","security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Paiement initie","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"paymentUrl":{"type":"string"},"reference":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/packs/{packId}/initiate-payment":{"post":{"tags":["File Bank - Client"],"summary":"Initier le paiement d'un pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"packId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Paiement initie"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/payment/verify/{ref}":{"get":{"tags":["File Bank - Client"],"summary":"Verifier un paiement FileBank","security":[{"bearerAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Statut du paiement"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/file-banks/{id}":{"get":{"tags":["File Bank - Public"],"summary":"Detail d'un FileBank (public)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail du FileBank","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FileBank"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/file-banks/{id}/items":{"get":{"tags":["File Bank - Public"],"summary":"Items d'un FileBank (public)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des items","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FileBankItem"}}}}}}}}}},"/admin/file-banks":{"get":{"tags":["File Bank - Admin"],"summary":"Lister tous les FileBanks (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des FileBanks","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FileBank"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/file-banks/{id}":{"get":{"tags":["File Bank - Admin"],"summary":"Detail d'un FileBank (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail du FileBank"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/parrain/validate-code":{"get":{"tags":["Parrain"],"summary":"Valider un code de parrainage","description":"Verifie si un code de parrainage est valide (utilise lors de l'inscription).","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string","example":"REF-A1B2C3D4"}}],"responses":{"200":{"description":"Code valide","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"valid":{"type":"boolean"},"parrainName":{"type":"string","nullable":true}}}}}}}}}}},"/parrain/my-code":{"get":{"tags":["Parrain"],"summary":"Mon code de parrainage","description":"Retourne le code de parrainage du parrain connecte (le genere si absent).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Code de parrainage","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"referralCode":{"type":"string","example":"REF-A1B2C3D4"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/parrain/stats":{"get":{"tags":["Parrain"],"summary":"Statistiques du parrain","description":"Retourne les statistiques du dashboard parrain (filleuls, commissions, etc.).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ParrainStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/parrain/filleuls":{"get":{"tags":["Parrain"],"summary":"Liste des filleuls","description":"Retourne la liste paginee des proprios referres par ce parrain.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Liste des filleuls","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Filleul"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/parrain/invite":{"post":{"tags":["Parrain"],"summary":"Inviter un proprio","description":"Envoie un email d'invitation a un potentiel proprio avec le code de parrainage.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","example":"proprio@example.com"}}}}}},"responses":{"200":{"description":"Invitation envoyee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Invitation envoyee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/parrain/admin/overview":{"get":{"tags":["Parrain - Admin"],"summary":"Vue d'ensemble des parrains (Admin)","description":"Retourne les stats globales et la liste de tous les parrains.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Vue d'ensemble","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/ParrainAdminOverview"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/parrain/admin/{parrainId}/filleuls":{"get":{"tags":["Parrain - Admin"],"summary":"Filleuls d'un parrain (Admin)","description":"Retourne les filleuls d'un parrain specifique.","security":[{"bearerAuth":[]}],"parameters":[{"name":"parrainId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des filleuls","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Filleul"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/publications/{entityType}/{entityId}/publish":{"post":{"tags":["Publication - Owner"],"summary":"Publier une entite","description":"Soumet une entite pour publication (passe de draft/rejected a pending).","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entite soumise pour publication","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Entite soumise pour validation"}}}}}},"400":{"description":"Entite incomplete ou deja publiee"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/publications/{entityType}/{entityId}/unpublish":{"post":{"tags":["Publication - Owner"],"summary":"Depublier une entite","description":"Retire une entite publiee (repasse en draft).","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entite depubliee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Entite depubliee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/publications/{entityType}/{entityId}/completeness":{"get":{"tags":["Publication - Owner"],"summary":"Verifier la completude d'une entite","description":"Retourne le pourcentage de completude et les champs manquants avant publication.","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statut de completude","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/PublicationCompleteness"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/publications/pending":{"get":{"tags":["Publication - Admin"],"summary":"Entites en attente de validation (Admin)","description":"Retourne la liste paginee des entites en attente de publication.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"entityType","in":"query","schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste des entites en attente","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/PendingPublication"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/publications/{entityType}/{entityId}/approve":{"post":{"tags":["Publication - Admin"],"summary":"Approuver une publication (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Publication approuvee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Entite publiee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/publications/{entityType}/{entityId}/reject":{"post":{"tags":["Publication - Admin"],"summary":"Rejeter une publication (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"entityType","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PublicationEntityType"}},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","example":"Photos de mauvaise qualite"}}}}}},"responses":{"200":{"description":"Publication rejetee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Entite rejetee"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/security-alerts/stats":{"get":{"tags":["Security Alerts - Admin"],"summary":"Statistiques des alertes de securite","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SecurityAlertStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/security-alerts":{"get":{"tags":["Security Alerts - Admin"],"summary":"Liste des alertes de securite","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/SecurityAlertStatus"}},{"name":"severity","in":"query","schema":{"$ref":"#/components/schemas/SecurityAlertSeverity"}},{"name":"type","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Liste des alertes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/SecurityAlert"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/security-alerts/{id}":{"get":{"tags":["Security Alerts - Admin"],"summary":"Detail d'une alerte","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail de l'alerte","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/SecurityAlert"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/security-alerts/{id}/acknowledge":{"put":{"tags":["Security Alerts - Admin"],"summary":"Accuser reception d'une alerte","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Alerte accusee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/security-alerts/{id}/resolve":{"put":{"tags":["Security Alerts - Admin"],"summary":"Resoudre une alerte","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","example":"IP bloquee"}}}}}},"responses":{"200":{"description":"Alerte resolue","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/security-alerts/{id}/dismiss":{"put":{"tags":["Security Alerts - Admin"],"summary":"Ignorer une alerte","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string"}}}}}},"responses":{"200":{"description":"Alerte ignoree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/service-phases/{serviceId}/phases":{"get":{"tags":["Service Phases - Owner"],"summary":"Lister les phases d'un service (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des phases","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ServicePhase"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Service Phases - Owner"],"summary":"Creer une phase","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServicePhaseCreateInput"}}}},"responses":{"201":{"description":"Phase creee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ServicePhase"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/service-phases/{serviceId}/phases/{phaseId}":{"put":{"tags":["Service Phases - Owner"],"summary":"Modifier une phase","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"phaseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServicePhaseCreateInput"}}}},"responses":{"200":{"description":"Phase modifiee"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Service Phases - Owner"],"summary":"Supprimer une phase","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"phaseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Phase supprimee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/service-phases/{serviceId}/multi-phase":{"put":{"tags":["Service Phases - Owner"],"summary":"Activer/desactiver le mode multi-phase","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiPhaseToggle"}}}},"responses":{"200":{"description":"Mode multi-phase mis a jour"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/service-phases/public/{serviceId}/phases":{"get":{"tags":["Service Phases - Public"],"summary":"Phases d'un service (public)","parameters":[{"name":"serviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des phases","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ServicePhase"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transport/popular-routes":{"get":{"tags":["Transport - Public"],"summary":"Routes populaires","description":"Retourne les itineraires les plus reserves.","responses":{"200":{"description":"Routes populaires","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportRoute"}}}}}}}}}},"/transport/trips":{"get":{"tags":["Transport - Public"],"summary":"Lister les voyages (sans recherche par ville)","description":"Filtres prédéfinis : `upcoming` (défaut), `bookable` (places dispo), `started` (parti / en retard de statut), `completed`, `all`. Fenêtre par défaut : aujourd’hui → +60 jours (sauf started/completed : 14 jours passés).","parameters":[{"name":"filter","in":"query","schema":{"type":"string","enum":["upcoming","bookable","started","completed","all"],"default":"upcoming"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"fromDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"toDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"routeId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"agencyId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste paginee","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportTrip"}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"totalPages":{"type":"integer"},"filter":{"type":"string"}}}}}}}}}}},"/transport/trips/search":{"get":{"tags":["Transport - Public"],"summary":"Rechercher des trajets","parameters":[{"name":"departureStationId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"arrivalStationId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}},{"name":"passengers","in":"query","schema":{"type":"integer","default":1}}],"responses":{"200":{"description":"Resultats de recherche","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportTrip"}}}}}}}}}},"/transport/trips/{id}":{"get":{"tags":["Transport - Public"],"summary":"Detail d'un trajet","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail du trajet","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportTrip"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transport/stations":{"get":{"tags":["Transport - Public"],"summary":"Liste des gares/stations","responses":{"200":{"description":"Liste des stations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportStation"}}}}}}}}}},"/transport/stations/{id}":{"get":{"tags":["Transport - Public"],"summary":"Detail d'une station","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail de la station","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportStation"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transport/agencies/{slug}":{"get":{"tags":["Transport - Public"],"summary":"Profil public d'une agence","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Profil de l'agence","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportAgency"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transport/bookings/{id}/pdf":{"get":{"tags":["Transport - Public"],"summary":"Telecharger le billet PDF","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Billet PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/client/transport/bookings":{"post":{"tags":["Transport - Client"],"summary":"Creer une ou plusieurs reservations (meme voyage)","description":"Sans `passengers`: une reservation (champs passager au singulier). Avec `passengers[]`: un billet par element (classes/paliers differents possibles). Reponse 201: soit `data` = un TransportBooking, soit `data.bookings[]` si multi.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tripId"],"properties":{"tripId":{"type":"string","format":"uuid"},"boardingStopIndex":{"type":"integer","default":0},"alightingStopIndex":{"type":"integer"},"paymentMethod":{"type":"string"},"passengerFirstName":{"type":"string","description":"Requis si passengers absent"},"passengerLastName":{"type":"string"},"passengerPhone":{"type":"string"},"passengerEmail":{"type":"string","format":"email"},"passengerIdNumber":{"type":"string"},"seatNumber":{"type":"string"},"seatClass":{"type":"string","enum":["standard","vip","couchette"],"default":"standard"},"tierId":{"type":"string","format":"uuid","description":"Palier tarifaire (segmentPrices)"},"luggageCount":{"type":"integer","default":1},"luggageWeightKg":{"type":"number"},"luggageVolumeM3":{"type":"number"},"passengers":{"type":"array","maxItems":40,"description":"Un objet par billet (mix VIP / standard / paliers). Meme tripId, boarding/alighting du parent.","items":{"type":"object","required":["passengerFirstName","passengerLastName","passengerPhone"],"properties":{"passengerFirstName":{"type":"string"},"passengerLastName":{"type":"string"},"passengerPhone":{"type":"string"},"passengerEmail":{"type":"string","format":"email"},"passengerIdNumber":{"type":"string"},"seatNumber":{"type":"string"},"seatClass":{"type":"string","enum":["standard","vip","couchette"]},"tierId":{"type":"string","format":"uuid"},"luggageCount":{"type":"integer"},"luggageWeightKg":{"type":"number"},"luggageVolumeM3":{"type":"number"}}}}}}}}},"responses":{"201":{"description":"Reservation creee (single ou batch)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"oneOf":[{"$ref":"#/components/schemas/TransportBooking"},{"type":"object","properties":{"bookings":{"type":"array","items":{"$ref":"#/components/schemas/TransportBooking"}},"count":{"type":"integer"},"tripId":{"type":"string","format":"uuid"}}}]}}}}}},"400":{"description":"Siege / classe / palier invalide (codes TRANSPORT_* , SEAT_ALREADY_BOOKED)"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"get":{"tags":["Transport - Client"],"summary":"Mes reservations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportBooking"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/client/transport/bookings/{id}":{"get":{"tags":["Transport - Client"],"summary":"Detail d'une reservation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportBooking"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/client/transport/bookings/{id}/cancel":{"patch":{"tags":["Transport - Client"],"summary":"Annuler une reservation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Reservation annulee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/agency":{"get":{"tags":["Transport - Proprio"],"summary":"Mon agence","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Mon agence","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportAgency"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Creer une agence","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"logo":{"type":"string","format":"uri"}}}}}},"responses":{"201":{"description":"Agence creee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/agency/{id}":{"put":{"tags":["Transport - Proprio"],"summary":"Modifier mon agence","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"logo":{"type":"string"}}}}}},"responses":{"200":{"description":"Agence modifiee"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer mon agence","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Agence supprimee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/routes":{"get":{"tags":["Transport - Proprio"],"summary":"Lister mes itineraires","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des itineraires","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportRoute"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Creer un itineraire","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","departureStationId","arrivalStationId"],"properties":{"name":{"type":"string"},"departureStationId":{"type":"string","format":"uuid"},"arrivalStationId":{"type":"string","format":"uuid"},"estimatedDuration":{"type":"integer"},"distance":{"type":"number"}}}}}},"responses":{"201":{"description":"Itineraire cree"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/routes/{id}":{"get":{"tags":["Transport - Proprio"],"summary":"Detail d'un itineraire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["Transport - Proprio"],"summary":"Modifier un itineraire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"estimatedDuration":{"type":"integer"},"distance":{"type":"number"}}}}}},"responses":{"200":{"description":"Itineraire modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer un itineraire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Itineraire supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/routes/{id}/stops":{"put":{"tags":["Transport - Proprio"],"summary":"Modifier les arrets d'un itineraire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stops":{"type":"array","items":{"type":"object","properties":{"stationId":{"type":"string","format":"uuid"},"order":{"type":"integer"},"durationFromPrevious":{"type":"integer"}}}}}}}}},"responses":{"200":{"description":"Arrets mis a jour"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/vehicles":{"get":{"tags":["Transport - Proprio"],"summary":"Lister mes vehicules","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des vehicules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportVehicle"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Ajouter un vehicule","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","type","capacity"],"properties":{"name":{"type":"string"},"type":{"type":"string"},"capacity":{"type":"integer"},"plateNumber":{"type":"string"}}}}}},"responses":{"201":{"description":"Vehicule ajoute"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/vehicles/{id}":{"get":{"tags":["Transport - Proprio"],"summary":"Detail d'un vehicule","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["Transport - Proprio"],"summary":"Modifier un vehicule","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Vehicule modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer un vehicule","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Vehicule supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/trips":{"get":{"tags":["Transport - Proprio"],"summary":"Lister mes trajets","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des trajets","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportTrip"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Creer un trajet","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["routeId","vehicleId","departureAt","price"],"properties":{"routeId":{"type":"string","format":"uuid"},"vehicleId":{"type":"string","format":"uuid"},"departureAt":{"type":"string","format":"date-time"},"arrivalAt":{"type":"string","format":"date-time"},"price":{"type":"number"}}}}}},"responses":{"201":{"description":"Trajet cree"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/trips/{id}":{"get":{"tags":["Transport - Proprio"],"summary":"Detail d'un trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["Transport - Proprio"],"summary":"Modifier un trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trajet modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer un trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trajet supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/trips/{id}/status":{"patch":{"tags":["Transport - Proprio"],"summary":"Changer le statut d'un trajet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["scheduled","boarding","departed","arrived","cancelled"]}}}}}},"responses":{"200":{"description":"Statut mis a jour"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings":{"get":{"tags":["Transport - Proprio"],"summary":"Lister les reservations de mon agence","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des reservations","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportBooking"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings/{id}":{"get":{"tags":["Transport - Proprio"],"summary":"Detail d'une reservation (Proprio)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings/{id}/confirm":{"patch":{"tags":["Transport - Proprio"],"summary":"Confirmer une reservation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Reservation confirmee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings/{id}/check-in":{"patch":{"tags":["Transport - Proprio"],"summary":"Check-in d'une reservation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Check-in effectue"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings/validate-qr":{"post":{"tags":["Transport - Proprio"],"summary":"Valider un QR code de reservation","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["qrCode"],"properties":{"qrCode":{"type":"string"}}}}}},"responses":{"200":{"description":"QR valide","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportBooking"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/bookings/{id}/cancel":{"patch":{"tags":["Transport - Proprio"],"summary":"Annuler une reservation (Proprio)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Reservation annulee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/schedules":{"get":{"tags":["Transport - Proprio"],"summary":"Lister mes horaires recurrents","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des horaires","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportSchedule"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Creer un horaire recurrent","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["routeId","vehicleId","departureTime","daysOfWeek"],"properties":{"routeId":{"type":"string","format":"uuid"},"vehicleId":{"type":"string","format":"uuid"},"departureTime":{"type":"string","example":"08:00"},"daysOfWeek":{"type":"array","items":{"type":"integer"}}}}}}},"responses":{"201":{"description":"Horaire cree"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/schedules/{id}":{"patch":{"tags":["Transport - Proprio"],"summary":"Modifier un horaire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Horaire modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer un horaire","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Horaire supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/service-tiers":{"get":{"tags":["Transport - Proprio"],"summary":"Lister les niveaux de service","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des tiers","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportServiceTier"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Transport - Proprio"],"summary":"Creer un niveau de service","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"priceMultiplier":{"type":"number"},"amenities":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Tier cree"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/service-tiers/{id}":{"get":{"tags":["Transport - Proprio"],"summary":"Detail d'un niveau de service","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["Transport - Proprio"],"summary":"Modifier un niveau de service","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Tier modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Supprimer un niveau de service","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Tier supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/service-tiers/{id}/design":{"post":{"tags":["Transport - Proprio"],"summary":"Upload un design de billet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Design uploade"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Transport - Proprio"],"summary":"Reinitialiser le design de billet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Design reinitialise"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/service-tiers/{id}/design/preview":{"get":{"tags":["Transport - Proprio"],"summary":"Previsualiser le design de billet","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Preview du design"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/stats":{"get":{"tags":["Transport - Proprio"],"summary":"Statistiques dashboard transport","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/transport/proprio/agency/{id}/completion":{"get":{"tags":["Transport - Proprio"],"summary":"Prerequis de publication de l'agence","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Statut de completion"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/admin/transport/agencies":{"get":{"tags":["Transport - Admin"],"summary":"Lister les agences (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des agences","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransportAgency"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/agencies/{id}":{"get":{"tags":["Transport - Admin"],"summary":"Detail d'une agence (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/agencies/{id}/status":{"patch":{"tags":["Transport - Admin"],"summary":"Changer le statut d'une agence (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["draft","pending","active","suspended"]}}}}}},"responses":{"200":{"description":"Statut mis a jour"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/stations":{"get":{"tags":["Transport - Admin"],"summary":"Lister les stations (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des stations"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Transport - Admin"],"summary":"Creer une station (Admin)","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","city"],"properties":{"name":{"type":"string"},"city":{"type":"string"},"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}}}}}},"responses":{"201":{"description":"Station creee"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/stations/{id}":{"get":{"tags":["Transport - Admin"],"summary":"Detail d'une station (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"patch":{"tags":["Transport - Admin"],"summary":"Modifier une station (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Station modifiee"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"delete":{"tags":["Transport - Admin"],"summary":"Supprimer une station (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Station supprimee"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/trips":{"get":{"tags":["Transport - Admin"],"summary":"Lister les trajets (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des trajets"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/trips/{id}":{"get":{"tags":["Transport - Admin"],"summary":"Detail d'un trajet (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/bookings":{"get":{"tags":["Transport - Admin"],"summary":"Lister les reservations (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des reservations"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/bookings/{id}":{"get":{"tags":["Transport - Admin"],"summary":"Detail d'une reservation (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/transport/stats":{"get":{"tags":["Transport - Admin"],"summary":"Statistiques transport (Admin)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Statistiques","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransportStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/owner/video-calls":{"post":{"tags":["Video Calls - Owner"],"summary":"Creer un appel video","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCallCreateInput"}}}},"responses":{"201":{"description":"Appel cree","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/VideoCall"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"get":{"tags":["Video Calls - Owner"],"summary":"Lister mes appels video","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/VideoCallStatus"}}],"responses":{"200":{"description":"Liste des appels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCall"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}":{"get":{"tags":["Video Calls - Owner"],"summary":"Detail d'un appel video (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/VideoCall"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Video Calls - Owner"],"summary":"Modifier un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCallCreateInput"}}}},"responses":{"200":{"description":"Appel modifie"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["Video Calls - Owner"],"summary":"Supprimer un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Appel supprime"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/cancel":{"post":{"tags":["Video Calls - Owner"],"summary":"Annuler un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Appel annule"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/start":{"post":{"tags":["Video Calls - Owner"],"summary":"Demarrer un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Appel demarre"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/end":{"post":{"tags":["Video Calls - Owner"],"summary":"Terminer un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Appel termine"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/join-requests":{"get":{"tags":["Video Calls - Owner"],"summary":"Demandes de participation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Liste des demandes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCallJoinRequest"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/join-requests/{requestId}/respond":{"post":{"tags":["Video Calls - Owner"],"summary":"Repondre a une demande de participation","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"requestId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accept"],"properties":{"accept":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Reponse envoyee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/remove-participant":{"post":{"tags":["Video Calls - Owner"],"summary":"Expulser un participant","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetUserId"],"properties":{"targetUserId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Participant expulse"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/mute-participant":{"post":{"tags":["Video Calls - Owner"],"summary":"Couper le micro d'un participant","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetUserId","trackSid"],"properties":{"targetUserId":{"type":"string","format":"uuid"},"trackSid":{"type":"string"}}}}}},"responses":{"200":{"description":"Participant mute"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/recordings/upload":{"post":{"tags":["Video Calls - Owner"],"summary":"Upload un enregistrement","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"Max 500MB"}}}}}},"responses":{"201":{"description":"Enregistrement uploade"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/recordings":{"get":{"tags":["Video Calls - Owner"],"summary":"Liste des enregistrements","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Enregistrements","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCallRecording"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/toggle-client-recording":{"post":{"tags":["Video Calls - Owner"],"summary":"Activer/desactiver l'enregistrement client","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Parametre mis a jour"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/chat":{"get":{"tags":["Video Calls - Owner"],"summary":"Historique du chat (Owner)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Messages","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCallChatMessage"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/owner/video-calls/{id}/interactions":{"get":{"tags":["Video Calls - Owner"],"summary":"Resume des interactions","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Resume des interactions"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/my-video-calls/my-calls":{"get":{"tags":["Video Calls - Client"],"summary":"Mes appels video","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/VideoCallStatus"}}],"responses":{"200":{"description":"Mes appels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCall"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/my-video-calls/{id}/register":{"post":{"tags":["Video Calls - Client"],"summary":"S'inscrire a un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Inscription confirmee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/my-video-calls/{id}/pay":{"post":{"tags":["Video Calls - Client"],"summary":"Payer un appel video","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Paiement initie"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/video-calls/by-slug/{slug}":{"get":{"tags":["Video Calls - Public"],"summary":"Detail d'un appel par slug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detail de l'appel","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/VideoCall"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/video-calls/{id}/join":{"post":{"tags":["Video Calls - Public"],"summary":"Rejoindre un appel (retourne token LiveKit)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Token LiveKit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"token":{"type":"string"},"roomName":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/video-calls/{id}/leave":{"post":{"tags":["Video Calls - Public"],"summary":"Quitter un appel","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Appel quitte"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/video-calls/{id}/request-join":{"post":{"tags":["Video Calls - Public"],"summary":"Demander a rejoindre un appel gratuit","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Demande envoyee"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/video-calls/{id}/chat":{"post":{"tags":["Video Calls - Public"],"summary":"Envoyer un message dans le chat","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string"}}}}}},"responses":{"201":{"description":"Message envoye"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"get":{"tags":["Video Calls - Public"],"summary":"Lire les messages du chat","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Messages du chat","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCallChatMessage"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/video-calls/{id}/recordings/{recordingId}/download":{"get":{"tags":["Video Calls - Public"],"summary":"Telecharger un enregistrement","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"recordingId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Fichier d'enregistrement","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/video-calls":{"get":{"tags":["Video Calls - Admin"],"summary":"Lister tous les appels video (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/VideoCallStatus"}}],"responses":{"200":{"description":"Liste des appels","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoCall"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/admin/video-calls/{id}":{"get":{"tags":["Video Calls - Admin"],"summary":"Detail d'un appel video (Admin)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detail de l'appel"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/admin/campaigns/templates":{"get":{"tags":["Campaigns - Admin"],"summary":"Lister les templates","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"channel","in":"query","schema":{"$ref":"#/components/schemas/CampaignChannel"}},{"name":"isActive","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Liste paginee de templates"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Campaigns - Admin"],"summary":"Creer un template","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignTemplateInput"}}}},"responses":{"201":{"description":"Template cree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignTemplate"}}}},"400":{"description":"Variables invalides (codes: CAMPAIGN_TEMPLATE_VARIABLE_UNKNOWN, CAMPAIGN_TEMPLATE_VARIABLE_MISSING)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/campaigns/templates/variables":{"get":{"tags":["Campaigns - Admin"],"summary":"Catalogue des variables systeme","description":"Retourne la liste des variables {{xxx}} resolues a l'envoi par destinataire.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des variables","content":{"application/json":{"example":{"success":true,"data":{"variables":[{"name":"firstName","placeholder":"{{firstName}}"},{"name":"lastName","placeholder":"{{lastName}}"},{"name":"fullName","placeholder":"{{fullName}}"},{"name":"email","placeholder":"{{email}}"},{"name":"phone","placeholder":"{{phone}}"}]}}}}}}}},"/admin/campaigns/templates/{id}":{"get":{"tags":["Campaigns - Admin"],"summary":"Detail d'un template","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Template trouve"},"404":{"description":"Template non trouve (code: CAMPAIGN_TEMPLATE_NOT_FOUND)"}}},"patch":{"tags":["Campaigns - Admin"],"summary":"Mettre a jour un template","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignTemplateInput"}}}},"responses":{"200":{"description":"Template mis a jour"},"400":{"description":"Variables invalides"},"404":{"description":"Template non trouve"}}},"delete":{"tags":["Campaigns - Admin"],"summary":"Supprimer un template","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Supprime"},"404":{"description":"Template non trouve"}}}},"/admin/campaigns/templates/{id}/apply":{"post":{"tags":["Campaigns - Admin"],"summary":"Appliquer un template — cree une campagne en draft","description":"Cree immediatement une campagne en status=draft a partir du template (canaux + contenus + variables non resolues). Le payload optionnel permet de surcharger le nom et d'attacher un segmentId. La campagne renvoyee peut etre completee/envoyee via POST /campaigns/{id}/send.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyCampaignTemplateInput"}}}},"responses":{"201":{"description":"Campagne draft creee","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"400":{"description":"Template inactif (code: CAMPAIGN_TEMPLATE_INACTIVE)"},"404":{"description":"Template ou segment non trouve (codes: CAMPAIGN_TEMPLATE_NOT_FOUND, CAMPAIGN_SEGMENT_NOT_FOUND)"}}}},"/admin/campaigns/segments":{"get":{"tags":["Campaigns - Admin"],"summary":"Lister les segments","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"source","in":"query","schema":{"$ref":"#/components/schemas/CampaignSegmentSource"}},{"name":"isActive","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Liste paginee"}}},"post":{"tags":["Campaigns - Admin"],"summary":"Creer un segment","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignSegmentInput"}}}},"responses":{"201":{"description":"Segment cree"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/campaigns/segments/preview-count":{"post":{"tags":["Campaigns - Admin"],"summary":"Compter une audience sans sauvegarder le segment","description":"Evalue un set de criteres ad-hoc (utile pour l'UI : feedback temps reel pendant la composition). Retourne {count, truncatedAt, sample?}. L'echantillon est anonymise (email/phone masques).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewSegmentCountInput"}}}},"responses":{"200":{"description":"Compte et echantillon optionnel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentCountResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/campaigns/segments/{id}":{"get":{"tags":["Campaigns - Admin"],"summary":"Detail d'un segment","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Segment trouve"},"404":{"description":"Segment non trouve (code: CAMPAIGN_SEGMENT_NOT_FOUND)"}}},"patch":{"tags":["Campaigns - Admin"],"summary":"Mettre a jour un segment (la source est verrouillee)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Segment mis a jour"},"400":{"description":"Changement de source interdit (code: CAMPAIGN_SEGMENT_SOURCE_LOCKED)"}}},"delete":{"tags":["Campaigns - Admin"],"summary":"Supprimer un segment","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Supprime"}}}},"/admin/campaigns/segments/{id}/count":{"get":{"tags":["Campaigns - Admin"],"summary":"Compte a jour d'un segment sauvegarde","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Compte courant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentCountResponse"}}}},"404":{"description":"Segment non trouve"}}}},"/admin/campaigns/campaigns":{"post":{"tags":["Campaigns - Admin"],"summary":"Creer une campagne (envoi immediat ou draft)","description":"Comportement historique inchange : `contacts[]` non vide + `mode=send` (defaut) declenche l'envoi. Nouveautes : `mode=draft` ne declenche pas l'envoi ; `segmentId` evalue l'audience au moment du `send` (snapshot fige). Au moins un de `contacts[]` ou `segmentId` est requis.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignInput"}}}},"responses":{"201":{"description":"Campagne creee","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/admin/campaigns/campaigns/{id}/send":{"post":{"tags":["Campaigns - Admin"],"summary":"Lancer l'envoi d'une campagne en draft","description":"Passe la campagne en `sending`. Si elle est attachee a un segmentId sans logs, le segment est resolu, fige (snapshot) puis envoye. Reponse 202 ; suivre l'avancee via SSE /campaigns/:id/stream.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Envoi declenche"},"400":{"description":"Campagne pas en draft (code: CAMPAIGN_NOT_DRAFT)"},"404":{"description":"Campagne non trouvee (code: CAMPAIGN_NOT_FOUND)"}}}},"/api/owner/csv-import/meta":{"get":{"tags":["Owner CSV Import"],"summary":"Metadonnees import CSV (types et sections)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liste des serviceType et sections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CsvImportMetaResponse"}}}}}}},"/api/owner/csv-import/{serviceType}/template":{"get":{"tags":["Owner CSV Import"],"summary":"Telecharger un modele CSV","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string","enum":["restaurant","hotel","event","transport","establishment","parking","rental_agency"]}},{"name":"section","in":"query","required":true,"schema":{"type":"string","example":"menuItems"}}],"responses":{"200":{"description":"Fichier CSV","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}},"headers":{"Content-Disposition":{"schema":{"type":"string","example":"attachment; filename=\"modele-restaurant-menuItems.csv\""}}}},"400":{"description":"Section invalide (INVALID_SECTION)"}}}},"/api/owner/csv-import/{serviceType}/{parentId}/preview":{"post":{"tags":["Owner CSV Import"],"summary":"Apercu import CSV (sans ecriture)","description":"Contrat BO: `section` (et `mode` optionnel) en **query string**. Body multipart: `file` (CSV) + `images` (0..n, champ repete). Ne pas envoyer section/mode comme champs texte multipart sauf fallback legacy.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"parentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"section","in":"query","required":true,"schema":{"type":"string","example":"services"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["partial","strict"]},"description":"Ignore en preview (influence canCommitStrict cote client)"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Fichier CSV (un seul)"},"images":{"type":"array","items":{"type":"string","format":"binary"},"description":"Images optionnelles (champ repete `images`). jpg, png, webp, gif, avif. Section/mode en query, pas dans le body."}}}}}},"responses":{"200":{"description":"Resultat de validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CsvImportPreviewResponse"}}}},"400":{"description":"CSV manquant, section invalide, champ multipart invalide (INVALID_MULTIPART_FIELD)"},"403":{"description":"parentId d un autre proprietaire"},"404":{"description":"parentId introuvable"}}}},"/api/owner/csv-import/{serviceType}/{parentId}/commit":{"post":{"tags":["Owner CSV Import"],"summary":"Valider et importer en base","description":"Meme multipart que preview. Query: `section` (requis), `mode` (`partial` defaut | `strict`). Strict: 422 IMPORT_VALIDATION_FAILED si erreurs.","security":[{"bearerAuth":[]}],"parameters":[{"name":"serviceType","in":"path","required":true,"schema":{"type":"string"}},{"name":"parentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"section","in":"query","required":true,"schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["partial","strict"],"default":"partial"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Fichier CSV (un seul)"},"images":{"type":"array","items":{"type":"string","format":"binary"},"description":"Images optionnelles (champ repete `images`). jpg, png, webp, gif, avif. Section/mode en query, pas dans le body."}}}}}},"responses":{"200":{"description":"Import partiel ou complet"},"422":{"description":"Mode strict avec lignes invalides (IMPORT_VALIDATION_FAILED)"}}}}}}