Table des matières
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