====== 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