====== Sprint 4 — Gestion des Propriétés ====== ===== Objectif ===== Construire le domaine métier principal de la plateforme : Property PropertyType PropertyAmenity PropertyImage PropertyAvailability PropertyPricing PropertyPolicy PropertyReview afin de permettre : Catalogue de propriétés Gestion des disponibilités Gestion tarifaire Avis clients Moteur de réservation Recherche avancée Revenue Management Channel Management Ready ---- ====== Architecture cible ====== Property ├── PropertyType ├── PropertyAmenity ├── PropertyImage ├── PropertyAvailability ├── PropertyPricing ├── PropertyPolicy └── PropertyReview ↓ Reservation Engine ↓ CRM ↓ Revenue Engine ---- ====== Sous-domaines du Sprint 4 ====== ===== Sprint 4-A ===== Modèle Property Core Property PropertyType PropertyAmenity Relations Multi-tenant ---- ===== Sprint 4-B ===== Catalogue des Propriétés PropertyModule CRUD Recherche Pagination Filtres ---- ===== Sprint 4-C ===== Gestion des Équipements Amenities Catégories Recherche Attribution ---- ===== Sprint 4-D ===== Gestion des Images PropertyImage Upload Galerie Ordonnancement MinIO/S3 ---- ===== Sprint 4-E ===== Disponibilités PropertyAvailability Calendrier Blocages Inventaire ---- ===== Sprint 4-F ===== Tarification PropertyPricing Tarifs saisonniers Tarifs dynamiques Revenue Ready ---- ===== Sprint 4-G ===== Politiques PropertyPolicy Annulation Check-in Check-out Règlement ---- ===== Sprint 4-H ===== Avis Clients PropertyReview Notation Modération Réputation ---- ===== Sprint 4-I ===== Recherche Avancée Recherche géographique Disponibilités Prix Filtres avancés ---- ===== Sprint 4-J ===== Analytics & Intelligence Performance propriétés Occupation Revenue Recommandations ---- ====== Architecture technique cible ====== src/modules property property-types property-amenities property-images property-availability property-pricing property-policies property-reviews property-search property-analytics ---- ====== Modèles principaux à livrer ====== Property PropertyType PropertyAmenity PropertyImage PropertyAvailability PropertyPricing PropertyPolicy PropertyReview ---- ====== Capacités Enterprise attendues ====== ✓ Multi-tenant ✓ AuditLog ✓ CRM Integration ✓ Reservation Ready ✓ Revenue Ready ✓ Analytics Ready ✓ Search Ready ✓ AI Ready ✓ Channel Manager Ready ---- ====== Définition de terminé ====== Le Sprint 4 est terminé lorsque : ✓ Catalogue complet ✓ Disponibilités ✓ Tarification ✓ Politiques ✓ Avis ✓ Recherche ✓ Analytics ✓ Réservation Ready ---- ====== Sprint 4-A.1 — Implémentation Prisma Property Core ====== ===== Objectif ===== Créer les fondations du domaine métier Property. À l'issue de cette étape : ✓ Property ✓ PropertyType ✓ PropertyAmenity ✓ Multi-tenant ✓ Catalogue Ready ✓ Reservation Ready ✓ CRM Ready ✓ Analytics Ready ---- ====== Architecture cible ====== Property ├── PropertyType ├── PropertyAmenity ├── PropertyImage ├── PropertyAvailability ├── PropertyPricing ├── PropertyPolicy └── PropertyReview ↓ Reservation Engine ↓ Revenue Engine ---- ====== Sprint 4-A.1-A ====== ===== PropertyType ===== ---- ====== Étape 1 — Création ====== ===== Ajouter dans schema.prisma ===== model PropertyType { id String @id @default(uuid()) tenantId String code String name String description String? icon String? active Boolean @default(true) displayOrder Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) properties Property[] @@unique([ tenantId, code ]) @@index([tenantId]) @@index([active]) } ---- ====== Étape 2 — Types par défaut ====== ===== Prévoir ===== HOTEL_ROOM APARTMENT HOUSE VILLA STUDIO HOSTEL RESORT CHALET CAMPING OTHER ---- ====== Sprint 4-A.1-B ====== ===== PropertyAmenity ===== ---- ====== Étape 3 — Création ====== ===== Ajouter ===== model PropertyAmenity { id String @id @default(uuid()) tenantId String code String name String description String? category String? icon String? active Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) properties PropertyAmenityAssignment[] @@unique([ tenantId, code ]) @@index([tenantId]) @@index([category]) @@index([active]) } ---- ====== Étape 4 — Relation M:N ====== ===== Ajouter ===== model PropertyAmenityAssignment { id String @id @default(uuid()) propertyId String amenityId String createdAt DateTime @default(now()) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) amenity PropertyAmenity @relation( fields:[amenityId], references:[id], onDelete:Cascade ) @@unique([ propertyId, amenityId ]) @@index([propertyId]) @@index([amenityId]) } ---- ====== Étape 5 — Catégories standards ====== ===== Prévoir ===== GENERAL KITCHEN BATHROOM BEDROOM CONNECTIVITY SECURITY ACCESSIBILITY ENTERTAINMENT OUTDOOR PARKING ---- ====== Sprint 4-A.1-C ====== ===== Property ===== ---- ====== Étape 6 — Création ====== ===== Ajouter ===== model Property { id String @id @default(uuid()) tenantId String propertyTypeId String propertyNumber String externalReference String? name String slug String description String? shortDescription String? active Boolean @default(true) featured Boolean @default(false) published Boolean @default(false) maxGuests Int @default(1) bedrooms Int @default(0) bathrooms Int @default(0) beds Int @default(1) floorArea Decimal? @db.Decimal(10,2) floorAreaUnit String? @default("m²") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? tenant Tenant @relation( fields:[tenantId], references:[id] ) propertyType PropertyType @relation( fields:[propertyTypeId], references:[id] ) amenities PropertyAmenityAssignment[] @@unique([ tenantId, propertyNumber ]) @@unique([ tenantId, slug ]) @@index([tenantId]) @@index([propertyTypeId]) @@index([active]) @@index([published]) @@index([featured]) } ---- ====== Étape 7 — Capacités réservation ====== ===== Ajouter ===== minimumStay Int? @default(1) maximumStay Int? advanceBookingDays Int? instantBooking Boolean @default(false) ---- ====== Étape 8 — Capacités CRM ====== ===== Ajouter ===== ownerName String? ownerEmail String? ownerPhone String? ---- ====== Étape 9 — Capacités Analytics ====== ===== Ajouter ===== viewCount Int @default(0) bookingCount Int @default(0) averageRating Float? ---- ====== Sprint 4-A.1-D ====== ===== Adresse Property ===== ---- ====== Étape 10 — Création ====== ===== Ajouter ===== model PropertyAddress { id String @id @default(uuid()) propertyId String @unique addressLine1 String addressLine2 String? postalCode String? city String region String? country String latitude Decimal? @db.Decimal(10,7) longitude Decimal? @db.Decimal(10,7) timezone String? geoValidated Boolean @default(false) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([city]) @@index([country]) @@index([latitude]) @@index([longitude]) } ---- ====== Étape 11 — Relation ====== ===== Ajouter dans Property ===== address PropertyAddress? ---- ====== Sprint 4-A.1-E ====== ===== SEO & Catalogue ===== ---- ====== Étape 12 — SEO ====== ===== Ajouter dans Property ===== seoTitle String? seoDescription String? seoKeywords String? ---- ====== Étape 13 — Publication ====== ===== Ajouter ===== publishedAt DateTime? publishedBy String? ---- ====== Étape 14 — Visibilité ====== ===== Ajouter ===== visibility PropertyVisibility @default(PRIVATE) ---- ====== Étape 15 — Enum ====== ===== Ajouter ===== enum PropertyVisibility { PRIVATE INTERNAL PUBLIC } ---- ====== Sprint 4-A.1-F ====== ===== Audit & Historisation ===== ---- ====== Étape 16 — Préparer ===== Compatible avec : AuditLog PropertyHistory Reservation ChannelManager ---- ====== Étape 17 — Champs métier ====== ===== Ajouter ===== metadata Json? ---- ====== Sprint 4-A.1-G ====== ===== Seed Initial ===== ---- ====== Étape 18 — Property Types ====== ===== Créer ===== Dans le seed : HOTEL_ROOM APARTMENT HOUSE VILLA STUDIO ---- ====== Étape 19 — Amenities ====== ===== Créer ===== WIFI AIR_CONDITIONING PARKING POOL TV KITCHEN WASHING_MACHINE BREAKFAST PET_FRIENDLY ---- ====== Sprint 4-A.1-H ====== ===== Migration ===== ---- ====== Étape 20 — Générer ====== npx prisma migrate dev \ --name property_core ---- ===== Générer ===== npx prisma generate ---- ====== Étape 21 — Vérification ====== ===== Contrôler ===== Property PropertyType PropertyAmenity PropertyAmenityAssignment PropertyAddress présents dans Prisma Client. ---- ====== Définition de terminé ====== Le Sprint 4-A.1 est terminé lorsque : ✓ Property créé ✓ PropertyType créé ✓ PropertyAmenity créé ✓ PropertyAmenityAssignment créé ✓ PropertyAddress créé ✓ Multi-tenant prêt ✓ Catalogue prêt ✓ Réservation prête ✓ Analytics prêt ---- ====== Livrables ====== Property PropertyType PropertyAmenity PropertyAmenityAssignment PropertyAddress PropertyVisibility ---- ====== Sprint 4-A.2 — Extension Enterprise du modèle Property ====== ===== Objectif ===== Transformer le modèle Property en véritable référentiel immobilier Enterprise. À l'issue de cette étape : ✓ PropertyStatus ✓ PropertyCategory ✓ PropertyOwner ✓ PropertyManager ✓ PropertyFeatures ✓ PropertyCompliance ✓ PropertyScore ✓ PropertyLifecycle ✓ Revenue Ready ✓ Enterprise Ready ---- ====== Architecture cible ====== Property ├── PropertyType ├── PropertyCategory ├── PropertyOwner ├── PropertyManager ├── PropertyFeatures ├── PropertyCompliance ├── PropertyScore └── PropertyLifecycle ↓ Reservation ↓ Revenue ↓ Analytics ↓ Compliance ---- ====== Sprint 4-A.2-A ====== ===== Property Status ===== ---- ====== Étape 1 — Enum PropertyStatus ====== ===== Ajouter dans schema.prisma ===== enum PropertyStatus { DRAFT PENDING_REVIEW ACTIVE INACTIVE SUSPENDED ARCHIVED } ---- ====== Étape 2 — Ajouter dans Property ====== status PropertyStatus @default(DRAFT) ---- ====== Étape 3 — Dates de cycle ====== ===== Ajouter ===== activatedAt DateTime? deactivatedAt DateTime? archivedAt DateTime? ---- ====== Sprint 4-A.2-B ====== ===== Property Category ===== ---- ====== Étape 4 — Création ====== ===== Ajouter ===== model PropertyCategory { id String @id @default(uuid()) tenantId String code String name String description String? parentCategoryId String? active Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) parentCategory PropertyCategory? @relation( "PropertyCategoryTree", fields:[parentCategoryId], references:[id] ) children PropertyCategory[] @relation( "PropertyCategoryTree" ) properties Property[] @@unique([ tenantId, code ]) @@index([tenantId]) @@index([parentCategoryId]) } ---- ====== Étape 5 — Relation ====== ===== Ajouter dans Property ===== propertyCategoryId String? propertyCategory PropertyCategory? @relation( fields:[propertyCategoryId], references:[id] ) ---- ====== Étape 6 — Catégories ====== ===== Prévoir ===== LUXURY BUSINESS FAMILY BUDGET LONG_STAY SHORT_STAY PREMIUM CORPORATE ---- ====== Sprint 4-A.2-C ====== ===== Property Owner ===== ---- ====== Étape 7 — Création ====== ===== Ajouter ===== model PropertyOwner { id String @id @default(uuid()) tenantId String code String companyName String? firstName String? lastName String? email String? phone String? taxNumber String? active Boolean @default(true) metadata Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt properties Property[] @@unique([ tenantId, code ]) @@index([tenantId]) } ---- ====== Étape 8 — Relation ====== ===== Ajouter dans Property ===== propertyOwnerId String? propertyOwner PropertyOwner? @relation( fields:[propertyOwnerId], references:[id] ) ---- ====== Sprint 4-A.2-D ====== ===== Property Manager ===== ---- ====== Étape 9 — Création ====== ===== Ajouter ===== model PropertyManager { id String @id @default(uuid()) tenantId String userId String? code String name String email String? phone String? active Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt properties Property[] @@unique([ tenantId, code ]) @@index([tenantId]) @@index([userId]) } ---- ====== Étape 10 — Relation ====== ===== Ajouter dans Property ===== propertyManagerId String? propertyManager PropertyManager? @relation( fields:[propertyManagerId], references:[id] ) ---- ====== Sprint 4-A.2-E ====== ===== Property Features ===== ---- ====== Étape 11 — Création ====== ===== Ajouter ===== model PropertyFeature { id String @id @default(uuid()) tenantId String code String name String category String? active Boolean @default(true) createdAt DateTime @default(now()) properties PropertyFeatureAssignment[] @@unique([ tenantId, code ]) @@index([tenantId]) } ---- ====== Étape 12 — Affectation ====== ===== Ajouter ===== model PropertyFeatureAssignment { id String @id @default(uuid()) propertyId String featureId String value String? property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) feature PropertyFeature @relation( fields:[featureId], references:[id], onDelete:Cascade ) @@unique([ propertyId, featureId ]) } ---- ====== Étape 13 — Exemples ====== SEA_VIEW MOUNTAIN_VIEW BALCONY TERRACE PRIVATE_POOL JACUZZI SMART_LOCK EV_CHARGER ---- ====== Sprint 4-A.2-F ====== ===== Property Compliance ===== ---- ====== Étape 14 — Création ====== ===== Ajouter ===== model PropertyCompliance { id String @id @default(uuid()) propertyId String @unique licenseNumber String? registrationNumber String? insurancePolicy String? insuranceExpiresAt DateTime? fireSafetyValidated Boolean @default(false) accessibilityValidated Boolean @default(false) complianceScore Int @default(0) lastAuditAt DateTime? property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) } ---- ====== Étape 15 — Relation ====== ===== Ajouter dans Property ===== compliance PropertyCompliance? ---- ====== Sprint 4-A.2-G ====== ===== Property Score ===== ---- ====== Étape 16 — Création ====== ===== Ajouter ===== model PropertyScore { id String @id @default(uuid()) propertyId String @unique qualityScore Int @default(0) reviewScore Int @default(0) occupancyScore Int @default(0) revenueScore Int @default(0) complianceScore Int @default(0) globalScore Int @default(0) calculatedAt DateTime @default(now()) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) } ---- ====== Étape 17 — Relation ====== ===== Ajouter dans Property ===== score PropertyScore? ---- ====== Sprint 4-A.2-H ====== ===== Property Lifecycle ===== ---- ====== Étape 18 — Création ====== ===== Ajouter ===== model PropertyLifecycle { id String @id @default(uuid()) propertyId String @unique onboardingCompleted Boolean @default(false) contentCompleted Boolean @default(false) pricingCompleted Boolean @default(false) availabilityCompleted Boolean @default(false) complianceCompleted Boolean @default(false) publishedCompleted Boolean @default(false) launchDate DateTime? property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) } ---- ====== Étape 19 — Relation ====== ===== Ajouter dans Property ===== lifecycle PropertyLifecycle? ---- ====== Sprint 4-A.2-I ====== ===== Analytics & Revenue Ready ===== ---- ====== Étape 20 — KPI ====== ===== Ajouter dans Property ===== occupancyRate Float? revenueYtd Decimal? @db.Decimal(14,2) averageNightlyRate Decimal? @db.Decimal(12,2) revPar Decimal? @db.Decimal(12,2) ---- ====== Étape 21 — Revenue Metrics ====== Compatible avec : ADR RevPAR Occupancy Yield Management ---- ====== Sprint 4-A.2-J ====== ===== Migration & Seed ===== ---- ====== Étape 22 — Seed ====== ===== Créer ===== Catégories : LUXURY BUSINESS FAMILY PREMIUM LONG_STAY ---- ====== Étape 23 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_enterprise ---- ===== Générer ===== npx prisma generate ---- ====== Étape 24 — Audit Ready ====== ===== Préparer ===== Compatible avec : PropertyHistory AuditLog Reservation ChannelManager RevenueManagement ---- ====== Définition de terminé ====== Le Sprint 4-A.2 est terminé lorsque : ✓ PropertyStatus ✓ PropertyCategory ✓ PropertyOwner ✓ PropertyManager ✓ PropertyFeature ✓ PropertyCompliance ✓ PropertyScore ✓ PropertyLifecycle ✓ Revenue KPI ✓ Analytics Ready ---- ====== Livrables ====== PropertyCategory PropertyOwner PropertyManager PropertyFeature PropertyFeatureAssignment PropertyCompliance PropertyScore PropertyLifecycle PropertyStatus ---- ====== Sprint 4-B.1 — Création du PropertyModule ====== ===== Objectif ===== Implémenter le premier module métier complet du domaine Property. À l'issue de cette étape : ✓ PropertyModule ✓ PropertyController ✓ PropertyService ✓ CRUD Property ✓ Recherche ✓ Pagination ✓ Multi-Tenant Security ✓ Swagger ---- ====== Architecture cible ====== PropertyModule ├── PropertyController ├── PropertyService ├── PropertyRepository ├── DTOs ├── Validators └── Policies ↓ Prisma ↓ Property ---- ====== Sprint 4-B.1-A ====== ===== Structure du module ===== ---- ====== Étape 1 — Création ====== src/modules/property ├── application │ │ └── dto │ │ ├── create-property.dto.ts │ │ ├── update-property.dto.ts │ │ ├── property-query.dto.ts │ │ └── property-response.dto.ts │ ├── domain │ │ └── services │ │ └── property.service.ts │ ├── presentation │ │ └── controllers │ │ └── property.controller.ts │ ├── property.module.ts │ └── property.constants.ts ---- ====== Étape 2 — Déclaration Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyController ], providers: [ PropertyService ], exports: [ PropertyService ] }) export class PropertyModule {} ---- ====== Sprint 4-B.1-B ====== ===== DTOs ===== ---- ====== Étape 3 — CreatePropertyDto ====== ===== Créer ===== create-property.dto.ts ---- ===== Implémentation ===== export class CreatePropertyDto { propertyTypeId: string; propertyNumber: string; name: string; slug: string; description?: string; shortDescription?: string; maxGuests?: number; bedrooms?: number; bathrooms?: number; beds?: number; instantBooking?: boolean; ownerName?: string; ownerEmail?: string; ownerPhone?: string; } ---- ====== Étape 4 — UpdatePropertyDto ====== ===== Créer ===== export class UpdatePropertyDto extends PartialType( CreatePropertyDto ) {} ---- ====== Étape 5 — PropertyQueryDto ====== ===== Créer ===== export class PropertyQueryDto { search?: string; propertyTypeId?: string; propertyCategoryId?: string; status?: string; published?: boolean; featured?: boolean; page?: number = 1; limit?: number = 25; sortBy?: string = 'createdAt'; sortOrder?: 'asc' | 'desc' = 'desc'; } ---- ====== Sprint 4-B.1-C ====== ===== PropertyService ===== ---- ====== Étape 6 — Création ====== ===== Créer ===== property.service.ts ---- ===== Méthodes ===== findAll() findById() create() update() remove() ---- ====== Étape 7 — Create ====== ===== Exemple ===== async create( tenantId: string, dto: CreatePropertyDto, userId: string, ) { return this.prisma.property.create({ data: { tenantId, ...dto } }); } ---- ====== Étape 8 — Lecture ====== ===== Vérifier ===== tenantId sur toutes les requêtes. ---- ===== Exemple ===== return this.prisma.property.findFirst({ where: { id, tenantId } }); ---- ====== Étape 9 — Mise à jour ====== ===== Vérifier ===== Property Tenant Permissions avant modification. ---- ====== Étape 10 — Suppression ====== ===== Soft Delete ===== deletedAt: new Date() status: PropertyStatus.ARCHIVED ---- ====== Sprint 4-B.1-D ====== ===== Recherche ===== ---- ====== Étape 11 — Recherche texte ====== ===== Champs ===== name description propertyNumber slug ---- ===== Prisma ===== OR: [ { name: { contains: search, mode: 'insensitive' } }, { propertyNumber: { contains: search, mode: 'insensitive' } } ] ---- ====== Étape 12 — Filtres ====== ===== Supporter ===== PropertyType Category Status Published Featured ---- ====== Étape 13 — Relations ====== ===== Charger ===== include: { propertyType: true, propertyCategory: true, address: true } ---- ====== Sprint 4-B.1-E ====== ===== Pagination ===== ---- ====== Étape 14 — Pagination ====== ===== Calcul ===== const skip = (page - 1) * limit; ---- ====== Étape 15 — Retour ====== { "items": [], "meta": { "page": 1, "limit": 25, "total": 150 } } ---- ====== Étape 16 — Tri ====== ===== Supporter ===== name createdAt updatedAt averageRating bookingCount ---- ====== Sprint 4-B.1-F ====== ===== Contrôleur ===== ---- ====== Étape 17 — Création ====== ===== Créer ===== property.controller.ts ---- ===== Déclaration ===== @ApiTags('Properties') @ApiBearerAuth() @Controller('properties') @UseGuards( JwtAuthGuard ) ---- ====== Étape 18 — GET ====== ===== Ajouter ===== GET /properties ---- ===== Permissions ===== property.read ---- ====== Étape 19 — GET BY ID ====== ===== Ajouter ===== GET /properties/{id} ---- ====== Étape 20 — POST ====== ===== Ajouter ===== POST /properties ---- ===== Permissions ===== property.create ---- ====== Étape 21 — PUT ====== ===== Ajouter ===== PUT /properties/{id} ---- ===== Permissions ===== property.update ---- ====== Étape 22 — DELETE ====== ===== Ajouter ===== DELETE /properties/{id} ---- ===== Permissions ===== property.delete ---- ====== Sprint 4-B.1-G ====== ===== Multi-Tenant Security ===== ---- ====== Étape 23 — Isolation ====== ===== Obligatoire ===== Toutes les requêtes : WHERE tenantId = currentTenant ---- ====== Étape 24 — Validation ====== ===== Refuser ===== Cross Tenant Access avec : ForbiddenException ---- ====== Étape 25 — Audit ====== ===== Journaliser ===== PROPERTY_CREATED PROPERTY_UPDATED PROPERTY_DELETED PROPERTY_VIEWED ---- ====== Sprint 4-B.1-H ====== ===== Swagger ===== ---- ====== Étape 26 — Documentation ====== ===== Ajouter ===== Properties Create Property Update Property Delete Property Search Properties ---- ====== Étape 27 — Exemples ====== ===== POST ===== { "propertyTypeId":"uuid", "propertyNumber":"APT-001", "name":"Appartement Centre Ville", "slug":"appartement-centre-ville", "maxGuests":4 } ---- ====== Sprint 4-B.1-I ====== ===== Permissions RBAC ===== ---- ====== Étape 28 — Ajouter ===== property.read property.create property.update property.delete property.publish property.manage ---- ====== Étape 29 — Rôles ====== SUPER_ADMIN TENANT_ADMIN PROPERTY_MANAGER RECEPTIONIST ---- ====== Sprint 4-B.1-J ====== ===== Préparation Sprint 4-E ===== ---- ====== Étape 30 — Compatibilité ====== Préparer les relations futures : PropertyAvailability PropertyPricing PropertyImage PropertyReview Reservation ---- ====== Définition de terminé ====== Le Sprint 4-B.1 est terminé lorsque : ✓ PropertyModule créé ✓ PropertyController créé ✓ PropertyService créé ✓ CRUD complet ✓ Recherche ✓ Pagination ✓ Multi-tenant Security ✓ RBAC ✓ AuditLog ✓ Swagger ---- ====== Livrables ====== PropertyModule PropertyController PropertyService CreatePropertyDto UpdatePropertyDto PropertyQueryDto PropertyResponseDto ---- ====== Sprint 4-B.2 — Catalogue Enterprise & Recherche Avancée des Propriétés ====== ===== Objectif ===== Transformer le catalogue Property en moteur de recherche immobilier Enterprise. À l'issue de cette étape : ✓ Filtres multicritères ✓ Recherche géographique ✓ Recherche par capacité ✓ Recherche par équipements ✓ Recherche par score ✓ Recherches sauvegardées ✓ Catalogue intelligent ✓ Property Discovery Engine ---- ====== Architecture cible ====== Property Catalog ↓ Search Engine ├── Geographic Search ├── Capacity Search ├── Amenity Search ├── Score Search ├── Availability Search └── Smart Ranking ↓ Catalog Intelligence ↓ Reservation Engine ---- ====== Sprint 4-B.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — PropertySavedSearch ====== ===== Ajouter dans schema.prisma ===== model PropertySavedSearch { id String @id @default(uuid()) tenantId String userId String name String query String? filters Json createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) user User @relation( fields:[userId], references:[id] ) @@index([tenantId]) @@index([userId]) } ---- ====== Étape 2 — PropertySearchHistory ====== ===== Ajouter ===== model PropertySearchHistory { id String @id @default(uuid()) tenantId String userId String? searchTerm String? filters Json? resultsCount Int @default(0) createdAt DateTime @default(now()) @@index([tenantId]) @@index([createdAt]) } ---- ====== Étape 3 — PropertySearchScore ====== ===== Ajouter dans Property ===== searchScore Float? ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_catalog_search ---- ====== Sprint 4-B.2-B ====== ===== Recherche Avancée ===== ---- ====== Étape 5 — PropertySearchDto ====== ===== Créer ===== property-search.dto.ts ---- ===== Implémentation ===== export class PropertySearchDto { search?: string; propertyTypeId?: string; propertyCategoryId?: string; city?: string; country?: string; minGuests?: number; maxGuests?: number; minBedrooms?: number; maxBedrooms?: number; amenities?: string[]; minScore?: number; maxScore?: number; featured?: boolean; page?: number = 1; limit?: number = 25; } ---- ====== Étape 6 — PropertyCatalogService ====== ===== Créer ===== property-catalog.service.ts ---- ===== Méthodes ===== search() advancedSearch() searchByLocation() searchByAmenities() searchByCapacity() ---- ====== Sprint 4-B.2-C ====== ===== Filtres Multicritères ===== ---- ====== Étape 7 — Recherche ====== ===== Supporter ===== Type Catégorie Ville Pays Statut Publication Score Capacité ---- ====== Étape 8 — Exemple Prisma ====== where: { tenantId, active: true, city, maxGuests: { gte: minGuests } } ---- ====== Étape 9 — Combinaisons ====== ===== Exemple ===== Appartement + Paris + 4 personnes + Wifi + Score > 80 ---- ====== Sprint 4-B.2-D ====== ===== Recherche Géographique ===== ---- ====== Étape 10 — Géolocalisation ====== ===== Utiliser ===== PropertyAddress Latitude Longitude ---- ====== Étape 11 — Recherche par rayon ====== ===== Ajouter ===== GET /properties/search/radius ---- ===== Paramètres ===== latitude longitude radiusKm ---- ====== Étape 12 — Calcul ====== ===== Implémenter ===== Formule : Haversine pour calculer la distance. ---- ====== Étape 13 — Retour ====== ===== Exemple ===== { "property":"Villa Prestige", "distanceKm":4.2 } ---- ====== Sprint 4-B.2-E ====== ===== Recherche par Capacité ===== ---- ====== Étape 14 — Critères ====== ===== Supporter ===== Guests Bedrooms Bathrooms Beds ---- ====== Étape 15 — Exemple ====== 8 voyageurs 4 chambres 3 salles de bain ---- ===== Retour ===== Toutes les propriétés compatibles. ---- ====== Sprint 4-B.2-F ====== ===== Recherche par Équipements ===== ---- ====== Étape 16 — Recherche ====== ===== Supporter ===== Wifi Piscine Parking Cuisine Climatisation Jacuzzi ---- ====== Étape 17 — Prisma ====== ===== Exemple ===== amenities: { some: { amenity: { code: 'WIFI' } } } ---- ====== Étape 18 — Mode ====== ===== Supporter ===== ANY ALL pour les équipements. ---- ====== Sprint 4-B.2-G ====== ===== Recherche par Score ===== ---- ====== Étape 19 — Utiliser ===== PropertyScore ---- ===== Critères ===== GlobalScore ReviewScore RevenueScore OccupancyScore ---- ====== Étape 20 — Exemple ====== Score > 90 ---- ===== Retour ===== Propriétés Premium. ---- ====== Sprint 4-B.2-H ====== ===== Recherches Sauvegardées ===== ---- ====== Étape 21 — PropertySavedSearchService ====== ===== Créer ===== property-saved-search.service.ts ---- ===== Méthodes ===== saveSearch() listSearches() executeSearch() deleteSearch() ---- ====== Étape 22 — Endpoints ====== ===== Ajouter ===== GET /properties/search/saved POST /properties/search/saved DELETE /properties/search/saved/{id} ---- ====== Étape 23 — Exemple ====== Paris Premium Wifi Piscine 6 personnes ---- ===== Sauvegarder ===== Mes Villas Premium ---- ====== Sprint 4-B.2-I ====== ===== Catalogue Intelligent ===== ---- ====== Étape 24 — Ranking ====== ===== Créer ===== property-ranking.service.ts ---- ===== Calcul ===== ReviewScore Occupancy Revenue Featured SearchPopularity ---- ====== Étape 25 — Search Score ====== ===== Exemple ===== 40% Reviews 20% Revenue 20% Occupation 20% Popularité ---- ====== Étape 26 — Recommandations ====== ===== Ajouter ===== getRecommendedProperties() ---- ===== Basé sur ===== Historique recherche Réservations Préférences utilisateur ---- ====== Sprint 4-B.2-J ====== ===== API Catalogue ===== ---- ====== Étape 27 — Endpoints ====== ===== Ajouter ===== GET /properties/search GET /properties/search/radius GET /properties/search/facets GET /properties/search/saved POST /properties/search/saved DELETE /properties/search/saved/{id} ---- ====== Étape 28 — Facettes ====== ===== Retour ===== { "cities": { "Paris": 142, "Lyon": 38 }, "types": { "APARTMENT": 97, "VILLA": 31 } } ---- ====== Étape 29 — Audit ====== ===== Journaliser ===== PROPERTY_SEARCH PROPERTY_RADIUS_SEARCH PROPERTY_SAVED_SEARCH PROPERTY_SEARCH_EXECUTED ---- ====== Étape 30 — Permissions ====== ===== Ajouter ===== property.search property.search.saved property.search.analytics ---- ====== Préparation Sprint 4-E ====== Compatible avec : PropertyAvailability Reservation Calendar Engine Inventory Engine ---- ====== Préparation Sprint 4-F ====== Compatible avec : PropertyPricing Dynamic Pricing Revenue Management ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Catalog Recommendation Engine Search Intelligence Booking Engine ---- ====== Définition de terminé ====== Le Sprint 4-B.2 est terminé lorsque : ✓ Filtres multicritères ✓ Recherche géographique ✓ Recherche capacité ✓ Recherche équipements ✓ Recherche score ✓ Recherches sauvegardées ✓ Catalogue intelligent ✓ API Catalogue ✓ Audit intégré ---- ====== Livrables ====== PropertyCatalogService PropertySavedSearch PropertySearchHistory PropertyRankingService PropertySearchDto Enterprise Property Search API ---- ====== Sprint 4-C.1 — Gestion des Équipements (Amenities) ====== ===== Objectif ===== Implémenter la gestion complète des équipements des propriétés. À l'issue de cette étape : ✓ PropertyAmenityModule ✓ PropertyAmenityController ✓ PropertyAmenityService ✓ CRUD Amenities ✓ Catégories ✓ Attribution aux propriétés ✓ Recherche équipements ✓ Catalogue enrichi ---- ====== Architecture cible ====== PropertyAmenity ↓ PropertyAmenityAssignment ↓ Property ↓ Property Search ↓ Reservation Engine ---- ====== Sprint 4-C.1-A ====== ===== Module Amenities ===== ---- ====== Étape 1 — Création ====== src/modules/property-amenities ├── application │ │ └── dto │ │ ├── create-property-amenity.dto.ts │ │ ├── update-property-amenity.dto.ts │ │ ├── property-amenity-query.dto.ts │ │ └── assign-property-amenity.dto.ts │ ├── domain │ │ └── services │ │ └── property-amenity.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-amenity.controller.ts │ └── property-amenity.module.ts ---- ====== Étape 2 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyAmenityController ], providers: [ PropertyAmenityService ], exports: [ PropertyAmenityService ] }) export class PropertyAmenityModule {} ---- ====== Sprint 4-C.1-B ====== ===== DTOs ===== ---- ====== Étape 3 — CreatePropertyAmenityDto ====== ===== Créer ===== export class CreatePropertyAmenityDto { code: string; name: string; description?: string; category?: string; icon?: string; active?: boolean; } ---- ====== Étape 4 — UpdatePropertyAmenityDto ====== ===== Créer ===== export class UpdatePropertyAmenityDto extends PartialType( CreatePropertyAmenityDto ) {} ---- ====== Étape 5 — AssignPropertyAmenityDto ====== ===== Créer ===== export class AssignPropertyAmenityDto { amenityIds: string[]; } ---- ====== Étape 6 — PropertyAmenityQueryDto ====== ===== Créer ===== export class PropertyAmenityQueryDto { search?: string; category?: string; active?: boolean; page?: number = 1; limit?: number = 25; } ---- ====== Sprint 4-C.1-C ====== ===== PropertyAmenityService ===== ---- ====== Étape 7 — Création ====== ===== Créer ===== property-amenity.service.ts ---- ===== Méthodes ===== findAll() findById() create() update() remove() assignToProperty() removeFromProperty() listPropertyAmenities() ---- ====== Étape 8 — Création ====== ===== Exemple ===== async create( tenantId: string, dto: CreatePropertyAmenityDto, ) { return this.prisma.propertyAmenity.create({ data: { tenantId, ...dto } }); } ---- ====== Étape 9 — Mise à jour ====== ===== Vérifier ===== Tenant Code unique Permissions avant modification. ---- ====== Étape 10 — Suppression ====== ===== Soft Delete ===== active: false afin de conserver l'historique. ---- ====== Sprint 4-C.1-D ====== ===== Gestion des Catégories ===== ---- ====== Étape 11 — Catégories Standards ====== ===== Supporter ===== GENERAL KITCHEN BATHROOM BEDROOM CONNECTIVITY SECURITY ACCESSIBILITY ENTERTAINMENT OUTDOOR PARKING ---- ====== Étape 12 — Endpoint ====== ===== Ajouter ===== GET /property-amenities/categories ---- ===== Retour ===== [ "GENERAL", "KITCHEN", "BATHROOM", "CONNECTIVITY" ] ---- ====== Étape 13 — Compteurs ====== ===== Ajouter ===== Nombre d'équipements par catégorie. ---- ====== Sprint 4-C.1-E ====== ===== Attribution aux propriétés ===== ---- ====== Étape 14 — Affectation ====== ===== Utiliser ===== PropertyAmenityAssignment ---- ====== Étape 15 — Service ====== ===== Exemple ===== await prisma.propertyAmenityAssignment.create({ data: { propertyId, amenityId } }); ---- ====== Étape 16 — Affectation multiple ====== ===== Supporter ===== Wifi Parking Piscine Climatisation en une seule requête. ---- ====== Étape 17 — Synchronisation ====== ===== Ajouter ===== syncPropertyAmenities() pour remplacer totalement la liste. ---- ====== Sprint 4-C.1-F ====== ===== Recherche Équipements ===== ---- ====== Étape 18 — Recherche ====== ===== Supporter ===== Code Nom Description Catégorie ---- ====== Étape 19 — Prisma ====== ===== Exemple ===== OR: [ { name: { contains: search, mode: 'insensitive' } }, { code: { contains: search, mode: 'insensitive' } } ] ---- ====== Étape 20 — Filtres ====== ===== Ajouter ===== Catégorie Actif Utilisation ---- ====== Sprint 4-C.1-G ====== ===== Contrôleur ===== ---- ====== Étape 21 — Création ====== ===== Créer ===== property-amenity.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Amenities' ) @ApiBearerAuth() @Controller( 'property-amenities' ) @UseGuards( JwtAuthGuard ) ---- ====== Étape 22 — CRUD ====== ===== Ajouter ===== GET /property-amenities GET /property-amenities/{id} POST /property-amenities PUT /property-amenities/{id} DELETE /property-amenities/{id} ---- ====== Étape 23 — Affectation ====== ===== Ajouter ===== POST /properties/{id}/amenities GET /properties/{id}/amenities DELETE /properties/{id}/amenities/{amenityId} ---- ====== Sprint 4-C.1-H ====== ===== Pagination ===== ---- ====== Étape 24 — Retour ====== { "items": [], "meta": { "page": 1, "limit": 25, "total": 93 } } ---- ====== Étape 25 — Tri ====== ===== Supporter ===== name category createdAt ---- ====== Sprint 4-C.1-I ====== ===== Sécurité ===== ---- ====== Étape 26 — Multi-Tenant ====== ===== Imposer ===== tenantId sur toutes les opérations. ---- ====== Étape 27 — Permissions ====== ===== Ajouter ===== property.amenity.read property.amenity.create property.amenity.update property.amenity.delete property.amenity.assign ---- ====== Étape 28 — Audit ====== ===== Journaliser ===== PROPERTY_AMENITY_CREATED PROPERTY_AMENITY_UPDATED PROPERTY_AMENITY_DELETED PROPERTY_AMENITY_ASSIGNED PROPERTY_AMENITY_REMOVED ---- ====== Sprint 4-C.1-J ====== ===== Préparation Sprint 4-I ===== ---- ====== Étape 29 — Recherche ====== Compatible avec : Property Search Availability Search Booking Search Recommendation Engine ---- ====== Étape 30 — Analytics ====== Préparer : Most Used Amenities Amenity Popularity Amenity Conversion Rate pour Sprint 4-J. ---- ====== Définition de terminé ====== Le Sprint 4-C.1 est terminé lorsque : ✓ PropertyAmenityModule créé ✓ PropertyAmenityController créé ✓ PropertyAmenityService créé ✓ CRUD Amenities ✓ Catégories ✓ Attribution aux propriétés ✓ Recherche équipements ✓ Multi-tenant Security ✓ AuditLog intégré ---- ====== Livrables ====== PropertyAmenityModule PropertyAmenityController PropertyAmenityService CreatePropertyAmenityDto AssignPropertyAmenityDto PropertyAmenityAssignment API ---- ====== Sprint 4-C.2 — Amenities Enterprise & Classification Intelligente ====== ===== Objectif ===== Faire évoluer le catalogue des équipements vers un moteur intelligent capable d'alimenter : Recherche avancée Matching réservation Scoring propriétés Recommandations IA Revenue Management Analytics À l'issue de cette étape : ✓ Hiérarchie équipements ✓ Tags équipements ✓ Popularité ✓ Scoring équipements ✓ Recommandations automatiques ✓ Classification IA ✓ Amenity Intelligence Engine ---- ====== Architecture cible ====== PropertyAmenity ↓ Amenity Intelligence ├── Hierarchy ├── Tags ├── Popularity ├── Scoring ├── Recommendations └── AI Classification ↓ Property Search ↓ Booking Engine ↓ Recommendation Engine ---- ====== Sprint 4-C.2-A ====== ===== Hiérarchie des Équipements ===== ---- ====== Étape 1 — Extension PropertyAmenity ====== ===== Ajouter dans schema.prisma ===== parentAmenityId String? ---- ====== Étape 2 — Relations ====== ===== Ajouter ===== parentAmenity PropertyAmenity? @relation( "AmenityHierarchy", fields:[parentAmenityId], references:[id] ) children PropertyAmenity[] @relation( "AmenityHierarchy" ) ---- ====== Étape 3 — Cas d'usage ====== ===== Exemple ===== CONNECTIVITY ├── WIFI ├── FIBER ├── ETHERNET └── WORKSPACE ---- ===== Exemple ===== OUTDOOR ├── TERRACE ├── GARDEN ├── BBQ └── PRIVATE_POOL ---- ====== Étape 4 — Niveau ====== ===== Ajouter ===== hierarchyLevel Int @default(0) ---- ====== Sprint 4-C.2-B ====== ===== Tags Équipements ===== ---- ====== Étape 5 — Création ====== ===== Ajouter ===== model AmenityTag { id String @id @default(uuid()) tenantId String code String name String createdAt DateTime @default(now()) amenities AmenityTagAssignment[] @@unique([ tenantId, code ]) @@index([tenantId]) } ---- ====== Étape 6 — Affectation ====== ===== Ajouter ===== model AmenityTagAssignment { id String @id @default(uuid()) amenityId String tagId String amenity PropertyAmenity @relation( fields:[amenityId], references:[id], onDelete:Cascade ) tag AmenityTag @relation( fields:[tagId], references:[id], onDelete:Cascade ) @@unique([ amenityId, tagId ]) } ---- ====== Étape 7 — Tags standards ====== ===== Prévoir ===== PREMIUM LUXURY BUSINESS FAMILY ACCESSIBLE PET_FRIENDLY REMOTE_WORK ECO_FRIENDLY ---- ====== Sprint 4-C.2-C ====== ===== Popularité ===== ---- ====== Étape 8 — Popularité ====== ===== Ajouter dans PropertyAmenity ===== usageCount Int @default(0) searchCount Int @default(0) bookingImpactScore Float? ---- ====== Étape 9 — Calcul ====== ===== Alimenter via ===== Property Search Bookings Property Views Recommendations ---- ====== Étape 10 — Classement ====== ===== Exemple ===== Wifi Utilisé dans 94% des biens ---- ===== Exemple ===== Piscine Impact réservation +22% ---- ====== Sprint 4-C.2-D ====== ===== Scoring Équipements ===== ---- ====== Étape 11 — AmenityScore ====== ===== Créer ===== model AmenityScore { id String @id @default(uuid()) amenityId String @unique popularityScore Float @default(0) conversionScore Float @default(0) revenueScore Float @default(0) recommendationScore Float @default(0) globalScore Float @default(0) calculatedAt DateTime @default(now()) amenity PropertyAmenity @relation( fields:[amenityId], references:[id], onDelete:Cascade ) } ---- ====== Étape 12 — Calcul ====== ===== Pondération ===== Popularity 30% Conversion 30% Revenue 20% Recommendation 20% ---- ====== Étape 13 — Classification ====== 90-100 Elite 75-89 Premium 50-74 Standard 0-49 Basic ---- ====== Sprint 4-C.2-E ====== ===== Recommandations Automatiques ===== ---- ====== Étape 14 — AmenityRecommendation ====== ===== Ajouter ===== model AmenityRecommendation { id String @id @default(uuid()) propertyId String amenityId String recommendationScore Float reason String? accepted Boolean? createdAt DateTime @default(now()) @@index([propertyId]) @@index([amenityId]) } ---- ====== Étape 15 — AmenityRecommendationService ====== ===== Créer ===== amenity-recommendation.service.ts ---- ===== Méthodes ===== generateRecommendations() findMissingAmenities() compareSimilarProperties() ---- ====== Étape 16 — Exemples ====== ===== Cas ===== Villa Premium Sans Piscine ↓ Suggestion PRIVATE_POOL ---- ===== Cas ===== Appartement Business Sans Wifi ↓ Suggestion WIFI ---- ====== Sprint 4-C.2-F ====== ===== Classification IA ===== ---- ====== Étape 17 — AmenityClassificationService ====== ===== Créer ===== amenity-classification.service.ts ---- ===== Méthodes ===== classifyAmenity() detectCategory() generateTags() detectPremiumLevel() ---- ====== Étape 18 — Exemple ====== ===== Entrée ===== Borne recharge Tesla ---- ===== Résultat ===== Category: PARKING Tags: PREMIUM ECO_FRIENDLY Score: 82 ---- ====== Étape 19 — Auto-tagging ====== ===== Générer automatiquement ===== Luxury Business Family Accessibility ---- ====== Sprint 4-C.2-G ====== ===== Analytics ===== ---- ====== Étape 20 — AmenityAnalyticsService ====== ===== Créer ===== amenity-analytics.service.ts ---- ===== Méthodes ===== getMostPopularAmenities() getHighestRevenueAmenities() getConversionImpact() ---- ====== Étape 21 — KPI ====== Top Amenities Revenue Impact Booking Impact Search Impact ---- ====== Étape 22 — Endpoint ====== ===== Ajouter ===== GET /property-amenities/analytics ---- ====== Sprint 4-C.2-H ====== ===== API Enterprise ===== ---- ====== Étape 23 — Endpoints ====== ===== Ajouter ===== GET /property-amenities/hierarchy GET /property-amenities/recommendations GET /property-amenities/analytics POST /property-amenities/classify ---- ====== Étape 24 — Exemple ====== ===== Retour ===== { "amenity":"WIFI", "globalScore":96, "classification":"ELITE" } ---- ====== Sprint 4-C.2-I ====== ===== Audit & Sécurité ===== ---- ====== Étape 25 — AuditLog ====== ===== Journaliser ===== AMENITY_CLASSIFIED AMENITY_RECOMMENDED AMENITY_SCORE_UPDATED AMENITY_TAG_ASSIGNED ---- ====== Étape 26 — Permissions ====== ===== Ajouter ===== property.amenity.analytics property.amenity.recommend property.amenity.classify ---- ====== Sprint 4-C.2-J ====== ===== Préparation Future ===== ---- ====== Étape 27 — Compatible Sprint 4-I ====== Property Search Recommendation Engine Smart Filters ---- ====== Étape 28 — Compatible Sprint 4-J ====== Property Analytics Revenue Analytics Property Intelligence ---- ====== Étape 29 — Compatible Sprint 13 ====== AI Recommendations Knowledge Graph Property Intelligence ---- ====== Étape 30 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name amenity_intelligence ---- ===== Générer ===== npx prisma generate ---- ====== Définition de terminé ====== Le Sprint 4-C.2 est terminé lorsque : ✓ Hiérarchie équipements ✓ Tags équipements ✓ Popularité ✓ Scoring équipements ✓ Recommandations automatiques ✓ Classification IA ✓ Analytics équipements ✓ API Enterprise ✓ Audit intégré ---- ====== Livrables ====== AmenityTag AmenityTagAssignment AmenityScore AmenityRecommendation AmenityRecommendationService AmenityClassificationService AmenityAnalyticsService Amenity Intelligence Engine ---- ====== Sprint 4-D.1 — Gestion des Images des Propriétés ====== ===== Objectif ===== Implémenter la gestion complète des médias immobiliers afin d'alimenter : Catalogue Moteur de réservation Galerie Property Marketing SEO Analytics À l'issue de cette étape : ✓ PropertyImage ✓ PropertyImageModule ✓ PropertyImageController ✓ PropertyImageService ✓ Upload ✓ Galerie ✓ Ordonnancement ✓ Multi-Tenant Security ---- ====== Architecture cible ====== Property ↓ PropertyImage ↓ Storage Layer (MinIO / S3) ↓ Image Processing ↓ Gallery API ↓ Property Catalog ---- ====== Sprint 4-D.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — Création PropertyImage ====== ===== Ajouter dans schema.prisma ===== model PropertyImage { id String @id @default(uuid()) tenantId String propertyId String fileName String originalFileName String mimeType String fileSize Int storagePath String publicUrl String? title String? altText String? caption String? displayOrder Int @default(0) isPrimary Boolean @default(false) width Int? height Int? uploadedAt DateTime @default(now()) deletedAt DateTime? tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) @@index([propertyId]) @@index([displayOrder]) @@index([isPrimary]) } ---- ====== Étape 2 — Relation Property ====== ===== Ajouter dans Property ===== images PropertyImage[] ---- ====== Étape 3 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_images ---- ===== Générer ===== npx prisma generate ---- ====== Sprint 4-D.1-B ====== ===== Module ===== ---- ====== Étape 4 — Création ====== src/modules/property-images ├── application │ │ └── dto │ │ ├── upload-property-image.dto.ts │ │ ├── reorder-property-images.dto.ts │ │ └── property-image-response.dto.ts │ ├── domain │ │ └── services │ │ └── property-image.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-image.controller.ts │ └── property-image.module.ts ---- ====== Étape 5 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, StorageModule, AuthModule, AuditModule ], controllers: [ PropertyImageController ], providers: [ PropertyImageService ], exports: [ PropertyImageService ] }) export class PropertyImageModule {} ---- ====== Sprint 4-D.1-C ====== ===== DTOs ===== ---- ====== Étape 6 — Upload ====== ===== Créer ===== export class UploadPropertyImageDto { title?: string; altText?: string; caption?: string; isPrimary?: boolean; } ---- ====== Étape 7 — Réorganisation ====== ===== Créer ===== export class ReorderPropertyImagesDto { images: { id: string; order: number; }[]; } ---- ====== Sprint 4-D.1-D ====== ===== PropertyImageService ===== ---- ====== Étape 8 — Création ====== ===== Créer ===== property-image.service.ts ---- ===== Méthodes ===== findAll() upload() delete() reorder() setPrimary() ---- ====== Étape 9 — Upload ====== ===== Workflow ===== Upload ↓ Validation ↓ Storage ↓ Prisma ↓ Gallery ---- ====== Étape 10 — Exemple ====== const image = await storage.upload(file); await prisma.propertyImage.create({ data: { tenantId, propertyId, storagePath: image.path, publicUrl: image.url } }); ---- ====== Étape 11 — Validation ====== ===== Autoriser ===== image/jpeg image/png image/webp ---- ===== Taille maximale ===== 10 MB ---- ====== Sprint 4-D.1-E ====== ===== Galerie ===== ---- ====== Étape 12 — Liste ====== ===== Endpoint ===== GET /properties/{id}/images ---- ===== Retour ===== [ { "id":"uuid", "url":"...", "isPrimary":true } ] ---- ====== Étape 13 — Image principale ====== ===== Garantir ===== Une seule image : isPrimary = true par propriété. ---- ====== Étape 14 — Tri ====== ===== Utiliser ===== displayOrder ASC ---- ====== Sprint 4-D.1-F ====== ===== Ordonnancement ===== ---- ====== Étape 15 — Endpoint ====== ===== Ajouter ===== PUT /properties/{id}/images/order ---- ====== Étape 16 — Mise à jour ====== ===== Exemple ===== { "images":[ { "id":"1", "order":1 }, { "id":"2", "order":2 } ] } ---- ====== Étape 17 — Transaction ====== ===== Utiliser ===== prisma.$transaction() pour garantir la cohérence. ---- ====== Sprint 4-D.1-G ====== ===== Suppression ===== ---- ====== Étape 18 — Endpoint ====== ===== Ajouter ===== DELETE /properties/{id}/images/{imageId} ---- ====== Étape 19 — Workflow ====== Prisma ↓ Storage ↓ Audit ---- ====== Étape 20 — Protection ====== ===== Refuser ===== Suppression de la dernière image principale. ---- ====== Sprint 4-D.1-H ====== ===== Contrôleur ===== ---- ====== Étape 21 — Création ====== ===== Créer ===== property-image.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Images' ) @ApiBearerAuth() @Controller( 'properties/:id/images' ) @UseGuards( JwtAuthGuard ) ---- ====== Étape 22 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/images POST /properties/{id}/images PUT /properties/{id}/images/order DELETE /properties/{id}/images/{imageId} ---- ====== Étape 23 — Upload ====== ===== Utiliser ===== @UseInterceptors( FileInterceptor('file') ) ---- ====== Sprint 4-D.1-I ====== ===== Sécurité ===== ---- ====== Étape 24 — Multi-Tenant ====== ===== Vérifier ===== tenantId propertyId avant toute opération. ---- ====== Étape 25 — Permissions ====== ===== Ajouter ===== property.image.read property.image.upload property.image.update property.image.delete ---- ====== Étape 26 — Audit ====== ===== Journaliser ===== PROPERTY_IMAGE_UPLOADED PROPERTY_IMAGE_REORDERED PROPERTY_IMAGE_DELETED PROPERTY_PRIMARY_IMAGE_CHANGED ---- ====== Sprint 4-D.1-J ====== ===== Préparation Sprint 4-D.2 ===== ---- ====== Étape 27 — Préparer ===== Compatible avec : MinIO AWS S3 CDN Thumbnail Generation Image Optimization ---- ====== Étape 28 — Préparer ===== Compatible avec : Property Gallery SEO Images Marketing Assets Review Images ---- ====== Définition de terminé ====== Le Sprint 4-D.1 est terminé lorsque : ✓ PropertyImage créé ✓ PropertyImageModule créé ✓ PropertyImageController créé ✓ PropertyImageService créé ✓ Upload opérationnel ✓ Galerie opérationnelle ✓ Ordonnancement opérationnel ✓ Multi-tenant Security ✓ AuditLog intégré ---- ====== Livrables ====== PropertyImage PropertyImageModule PropertyImageController PropertyImageService UploadPropertyImageDto ReorderPropertyImagesDto Property Gallery API ---- ====== Sprint 4-D.2 — Gestion Média Enterprise & Optimisation d'Images ====== ===== Objectif ===== Transformer la gestion d'images Property en véritable plateforme média Enterprise. À l'issue de cette étape : ✓ MinIO / S3 ✓ CDN ✓ Thumbnails ✓ WebP ✓ Compression ✓ Watermark ✓ Vision IA ✓ Détection qualité ✓ Media Intelligence Platform ---- ====== Architecture cible ====== PropertyImage ↓ Media Platform ├── Storage ├── CDN ├── Image Processing ├── AI Vision ├── Optimization └── Analytics ↓ Property Catalog ↓ Reservation Platform ---- ====== Sprint 4-D.2-A ====== ===== Architecture de Stockage ===== ---- ====== Étape 1 — Extension PropertyImage ====== ===== Ajouter dans schema.prisma ===== storageProvider String? cdnUrl String? thumbnailUrl String? mediumUrl String? largeUrl String? webpUrl String? checksum String? processingStatus ImageProcessingStatus @default(PENDING) ---- ====== Étape 2 — Enum ====== ===== Ajouter ===== enum ImageProcessingStatus { PENDING PROCESSING COMPLETED FAILED } ---- ====== Étape 3 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name media_platform ---- ====== Sprint 4-D.2-B ====== ===== Storage Enterprise ===== ---- ====== Étape 4 — MediaModule ====== ===== Créer ===== src/modules/media ├── storage │ ├── image-processing │ ├── ai-vision │ ├── cdn │ └── analytics ---- ====== Étape 5 — StorageService ====== ===== Créer ===== storage.service.ts ---- ===== Interface ===== upload() delete() copy() move() exists() generateSignedUrl() ---- ====== Étape 6 — Providers ====== ===== Supporter ===== MinIO AWS S3 Cloudflare R2 Azure Blob Google Cloud Storage ---- ====== Étape 7 — Configuration ====== ===== Ajouter ===== STORAGE_PROVIDER=minio MINIO_ENDPOINT= MINIO_BUCKET= MINIO_ACCESS_KEY= MINIO_SECRET_KEY= ---- ====== Sprint 4-D.2-C ====== ===== CDN ===== ---- ====== Étape 8 — CDN Service ====== ===== Créer ===== cdn.service.ts ---- ===== Méthodes ===== buildUrl() invalidate() purgeCache() ---- ====== Étape 9 — Fournisseurs ====== ===== Préparer ===== Cloudflare CloudFront Fastly Bunny CDN ---- ====== Étape 10 — URLs ====== ===== Générer ===== thumbnailUrl mediumUrl largeUrl webpUrl automatiquement. ---- ====== Sprint 4-D.2-D ====== ===== Génération des Variantes ===== ---- ====== Étape 11 — ImageProcessingService ====== ===== Créer ===== image-processing.service.ts ---- ===== Librairie ===== Sharp ---- ====== Étape 12 — Générer ====== ===== Formats ===== Thumbnail Medium Large WebP ---- ====== Étape 13 — Tailles ====== Thumbnail : 300px Medium : 1200px Large : 2400px ---- ====== Étape 14 — Workflow ====== Upload ↓ Original ↓ Resize ↓ WebP ↓ CDN ↓ Gallery ---- ====== Sprint 4-D.2-E ====== ===== Compression ===== ---- ====== Étape 15 — Optimisation ====== ===== Utiliser ===== Sharp MozJPEG WebP ---- ====== Étape 16 — Objectifs ====== JPEG 80% WebP 75% PNG optimisé ---- ====== Étape 17 — KPI ====== ===== Calculer ===== Compression Ratio Storage Saved Bandwidth Saved ---- ====== Sprint 4-D.2-F ====== ===== Watermark ===== ---- ====== Étape 18 — WatermarkService ====== ===== Créer ===== watermark.service.ts ---- ===== Supporter ===== Logo Texte Dynamic Branding ---- ====== Étape 19 — Configuration ====== ===== Ajouter ===== Position Opacity Scale Margins ---- ====== Étape 20 — Cas d'usage ====== Marketplace Partenaires Protection contenu ---- ====== Sprint 4-D.2-G ====== ===== Vision IA ===== ---- ====== Étape 21 — ImageVisionAnalysis ====== ===== Ajouter ===== model ImageVisionAnalysis { id String @id @default(uuid()) imageId String @unique labels Json? objects Json? qualityScore Float? blurScore Float? brightnessScore Float? adultContentDetected Boolean @default(false) duplicateDetected Boolean @default(false) analyzedAt DateTime @default(now()) image PropertyImage @relation( fields:[imageId], references:[id], onDelete:Cascade ) } ---- ====== Étape 22 — VisionService ====== ===== Créer ===== vision-analysis.service.ts ---- ===== Fournisseurs ===== AWS Rekognition Google Vision Azure Vision OpenAI Vision ---- ====== Étape 23 — Détections ====== Bedroom Bathroom Kitchen Pool Garden Sea View Pets ---- ====== Étape 24 — Auto-tagging ====== ===== Exemple ===== Photo ↓ Pool ↓ Amenity: PRIVATE_POOL ---- ====== Sprint 4-D.2-H ====== ===== Détection Qualité ===== ---- ====== Étape 25 — QualityScore ====== ===== Calculer ===== Sharpness Brightness Contrast Resolution Composition ---- ====== Étape 26 — Classification ====== 90-100 Excellent 75-89 Good 50-74 Acceptable 0-49 Poor ---- ====== Étape 27 — Recommandations ====== ===== Exemple ===== Image sombre ↓ Augmenter luminosité ---- Image floue ↓ Remplacer photo ---- ====== Sprint 4-D.2-I ====== ===== Analytics Média ===== ---- ====== Étape 28 — MediaAnalyticsService ====== ===== Créer ===== media-analytics.service.ts ---- ===== KPI ===== Images Uploaded Storage Used Compression Ratio AI Quality Score Most Viewed Images ---- ====== Étape 29 — Endpoint ====== ===== Ajouter ===== GET /media/analytics ---- ====== Sprint 4-D.2-J ====== ===== API Enterprise ===== ---- ====== Étape 30 — Endpoints ====== ===== Ajouter ===== POST /media/process POST /media/watermark POST /media/analyze GET /media/analytics GET /media/storage ---- ====== Étape 31 — AuditLog ====== ===== Journaliser ===== IMAGE_UPLOADED IMAGE_PROCESSED IMAGE_ANALYZED IMAGE_WATERMARKED IMAGE_OPTIMIZED ---- ====== Étape 32 — Permissions ====== ===== Ajouter ===== media.read media.upload media.process media.analyze media.admin ---- ====== Préparation Sprint 4-H ====== Compatible avec : Review Images User Uploads Moderation ---- ====== Préparation Sprint 4-I ====== Compatible avec : Property Search AI Ranking Visual Search ---- ====== Préparation Sprint 13 ====== Compatible avec : Computer Vision Property Intelligence AI Classification Knowledge Graph ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Media Platform Global CDN AI Vision Digital Asset Management ---- ====== Définition de terminé ====== Le Sprint 4-D.2 est terminé lorsque : ✓ MinIO/S3 intégré ✓ CDN intégré ✓ Variantes d'images ✓ WebP ✓ Compression ✓ Watermark ✓ Vision IA ✓ Détection qualité ✓ Analytics média ✓ Audit intégré ---- ====== Livrables ====== StorageService ImageProcessingService CDNService WatermarkService VisionAnalysisService MediaAnalyticsService ImageVisionAnalysis Enterprise Media Platform ---- ====== Sprint 4-E.1 — Gestion des Disponibilités ====== ===== Objectif ===== Implémenter le moteur de disponibilités des propriétés. Cette couche constitue la fondation du futur moteur de réservation. À l'issue de cette étape : ✓ PropertyAvailability ✓ PropertyAvailabilityModule ✓ PropertyAvailabilityController ✓ PropertyAvailabilityService ✓ Calendrier ✓ Blocages ✓ Inventaire ✓ Reservation Ready ---- ====== Architecture cible ====== Property ↓ PropertyAvailability ↓ Calendar Engine ↓ Inventory Engine ↓ Reservation Engine ---- ====== Sprint 4-E.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — Création PropertyAvailability ====== ===== Ajouter dans schema.prisma ===== model PropertyAvailability { id String @id @default(uuid()) tenantId String propertyId String startDate DateTime endDate DateTime status AvailabilityStatus inventory Int @default(1) availableUnits Int @default(1) reason String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) @@index([propertyId]) @@index([startDate]) @@index([endDate]) @@index([status]) } ---- ====== Étape 2 — Enum ====== ===== Ajouter ===== enum AvailabilityStatus { AVAILABLE BLOCKED RESERVED MAINTENANCE CLOSED } ---- ====== Étape 3 — Relation ====== ===== Ajouter dans Property ===== availabilities PropertyAvailability[] ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_availability ---- ===== Générer ===== npx prisma generate ---- ====== Sprint 4-E.1-B ====== ===== Module ===== ---- ====== Étape 5 — Création ====== src/modules/property-availability ├── application │ │ └── dto │ │ ├── create-property-availability.dto.ts │ │ ├── update-property-availability.dto.ts │ │ ├── availability-query.dto.ts │ │ └── calendar-response.dto.ts │ ├── domain │ │ └── services │ │ └── property-availability.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-availability.controller.ts │ └── property-availability.module.ts ---- ====== Étape 6 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyAvailabilityController ], providers: [ PropertyAvailabilityService ], exports: [ PropertyAvailabilityService ] }) export class PropertyAvailabilityModule {} ---- ====== Sprint 4-E.1-C ====== ===== DTOs ===== ---- ====== Étape 7 — CreatePropertyAvailabilityDto ====== ===== Créer ===== export class CreatePropertyAvailabilityDto { startDate: Date; endDate: Date; status: AvailabilityStatus; inventory?: number; availableUnits?: number; reason?: string; notes?: string; } ---- ====== Étape 8 — UpdatePropertyAvailabilityDto ====== ===== Créer ===== export class UpdatePropertyAvailabilityDto extends PartialType( CreatePropertyAvailabilityDto ) {} ---- ====== Étape 9 — AvailabilityQueryDto ====== ===== Créer ===== export class AvailabilityQueryDto { startDate?: Date; endDate?: Date; status?: AvailabilityStatus; } ---- ====== Sprint 4-E.1-D ====== ===== PropertyAvailabilityService ===== ---- ====== Étape 10 — Création ====== ===== Créer ===== property-availability.service.ts ---- ===== Méthodes ===== findAll() findCalendar() create() update() remove() checkAvailability() ---- ====== Étape 11 — Création ====== ===== Exemple ===== async create( tenantId: string, propertyId: string, dto: CreatePropertyAvailabilityDto, ) { return this.prisma.propertyAvailability.create({ data: { tenantId, propertyId, ...dto } }); } ---- ====== Étape 12 — Validation ====== ===== Vérifier ===== startDate < endDate et absence de conflits. ---- ====== Étape 13 — Détection de chevauchement ====== ===== Refuser ===== Périodes superposées pour les statuts incompatibles. ---- ===== Prisma ===== where: { propertyId, startDate: { lte: dto.endDate }, endDate: { gte: dto.startDate } } ---- ====== Sprint 4-E.1-E ====== ===== Calendrier ===== ---- ====== Étape 14 — Endpoint ====== ===== Ajouter ===== GET /properties/{id}/availability ---- ====== Étape 15 — Vue calendrier ====== ===== Retour ===== [ { "startDate":"2026-07-01", "endDate":"2026-07-10", "status":"AVAILABLE" } ] ---- ====== Étape 16 — Vue mensuelle ====== ===== Ajouter ===== GET /properties/{id}/availability/calendar ---- ===== Paramètres ===== month year ---- ====== Sprint 4-E.1-F ====== ===== Blocages ===== ---- ====== Étape 17 — Supporter ===== Maintenance Travaux Usage privé Fermeture saisonnière ---- ====== Étape 18 — Exemple ====== { "status":"MAINTENANCE", "reason":"Pool renovation" } ---- ====== Étape 19 — Endpoint ====== ===== Ajouter ===== POST /properties/{id}/availability/block ---- ====== Sprint 4-E.1-G ====== ===== Inventaire ===== ---- ====== Étape 20 — Support Multi-unités ====== ===== Utiliser ===== inventory availableUnits ---- ====== Étape 21 — Exemple ====== Inventaire : 10 Disponibles : 7 Réservées : 3 ---- ====== Étape 22 — Vérification ====== ===== Empêcher ===== availableUnits > inventory ---- ====== Sprint 4-E.1-H ====== ===== Contrôleur ===== ---- ====== Étape 23 — Création ====== ===== Créer ===== property-availability.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Availability' ) @ApiBearerAuth() @Controller( 'properties/:id/availability' ) @UseGuards( JwtAuthGuard ) ---- ====== Étape 24 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/availability GET /properties/{id}/availability/calendar POST /properties/{id}/availability PUT /properties/{id}/availability/{availabilityId} DELETE /properties/{id}/availability/{availabilityId} POST /properties/{id}/availability/block ---- ====== Sprint 4-E.1-I ====== ===== Sécurité ===== ---- ====== Étape 25 — Multi-Tenant ====== ===== Vérifier ===== tenantId propertyId sur toutes les opérations. ---- ====== Étape 26 — Permissions ====== ===== Ajouter ===== property.availability.read property.availability.create property.availability.update property.availability.delete property.availability.manage ---- ====== Étape 27 — Audit ====== ===== Journaliser ===== PROPERTY_AVAILABILITY_CREATED PROPERTY_AVAILABILITY_UPDATED PROPERTY_AVAILABILITY_DELETED PROPERTY_BLOCKED PROPERTY_UNBLOCKED ---- ====== Sprint 4-E.1-J ====== ===== Préparation Sprint 4-E.2 ===== ---- ====== Étape 28 — Compatibilité ====== Préparer : Reservation Booking Engine Inventory Engine Channel Manager ---- ====== Étape 29 — Préparer ====== Compatible avec : iCal Airbnb Booking.com Expedia ---- ====== Étape 30 — Préparer ====== Compatible avec : Dynamic Pricing Yield Management Revenue Engine ---- ====== Définition de terminé ====== Le Sprint 4-E.1 est terminé lorsque : ✓ PropertyAvailability créé ✓ PropertyAvailabilityModule créé ✓ PropertyAvailabilityController créé ✓ PropertyAvailabilityService créé ✓ Calendrier opérationnel ✓ Blocages opérationnels ✓ Inventaire opérationnel ✓ Multi-tenant Security ✓ AuditLog intégré ---- ====== Livrables ====== PropertyAvailability AvailabilityStatus PropertyAvailabilityModule PropertyAvailabilityController PropertyAvailabilityService Availability Calendar API ---- ====== Sprint 4-E.2 — Disponibilités Enterprise & Synchronisation Multi-Canaux ====== ===== Objectif ===== Transformer le moteur de disponibilités en véritable plateforme Channel Manager Enterprise. À l'issue de cette étape : ✓ iCal ✓ Airbnb Sync ✓ Booking.com Sync ✓ Expedia Sync ✓ Channel Manager ✓ Availability Intelligence ✓ Conflict Resolution ✓ Multi-Channel Inventory ---- ====== Architecture cible ====== Property Availability ↓ Channel Manager ├── iCal ├── Airbnb ├── Booking.com ├── Expedia ├── Direct Booking └── Future OTA Connectors ↓ Availability Intelligence ↓ Reservation Engine ---- ====== Sprint 4-E.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — ChannelConnection ====== ===== Ajouter dans schema.prisma ===== model ChannelConnection { id String @id @default(uuid()) tenantId String propertyId String channelType ChannelType externalPropertyId String? syncEnabled Boolean @default(true) lastSyncAt DateTime? syncStatus SyncStatus @default(PENDING) configuration Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) @@index([propertyId]) @@index([channelType]) } ---- ====== Étape 2 — AvailabilitySyncLog ====== ===== Ajouter ===== model AvailabilitySyncLog { id String @id @default(uuid()) channelConnectionId String syncType SyncType status SyncStatus startedAt DateTime completedAt DateTime? recordsProcessed Int @default(0) errorMessage String? payload Json? @@index([status]) @@index([startedAt]) } ---- ====== Étape 3 — AvailabilityConflict ====== ===== Ajouter ===== model AvailabilityConflict { id String @id @default(uuid()) propertyId String channelType ChannelType conflictType ConflictType localData Json externalData Json resolved Boolean @default(false) resolvedAt DateTime? resolvedBy String? createdAt DateTime @default(now()) @@index([propertyId]) @@index([resolved]) } ---- ====== Étape 4 — Enums ====== ===== Ajouter ===== enum ChannelType { ICAL AIRBNB BOOKING EXPEDIA DIRECT } enum SyncStatus { PENDING RUNNING SUCCESS FAILED PARTIAL } enum SyncType { IMPORT EXPORT BIDIRECTIONAL } enum ConflictType { INVENTORY BOOKING AVAILABILITY PRICE } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name channel_manager ---- ====== Sprint 4-E.2-B ====== ===== Channel Manager Module ===== ---- ====== Étape 6 — Création ====== src/modules/channel-manager ├── connectors │ │ ├── ical │ │ ├── airbnb │ │ ├── booking │ │ └── expedia │ ├── synchronization │ ├── conflict-resolution │ ├── intelligence │ └── channel-manager.module.ts ---- ====== Étape 7 — Services ====== ===== Créer ===== ChannelManagerService AvailabilitySyncService ConflictResolutionService AvailabilityIntelligenceService ---- ====== Sprint 4-E.2-C ====== ===== Synchronisation iCal ===== ---- ====== Étape 8 — IcalConnection ====== ===== Ajouter ===== icalUrl String? icalExportUrl String? dans : ChannelConnection ---- ====== Étape 9 — IcalSyncService ====== ===== Créer ===== ical-sync.service.ts ---- ===== Méthodes ===== importCalendar() exportCalendar() syncCalendar() ---- ====== Étape 10 — Endpoints ====== ===== Ajouter ===== POST /channels/ical/connect POST /channels/ical/sync GET /channels/ical/status ---- ====== Sprint 4-E.2-D ====== ===== Airbnb Connector ===== ---- ====== Étape 11 — AirbnbConnector ====== ===== Créer ===== airbnb-connector.service.ts ---- ===== Fonctions ===== syncAvailability() syncInventory() syncReservations() ---- ====== Étape 12 — Mapping ====== ===== Synchroniser ===== Property Availability Inventory Reservations ---- ====== Étape 13 — Endpoint ====== ===== Ajouter ===== POST /channels/airbnb/connect POST /channels/airbnb/sync ---- ====== Sprint 4-E.2-E ====== ===== Booking.com Connector ===== ---- ====== Étape 14 — BookingConnector ====== ===== Créer ===== booking-connector.service.ts ---- ===== Fonctions ===== syncAvailability() syncInventory() syncRates() ---- ====== Étape 15 — Endpoint ====== ===== Ajouter ===== POST /channels/booking/connect POST /channels/booking/sync ---- ====== Sprint 4-E.2-F ====== ===== Expedia Connector ===== ---- ====== Étape 16 — ExpediaConnector ====== ===== Créer ===== expedia-connector.service.ts ---- ===== Fonctions ===== syncAvailability() syncInventory() syncRates() ---- ====== Étape 17 — Endpoint ====== ===== Ajouter ===== POST /channels/expedia/connect POST /channels/expedia/sync ---- ====== Sprint 4-E.2-G ====== ===== Résolution de Conflits ===== ---- ====== Étape 18 — ConflictResolutionService ====== ===== Créer ===== conflict-resolution.service.ts ---- ===== Méthodes ===== detectConflicts() resolveConflict() autoResolve() ---- ====== Étape 19 — Types ====== ===== Détecter ===== Double réservation Inventaire incohérent Disponibilité divergente Tarif divergent ---- ====== Étape 20 — Politique ====== ===== Priorité ===== Reservation Engine ↓ Direct Booking ↓ OTA ---- ====== Sprint 4-E.2-H ====== ===== Availability Intelligence ===== ---- ====== Étape 21 — AvailabilityIntelligenceService ====== ===== Créer ===== availability-intelligence.service.ts ---- ===== Méthodes ===== detectGaps() forecastOccupancy() recommendAvailabilityRules() ---- ====== Étape 22 — Détections ====== ===== Identifier ===== Dates non ouvertes Blocages anormaux Fenêtres d'opportunité Périodes sous-occupées ---- ====== Étape 23 — Exemple ====== Weekend libre Taux occupation élevé ↓ Suggestion ouverture ---- ====== Sprint 4-E.2-I ====== ===== Dashboard Channel Manager ===== ---- ====== Étape 24 — Endpoint ====== ===== Ajouter ===== GET /channels/dashboard ---- ===== Retour ===== { "connectedChannels":4, "lastSync":"2026-07-01T10:00:00Z", "pendingConflicts":2, "occupancyForecast":84 } ---- ====== Étape 25 — Monitoring ====== ===== Afficher ===== Canaux actifs Derniers syncs Erreurs Conflits Performance OTA ---- ====== Sprint 4-E.2-J ====== ===== Sécurité & Gouvernance ===== ---- ====== Étape 26 — Permissions ====== ===== Ajouter ===== channel.read channel.manage channel.sync channel.resolve channel.admin ---- ====== Étape 27 — Audit ====== ===== Journaliser ===== CHANNEL_CONNECTED CHANNEL_SYNC_STARTED CHANNEL_SYNC_COMPLETED CHANNEL_CONFLICT_DETECTED CHANNEL_CONFLICT_RESOLVED ---- ====== Étape 28 — Jobs ====== ===== Ajouter ===== Cron : Toutes les 15 min iCal Sync OTA Sync Conflict Detection ---- ====== Étape 29 — Compatibilité Sprint 5 ====== Préparer : Reservation Booking Engine Inventory Locking Overbooking Protection ---- ====== Étape 30 — Compatibilité Sprint 20 ====== Préparer : Enterprise Channel Manager Multi OTA Revenue Management Enterprise Inventory ---- ====== Définition de terminé ====== Le Sprint 4-E.2 est terminé lorsque : ✓ iCal Sync ✓ Airbnb Connector ✓ Booking Connector ✓ Expedia Connector ✓ Channel Manager ✓ Conflict Resolution ✓ Availability Intelligence ✓ Dashboard ✓ Audit intégré ---- ====== Livrables ====== ChannelConnection AvailabilitySyncLog AvailabilityConflict ChannelManagerService AvailabilitySyncService ConflictResolutionService AvailabilityIntelligenceService Enterprise Channel Manager ---- ====== Sprint 4-F.1 — Gestion de la Tarification ====== ===== Objectif ===== Implémenter le moteur tarifaire des propriétés. Cette couche constitue la fondation du futur Revenue Management System. À l'issue de cette étape : ✓ PropertyPricing ✓ PropertyPricingModule ✓ PropertyPricingController ✓ PropertyPricingService ✓ Tarifs de base ✓ Tarifs saisonniers ✓ Tarifs par période ✓ Inventaire tarifaire ✓ Revenue Ready ---- ====== Architecture cible ====== Property ↓ PropertyPricing ↓ Pricing Engine ↓ Reservation Engine ↓ Revenue Management ---- ====== Sprint 4-F.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — Création PropertyPricing ====== ===== Ajouter dans schema.prisma ===== model PropertyPricing { id String @id @default(uuid()) tenantId String propertyId String pricingType PricingType name String startDate DateTime? endDate DateTime? basePrice Decimal @db.Decimal(12,2) weekendPrice Decimal? @db.Decimal(12,2) extraGuestPrice Decimal? @db.Decimal(12,2) cleaningFee Decimal? @db.Decimal(12,2) serviceFee Decimal? @db.Decimal(12,2) securityDeposit Decimal? @db.Decimal(12,2) minimumStay Int? @default(1) maximumStay Int? priority Int @default(0) active Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) @@index([propertyId]) @@index([pricingType]) @@index([startDate]) @@index([endDate]) @@index([active]) } ---- ====== Étape 2 — Enum PricingType ====== ===== Ajouter ===== enum PricingType { BASE SEASONAL SPECIAL_EVENT PROMOTIONAL LAST_MINUTE LONG_STAY } ---- ====== Étape 3 — Relation ====== ===== Ajouter dans Property ===== pricingRules PropertyPricing[] ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_pricing ---- ===== Générer ===== npx prisma generate ---- ====== Sprint 4-F.1-B ====== ===== Module ===== ---- ====== Étape 5 — Création ====== src/modules/property-pricing ├── application │ │ └── dto │ │ ├── create-property-pricing.dto.ts │ │ ├── update-property-pricing.dto.ts │ │ ├── pricing-query.dto.ts │ │ └── pricing-calculation.dto.ts │ ├── domain │ │ └── services │ │ ├── property-pricing.service.ts │ │ └── pricing-calculation.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-pricing.controller.ts │ └── property-pricing.module.ts ---- ====== Étape 6 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyPricingController ], providers: [ PropertyPricingService, PricingCalculationService ], exports: [ PropertyPricingService, PricingCalculationService ] }) export class PropertyPricingModule {} ---- ====== Sprint 4-F.1-C ====== ===== DTOs ===== ---- ====== Étape 7 — CreatePropertyPricingDto ====== ===== Créer ===== export class CreatePropertyPricingDto { pricingType: PricingType; name: string; startDate?: Date; endDate?: Date; basePrice: number; weekendPrice?: number; extraGuestPrice?: number; cleaningFee?: number; serviceFee?: number; securityDeposit?: number; minimumStay?: number; maximumStay?: number; priority?: number; } ---- ====== Étape 8 — UpdatePropertyPricingDto ====== ===== Créer ===== export class UpdatePropertyPricingDto extends PartialType( CreatePropertyPricingDto ) {} ---- ====== Étape 9 — PricingQueryDto ====== ===== Créer ===== export class PricingQueryDto { startDate?: Date; endDate?: Date; pricingType?: PricingType; active?: boolean; } ---- ====== Sprint 4-F.1-D ====== ===== PropertyPricingService ===== ---- ====== Étape 10 — Création ====== ===== Créer ===== property-pricing.service.ts ---- ===== Méthodes ===== findAll() findById() create() update() remove() findApplicablePricing() ---- ====== Étape 11 — Validation ====== ===== Vérifier ===== basePrice > 0 minimumStay >= 1 startDate <= endDate ---- ====== Étape 12 — Gestion des conflits ====== ===== Contrôler ===== Chevauchements de périodes. ---- ===== Priorité ===== LAST_MINUTE ↓ PROMOTIONAL ↓ SPECIAL_EVENT ↓ SEASONAL ↓ BASE ---- ====== Étape 13 — Tarification applicable ====== ===== Sélection ===== Règle active : plus haute priorité pour une période donnée. ---- ====== Sprint 4-F.1-E ====== ===== Tarifs de Base ===== ---- ====== Étape 14 — Règle par défaut ====== ===== Exiger ===== Une règle : PricingType.BASE par propriété. ---- ====== Étape 15 — Exemple ====== { "pricingType":"BASE", "name":"Tarif Standard", "basePrice":120 } ---- ====== Sprint 4-F.1-F ====== ===== Tarifs Saisonniers ===== ---- ====== Étape 16 — Cas d'usage ====== ===== Supporter ===== Haute saison Basse saison Vacances Événements ---- ====== Étape 17 — Exemple ====== { "pricingType":"SEASONAL", "name":"Été 2027", "startDate":"2027-06-01", "endDate":"2027-09-01", "basePrice":180 } ---- ====== Étape 18 — Calendrier ====== ===== Préparer ===== Compatible avec : PropertyAvailability ---- ====== Sprint 4-F.1-G ====== ===== Calcul Tarifaire ===== ---- ====== Étape 19 — PricingCalculationService ====== ===== Créer ===== pricing-calculation.service.ts ---- ===== Méthodes ===== calculatePrice() calculateStayPrice() calculateFees() calculateDeposit() ---- ====== Étape 20 — Calcul ====== ===== Exemple ===== 3 nuits Base : 120 € ↓ 360 € ---- ====== Étape 21 — Frais ====== ===== Ajouter ===== Cleaning Fee Service Fee Security Deposit Extra Guests ---- ====== Étape 22 — Retour ====== ===== Exemple ===== { "baseAmount":360, "cleaningFee":30, "serviceFee":15, "total":405 } ---- ====== Sprint 4-F.1-H ====== ===== Contrôleur ===== ---- ====== Étape 23 — Création ====== ===== Créer ===== property-pricing.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Pricing' ) @ApiBearerAuth() @Controller( 'properties/:id/pricing' ) @UseGuards( JwtAuthGuard ) ---- ====== Étape 24 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/pricing POST /properties/{id}/pricing PUT /properties/{id}/pricing/{pricingId} DELETE /properties/{id}/pricing/{pricingId} POST /properties/{id}/pricing/calculate ---- ====== Étape 25 — Endpoint calcul ====== ===== Exemple ===== { "checkIn":"2027-07-10", "checkOut":"2027-07-15", "guests":4 } ---- ====== Sprint 4-F.1-I ====== ===== Sécurité ===== ---- ====== Étape 26 — Multi-Tenant ====== ===== Vérifier ===== tenantId propertyId sur toutes les opérations. ---- ====== Étape 27 — Permissions ====== ===== Ajouter ===== property.pricing.read property.pricing.create property.pricing.update property.pricing.delete property.pricing.calculate ---- ====== Étape 28 — Audit ====== ===== Journaliser ===== PROPERTY_PRICING_CREATED PROPERTY_PRICING_UPDATED PROPERTY_PRICING_DELETED PROPERTY_PRICE_CALCULATED ---- ====== Sprint 4-F.1-J ====== ===== Préparation Sprint 4-F.2 ===== ---- ====== Étape 29 — Compatible ===== Préparer : Dynamic Pricing Yield Management Revenue Forecast Competitor Rates ---- ====== Étape 30 — Compatible ===== Préparer : Reservation Booking Engine Channel Manager Revenue Management ---- ====== Définition de terminé ====== Le Sprint 4-F.1 est terminé lorsque : ✓ PropertyPricing créé ✓ PropertyPricingModule créé ✓ PropertyPricingController créé ✓ PropertyPricingService créé ✓ Tarifs de base ✓ Tarifs saisonniers ✓ Tarifs par période ✓ Calcul tarifaire ✓ Audit intégré ---- ====== Livrables ====== PropertyPricing PricingType PropertyPricingModule PropertyPricingController PropertyPricingService PricingCalculationService Property Pricing API ---- ====== Sprint 4-F.2 — Revenue Management & Tarification Dynamique ====== ===== Objectif ===== Transformer le moteur tarifaire en véritable Revenue Management System Enterprise. À l'issue de cette étape : ✓ Dynamic Pricing ✓ Yield Management ✓ Occupancy Pricing ✓ Competitor Pricing ✓ Demand Forecast ✓ Revenue Intelligence ✓ Revenue Optimization Engine ---- ====== Architecture cible ====== Property Pricing ↓ Revenue Engine ├── Dynamic Pricing ├── Yield Management ├── Occupancy Analysis ├── Competitor Intelligence ├── Demand Forecast └── Revenue Optimization ↓ Reservation Engine ↓ Channel Manager ---- ====== Sprint 4-F.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — DynamicPricingRule ====== ===== Ajouter dans schema.prisma ===== model DynamicPricingRule { id String @id @default(uuid()) tenantId String propertyId String name String active Boolean @default(true) triggerType DynamicPricingTrigger triggerValue Float adjustmentType PriceAdjustmentType adjustmentValue Float priority Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([tenantId]) @@index([propertyId]) @@index([active]) } ---- ====== Étape 2 — RevenueSnapshot ====== ===== Ajouter ===== model RevenueSnapshot { id String @id @default(uuid()) propertyId String snapshotDate DateTime occupancyRate Float averageDailyRate Decimal @db.Decimal(12,2) revPar Decimal @db.Decimal(12,2) projectedRevenue Decimal @db.Decimal(14,2) createdAt DateTime @default(now()) @@index([propertyId]) @@index([snapshotDate]) } ---- ====== Étape 3 — CompetitorRate ====== ===== Ajouter ===== model CompetitorRate { id String @id @default(uuid()) propertyId String competitorName String competitorPropertyId String? stayDate DateTime nightlyRate Decimal @db.Decimal(12,2) source String? collectedAt DateTime @default(now()) @@index([propertyId]) @@index([stayDate]) } ---- ====== Étape 4 — Enums ====== ===== Ajouter ===== enum DynamicPricingTrigger { OCCUPANCY DEMAND BOOKING_WINDOW COMPETITOR_RATE EVENT SEASON } enum PriceAdjustmentType { PERCENTAGE FIXED_AMOUNT } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name revenue_management ---- ====== Sprint 4-F.2-B ====== ===== Revenue Management Module ===== ---- ====== Étape 6 — Création ====== src/modules/revenue-management ├── dynamic-pricing │ ├── yield-management │ ├── occupancy-pricing │ ├── competitor-pricing │ ├── demand-forecast │ ├── revenue-intelligence │ └── revenue-management.module.ts ---- ====== Étape 7 — Services ====== ===== Créer ===== DynamicPricingService YieldManagementService OccupancyPricingService CompetitorPricingService DemandForecastService RevenueIntelligenceService ---- ====== Sprint 4-F.2-C ====== ===== Dynamic Pricing ===== ---- ====== Étape 8 — DynamicPricingService ====== ===== Créer ===== dynamic-pricing.service.ts ---- ===== Méthodes ===== calculateDynamicPrice() applyPricingRules() simulatePricing() ---- ====== Étape 9 — Exemple ====== ===== Règle ===== Occupation > 85% ↓ +15% ---- ===== Résultat ===== 120 € ↓ 138 € ---- ====== Étape 10 — Endpoint ====== ===== Ajouter ===== POST /revenue/dynamic-pricing/calculate ---- ====== Sprint 4-F.2-D ====== ===== Yield Management ===== ---- ====== Étape 11 — YieldManagementService ====== ===== Créer ===== yield-management.service.ts ---- ===== Méthodes ===== calculateOptimalRate() calculateYield() optimizeRevenue() ---- ====== Étape 12 — Facteurs ====== Occupation Historique réservations Saisonnalité Demande Concurrence ---- ====== Étape 13 — KPI ====== ===== Calculer ===== ADR RevPAR Revenue per Stay Yield Index ---- ====== Sprint 4-F.2-E ====== ===== Occupancy Pricing ===== ---- ====== Étape 14 — OccupancyPricingService ====== ===== Créer ===== occupancy-pricing.service.ts ---- ===== Méthodes ===== adjustByOccupancy() predictOccupancyImpact() ---- ====== Étape 15 — Exemple ====== Occupation 95% ↓ +20% ---- Occupation 30% ↓ -15% ---- ====== Étape 16 — Paliers ====== 0-30% 31-60% 61-85% 86-100% ---- ====== Sprint 4-F.2-F ====== ===== Competitor Pricing ===== ---- ====== Étape 17 — CompetitorPricingService ====== ===== Créer ===== competitor-pricing.service.ts ---- ===== Méthodes ===== collectCompetitorRates() compareRates() recommendAdjustment() ---- ====== Étape 18 — Comparaison ====== ===== Exemple ===== Votre prix 120 € Concurrence 145 € ---- ===== Recommandation ===== Augmenter à 132 € ---- ====== Étape 19 — Endpoint ====== ===== Ajouter ===== GET /revenue/competitors ---- ====== Sprint 4-F.2-G ====== ===== Demand Forecast ===== ---- ====== Étape 20 — DemandForecastService ====== ===== Créer ===== demand-forecast.service.ts ---- ===== Méthodes ===== forecastDemand() forecastRevenue() forecastOccupancy() ---- ====== Étape 21 — Sources ====== Réservations Historique Événements Saisonnalité Recherche ---- ====== Étape 22 — Exemple ====== Juillet Demande +24% ---- ===== Action ===== Augmenter tarifs ---- ====== Sprint 4-F.2-H ====== ===== Revenue Intelligence ===== ---- ====== Étape 23 — RevenueIntelligenceService ====== ===== Créer ===== revenue-intelligence.service.ts ---- ===== Méthodes ===== generateInsights() detectRevenueOpportunities() recommendStrategies() ---- ====== Étape 24 — Exemples ====== ===== Insight ===== Week-end Taux réservation 96% ---- ===== Recommandation ===== +12% tarif ---- ===== Insight ===== Sous-performance Août ↓ Promotion ciblée ---- ====== Étape 25 — Revenue Insight ====== ===== Ajouter ===== model RevenueInsight { id String @id @default(uuid()) propertyId String severity String title String description String recommendation String? createdAt DateTime @default(now()) resolved Boolean @default(false) @@index([propertyId]) @@index([resolved]) } ---- ====== Sprint 4-F.2-I ====== ===== Dashboard Revenue ===== ---- ====== Étape 26 — Endpoint ====== ===== Ajouter ===== GET /revenue/dashboard ---- ===== KPI ===== Revenue ADR RevPAR Occupation Forecast Opportunités ---- ====== Étape 27 — Exemple ====== { "adr":142, "revPar":121, "occupancy":85, "forecastRevenue":42000 } ---- ====== Étape 28 — Snapshot ====== ===== Alimenter ===== RevenueSnapshot quotidiennement. ---- ====== Sprint 4-F.2-J ====== ===== Gouvernance & Sécurité ===== ---- ====== Étape 29 — Permissions ====== ===== Ajouter ===== revenue.read revenue.manage revenue.optimize revenue.forecast revenue.admin ---- ====== Étape 30 — Audit ====== ===== Journaliser ===== REVENUE_RULE_CREATED DYNAMIC_PRICE_CALCULATED REVENUE_FORECAST_GENERATED REVENUE_INSIGHT_CREATED REVENUE_OPTIMIZATION_APPLIED ---- ====== Étape 31 — Jobs ====== ===== Ajouter ===== Toutes les heures Dynamic Pricing Toutes les nuits Revenue Forecast Revenue Insights ---- ====== Préparation Sprint 5 ====== Compatible avec : Reservation Booking Engine Upsell Promotion Engine ---- ====== Préparation Sprint 17 ====== Compatible avec : Financial Forecast Profitability Analysis Business Intelligence ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Revenue Management AI Pricing Predictive Revenue Revenue Intelligence ---- ====== Définition de terminé ====== Le Sprint 4-F.2 est terminé lorsque : ✓ Dynamic Pricing ✓ Yield Management ✓ Occupancy Pricing ✓ Competitor Pricing ✓ Demand Forecast ✓ Revenue Intelligence ✓ Revenue Dashboard ✓ Audit intégré ---- ====== Livrables ====== DynamicPricingRule RevenueSnapshot CompetitorRate RevenueInsight DynamicPricingService YieldManagementService DemandForecastService RevenueIntelligenceService Revenue Dashboard ---- ====== Sprint 4-G.1 — Gestion des Politiques des Propriétés ====== ===== Objectif ===== Implémenter le moteur de politiques métier des propriétés. Cette couche constitue la fondation des règles de réservation, d'annulation et d'exploitation. À l'issue de cette étape : ✓ PropertyPolicy ✓ PropertyPolicyModule ✓ PropertyPolicyController ✓ PropertyPolicyService ✓ Check-in ✓ Check-out ✓ Annulation ✓ Règlement intérieur ✓ Reservation Ready ---- ====== Architecture cible ====== Property ↓ PropertyPolicy ├── Check-in ├── Check-out ├── Cancellation ├── House Rules ├── Guest Rules └── Booking Restrictions ↓ Reservation Engine ↓ Revenue Engine ---- ====== Sprint 4-G.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — Création PropertyPolicy ====== ===== Ajouter dans schema.prisma ===== model PropertyPolicy { id String @id @default(uuid()) tenantId String propertyId String @unique cancellationPolicy CancellationPolicyType checkInFrom String? checkInTo String? checkOutFrom String? checkOutTo String? minimumGuestAge Int? petsAllowed Boolean @default(false) smokingAllowed Boolean @default(false) partiesAllowed Boolean @default(false) childrenAllowed Boolean @default(true) eventsAllowed Boolean @default(false) quietHoursStart String? quietHoursEnd String? houseRules String? guestInstructions String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) @@index([cancellationPolicy]) } ---- ====== Étape 2 — Enum ====== ===== Ajouter ===== enum CancellationPolicyType { FLEXIBLE MODERATE STRICT NON_REFUNDABLE CUSTOM } ---- ====== Étape 3 — Relation ====== ===== Ajouter dans Property ===== policy PropertyPolicy? ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_policy ---- ===== Générer ===== npx prisma generate ---- ====== Sprint 4-G.1-B ====== ===== Politiques d'Annulation ===== ---- ====== Étape 5 — Règles Standards ====== ===== FLEXIBLE ===== Annulation gratuite jusqu'à 24h avant arrivée ---- ===== MODERATE ===== Annulation gratuite jusqu'à 5 jours avant arrivée ---- ===== STRICT ===== Remboursement partiel selon conditions ---- ===== NON_REFUNDABLE ===== Aucun remboursement ---- ====== Étape 6 — Politique personnalisée ====== ===== Ajouter ===== customCancellationPolicy String? pour : CancellationPolicyType.CUSTOM ---- ====== Sprint 4-G.1-C ====== ===== Check-in & Check-out ===== ---- ====== Étape 7 — Gestion horaires ====== ===== Supporter ===== Check-in From Check-in To Check-out From Check-out To ---- ====== Étape 8 — Exemples ====== Check-in 15:00 → 22:00 ---- Check-out 08:00 → 11:00 ---- ====== Étape 9 — Validation ====== ===== Vérifier ===== Format : HH:mm sur tous les horaires. ---- ====== Sprint 4-G.1-D ====== ===== Règlement Intérieur ===== ---- ====== Étape 10 — Gestion ====== ===== Supporter ===== Animaux Fumeurs Fêtes Enfants Événements ---- ====== Étape 11 — Exemple ====== { "petsAllowed":true, "smokingAllowed":false, "partiesAllowed":false } ---- ====== Étape 12 — Texte libre ====== ===== Utiliser ===== houseRules guestInstructions pour les consignes détaillées. ---- ====== Sprint 4-G.1-E ====== ===== Module ===== ---- ====== Étape 13 — Création ====== src/modules/property-policy ├── application │ │ └── dto │ │ ├── update-property-policy.dto.ts │ │ └── property-policy-response.dto.ts │ ├── domain │ │ └── services │ │ └── property-policy.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-policy.controller.ts │ └── property-policy.module.ts ---- ====== Étape 14 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyPolicyController ], providers: [ PropertyPolicyService ], exports: [ PropertyPolicyService ] }) export class PropertyPolicyModule {} ---- ====== Sprint 4-G.1-F ====== ===== DTOs ===== ---- ====== Étape 15 — UpdatePropertyPolicyDto ====== ===== Créer ===== export class UpdatePropertyPolicyDto { cancellationPolicy: CancellationPolicyType; customCancellationPolicy?: string; checkInFrom?: string; checkInTo?: string; checkOutFrom?: string; checkOutTo?: string; minimumGuestAge?: number; petsAllowed?: boolean; smokingAllowed?: boolean; partiesAllowed?: boolean; childrenAllowed?: boolean; eventsAllowed?: boolean; quietHoursStart?: string; quietHoursEnd?: string; houseRules?: string; guestInstructions?: string; } ---- ====== Sprint 4-G.1-G ====== ===== PropertyPolicyService ===== ---- ====== Étape 16 — Création ====== ===== Créer ===== property-policy.service.ts ---- ===== Méthodes ===== getPolicy() updatePolicy() validatePolicy() initializePolicy() ---- ====== Étape 17 — Initialisation ====== ===== Créer automatiquement ===== lors de la création d'une propriété : MODERATE 15:00-22:00 08:00-11:00 comme valeurs par défaut. ---- ====== Étape 18 — Validation ====== ===== Contrôler ===== Check-in Check-out Âge minimum Règles cohérentes avant sauvegarde. ---- ====== Sprint 4-G.1-H ====== ===== Contrôleur ===== ---- ====== Étape 19 — Création ====== ===== Créer ===== property-policy.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Policies' ) @ApiBearerAuth() @Controller( 'properties/:id/policies' ) @UseGuards( JwtAuthGuard ) ---- ====== Étape 20 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/policies PUT /properties/{id}/policies ---- ====== Étape 21 — Exemple ====== ===== Retour ===== { "cancellationPolicy":"MODERATE", "checkInFrom":"15:00", "checkInTo":"22:00", "petsAllowed":true } ---- ====== Sprint 4-G.1-I ====== ===== Sécurité ===== ---- ====== Étape 22 — Multi-Tenant ====== ===== Vérifier ===== tenantId propertyId sur toutes les opérations. ---- ====== Étape 23 — Permissions ====== ===== Ajouter ===== property.policy.read property.policy.update property.policy.manage ---- ====== Étape 24 — Audit ====== ===== Journaliser ===== PROPERTY_POLICY_VIEWED PROPERTY_POLICY_UPDATED PROPERTY_CANCELLATION_UPDATED PROPERTY_RULES_UPDATED ---- ====== Sprint 4-G.1-J ====== ===== Préparation Sprint 5 ===== ---- ====== Étape 25 — Compatible ===== Préparer : Reservation Booking Workflow Refund Engine Guest Management ---- ====== Étape 26 — Compatible ===== Préparer : Revenue Management Legal Compliance Terms & Conditions Insurance Rules ---- ====== Étape 27 — Préparer ===== Compatible avec : Airbnb Booking.com Expedia OTA Mapping ---- ====== Définition de terminé ====== Le Sprint 4-G.1 est terminé lorsque : ✓ PropertyPolicy créé ✓ PropertyPolicyModule créé ✓ PropertyPolicyController créé ✓ PropertyPolicyService créé ✓ Check-in géré ✓ Check-out géré ✓ Annulation gérée ✓ Règlement intérieur géré ✓ Audit intégré ---- ====== Livrables ====== PropertyPolicy CancellationPolicyType PropertyPolicyModule PropertyPolicyController PropertyPolicyService Property Policy API ---- ====== Sprint 4-G.2 — Politiques Enterprise & Conformité Juridique ====== ===== Objectif ===== Transformer le moteur de politiques en véritable couche de gouvernance juridique Enterprise. À l'issue de cette étape : ✓ Conditions contractuelles ✓ Dépôts de garantie ✓ Conformité locale ✓ RGPD ✓ Documents légaux ✓ Signature électronique ✓ Gestion des exceptions ✓ Legal Compliance Engine ---- ====== Architecture cible ====== Property Policy ↓ Legal Engine ├── Contracts ├── Deposits ├── Compliance ├── GDPR ├── Legal Documents ├── E-Signature └── Exceptions ↓ Reservation Engine ↓ Governance Layer ---- ====== Sprint 4-G.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — PropertyLegalPolicy ====== ===== Ajouter dans schema.prisma ===== model PropertyLegalPolicy { id String @id @default(uuid()) tenantId String propertyId String @unique termsAndConditions String? privacyPolicy String? liabilityWaiver String? cancellationTerms String? localComplianceNotes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) @@index([tenantId]) } ---- ====== Étape 2 — SecurityDepositPolicy ====== ===== Ajouter ===== model SecurityDepositPolicy { id String @id @default(uuid()) propertyId String @unique depositRequired Boolean @default(false) depositAmount Decimal? @db.Decimal(12,2) depositCurrency String? @default("EUR") refundDelayDays Int? @default(7) refundConditions String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([propertyId]) } ---- ====== Étape 3 — LegalDocument ====== ===== Ajouter ===== model LegalDocument { id String @id @default(uuid()) tenantId String propertyId String? documentType LegalDocumentType version String title String storagePath String published Boolean @default(false) effectiveDate DateTime createdAt DateTime @default(now()) @@index([tenantId]) @@index([documentType]) @@index([effectiveDate]) } ---- ====== Étape 4 — Enums ====== ===== Ajouter ===== enum LegalDocumentType { TERMS PRIVACY_POLICY HOUSE_RULES RENTAL_CONTRACT LIABILITY_WAIVER GDPR_NOTICE } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name legal_compliance ---- ====== Sprint 4-G.2-B ====== ===== Gestion Contractuelle ===== ---- ====== Étape 6 — ContractModule ====== ===== Créer ===== src/modules/legal ├── contracts │ ├── compliance │ ├── gdpr │ ├── signatures │ └── documents ---- ====== Étape 7 — ContractService ====== ===== Créer ===== contract.service.ts ---- ===== Méthodes ===== generateContract() validateContract() publishContract() archiveContract() ---- ====== Étape 8 — Contrat réservation ====== ===== Générer automatiquement ===== à partir de : Property Reservation Policies Guest ---- ====== Sprint 4-G.2-C ====== ===== Dépôts de Garantie ===== ---- ====== Étape 9 — SecurityDepositService ====== ===== Créer ===== security-deposit.service.ts ---- ===== Méthodes ===== calculateDeposit() reserveDeposit() releaseDeposit() claimDeposit() ---- ====== Étape 10 — Types ====== ===== Supporter ===== Montant fixe Pourcentage réservation Selon catégorie ---- ====== Étape 11 — Exemple ====== Réservation 1 000 € Dépôt 20 % ↓ 200 € ---- ====== Sprint 4-G.2-D ====== ===== Conformité Locale ===== ---- ====== Étape 12 — LocalComplianceRule ====== ===== Ajouter ===== model LocalComplianceRule { id String @id @default(uuid()) countryCode String regionCode String? ruleType String title String description String active Boolean @default(true) createdAt DateTime @default(now()) @@index([countryCode]) @@index([ruleType]) } ---- ====== Étape 13 — ComplianceService ====== ===== Créer ===== compliance.service.ts ---- ===== Méthodes ===== validatePropertyCompliance() getApplicableRules() generateComplianceReport() ---- ====== Étape 14 — Contrôles ====== ===== Vérifier ===== Taxe séjour Déclaration hébergement Assurance Capacité légale Sécurité incendie ---- ====== Sprint 4-G.2-E ====== ===== RGPD ===== ---- ====== Étape 15 — GDPRConsent ====== ===== Ajouter ===== model GDPRConsent { id String @id @default(uuid()) userId String consentType String accepted Boolean acceptedAt DateTime? revokedAt DateTime? ipAddress String? createdAt DateTime @default(now()) @@index([userId]) @@index([consentType]) } ---- ====== Étape 16 — GDPRService ====== ===== Créer ===== gdpr.service.ts ---- ===== Méthodes ===== recordConsent() revokeConsent() exportUserData() anonymizeUserData() ---- ====== Étape 17 — Supporter ===== Consentement Portabilité Rectification Droit à l'oubli ---- ====== Sprint 4-G.2-F ====== ===== Signature Électronique ===== ---- ====== Étape 18 — ElectronicSignature ====== ===== Ajouter ===== model ElectronicSignature { id String @id @default(uuid()) documentId String signerId String signedAt DateTime? ipAddress String? status SignatureStatus signatureHash String? @@index([documentId]) @@index([signerId]) } ---- ====== Étape 19 — Enum ====== ===== Ajouter ===== enum SignatureStatus { PENDING SIGNED REJECTED EXPIRED } ---- ====== Étape 20 — SignatureService ====== ===== Créer ===== signature.service.ts ---- ===== Méthodes ===== requestSignature() signDocument() verifySignature() ---- ====== Sprint 4-G.2-G ====== ===== Gestion des Exceptions ===== ---- ====== Étape 21 — PolicyException ====== ===== Ajouter ===== model PolicyException { id String @id @default(uuid()) propertyId String exceptionType String reason String approvedBy String? validFrom DateTime? validUntil DateTime? active Boolean @default(true) createdAt DateTime @default(now()) @@index([propertyId]) @@index([active]) } ---- ====== Étape 22 — Cas d'usage ====== ===== Supporter ===== Animal exceptionnel Check-in tardif Annulation exceptionnelle Remise exceptionnelle ---- ====== Étape 23 — Validation ====== ===== Exiger ===== Approbation selon RBAC. ---- ====== Sprint 4-G.2-H ====== ===== API Enterprise ===== ---- ====== Étape 24 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/legal PUT /properties/{id}/legal GET /properties/{id}/compliance POST /properties/{id}/compliance/validate POST /contracts/generate POST /contracts/sign GET /gdpr/export POST /gdpr/delete-request ---- ====== Étape 25 — Documents ====== ===== Ajouter ===== GET /legal-documents POST /legal-documents PUT /legal-documents/{id} DELETE /legal-documents/{id} ---- ====== Sprint 4-G.2-I ====== ===== Gouvernance ===== ---- ====== Étape 26 — Permissions ====== ===== Ajouter ===== legal.read legal.manage legal.contracts legal.compliance legal.gdpr legal.signatures ---- ====== Étape 27 — Audit ====== ===== Journaliser ===== LEGAL_DOCUMENT_CREATED CONTRACT_GENERATED CONTRACT_SIGNED GDPR_EXPORT_REQUESTED GDPR_DELETE_REQUESTED COMPLIANCE_VALIDATED POLICY_EXCEPTION_CREATED ---- ====== Étape 28 — Reporting ====== ===== Générer ===== Compliance Score GDPR Status Pending Signatures Legal Risks ---- ====== Sprint 4-G.2-J ====== ===== Préparation Future ===== ---- ====== Étape 29 — Compatible Sprint 5 ====== Préparer : Reservation Contract Guest Agreements Refund Workflow ---- ====== Étape 30 — Compatible Sprint 19 ====== Préparer : Governance Risk Management Audit Framework Compliance Dashboard ---- ====== Étape 31 — Compatible Sprint 20 ====== Préparer : Enterprise Compliance Legal Automation Contract Intelligence Global Regulations ---- ====== Définition de terminé ====== Le Sprint 4-G.2 est terminé lorsque : ✓ Contrats gérés ✓ Dépôts de garantie gérés ✓ Conformité locale gérée ✓ RGPD géré ✓ Documents légaux gérés ✓ Signature électronique gérée ✓ Exceptions gérées ✓ Audit intégré ---- ====== Livrables ====== PropertyLegalPolicy SecurityDepositPolicy LegalDocument ElectronicSignature GDPRConsent PolicyException ComplianceService GDPRService SignatureService Enterprise Legal Engine ---- ====== Sprint 4-H.1 — Gestion des Avis Clients ====== ===== Objectif ===== Implémenter le système d'avis clients des propriétés. Cette couche constitue la fondation de la réputation, de la confiance et du classement des biens. À l'issue de cette étape : ✓ PropertyReview ✓ PropertyReviewModule ✓ PropertyReviewController ✓ PropertyReviewService ✓ Avis ✓ Notes ✓ Commentaires ✓ Réponses propriétaires ✓ Reputation Ready ---- ====== Architecture cible ====== Reservation ↓ Review Eligibility ↓ PropertyReview ├── Rating ├── Comment ├── Owner Response ├── Moderation └── Analytics ↓ Property Score ↓ Search Ranking ---- ====== Sprint 4-H.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — Création PropertyReview ====== ===== Ajouter dans schema.prisma ===== model PropertyReview { id String @id @default(uuid()) tenantId String propertyId String customerId String reservationId String? overallRating Int cleanlinessRating Int? communicationRating Int? locationRating Int? valueRating Int? checkInRating Int? title String? comment String? verifiedStay Boolean @default(false) published Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? tenant Tenant @relation( fields:[tenantId], references:[id] ) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) customer Customer @relation( fields:[customerId], references:[id] ) responses PropertyReviewResponse[] @@index([tenantId]) @@index([propertyId]) @@index([customerId]) @@index([overallRating]) @@index([published]) } ---- ====== Étape 2 — Réponse propriétaire ====== ===== Ajouter ===== model PropertyReviewResponse { id String @id @default(uuid()) reviewId String userId String response String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt review PropertyReview @relation( fields:[reviewId], references:[id], onDelete:Cascade ) @@index([reviewId]) } ---- ====== Étape 3 — Relation Property ====== ===== Ajouter dans Property ===== reviews PropertyReview[] ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_reviews ---- ===== Générer ===== npx prisma generate ---- ====== Sprint 4-H.1-B ====== ===== Module ===== ---- ====== Étape 5 — Création ====== src/modules/property-reviews ├── application │ │ └── dto │ │ ├── create-review.dto.ts │ │ ├── update-review.dto.ts │ │ ├── review-response.dto.ts │ │ └── review-query.dto.ts │ ├── domain │ │ └── services │ │ └── property-review.service.ts │ ├── presentation │ │ └── controllers │ │ └── property-review.controller.ts │ └── property-review.module.ts ---- ====== Étape 6 — Module ====== ===== Créer ===== @Module({ imports: [ PrismaModule, AuthModule, AuditModule ], controllers: [ PropertyReviewController ], providers: [ PropertyReviewService ], exports: [ PropertyReviewService ] }) export class PropertyReviewModule {} ---- ====== Sprint 4-H.1-C ====== ===== DTOs ===== ---- ====== Étape 7 — CreateReviewDto ====== ===== Créer ===== export class CreateReviewDto { reservationId?: string; overallRating: number; cleanlinessRating?: number; communicationRating?: number; locationRating?: number; valueRating?: number; checkInRating?: number; title?: string; comment?: string; } ---- ====== Étape 8 — Validation ====== ===== Contraindre ===== 1 <= Rating <= 5 sur toutes les notes. ---- ====== Étape 9 — ReviewResponseDto ====== ===== Créer ===== export class ReviewResponseDto { response: string; } ---- ====== Sprint 4-H.1-D ====== ===== PropertyReviewService ===== ---- ====== Étape 10 — Création ====== ===== Créer ===== property-review.service.ts ---- ===== Méthodes ===== findAll() findById() create() update() remove() respond() calculatePropertyRating() ---- ====== Étape 11 — Vérification séjour ====== ===== Contrôler ===== Le client doit : Posséder réservation ET Réservation terminée pour déposer un avis. ---- ====== Étape 12 — Verified Stay ====== ===== Activer ===== verifiedStay = true si réservation validée. ---- ====== Étape 13 — Un avis par réservation ====== ===== Refuser ===== plusieurs avis : reservationId identique. ---- ====== Sprint 4-H.1-E ====== ===== Notes & Commentaires ===== ---- ====== Étape 14 — Notes supportées ====== Global Propreté Communication Emplacement Rapport qualité/prix Check-in ---- ====== Étape 15 — Calcul ====== ===== Note moyenne ===== AVG(overallRating) par propriété. ---- ====== Étape 16 — Mise à jour ====== ===== Alimenter ===== PropertyScore.reviewScore automatiquement. ---- ====== Sprint 4-H.1-F ====== ===== Réponses Propriétaires ===== ---- ====== Étape 17 — Endpoint ====== ===== Ajouter ===== POST /reviews/{id}/response ---- ====== Étape 18 — Autoriser ====== Property Manager Tenant Admin Owner uniquement. ---- ====== Étape 19 — Exemple ====== { "response":"Merci pour votre séjour." } ---- ====== Sprint 4-H.1-G ====== ===== Contrôleur ===== ---- ====== Étape 20 — Création ====== ===== Créer ===== property-review.controller.ts ---- ===== Déclaration ===== @ApiTags( 'Property Reviews' ) @ApiBearerAuth() ---- ====== Étape 21 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/reviews POST /properties/{id}/reviews PUT /reviews/{id} DELETE /reviews/{id} POST /reviews/{id}/response ---- ====== Étape 22 — Recherche ====== ===== Supporter ===== Rating Verified Date Published ---- ====== Sprint 4-H.1-H ====== ===== Modération ===== ---- ====== Étape 23 — ReviewModeration ====== ===== Ajouter ===== model ReviewModeration { id String @id @default(uuid()) reviewId String @unique flagged Boolean @default(false) reason String? reviewedBy String? reviewedAt DateTime? createdAt DateTime @default(now()) } ---- ====== Étape 24 — Contrôles ====== ===== Détecter ===== Spam Abus Langage interdit Fraude ---- ====== Étape 25 — Actions ====== Publish Hide Delete Escalate ---- ====== Sprint 4-H.1-I ====== ===== Sécurité ===== ---- ====== Étape 26 — Multi-Tenant ====== ===== Vérifier ===== tenantId propertyId sur toutes les opérations. ---- ====== Étape 27 — Permissions ====== ===== Ajouter ===== property.review.read property.review.create property.review.update property.review.delete property.review.respond property.review.moderate ---- ====== Étape 28 — Audit ====== ===== Journaliser ===== PROPERTY_REVIEW_CREATED PROPERTY_REVIEW_UPDATED PROPERTY_REVIEW_DELETED PROPERTY_REVIEW_RESPONDED PROPERTY_REVIEW_MODERATED ---- ====== Sprint 4-H.1-J ====== ===== Préparation Sprint 4-H.2 ===== ---- ====== Étape 29 — Compatible ===== Préparer : Review Images Review Sentiment AI Moderation Review Analytics ---- ====== Étape 30 — Compatible ===== Préparer : Search Ranking Property Score Recommendation Engine Trust Score ---- ====== Définition de terminé ====== Le Sprint 4-H.1 est terminé lorsque : ✓ PropertyReview créé ✓ PropertyReviewModule créé ✓ PropertyReviewController créé ✓ PropertyReviewService créé ✓ Avis opérationnels ✓ Notes opérationnelles ✓ Commentaires opérationnels ✓ Réponses propriétaires opérationnelles ✓ Modération intégrée ---- ====== Livrables ====== PropertyReview PropertyReviewResponse ReviewModeration PropertyReviewModule PropertyReviewController PropertyReviewService Property Reviews API ---- ====== Sprint 4-H.2 — Review Intelligence & Réputation Enterprise ====== ===== Objectif ===== Transformer le système d'avis en plateforme de réputation intelligente Enterprise. À l'issue de cette étape : ✓ Analyse de sentiment ✓ IA de modération ✓ Review Images ✓ Détection fraude ✓ Trust Score ✓ Réputation globale ✓ Insights clients ✓ Reputation Intelligence Platform ---- ====== Architecture cible ====== Property Reviews ↓ Review Intelligence Engine ├── Sentiment Analysis ├── AI Moderation ├── Review Images ├── Fraud Detection ├── Trust Scoring ├── Reputation Analytics └── Customer Insights ↓ Property Score ↓ Search Ranking ↓ Recommendation Engine ---- ====== Sprint 4-H.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — ReviewSentiment ====== ===== Ajouter dans schema.prisma ===== model ReviewSentiment { id String @id @default(uuid()) reviewId String @unique sentiment SentimentType score Float positiveKeywords Json? negativeKeywords Json? emotions Json? analyzedAt DateTime @default(now()) review PropertyReview @relation( fields:[reviewId], references:[id], onDelete:Cascade ) } ---- ====== Étape 2 — ReviewTrustScore ====== ===== Ajouter ===== model ReviewTrustScore { id String @id @default(uuid()) reviewId String @unique trustScore Float fraudRisk Float authenticityScore Float behaviorScore Float calculatedAt DateTime @default(now()) review PropertyReview @relation( fields:[reviewId], references:[id], onDelete:Cascade ) } ---- ====== Étape 3 — ReviewImage ====== ===== Ajouter ===== model ReviewImage { id String @id @default(uuid()) reviewId String imageUrl String thumbnailUrl String? moderationStatus ModerationStatus @default(PENDING) uploadedAt DateTime @default(now()) review PropertyReview @relation( fields:[reviewId], references:[id], onDelete:Cascade ) @@index([reviewId]) } ---- ====== Étape 4 — Enums ====== ===== Ajouter ===== enum SentimentType { VERY_POSITIVE POSITIVE NEUTRAL NEGATIVE VERY_NEGATIVE } enum ModerationStatus { PENDING APPROVED REJECTED FLAGGED } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name review_intelligence ---- ====== Sprint 4-H.2-B ====== ===== Analyse de Sentiment ===== ---- ====== Étape 6 — ReviewSentimentService ====== ===== Créer ===== review-sentiment.service.ts ---- ===== Méthodes ===== analyzeSentiment() extractKeywords() detectEmotions() generateSummary() ---- ====== Étape 7 — Classification ====== Très positif Positif Neutre Négatif Très négatif ---- ====== Étape 8 — Exemple ====== ===== Avis ===== Appartement magnifique, très propre, hôte exceptionnel ---- ===== Résultat ===== Sentiment: VERY_POSITIVE Score: 94 ---- ====== Sprint 4-H.2-C ====== ===== IA de Modération ===== ---- ====== Étape 9 — ReviewModerationAIService ====== ===== Créer ===== review-moderation-ai.service.ts ---- ===== Méthodes ===== detectSpam() detectAbuse() detectToxicity() detectFakeReview() ---- ====== Étape 10 — Contrôles ====== ===== Détecter ===== Spam Insultes Contenu haineux Fraude Bots ---- ====== Étape 11 — Actions ====== Approve Flag Reject Escalate ---- ====== Sprint 4-H.2-D ====== ===== Gestion des Images d'Avis ===== ---- ====== Étape 12 — Upload ====== ===== Ajouter ===== POST /reviews/{id}/images ---- ====== Étape 13 — Validation ====== ===== Vérifier ===== Format Poids Qualité Contenu interdit ---- ====== Étape 14 — Analyse IA ====== ===== Détecter ===== Chambre Salle de bain Piscine Cuisine Animaux Personnes ---- ====== Étape 15 — Auto-tagging ====== ===== Associer ===== aux équipements détectés. ---- ====== Sprint 4-H.2-E ====== ===== Détection de Fraude ===== ---- ====== Étape 16 — FraudDetectionService ====== ===== Créer ===== review-fraud-detection.service.ts ---- ===== Méthodes ===== detectFraud() calculateRisk() detectReviewFarm() detectDuplicatePatterns() ---- ====== Étape 17 — Signaux ====== ===== Analyser ===== IP Device Timing Texte Historique ---- ====== Étape 18 — Alertes ====== ===== Déclencher ===== Suspicious Review Fake Review Mass Review Activity ---- ====== Sprint 4-H.2-F ====== ===== Trust Score ===== ---- ====== Étape 19 — TrustScoreService ====== ===== Créer ===== review-trust-score.service.ts ---- ===== Calcul ===== Verified Stay Historique client Fraud Risk Sentiment Consistency Review Completeness ---- ====== Étape 20 — Classification ====== 90-100 Trusted 75-89 Reliable 50-74 Medium 0-49 Suspicious ---- ====== Étape 21 — Exemple ====== Trust Score 96 Trusted ---- ====== Sprint 4-H.2-G ====== ===== Réputation Globale ===== ---- ====== Étape 22 — ReputationService ====== ===== Créer ===== reputation.service.ts ---- ===== Méthodes ===== calculatePropertyReputation() calculateTenantReputation() calculateBrandReputation() ---- ====== Étape 23 — KPI ====== ===== Calculer ===== Average Rating Review Volume Trust Score Response Rate Response Time ---- ====== Étape 24 — Reputation Index ====== ===== Exemple ===== Property Reputation 92 Excellent ---- ====== Sprint 4-H.2-H ====== ===== Customer Insights ===== ---- ====== Étape 25 — ReviewInsight ====== ===== Ajouter ===== model ReviewInsight { id String @id @default(uuid()) propertyId String category String title String description String severity String? createdAt DateTime @default(now()) resolved Boolean @default(false) @@index([propertyId]) } ---- ====== Étape 26 — Génération ====== ===== Identifier ===== Forces Faiblesses Opportunités Problèmes récurrents ---- ====== Étape 27 — Exemple ====== 32% des avis mentionnent Wifi lent ---- ===== Action ===== Améliorer réseau ---- ====== Sprint 4-H.2-I ====== ===== Dashboard Réputation ===== ---- ====== Étape 28 — Endpoint ====== ===== Ajouter ===== GET /reviews/reputation/dashboard ---- ===== Retour ===== { "averageRating":4.7, "trustScore":91, "responseRate":96, "sentiment":"POSITIVE" } ---- ====== Étape 29 — Analytics ====== ===== Afficher ===== Sentiment Trends Review Trends Trust Trends Customer Insights ---- ====== Sprint 4-H.2-J ====== ===== Gouvernance & Sécurité ===== ---- ====== Étape 30 — Permissions ====== ===== Ajouter ===== property.review.analytics property.review.moderate property.review.trust property.review.reputation ---- ====== Étape 31 — Audit ====== ===== Journaliser ===== REVIEW_ANALYZED REVIEW_FLAGGED REVIEW_FRAUD_DETECTED REPUTATION_UPDATED TRUST_SCORE_UPDATED ---- ====== Étape 32 — Jobs ====== ===== Ajouter ===== Toutes les heures Sentiment Analysis Fraud Detection Toutes les nuits Reputation Calculation Insights Generation ---- ====== Préparation Sprint 4-I ====== Compatible avec : Search Ranking Property Score Recommendation Engine ---- ====== Préparation Sprint 13 ====== Compatible avec : LLM Analytics AI Insights Customer Intelligence Knowledge Graph ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Reputation Platform AI Moderation Fraud Prevention Brand Intelligence ---- ====== Définition de terminé ====== Le Sprint 4-H.2 est terminé lorsque : ✓ Analyse de sentiment ✓ IA de modération ✓ Review Images ✓ Détection fraude ✓ Trust Score ✓ Réputation globale ✓ Insights clients ✓ Dashboard réputation ✓ Audit intégré ---- ====== Livrables ====== ReviewSentiment ReviewTrustScore ReviewImage ReviewInsight ReviewSentimentService ReviewModerationAIService FraudDetectionService ReputationService Enterprise Reputation Platform ---- ====== Sprint 4-I.1 — Moteur de Recherche Immobilier ====== ===== Objectif ===== Construire le moteur de recherche central de la plateforme. Cette couche unifie : Property Amenities Availability Pricing Reviews Scores Analytics dans une expérience de recherche Enterprise unique. À l'issue de cette étape : ✓ PropertySearchEngine ✓ Faceted Search ✓ Geo Search ✓ Availability Search ✓ Ranking Engine ✓ Search Analytics ✓ Search API Enterprise ---- ====== Architecture cible ====== Property Search Engine ├── Catalog Search ├── Availability Search ├── Geo Search ├── Pricing Search ├── Review Search ├── Faceted Search ├── Ranking Engine └── Search Analytics ↓ Booking Engine ↓ Recommendation Engine ---- ====== Sprint 4-I.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — SearchQueryLog ====== ===== Ajouter dans schema.prisma ===== model SearchQueryLog { id String @id @default(uuid()) tenantId String? userId String? query String? filters Json? resultCount Int @default(0) executionTimeMs Int? createdAt DateTime @default(now()) @@index([tenantId]) @@index([userId]) @@index([createdAt]) } ---- ====== Étape 2 — PropertySearchIndex ====== ===== Ajouter ===== model PropertySearchIndex { propertyId String @id searchableText String amenities Json? city String? country String? averageRating Float? reviewCount Int? minPrice Decimal? @db.Decimal(12,2) maxGuests Int? searchScore Float? @default(0) updatedAt DateTime @updatedAt @@index([city]) @@index([country]) @@index([searchScore]) } ---- ====== Étape 3 — SavedSearch ====== ===== Ajouter ===== model SavedPropertySearch { id String @id @default(uuid()) userId String tenantId String name String filters Json createdAt DateTime @default(now()) @@index([userId]) @@index([tenantId]) } ---- ====== Étape 4 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_search_engine ---- ====== Sprint 4-I.1-B ====== ===== Search Engine Module ===== ---- ====== Étape 5 — Création ====== src/modules/property-search ├── search │ ├── ranking │ ├── analytics │ ├── facets │ ├── geo │ └── property-search.module.ts ---- ====== Étape 6 — Services ====== ===== Créer ===== PropertySearchEngineService FacetedSearchService GeoSearchService AvailabilitySearchService RankingEngineService SearchAnalyticsService ---- ====== Sprint 4-I.1-C ====== ===== Recherche Unifiée ===== ---- ====== Étape 7 — PropertySearchDto ====== ===== Créer ===== export class PropertySearchDto { query?: string; city?: string; country?: string; latitude?: number; longitude?: number; radiusKm?: number; checkIn?: Date; checkOut?: Date; guests?: number; minPrice?: number; maxPrice?: number; minRating?: number; amenities?: string[]; propertyTypeId?: string; page?: number = 1; limit?: number = 25; } ---- ====== Étape 8 — Search Engine ====== ===== Méthode ===== search() ---- ===== Agrège ===== Property Availability Pricing Reviews Amenities dans une requête unique. ---- ====== Étape 9 — Recherche texte ====== ===== Champs ===== Name Description Location Amenities Reviews ---- ====== Sprint 4-I.1-D ====== ===== Faceted Search ===== ---- ====== Étape 10 — FacetedSearchService ====== ===== Créer ===== faceted-search.service.ts ---- ===== Générer ===== Cities Countries Amenities Ratings Price Ranges Property Types ---- ====== Étape 11 — Endpoint ====== ===== Ajouter ===== GET /search/facets ---- ====== Étape 12 — Exemple ====== { "cities": { "Paris": 132 }, "amenities": { "Wifi": 218 } } ---- ====== Sprint 4-I.1-E ====== ===== Recherche Géographique ===== ---- ====== Étape 13 — GeoSearchService ====== ===== Créer ===== geo-search.service.ts ---- ===== Méthodes ===== searchByRadius() calculateDistance() sortByDistance() ---- ====== Étape 14 — Utiliser ===== Latitude Longitude Haversine ---- ====== Étape 15 — Exemple ====== Rayon 10 km autour de Paris ---- ====== Sprint 4-I.1-F ====== ===== Recherche de Disponibilités ===== ---- ====== Étape 16 — AvailabilitySearchService ====== ===== Créer ===== availability-search.service.ts ---- ===== Vérifier ===== Check-In Check-Out Inventory Blocks ---- ====== Étape 17 — Endpoint ====== ===== Ajouter ===== GET /search/availability ---- ====== Étape 18 — Retour ====== Uniquement les biens : Disponibles sur la période demandée. ---- ====== Sprint 4-I.1-G ====== ===== Ranking Engine ===== ---- ====== Étape 19 — RankingEngineService ====== ===== Créer ===== ranking-engine.service.ts ---- ===== Facteurs ===== Review Score Trust Score Price Score Availability Score Popularity Revenue Score ---- ====== Étape 20 — Pondération ====== Reviews 30% Popularity 20% Availability 20% Price 15% Revenue 15% ---- ====== Étape 21 — Search Score ====== ===== Alimenter ===== PropertySearchIndex.searchScore automatiquement. ---- ====== Sprint 4-I.1-H ====== ===== Search Analytics ===== ---- ====== Étape 22 — SearchAnalyticsService ====== ===== Créer ===== search-analytics.service.ts ---- ===== Méthodes ===== trackSearch() getPopularSearches() getZeroResultsQueries() getConversionRate() ---- ====== Étape 23 — KPI ====== ===== Mesurer ===== Search Volume CTR Bookings Search Conversion Top Filters ---- ====== Étape 24 — Endpoint ====== ===== Ajouter ===== GET /search/analytics ---- ====== Sprint 4-I.1-I ====== ===== API Enterprise ===== ---- ====== Étape 25 — Endpoints ====== ===== Ajouter ===== GET /search GET /search/facets GET /search/availability GET /search/analytics POST /search/saved GET /search/saved DELETE /search/saved/{id} ---- ====== Étape 26 — Exemple ====== ===== Requête ===== Paris 4 personnes Wifi Piscine 14-20 juillet ---- ===== Retour ===== { "items": [], "facets": {}, "meta": {} } ---- ====== Étape 27 — Pagination ====== ===== Supporter ===== Offset Cursor Infinite Scroll ---- ====== Sprint 4-I.1-J ====== ===== Gouvernance ===== ---- ====== Étape 28 — Permissions ====== ===== Ajouter ===== property.search property.search.saved property.search.analytics property.search.admin ---- ====== Étape 29 — Audit ====== ===== Journaliser ===== PROPERTY_SEARCH_EXECUTED PROPERTY_SEARCH_SAVED PROPERTY_SEARCH_ANALYTICS_VIEWED ---- ====== Étape 30 — Jobs ====== ===== Ajouter ===== Toutes les heures Search Index Refresh Toutes les nuits Ranking Rebuild Analytics Aggregation ---- ====== Préparation Sprint 4-I.2 ====== Compatible avec : Semantic Search AI Search Recommendations Personalization ---- ====== Préparation Sprint 13 ====== Compatible avec : Vector Search LLM Search Knowledge Graph RAG ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Search Platform Global Catalog AI Discovery Unified Search ---- ====== Définition de terminé ====== Le Sprint 4-I.1 est terminé lorsque : ✓ PropertySearchEngine ✓ Faceted Search ✓ Geo Search ✓ Availability Search ✓ Ranking Engine ✓ Search Analytics ✓ Search API Enterprise ✓ Audit intégré ---- ====== Livrables ====== PropertySearchEngineService FacetedSearchService GeoSearchService AvailabilitySearchService RankingEngineService SearchAnalyticsService PropertySearchIndex Enterprise Search Platform ---- ====== Sprint 4-I.2 — Recherche IA & Discovery Platform ====== ===== Objectif ===== Transformer le moteur de recherche immobilier en plateforme de découverte intelligente alimentée par l'IA. À l'issue de cette étape : ✓ Recherche sémantique ✓ Vector Search ✓ Recommandations ✓ Personnalisation ✓ Intent Detection ✓ AI Discovery ✓ Property Intelligence Graph ---- ====== Architecture cible ====== User Query ↓ AI Discovery Platform ├── Intent Detection ├── Semantic Search ├── Vector Search ├── Recommendation Engine ├── Personalization Engine ├── Property Intelligence Graph └── Ranking AI ↓ Search Engine ↓ Booking Engine ---- ====== Sprint 4-I.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — PropertyEmbedding ====== ===== Ajouter dans schema.prisma ===== model PropertyEmbedding { propertyId String @id embeddingModel String embeddingVersion String vectorId String generatedAt DateTime @default(now()) property Property @relation( fields:[propertyId], references:[id], onDelete:Cascade ) } ---- ====== Étape 2 — SearchIntent ====== ===== Ajouter ===== model SearchIntent { id String @id @default(uuid()) query String detectedIntent String confidence Float entities Json? createdAt DateTime @default(now()) @@index([detectedIntent]) } ---- ====== Étape 3 — RecommendationProfile ====== ===== Ajouter ===== model RecommendationProfile { id String @id @default(uuid()) userId String @unique preferences Json? interests Json? travelPatterns Json? preferredAmenities Json? preferredLocations Json? updatedAt DateTime @updatedAt @@index([userId]) } ---- ====== Étape 4 — PropertyRecommendation ====== ===== Ajouter ===== model PropertyRecommendation { id String @id @default(uuid()) userId String propertyId String recommendationScore Float reason String? generatedAt DateTime @default(now()) clicked Boolean @default(false) booked Boolean @default(false) @@index([userId]) @@index([propertyId]) } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name ai_discovery_platform ---- ====== Sprint 4-I.2-B ====== ===== AI Discovery Module ===== ---- ====== Étape 6 — Création ====== src/modules/ai-discovery ├── semantic-search │ ├── vector-search │ ├── recommendations │ ├── personalization │ ├── intent-detection │ ├── intelligence-graph │ └── ai-discovery.module.ts ---- ====== Étape 7 — Services ====== ===== Créer ===== SemanticSearchService VectorSearchService RecommendationEngineService PersonalizationService IntentDetectionService PropertyIntelligenceGraphService ---- ====== Sprint 4-I.2-C ====== ===== Recherche Sémantique ===== ---- ====== Étape 8 — SemanticSearchService ====== ===== Créer ===== semantic-search.service.ts ---- ===== Méthodes ===== semanticSearch() expandQuery() extractConcepts() rankSemanticResults() ---- ====== Étape 9 — Exemples ====== ===== Requête ===== Appartement calme pour télétravail près de la mer ---- ===== Compréhension ===== Remote Work Wifi Workspace Sea View Quiet Area ---- ====== Étape 10 — Sources ====== ===== Indexer ===== Property Amenities Reviews Descriptions Policies ---- ====== Sprint 4-I.2-D ====== ===== Vector Search ===== ---- ====== Étape 11 — VectorSearchService ====== ===== Créer ===== vector-search.service.ts ---- ===== Méthodes ===== generateEmbedding() searchSimilarProperties() findNearestNeighbors() ---- ====== Étape 12 — Infrastructure ====== ===== Préparer ===== pgvector Qdrant Weaviate Pinecone ---- ====== Étape 13 — Embeddings ====== ===== Générer pour ===== Properties Reviews Amenities Policies Locations ---- ====== Étape 14 — Similarité ====== ===== Exemple ===== Villa luxe avec piscine ↓ Biens similaires ---- ====== Sprint 4-I.2-E ====== ===== Recommandations ===== ---- ====== Étape 15 — RecommendationEngineService ====== ===== Créer ===== recommendation-engine.service.ts ---- ===== Méthodes ===== recommendForUser() recommendSimilarProperties() recommendTrending() ---- ====== Étape 16 — Facteurs ====== Historique recherches Réservations Favoris Reviews Préférences ---- ====== Étape 17 — Types ====== ===== Supporter ===== Similar Trending Recently Viewed Personalized Popular ---- ====== Sprint 4-I.2-F ====== ===== Personnalisation ===== ---- ====== Étape 18 — PersonalizationService ====== ===== Créer ===== personalization.service.ts ---- ===== Méthodes ===== buildUserProfile() updatePreferences() personalizeRanking() ---- ====== Étape 19 — Profil ====== ===== Utiliser ===== Search History Bookings Preferences Behavior ---- ====== Étape 20 — Exemple ====== Utilisateur Voyage famille ↓ Prioriser Family Friendly ---- ====== Sprint 4-I.2-G ====== ===== Intent Detection ===== ---- ====== Étape 21 — IntentDetectionService ====== ===== Créer ===== intent-detection.service.ts ---- ===== Détecter ===== Business Travel Family Vacation Luxury Stay Remote Work Romantic Getaway ---- ====== Étape 22 — Extraction ====== ===== Identifier ===== Budget Guests Location Amenities Dates ---- ====== Étape 23 — Exemple ====== ===== Requête ===== Je cherche un logement calme pour travailler à distance ---- ===== Résultat ===== Intent: REMOTE_WORK Confidence: 94% ---- ====== Sprint 4-I.2-H ====== ===== Property Intelligence Graph ===== ---- ====== Étape 24 — PropertyIntelligenceGraphService ====== ===== Créer ===== property-intelligence-graph.service.ts ---- ===== Connecter ===== Properties Amenities Reviews Locations Customers ---- ====== Étape 25 — Relations ====== ===== Exemple ===== Property ↓ Wifi ↓ Remote Work ↓ Business Traveler ---- ====== Étape 26 — Utilisation ====== ===== Alimenter ===== Recommendations Semantic Search Discovery ---- ====== Sprint 4-I.2-I ====== ===== API Discovery ===== ---- ====== Étape 27 — Endpoints ====== ===== Ajouter ===== POST /discovery/search GET /discovery/recommendations GET /discovery/trending GET /discovery/similar/{propertyId} POST /discovery/intent ---- ====== Étape 28 — Exemple ====== ===== Requête ===== { "query":"Villa avec piscine pour famille" } ---- ===== Réponse ===== { "intent":"FAMILY_VACATION", "results":[], "recommendations":[] } ---- ====== Étape 29 — Analytics IA ====== ===== Mesurer ===== Recommendation CTR Search Satisfaction Discovery Conversion Intent Accuracy ---- ====== Sprint 4-I.2-J ====== ===== Gouvernance ===== ---- ====== Étape 30 — Permissions ====== ===== Ajouter ===== discovery.search discovery.recommend discovery.personalization discovery.analytics discovery.admin ---- ====== Étape 31 — Audit ====== ===== Journaliser ===== SEMANTIC_SEARCH_EXECUTED VECTOR_SEARCH_EXECUTED RECOMMENDATION_GENERATED INTENT_DETECTED DISCOVERY_RESULT_CLICKED ---- ====== Étape 32 — Jobs ====== ===== Ajouter ===== Toutes les heures Recommendation Refresh Toutes les nuits Embedding Generation Intent Training Ranking Rebuild ---- ====== Préparation Sprint 5 ====== Compatible avec : Reservation Suggestions Upsell Engine Cross Sell Engine ---- ====== Préparation Sprint 13 ====== Compatible avec : LLM Assistant RAG Knowledge Graph Agentic Search ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise AI Discovery Predictive Booking Hyper Personalization Property Intelligence Platform ---- ====== Définition de terminé ====== Le Sprint 4-I.2 est terminé lorsque : ✓ Recherche sémantique ✓ Vector Search ✓ Recommandations ✓ Personnalisation ✓ Intent Detection ✓ AI Discovery ✓ Analytics IA ✓ Audit intégré ---- ====== Livrables ====== PropertyEmbedding SearchIntent RecommendationProfile PropertyRecommendation SemanticSearchService VectorSearchService RecommendationEngineService PersonalizationService IntentDetectionService PropertyIntelligenceGraphService AI Discovery Platform ---- ====== Sprint 4-J.1 — Property Analytics & Dashboard ====== ===== Objectif ===== Construire le cockpit opérationnel central des propriétés. Cette couche fournit une vision temps réel de : Occupation Revenus Avis Disponibilités Performance Réservations afin de permettre le pilotage métier des propriétés. À l'issue de cette étape : ✓ Property Dashboard ✓ Occupancy Analytics ✓ Revenue Analytics ✓ Review Analytics ✓ Availability Analytics ✓ Performance KPIs ✓ Executive Dashboard ---- ====== Architecture cible ====== Property Analytics Platform ├── Occupancy Analytics ├── Revenue Analytics ├── Review Analytics ├── Availability Analytics ├── Search Analytics ├── Booking Analytics └── KPI Dashboard ↓ Property Intelligence ↓ Revenue Management ---- ====== Sprint 4-J.1-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — PropertyAnalyticsSnapshot ====== ===== Ajouter dans schema.prisma ===== model PropertyAnalyticsSnapshot { id String @id @default(uuid()) tenantId String propertyId String snapshotDate DateTime occupancyRate Float? averageDailyRate Decimal? @db.Decimal(12,2) revenue Decimal? @db.Decimal(14,2) reviewScore Float? reviewCount Int? availabilityRate Float? searchViews Int? @default(0) bookings Int? @default(0) createdAt DateTime @default(now()) @@unique([ propertyId, snapshotDate ]) @@index([tenantId]) @@index([propertyId]) @@index([snapshotDate]) } ---- ====== Étape 2 — PropertyKPI ====== ===== Ajouter ===== model PropertyKPI { propertyId String @id occupancyRate Float? averageDailyRate Float? revPar Float? revenue Float? reviewScore Float? conversionRate Float? searchRanking Float? reputationScore Float? updatedAt DateTime @updatedAt } ---- ====== Étape 3 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_analytics ---- ====== Sprint 4-J.1-B ====== ===== Analytics Module ===== ---- ====== Étape 4 — Création ====== src/modules/property-analytics ├── dashboard │ ├── occupancy │ ├── revenue │ ├── reviews │ ├── availability │ ├── kpi │ └── property-analytics.module.ts ---- ====== Étape 5 — Services ====== ===== Créer ===== PropertyDashboardService OccupancyAnalyticsService RevenueAnalyticsService ReviewAnalyticsService AvailabilityAnalyticsService PropertyKPIService ---- ====== Sprint 4-J.1-C ====== ===== Occupancy Analytics ===== ---- ====== Étape 6 — OccupancyAnalyticsService ====== ===== Créer ===== occupancy-analytics.service.ts ---- ===== Méthodes ===== calculateOccupancyRate() calculateOccupancyTrend() forecastOccupancy() ---- ====== Étape 7 — KPI ====== ===== Calculer ===== Occupied Nights Available Nights Occupancy % Average Stay ---- ====== Étape 8 — Exemple ====== Occupancy 82% ↑ +6% ---- ====== Sprint 4-J.1-D ====== ===== Revenue Analytics ===== ---- ====== Étape 9 — RevenueAnalyticsService ====== ===== Créer ===== revenue-analytics.service.ts ---- ===== Méthodes ===== calculateRevenue() calculateADR() calculateRevPAR() calculateRevenueTrend() ---- ====== Étape 10 — KPI ====== ===== Mesurer ===== Revenue ADR RevPAR Revenue Growth ---- ====== Étape 11 — Exemple ====== Revenue 45 000 € ↑ 12% ---- ====== Sprint 4-J.1-E ====== ===== Review Analytics ===== ---- ====== Étape 12 — ReviewAnalyticsService ====== ===== Créer ===== review-analytics.service.ts ---- ===== Méthodes ===== calculateAverageRating() analyzeSentimentTrend() calculateResponseRate() ---- ====== Étape 13 — KPI ====== ===== Mesurer ===== Average Rating Review Count Trust Score Sentiment Trend ---- ====== Étape 14 — Exemple ====== Rating 4.8 / 5 ↑ 0.2 ---- ====== Sprint 4-J.1-F ====== ===== Availability Analytics ===== ---- ====== Étape 15 — AvailabilityAnalyticsService ====== ===== Créer ===== availability-analytics.service.ts ---- ===== Méthodes ===== calculateAvailabilityRate() detectAvailabilityGaps() analyzeBlockedDates() ---- ====== Étape 16 — KPI ====== ===== Mesurer ===== Available Days Blocked Days Maintenance Days Availability % ---- ====== Étape 17 — Exemple ====== Availability 74% Blocked 12 jours ---- ====== Sprint 4-J.1-G ====== ===== Dashboard Principal ===== ---- ====== Étape 18 — PropertyDashboardService ====== ===== Créer ===== property-dashboard.service.ts ---- ===== Agréger ===== Occupancy Revenue Reviews Availability Search Bookings ---- ====== Étape 19 — Endpoint ====== ===== Ajouter ===== GET /properties/{id}/dashboard ---- ====== Étape 20 — Exemple ====== ===== Retour ===== { "occupancy":82, "revenue":45000, "rating":4.8, "availability":74, "bookings":34 } ---- ====== Sprint 4-J.1-H ====== ===== KPI Engine ===== ---- ====== Étape 21 — PropertyKPIService ====== ===== Créer ===== property-kpi.service.ts ---- ===== Calculer ===== Occupancy Score Revenue Score Review Score Availability Score Search Score Global Score ---- ====== Étape 22 — Global Score ====== ===== Pondération ===== Revenue 30% Occupancy 25% Reviews 20% Availability 15% Search 10% ---- ====== Étape 23 — Classement ====== ===== Supporter ===== Top Properties Most Profitable Best Rated Highest Occupancy ---- ====== Sprint 4-J.1-I ====== ===== API Analytics ===== ---- ====== Étape 24 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/dashboard GET /properties/{id}/analytics/occupancy GET /properties/{id}/analytics/revenue GET /properties/{id}/analytics/reviews GET /properties/{id}/analytics/availability GET /properties/{id}/analytics/kpis ---- ====== Étape 25 — Périodes ====== ===== Supporter ===== Today 7 Days 30 Days 90 Days 12 Months Custom Range ---- ====== Étape 26 — Export ====== ===== Ajouter ===== GET /properties/{id}/analytics/export Formats : CSV Excel PDF ---- ====== Sprint 4-J.1-J ====== ===== Gouvernance ===== ---- ====== Étape 27 — Permissions ====== ===== Ajouter ===== property.analytics.read property.analytics.export property.analytics.kpi property.analytics.admin ---- ====== Étape 28 — Audit ====== ===== Journaliser ===== PROPERTY_DASHBOARD_VIEWED PROPERTY_ANALYTICS_VIEWED PROPERTY_KPI_CALCULATED PROPERTY_ANALYTICS_EXPORTED ---- ====== Étape 29 — Jobs ====== ===== Ajouter ===== Toutes les heures KPI Refresh Toutes les nuits Analytics Snapshot Score Rebuild ---- ====== Étape 30 — Compatibilité ====== Préparer : Revenue Management Booking Engine Business Intelligence Executive Reporting ---- ====== Définition de terminé ====== Le Sprint 4-J.1 est terminé lorsque : ✓ Dashboard propriété ✓ Occupancy Analytics ✓ Revenue Analytics ✓ Review Analytics ✓ Availability Analytics ✓ KPI Engine ✓ Export Analytics ✓ Audit intégré ---- ====== Livrables ====== PropertyAnalyticsSnapshot PropertyKPI PropertyDashboardService OccupancyAnalyticsService RevenueAnalyticsService ReviewAnalyticsService AvailabilityAnalyticsService PropertyKPIService Property Analytics Dashboard ---- ====== Sprint 4-J.2 — Property Intelligence & Analytics Prédictifs ====== ===== Objectif ===== Transformer le cockpit analytique en plateforme Property Intelligence Enterprise. À l'issue de cette étape : ✓ Prévision occupation ✓ Prévision revenus ✓ Prévision demande ✓ Détection anomalies ✓ Insights IA ✓ Property Health Score ✓ Property Intelligence Platform ---- ====== Architecture cible ====== Property Analytics ↓ Property Intelligence Engine ├── Occupancy Forecast ├── Revenue Forecast ├── Demand Forecast ├── Anomaly Detection ├── AI Insights ├── Health Scoring └── Optimization Recommendations ↓ Revenue Management ↓ Executive Intelligence ---- ====== Sprint 4-J.2-A ====== ===== Extension Prisma ===== ---- ====== Étape 1 — PropertyForecast ====== ===== Ajouter dans schema.prisma ===== model PropertyForecast { id String @id @default(uuid()) propertyId String forecastType ForecastType forecastDate DateTime predictedValue Float confidenceScore Float? generatedAt DateTime @default(now()) @@index([propertyId]) @@index([forecastType]) @@index([forecastDate]) } ---- ====== Étape 2 — PropertyInsight ====== ===== Ajouter ===== model PropertyInsight { id String @id @default(uuid()) propertyId String severity InsightSeverity category InsightCategory title String description String recommendation String? impactScore Float? resolved Boolean @default(false) createdAt DateTime @default(now()) @@index([propertyId]) @@index([resolved]) @@index([category]) } ---- ====== Étape 3 — PropertyHealthScore ====== ===== Ajouter ===== model PropertyHealthScore { propertyId String @id overallScore Float occupancyScore Float revenueScore Float reviewScore Float availabilityScore Float complianceScore Float reputationScore Float calculatedAt DateTime @updatedAt } ---- ====== Étape 4 — Enums ====== ===== Ajouter ===== enum ForecastType { OCCUPANCY REVENUE DEMAND BOOKINGS } enum InsightSeverity { LOW MEDIUM HIGH CRITICAL } enum InsightCategory { OCCUPANCY REVENUE REVIEWS DEMAND AVAILABILITY COMPLIANCE } ---- ====== Étape 5 — Migration ====== ===== Générer ===== npx prisma migrate dev \ --name property_intelligence ---- ====== Sprint 4-J.2-B ====== ===== Intelligence Module ===== ---- ====== Étape 6 — Création ====== src/modules/property-intelligence ├── forecasts │ ├── anomalies │ ├── insights │ ├── health-score │ ├── optimization │ └── property-intelligence.module.ts ---- ====== Étape 7 — Services ====== ===== Créer ===== OccupancyForecastService RevenueForecastService DemandForecastService AnomalyDetectionService PropertyInsightService PropertyHealthScoreService ---- ====== Sprint 4-J.2-C ====== ===== Prévision d'Occupation ===== ---- ====== Étape 8 — OccupancyForecastService ====== ===== Créer ===== occupancy-forecast.service.ts ---- ===== Méthodes ===== forecastOccupancy() forecastSeasonality() forecastBookingWindow() ---- ====== Étape 9 — Sources ====== ===== Utiliser ===== Availability Reservations Seasonality Events Historical Occupancy ---- ====== Étape 10 — Exemple ====== Août Occupation prévue 91% Confiance 88% ---- ====== Sprint 4-J.2-D ====== ===== Prévision de Revenus ===== ---- ====== Étape 11 — RevenueForecastService ====== ===== Créer ===== revenue-forecast.service.ts ---- ===== Méthodes ===== forecastRevenue() forecastADR() forecastRevPAR() ---- ====== Étape 12 — Sources ====== Revenue History Pricing Occupancy Forecast Demand Forecast ---- ====== Étape 13 — Exemple ====== Revenu prévisionnel 52 000 € +14% ---- ====== Sprint 4-J.2-E ====== ===== Prévision de Demande ===== ---- ====== Étape 14 — DemandForecastService ====== ===== Créer ===== demand-forecast.service.ts ---- ===== Détecter ===== Haute saison Vacances Événements Tendances marché ---- ====== Étape 15 — Méthodes ====== forecastDemand() detectDemandPeaks() recommendPricingActions() ---- ====== Étape 16 — Exemple ====== Demande +27% ↓ Augmentation tarifaire recommandée ---- ====== Sprint 4-J.2-F ====== ===== Détection d'Anomalies ===== ---- ====== Étape 17 — AnomalyDetectionService ====== ===== Créer ===== anomaly-detection.service.ts ---- ===== Méthodes ===== detectOccupancyAnomalies() detectRevenueAnomalies() detectReviewAnomalies() detectAvailabilityAnomalies() ---- ====== Étape 18 — Détecter ====== Baisse brutale occupation Chute revenus Explosion annulations Avis négatifs anormaux Blocages excessifs ---- ====== Étape 19 — Exemple ====== Occupation -32% ↓ Alerte HIGH ---- ====== Sprint 4-J.2-G ====== ===== Insights IA ===== ---- ====== Étape 20 — PropertyInsightService ====== ===== Créer ===== property-insight.service.ts ---- ===== Générer ===== Opportunités Risques Optimisations Recommandations ---- ====== Étape 21 — Exemple ====== Les week-ends sont réservés à 96% ↓ Augmenter tarifs de 10% ---- ====== Étape 22 — Exemple ====== Faible taux de réservation en novembre ↓ Lancer campagne promotionnelle ---- ====== Sprint 4-J.2-H ====== ===== Property Health Score ===== ---- ====== Étape 23 — PropertyHealthScoreService ====== ===== Créer ===== property-health-score.service.ts ---- ===== Calcul ===== Occupation 25% Revenus 25% Avis 20% Réputation 10% Disponibilité 10% Conformité 10% ---- ====== Étape 24 — Classification ====== 90-100 Excellent 75-89 Healthy 50-74 At Risk 0-49 Critical ---- ====== Étape 25 — Exemple ====== Property Health 93 Excellent ---- ====== Sprint 4-J.2-I ====== ===== Dashboard Intelligence ===== ---- ====== Étape 26 — Endpoint ====== ===== Ajouter ===== GET /properties/{id}/intelligence ---- ===== Retour ===== { "healthScore":93, "occupancyForecast":91, "revenueForecast":52000, "insights":[] } ---- ====== Étape 27 — Endpoints ====== ===== Ajouter ===== GET /properties/{id}/forecasts GET /properties/{id}/insights GET /properties/{id}/health-score GET /properties/{id}/anomalies ---- ====== Étape 28 — Analytics IA ====== ===== Mesurer ===== Forecast Accuracy Insight Adoption Health Score Trends Anomaly Resolution Rate ---- ====== Sprint 4-J.2-J ====== ===== Gouvernance ===== ---- ====== Étape 29 — Permissions ====== ===== Ajouter ===== property.intelligence.read property.intelligence.forecast property.intelligence.insights property.intelligence.health property.intelligence.admin ---- ====== Étape 30 — Audit ====== ===== Journaliser ===== FORECAST_GENERATED ANOMALY_DETECTED PROPERTY_INSIGHT_CREATED HEALTH_SCORE_UPDATED INTELLIGENCE_DASHBOARD_VIEWED ---- ====== Étape 31 — Jobs ====== ===== Ajouter ===== Toutes les heures Anomaly Detection Toutes les nuits Forecast Generation Health Score Refresh Insight Generation ---- ====== Clôture Sprint 4 ====== À la fin du Sprint 4, la plateforme dispose désormais de : ✓ Catalogue Propriétés ✓ Amenities ✓ Images Enterprise ✓ Disponibilités ✓ Channel Manager ✓ Tarification ✓ Revenue Management ✓ Policies ✓ Legal Compliance ✓ Reviews ✓ Reputation Intelligence ✓ Search Engine ✓ AI Discovery ✓ Analytics ✓ Property Intelligence ---- ====== Préparation Sprint 5 ====== Compatible avec : Reservations Booking Workflow Payments Check-In Guest Journey ---- ====== Préparation Sprint 13 ====== Compatible avec : AI Platform Knowledge Graph LLM Agents Predictive Intelligence ---- ====== Préparation Sprint 20 ====== Compatible avec : Enterprise Property Platform AI Revenue Management Predictive Operations Global Hospitality OS ---- ====== Définition de terminé ====== Le Sprint 4-J.2 est terminé lorsque : ✓ Prévision occupation ✓ Prévision revenus ✓ Prévision demande ✓ Détection anomalies ✓ Insights IA ✓ Property Health Score ✓ Dashboard Intelligence ✓ Audit intégré ---- ====== Livrables ====== PropertyForecast PropertyInsight PropertyHealthScore OccupancyForecastService RevenueForecastService DemandForecastService AnomalyDetectionService PropertyInsightService PropertyHealthScoreService Property Intelligence Platform