Ceci est une ancienne révision du document !
Table des matières
Sprint 3 — Gestion des Clients
Objectif
Implémenter le premier domaine métier CRM complet de la plateforme.
Le domaine :
Customer
deviendra le pivot central de :
Réservations Facturation CRM Marketing Communication Programme de fidélité Revenue Management
Périmètre du Sprint 3
Entités
Customer CustomerAddress CustomerDocument CustomerTag CustomerNote CustomerCommunication CustomerPreference
Fonctionnalités
CRUD Clients Profil Client Adresses Documents Tags CRM Notes internes Historique communications Préférences client Segmentation Fidélisation
Architecture cible
Customer ├── Addresses ├── Documents ├── Tags ├── Notes ├── Communications ├── Preferences ├── Reservations ├── Invoices └── CRM Activities
Découpage du Sprint
Sprint 3-A
Modèle CRM Prisma
Customer CustomerAddress CustomerPreference
Sprint 3-B
CRUD Clients
CustomerModule CustomerController CustomerService
Sprint 3-C
Adresses Client
CustomerAddressModule
Sprint 3-D
Documents Client
CustomerDocument Upload Stockage
Sprint 3-E
Tags CRM
CustomerTag Segmentation
Sprint 3-F
Notes CRM
CustomerNote
Sprint 3-G
Communications
CustomerCommunication
Sprint 3-H
Préférences Client
CustomerPreference
Sprint 3-I
Recherche CRM Avancée
Filtres Segmentation Recherche globale
Sprint 3-J
Vue CRM Enterprise
Dashboard Client Vue 360° Historique complet
Sprint 3-A.1 — Implémentation Prisma CRM Core
Objectif
Créer le socle CRM principal de la plateforme.
Ces modèles deviendront les fondations de :
Reservations CRM Marketing Facturation Communication Fidélisation Revenue Management
Architecture CRM
Customer ├── CustomerAddress ├── CustomerPreference ├── Reservations ├── Invoices ├── Notes ├── Tags ├── Documents └── Communications
Étape 1 — Création Customer
Ajouter dans schema.prisma
model Customer {
id String
@id
@default(uuid())
tenantId String
customerNumber String?
externalReference String?
type String
@default("INDIVIDUAL")
status String
@default("ACTIVE")
firstName String
lastName String
companyName String?
email String?
phone String?
mobilePhone String?
dateOfBirth DateTime?
nationality String?
language String?
source String?
acquisitionChannel String?
notes String?
vip Boolean
@default(false)
blacklisted Boolean
@default(false)
marketingConsent Boolean
@default(false)
emailVerified Boolean
@default(false)
phoneVerified Boolean
@default(false)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
deletedAt DateTime?
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
addresses CustomerAddress[]
preferences CustomerPreference?
@@index([tenantId])
@@index([status])
@@index([email])
@@index([phone])
@@index([vip])
@@index([createdAt])
@@unique([
tenantId,
customerNumber
])
}
Étape 2 — Création CustomerAddress
Ajouter
model CustomerAddress {
id String
@id
@default(uuid())
customerId String
label String
addressLine1 String
addressLine2 String?
postalCode String
city String
state String?
country String
latitude Decimal?
@db.Decimal(10,7)
longitude Decimal?
@db.Decimal(10,7)
formattedAddress String?
placeId String?
isDefault Boolean
@default(false)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
@@index([customerId])
@@index([country])
@@index([city])
@@index([isDefault])
}
Étape 3 — Création CustomerPreference
Ajouter
model CustomerPreference {
id String
@id
@default(uuid())
customerId String
@unique
preferredLanguage String?
preferredCurrency String?
preferredChannel String?
prefersEmail Boolean
@default(true)
prefersSms Boolean
@default(false)
prefersPhone Boolean
@default(false)
acceptsMarketing Boolean
@default(false)
acceptsNewsletter Boolean
@default(false)
acceptsPromotions Boolean
@default(false)
acceptsSurveys Boolean
@default(false)
loyaltyEligible Boolean
@default(true)
vipProgramEligible Boolean
@default(false)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
@@index([preferredLanguage])
@@index([preferredCurrency])
@@index([acceptsMarketing])
}
Étape 4 — Relation Tenant
Ajouter dans Tenant
customers Customer[]
Étape 5 — Préparation Reservations
Ajouter dans Customer
reservations Reservation[]
Ajouter dans Reservation
customerId String?
customer Customer?
@relation(
fields:[customerId],
references:[id]
)
Étape 6 — Préparation CRM
Ajouter dans Customer
Relations futures :
notes CustomerNote[] documents CustomerDocument[] communications CustomerCommunication[] tags CustomerTag[]
Ne pas créer encore
Ces modèles arriveront dans :
Sprint 3-D Sprint 3-E Sprint 3-F Sprint 3-G
Étape 7 — Préparation Marketing
Champs CRM
Déjà présents :
source acquisitionChannel marketingConsent
Exemples
Website Booking Airbnb Google Ads Facebook Referral Direct
Étape 8 — Préparation Fidélité
Champs
vip loyaltyEligible vipProgramEligible
Utilisation future
Loyalty Program Reward Engine Customer Segmentation
Étape 9 — Migration
Générer
npx prisma migrate dev \
--name crm_customer_core
Générer
npx prisma generate
Étape 10 — Validation
Exécuter
npx prisma validate
Résultat attendu
The schema at prisma/schema.prisma is valid
Étape 11 — Vérification SQL
PostgreSQL
\d "Customer" \d "CustomerAddress" \d "CustomerPreference"
Modèle CRM obtenu
Customer │ ├── Profil CRM │ ├── Préférences │ ├── Adresses │ ├── Réservations │ ├── Marketing │ └── Fidélité
Définition de terminé
Le Sprint 3-A.1 est terminé lorsque :
✓ Customer créé ✓ CustomerAddress créée ✓ CustomerPreference créée ✓ Tenant relation ajoutée ✓ Reservation relation préparée ✓ Migration exécutée ✓ Prisma Client généré ✓ Validation Prisma verte
Livrables
Customer CustomerAddress CustomerPreference Migration crm_customer_core Prisma Client mis à jour
Sprint 3-A.2 — Amélioration Enterprise du modèle Customer
Objectif
Faire évoluer le modèle CRM Core vers un modèle Enterprise capable de supporter :
CRM avancé Segmentation Marketing Automation Fidélisation Analyse comportementale Revenue Management RGPD Conformité
Architecture cible
Customer ├── Profile ├── Preferences ├── Addresses ├── Segmentation ├── Scoring ├── Risk ├── Lifetime Value ├── GDPR ├── Communications ├── Reservations └── CRM History
Sprint 3-A.2-A
CustomerStatus
Étape 1 — Création Enum
Ajouter
enum CustomerStatus {
LEAD
ACTIVE
VIP
INACTIVE
BLOCKED
BLACKLISTED
}
Étape 2 — Utilisation
Remplacer
Dans :
model Customer
Ancien
status String
Nouveau
status CustomerStatus
@default(ACTIVE)
Sprint 3-A.2-B
CustomerSource
Étape 3 — Enum Source
Ajouter
enum CustomerSource {
WEBSITE
DIRECT
AIRBNB
BOOKING
EXPEDIA
VRBO
GOOGLE
FACEBOOK
INSTAGRAM
REFERRAL
PARTNER
IMPORT
OTHER
}
Étape 4 — Utilisation
Remplacer
source String?
Par
source CustomerSource?
Sprint 3-A.2-C
Customer Score
Étape 5 — Ajouter
Dans :
model Customer
Champs
customerScore Int
@default(0)
engagementScore Int
@default(0)
satisfactionScore Int
@default(0)
loyaltyScore Int
@default(0)
Utilisation
Segmentation CRM Marketing Fidélisation
Sprint 3-A.2-D
Customer Lifetime Value
Étape 6 — Ajouter
lifetimeValue Decimal?
@db.Decimal(14,2)
totalReservations Int
@default(0)
totalRevenue Decimal?
@db.Decimal(14,2)
averageBasket Decimal?
@db.Decimal(14,2)
lastReservationAt DateTime?
Préparation
Pour :
Revenue Management Business Intelligence Customer Analytics
Sprint 3-A.2-E
Customer Risk
Étape 7 — Enum
enum CustomerRiskLevel {
LOW
MEDIUM
HIGH
CRITICAL
}
Étape 8 — Ajouter
Dans Customer :
riskLevel CustomerRiskLevel
@default(LOW)
riskScore Int
@default(0)
fraudFlag Boolean
@default(false)
Utilisation
Fraude Paiements Réservations Sécurité
Sprint 3-A.2-F
Segmentation
Étape 9 — Enum
enum CustomerSegment {
STANDARD
FREQUENT
VIP
CORPORATE
OWNER
PARTNER
BLACKLISTED
}
Étape 10 — Ajouter
segment CustomerSegment
@default(STANDARD)
Utilisation
Campagnes CRM Automatisation Fidélisation
Sprint 3-A.2-G
RGPD
Étape 11 — Ajouter
Dans Customer :
gdprConsentGiven Boolean
@default(false)
gdprConsentAt DateTime?
marketingConsentAt DateTime?
privacyPolicyAccepted Boolean
@default(false)
privacyPolicyAcceptedAt DateTime?
dataRetentionUntil DateTime?
Préparation
Pour :
Consent ComplianceAudit RetentionPolicy
Sprint 3-A.2-H
Historisation CRM
Étape 12 — Création CustomerHistory
Ajouter
model CustomerHistory {
id String
@id
@default(uuid())
customerId String
changedField String
oldValue String?
newValue String?
changedBy String?
changedAt DateTime
@default(now())
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
@@index([customerId])
@@index([changedAt])
}
Étape 13 — Relation
Ajouter
Dans :
model Customer
history CustomerHistory[]
Sprint 3-A.2-I
Scoring Automatique
Étape 14 — Préparer
Ajouter dans Customer :
firstReservationAt DateTime? lastCommunicationAt DateTime? lastActivityAt DateTime?
Calcul futur
Customer Score Engagement Score Loyalty Score Risk Score
seront alimentés par :
Reservations Invoices CRM Activities Communications
Sprint 3-A.2-J
Préparation Marketing
Étape 15 — Ajouter
preferredPropertyType String? preferredStayDuration Int? preferredDestination String? preferredTravelSeason String?
Utilisation
Marketing IA Recommandations Segmentation Campagnes
Étape 16 — Index CRM
Ajouter
Dans Customer :
@@index([segment]) @@index([customerScore]) @@index([riskLevel]) @@index([source]) @@index([lifetimeValue]) @@index([lastReservationAt]) @@index([gdprConsentGiven])
Étape 17 — Migration
Générer
npx prisma migrate dev \
--name customer_enterprise
Générer
npx prisma generate
Étape 18 — Validation
Exécuter
npx prisma validate
Résultat attendu
The schema at prisma/schema.prisma is valid
Modèle CRM Enterprise obtenu
Customer ├── Profil ├── Adresses ├── Préférences ├── Segmentation ├── Score ├── Lifetime Value ├── Risque ├── RGPD ├── Historique ├── Marketing └── Fidélisation
Définition de terminé
Le Sprint 3-A.2 est terminé lorsque :
✓ CustomerStatus ✓ CustomerSource ✓ CustomerScore ✓ CustomerLifetimeValue ✓ CustomerRisk ✓ CustomerSegment ✓ RGPD ✓ CustomerHistory ✓ Index CRM ✓ Migration exécutée
Livrables
Customer Enterprise CustomerHistory CustomerStatus CustomerSource CustomerSegment CustomerRiskLevel Migration customer_enterprise
Sprint 3-B.1 — Création du CustomerModule
Objectif
Implémenter le premier module CRM métier complet basé sur :
Customer
avec :
CRUD Clients Recherche CRM Pagination Tri Filtres Multi-Tenant Security Swagger
Architecture
Créer
src/modules/customers
Structure
customers ├── application │ │ └── dto │ │ ├── create-customer.dto.ts │ ├── update-customer.dto.ts │ ├── customer-query.dto.ts │ └── customer-response.dto.ts │ ├── domain │ │ └── services │ │ └── customer.service.ts │ ├── presentation │ │ └── controllers │ │ └── customer.controller.ts │ └── customer.module.ts
Sprint 3-B.1-A
DTOs
Étape 1 — CreateCustomerDto
Créer
create-customer.dto.ts
Implémentation
export class CreateCustomerDto {
firstName: string;
lastName: string;
email?: string;
phone?: string;
mobilePhone?: string;
companyName?: string;
language?: string;
source?: string;
marketingConsent?: boolean;
}
Étape 2 — UpdateCustomerDto
Créer
update-customer.dto.ts
Implémentation
export class UpdateCustomerDto
extends PartialType(
CreateCustomerDto
) {}
Étape 3 — CustomerQueryDto
Créer
customer-query.dto.ts
Ajouter
export class CustomerQueryDto {
page?: number = 1;
limit?: number = 25;
search?: string;
status?: string;
segment?: string;
source?: string;
vip?: boolean;
sortBy?: string =
'createdAt';
sortOrder?: 'asc' | 'desc' =
'desc';
}
Étape 4 — CustomerResponseDto
Créer
customer-response.dto.ts
Ajouter
export class CustomerResponseDto {
id: string;
firstName: string;
lastName: string;
email?: string;
phone?: string;
status: string;
segment: string;
customerScore: number;
lifetimeValue?: number;
vip: boolean;
createdAt: Date;
}
Sprint 3-B.1-B
CustomerService
Étape 5 — Création
Créer
customer.service.ts
Injection
@Injectable()
export class CustomerService {
constructor(
private readonly prisma:
PrismaService
) {}
}
Étape 6 — Méthodes
Ajouter
findAll() findOne() create() update() remove()
Étape 7 — Multi-Tenant Security
Principe
Aucune requête CRM ne doit sortir du tenant.
Exemple
where: {
tenantId:
currentTenantId
}
Obligatoire
Dans :
Toutes les requêtes
Étape 8 — Recherche CRM
Recherche globale
OR: [
{
firstName: {
contains: search,
mode: 'insensitive'
}
},
{
lastName: {
contains: search,
mode: 'insensitive'
}
},
{
email: {
contains: search,
mode: 'insensitive'
}
},
{
companyName: {
contains: search,
mode: 'insensitive'
}
}
]
Étape 9 — Filtres
Ajouter
status segment source vip
Exemple
if (query.vip !== undefined) {
where.vip =
query.vip;
}
Étape 10 — Pagination
Calcul
const skip = (page - 1) * limit;
Prisma
skip, take: limit
Étape 11 — Tri
Ajouter
orderBy: {
[query.sortBy]:
query.sortOrder
}
Étape 12 — findAll
Implémentation
async findAll(
tenantId: string,
query:
CustomerQueryDto
)
Retour
return {
data:
customers,
meta: {
page,
limit,
total
}
};
Étape 13 — findOne
Implémentation
async findOne( tenantId: string, id: string )
Sécurité
where: {
id,
tenantId
}
Sinon
throw new NotFoundException( 'Customer not found' );
Étape 14 — create
Génération CRM
customerNumber =
`CUS-${Date.now()}`
Création
await prisma.customer.create({
data: {
tenantId,
customerNumber,
...dto
}
});
Étape 15 — CustomerPreference
Création automatique
await prisma.customerPreference.create({
data: {
customerId:
customer.id
}
});
Étape 16 — update
Vérifier
Customer existe + Même tenant
Mise à jour
await prisma.customer.update(...)
Étape 17 — remove
Soft Delete
Ne jamais supprimer réellement.
Ajouter
deletedAt: new Date()
Mise à jour
await prisma.customer.update({
where: {
id
},
data: {
deletedAt:
new Date(),
status:
'INACTIVE'
}
});
Sprint 3-B.1-C
CustomerController
Étape 18 — Création
Créer
customer.controller.ts
Déclaration
@ApiTags('Customers')
@Controller('customers')
@UseGuards(
JwtAuthGuard
)
@ApiBearerAuth()
Étape 19 — GET /customers
Route
@Get()
Paramètres
Recherche Pagination Filtres
Étape 20 — GET /customers/{id}
Route
@Get(':id')
Étape 21 — POST /customers
Route
@Post()
Étape 22 — PUT /customers/{id}
Route
@Put(':id')
Étape 23 — DELETE /customers/{id}
Route
@Delete(':id')
Sprint 3-B.1-D
CustomerModule
Étape 24 — Création
Créer
customer.module.ts
Implémentation
@Module({
imports: [
PrismaModule,
AuthModule
],
controllers: [
CustomerController
],
providers: [
CustomerService
],
exports: [
CustomerService
]
})
export class CustomerModule {}
Étape 25 — AppModule
Ajouter
imports: [ ... CustomerModule ]
Sprint 3-B.1-E
Swagger
Étape 26 — Vérification
Endpoints
GET /customers
GET /customers/{id}
POST /customers
PUT /customers/{id}
DELETE /customers/{id}
Étape 27 — Exemple GET
Requête
GET /customers?page=1&limit=25
Réponse
{
"data": [
{
"id": "xxx",
"firstName": "Jean",
"lastName": "Dupont",
"segment": "VIP"
}
],
"meta": {
"page": 1,
"limit": 25,
"total": 132
}
}
Étape 28 — Exemple POST
Body
{
"firstName": "Jean",
"lastName": "Dupont",
"email": "jean@demo.fr",
"marketingConsent": true
}
Résultat
Customer créé CustomerPreference créée Numéro CRM généré
Préparation Sprint 3-C
Ce module servira directement à :
CustomerAddress CustomerDocument CustomerTag CustomerNote CustomerCommunication
Définition de terminé
Le Sprint 3-B.1 est terminé lorsque :
✓ CustomerModule créé ✓ CustomerController créé ✓ CustomerService créé ✓ CRUD Clients opérationnel ✓ Recherche CRM ✓ Pagination ✓ Filtres ✓ Multi-Tenant Security ✓ Swagger documenté ✓ Soft Delete
Livrables
CustomerModule CustomerController CustomerService CreateCustomerDto UpdateCustomerDto CustomerQueryDto CustomerResponseDto
Sprint 3-B.2 — CRM Enterprise Search & Segmentation
Objectif
Transformer le CRUD Clients en véritable CRM Enterprise.
À l'issue de cette étape :
✓ Recherche avancée ✓ Segmentation dynamique ✓ Smart Segments ✓ Scores CRM ✓ Filtres combinés ✓ Export CSV ✓ Vues enregistrées ✓ CRM Analytics Ready
Architecture cible
Customer ↓ CRM Search Engine ↓ Dynamic Filters ↓ Segmentation Engine ↓ Smart Segments ↓ Export / Campaigns / Analytics
Sprint 3-B.2-A
Segments CRM
Étape 1 — Création SavedCustomerView
Ajouter dans schema.prisma
model SavedCustomerView {
id String
@id
@default(uuid())
tenantId String
userId String
name String
description String?
filters Json
isDefault Boolean
@default(false)
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 — Création CustomerSegmentRule
Ajouter
model CustomerSegmentRule {
id String
@id
@default(uuid())
tenantId String
name String
code String
@unique
description String?
conditions Json
active Boolean
@default(true)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
@@index([tenantId])
@@index([active])
}
Étape 3 — Migration
Générer
npx prisma migrate dev \
--name crm_segmentation
Générer
npx prisma generate
Sprint 3-B.2-B
Recherche CRM Avancée
Étape 4 — Extension CustomerQueryDto
Ajouter
customerScoreMin?: number; customerScoreMax?: number; lifetimeValueMin?: number; lifetimeValueMax?: number; riskLevel?: string; country?: string; language?: string; createdFrom?: Date; createdTo?: Date; lastReservationFrom?: Date; lastReservationTo?: Date; marketingConsent?: boolean; segment?: string; vip?: boolean;
Étape 5 — Recherche multi-critères
Exemple
AND: [ status, segment, vip, marketingConsent, riskLevel ]
Recherche texte
OR: [ firstName, lastName, email, companyName, customerNumber ]
Étape 6 — Recherche CRM complète
Exemple
VIP ET Score > 80 ET LifetimeValue > 5000€ ET MarketingConsent = true
Résultat
Liste filtrée
Sprint 3-B.2-C
CRM Score Engine
Étape 7 — Création
crm-score.service.ts
Méthodes
calculateCustomerScore() calculateEngagementScore() calculateLoyaltyScore()
Étape 8 — Exemple Score
Réservations +30 Paiements +20 Avis positifs +15 Ancienneté +20 Marketing +15
Total
100
Étape 9 — Classification
0-25 LOW
26-50 NORMAL
51-75 GOOD
76-100 EXCELLENT
Sprint 3-B.2-D
Smart Segments
Étape 10 — Segments automatiques
Créer
crm-segmentation.service.ts
Segments
VIP Frequent Travelers Corporate High Revenue Inactive High Risk Marketing Qualified
Étape 11 — Segment VIP
Règle
LifetimeValue > 10000 ET Score > 80
Étape 12 — Segment Inactif
Règle
Dernière réservation > 365 jours
Étape 13 — Segment Corporate
Règle
CompanyName != null
Sprint 3-B.2-E
Vues enregistrées
Étape 14 — DTO
Créer
create-saved-view.dto.ts
Structure
export class CreateSavedViewDto {
name: string;
description?: string;
filters: Record<
string,
unknown
>;
}
Étape 15 — API
Ajouter
GET /customers/views
POST /customers/views
DELETE /customers/views/{id}
Exemple
Mes VIP Clients inactifs Corporate France Top Revenue
Sprint 3-B.2-F
Export CSV
Étape 16 — Service
Créer
crm-export.service.ts
Méthodes
exportCsv() exportExcel()
Étape 17 — Colonnes
CustomerNumber FirstName LastName Email Segment Score LifetimeValue Status
Étape 18 — Endpoint
Ajouter
GET /customers/export
Paramètres
Même filtres CRM
Sprint 3-B.2-G
API CRM Enterprise
Étape 19 — Nouveaux endpoints
GET /customers/search
GET /customers/export
GET /customers/views
POST /customers/views
DELETE /customers/views/{id}
GET /customers/segments
POST /customers/segments/recalculate
Étape 20 — Exemple recherche
Requête
GET /customers/search
Paramètres
segment=VIP scoreMin=80 marketingConsent=true country=FR
Résultat
Liste CRM filtrée
Sprint 3-B.2-H
Multi-Tenant Security
Étape 21 — Obligatoire
Toutes les requêtes :
tenantId
doivent être injectées automatiquement.
Vérification
SavedCustomerView CustomerSegmentRule Customer Export
Étape 22 — Audit
Journaliser
CRM_SEARCH CRM_EXPORT CRM_SEGMENT_UPDATE CRM_VIEW_CREATE
dans :
AuditLog
Sprint 3-B.2-I
Préparation Marketing
Compatible
Campaign CampaignRecipient MarketingSegment AutomationRule Recommendation
Préparation IA
Compatible avec :
Customer Scoring Recommendations Lead Scoring Predictive Segmentation
Définition de terminé
Le Sprint 3-B.2 est terminé lorsque :
✓ Recherche avancée ✓ Segmentation dynamique ✓ Smart Segments ✓ CRM Score Engine ✓ Export CSV ✓ Vues enregistrées ✓ Audit CRM ✓ Swagger documenté
Livrables
SavedCustomerView CustomerSegmentRule CrmScoreService CrmSegmentationService CrmExportService CRM Search API CRM Segments API CRM Views API
Sprint 3-C.1 — Gestion des Adresses Client
Objectif
Implémenter la gestion complète des adresses CRM client basée sur :
CustomerAddress
avec :
CRUD Adresses Adresse principale Géolocalisation Validation avancée Multi-Tenant Security Historisation CRM
Architecture
Créer
src/modules/customer-addresses
Structure
customer-addresses ├── application │ │ └── dto │ │ ├── create-customer-address.dto.ts │ ├── update-customer-address.dto.ts │ └── customer-address-response.dto.ts │ ├── domain │ │ └── services │ │ └── customer-address.service.ts │ ├── presentation │ │ └── controllers │ │ └── customer-address.controller.ts │ └── customer-address.module.ts
Sprint 3-C.1-A
DTOs
Étape 1 — CreateCustomerAddressDto
Créer
create-customer-address.dto.ts
Implémentation
export class CreateCustomerAddressDto {
label: string;
addressLine1: string;
addressLine2?: string;
postalCode: string;
city: string;
state?: string;
country: string;
isDefault?: boolean;
}
Étape 2 — UpdateCustomerAddressDto
Créer
update-customer-address.dto.ts
Implémentation
export class UpdateCustomerAddressDto
extends PartialType(
CreateCustomerAddressDto
) {}
Étape 3 — CustomerAddressResponseDto
Créer
customer-address-response.dto.ts
Ajouter
export class CustomerAddressResponseDto {
id: string;
label: string;
addressLine1: string;
postalCode: string;
city: string;
country: string;
latitude?: number;
longitude?: number;
formattedAddress?: string;
isDefault: boolean;
createdAt: Date;
}
Sprint 3-C.1-B
CustomerAddressService
Étape 4 — Création
Créer
customer-address.service.ts
Injection
@Injectable()
export class CustomerAddressService {
constructor(
private readonly prisma:
PrismaService,
private readonly geocodingService:
GeocodingService
) {}
}
Étape 5 — Méthodes
Ajouter
findAll() create() update() remove() setDefault()
Étape 6 — Vérification CRM
Vérifier
Le client appartient au tenant.
Requête
const customer =
await prisma.customer.findFirst({
where: {
id: customerId,
tenantId
}
});
Sinon
throw new NotFoundException( 'Customer not found' );
Étape 7 — Recherche adresses
Implémentation
async findAll( tenantId: string, customerId: string )
Requête
return prisma.customerAddress.findMany({
where: {
customerId
},
orderBy: [
{
isDefault:
'desc'
},
{
createdAt:
'desc'
}
]
});
Sprint 3-C.1-C
Adresse principale
Étape 8 — Reset adresse principale
Ajouter
private async resetDefaultAddress( customerId: string )
Implémentation
await prisma.customerAddress.updateMany({
where: {
customerId
},
data: {
isDefault: false
}
});
Étape 9 — Création
Si
dto.isDefault === true
Exécuter
await resetDefaultAddress( customerId );
Étape 10 — Première adresse
Si aucune adresse
count === 0
Alors
isDefault = true
Sprint 3-C.1-D
Géolocalisation
Étape 11 — Construction adresse
Ajouter
const fullAddress =
`${dto.addressLine1}
${dto.postalCode}
${dto.city}
${dto.country}`;
Étape 12 — Géocoder
Utiliser
await geocodingService.geocode( fullAddress );
Retour
latitude longitude formattedAddress placeId
Étape 13 — Gestion erreur
Fallback
Si :
OpenStreetMap indisponible
Alors
Créer quand même l'adresse.
Valeurs
latitude = null longitude = null
Sprint 3-C.1-E
Validation avancée
Étape 14 — Validation pays
Réutiliser
SUPPORTED_COUNTRIES
Étape 15 — Validation code postal
Réutiliser
PostalCodeValidator
Étape 16 — Validation géographique
Vérifier
Ville Code postal Pays
sont cohérents avec :
GeocodingResult
Sinon
throw new BadRequestException( 'Address validation failed' );
Sprint 3-C.1-F
Historisation CRM
Étape 17 — CustomerHistory
Ajouter
Lors de :
CREATE UPDATE DELETE
Exemple
await prisma.customerHistory.create({
data: {
customerId,
changedField:
'address',
oldValue:
oldAddress,
newValue:
newAddress
}
});
Étape 18 — AuditLog
Journaliser
CUSTOMER_ADDRESS_CREATED CUSTOMER_ADDRESS_UPDATED CUSTOMER_ADDRESS_DELETED CUSTOMER_ADDRESS_DEFAULT_CHANGED
Sprint 3-C.1-G
Update
Étape 19 — Contrôle tenant
Vérifier
Customer Adresse Tenant
avant toute modification.
Étape 20 — Mise à jour
Si
dto.isDefault = true
Alors
resetDefaultAddress()
Puis
update()
Étape 21 — Delete
Soft Delete recommandé
Ajouter dans Prisma :
deletedAt DateTime?
à :
CustomerAddress
Suppression
deletedAt: new Date()
Sprint 3-C.1-H
CustomerAddressController
Étape 22 — Création
Créer
customer-address.controller.ts
Déclaration
@ApiTags('Customer Addresses')
@Controller(
'customers/:id/addresses'
)
@UseGuards(
JwtAuthGuard
)
@ApiBearerAuth()
Étape 23 — GET
Route
GET /customers/{id}/addresses
Étape 24 — POST
Route
POST /customers/{id}/addresses
Étape 25 — PUT
Route
PUT /customers/{id}/addresses/{addressId}
Étape 26 — DELETE
Route
DELETE /customers/{id}/addresses/{addressId}
Sprint 3-C.1-I
CustomerAddressModule
Étape 27 — Création
Créer
customer-address.module.ts
Implémentation
@Module({
imports: [
PrismaModule,
AuthModule,
GeocodingModule
],
controllers: [
CustomerAddressController
],
providers: [
CustomerAddressService
],
exports: [
CustomerAddressService
]
})
export class CustomerAddressModule {}
Étape 28 — Swagger
Vérifier
GET /customers/{id}/addresses
POST /customers/{id}/addresses
PUT /customers/{id}/addresses/{addressId}
DELETE /customers/{id}/addresses/{addressId}
Étape 29 — Exemple POST
Body
{
"label": "Residence",
"addressLine1": "10 Rue Victor Hugo",
"postalCode": "75001",
"city": "Paris",
"country": "FR",
"isDefault": true
}
Résultat
Adresse créée Adresse principale définie Coordonnées GPS calculées Historique CRM enregistré
Préparation Sprint 3-D
Les adresses client seront utilisées par :
Reservations Invoices Documents Marketing CRM Analytics
Définition de terminé
Le Sprint 3-C.1 est terminé lorsque :
✓ CustomerAddressModule créé ✓ CustomerAddressController créé ✓ CustomerAddressService créé ✓ CRUD adresses opérationnel ✓ Adresse principale opérationnelle ✓ Géolocalisation opérationnelle ✓ Validation avancée ✓ Historisation CRM ✓ AuditLog intégré ✓ Swagger documenté
Livrables
CustomerAddressModule CustomerAddressController CustomerAddressService CreateCustomerAddressDto UpdateCustomerAddressDto CustomerAddressResponseDto
Sprint 3-C.2 — Adresses Enterprise & Cartographie CRM
Objectif
Transformer le système d'adresses CRM en moteur géospatial Enterprise.
À l'issue de cette étape :
✓ Multi-adresses ✓ Zones géographiques ✓ Distance client ✓ Recherche par rayon ✓ Clustering géographique ✓ Cartographie CRM ✓ Heatmaps ✓ Géo-segmentation
Architecture cible
Customer ↓ CustomerAddress ↓ Geo Engine ↓ Spatial Queries ↓ Maps ↓ CRM Analytics
Sprint 3-C.2-A
Extension Prisma
Étape 1 — Création GeoZone
Ajouter
model GeoZone {
id String
@id
@default(uuid())
tenantId String
code String
name String
description String?
zoneType GeoZoneType
country String?
region String?
city String?
polygon Json?
centerLatitude Decimal?
@db.Decimal(10,7)
centerLongitude Decimal?
@db.Decimal(10,7)
radiusKm Decimal?
@db.Decimal(10,2)
active Boolean
@default(true)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
@@index([tenantId])
@@index([zoneType])
@@index([active])
}
Étape 2 — Enum GeoZoneType
Ajouter
enum GeoZoneType {
COUNTRY
REGION
CITY
CUSTOM
SALES
MARKETING
DELIVERY
}
Étape 3 — Extension CustomerAddress
Ajouter
geoHash String?
geoValidated Boolean
@default(false)
geoValidatedAt DateTime?
timezone String?
district String?
Étape 4 — Migration
Générer
npx prisma migrate dev \
--name crm_geospatial
Générer
npx prisma generate
Sprint 3-C.2-B
GeoSpatial Module
Étape 5 — Création
src/modules/geospatial
Structure
geospatial ├── domain │ │ └── services │ │ ├── geo-distance.service.ts │ │ ├── geo-search.service.ts │ │ ├── geo-clustering.service.ts │ │ └── geo-zone.service.ts │ └── geospatial.module.ts
Étape 6 — Dépendances
Installer
npm install geolib npm install ngeohash
Sprint 3-C.2-C
Distance Client
Étape 7 — GeoDistanceService
Créer
geo-distance.service.ts
Méthodes
calculateDistance() calculateTravelRadius() findNearestCustomers()
Étape 8 — Calcul
Exemple
getDistance(
{
latitude: lat1,
longitude: lng1
},
{
latitude: lat2,
longitude: lng2
}
)
Retour
Distance en kilomètres
Étape 9 — Cas d'usage
Client ↔ Propriété Client ↔ Agence Client ↔ Région Client ↔ Zone commerciale
Sprint 3-C.2-D
Recherche par rayon
Étape 10 — Endpoint
Ajouter
GET /customers/search/radius
Paramètres
latitude longitude radiusKm
Étape 11 — Service
Ajouter
findCustomersInRadius( tenantId, lat, lng, radiusKm )
Retour
Tous les clients dans le rayon demandé
Étape 12 — Exemple
Recherche
Paris 50 km
Retour
Clients Paris Clients Versailles Clients Saint-Denis
Sprint 3-C.2-E
Clustering CRM
Étape 13 — GeoClusteringService
Créer
geo-clustering.service.ts
Méthodes
clusterCustomers() clusterByCity() clusterByRegion()
Étape 14 — Types
Ville Région Pays Distance Segment CRM
Étape 15 — Exemple
Résultat
{
"cluster":"Paris",
"customers":421
}
Sprint 3-C.2-F
Cartographie CRM
Étape 16 — DTO
Créer
customer-map-point.dto.ts
Structure
export class CustomerMapPointDto {
customerId: string;
customerNumber: string;
latitude: number;
longitude: number;
city: string;
segment: string;
customerScore: number;
}
Étape 17 — Endpoint
Ajouter
GET /customers/map
Retour
Points cartographiques CRM
Étape 18 — Préparation Front
Compatible :
Leaflet Mapbox Google Maps OpenLayers
Sprint 3-C.2-G
Heatmaps CRM
Étape 19 — Endpoint
Ajouter
GET /customers/heatmap
Retour
Densité clients par zone géographique
Étape 20 — Agrégation
Calcul
Nombre clients par géohash ou par ville
Exemple
[
{
"city":"Paris",
"count":421
},
{
"city":"Lyon",
"count":187
}
]
Sprint 3-C.2-H
Zones Marketing
Étape 21 — Gestion GeoZone
Endpoints
GET /geo-zones
POST /geo-zones
PUT /geo-zones/{id}
DELETE /geo-zones/{id}
Étape 22 — Segmentation
Exemple
Zone Paris ↓ Clients VIP ↓ Campagne Marketing
Étape 23 — Attribution automatique
Workflow
Adresse Client ↓ GeoZone Matching ↓ Segment Géographique ↓ Marketing
Sprint 3-C.2-I
CRM Analytics
Étape 24 — Dashboard
Ajouter
GET /customers/geographic-statistics
Retour
{
"countries":12,
"regions":38,
"cities":142,
"topCity":"Paris"
}
Étape 25 — Métriques
Top villes Top régions Répartition pays Répartition segments Lifetime Value géographique
Sprint 3-C.2-J
Audit & Sécurité
Étape 26 — Journaliser
Dans :
AuditLog
Événements
CRM_GEO_SEARCH CRM_MAP_VIEW CRM_HEATMAP_VIEW CRM_ZONE_CREATED CRM_ZONE_UPDATED
Étape 27 — Multi-Tenant
Obligatoire
Toutes les requêtes :
tenantId
doivent filtrer :
GeoZone Customer CustomerAddress
Préparation Sprint 9
Compatible avec :
Campaign MarketingSegment CampaignRecipient
Préparation Sprint 13
Compatible avec :
Recommendation AutomationScenario AI Segmentation
Définition de terminé
Le Sprint 3-C.2 est terminé lorsque :
✓ GeoZone créée ✓ Distance Client ✓ Recherche par rayon ✓ Clustering CRM ✓ Cartographie CRM ✓ Heatmaps ✓ Dashboard géographique ✓ Multi-Tenant Security ✓ Swagger documenté
Livrables
GeoZone GeoDistanceService GeoSearchService GeoClusteringService GeoZoneService CRM Map API CRM Heatmap API CRM Geographic Analytics
Sprint 3-D.1 — Gestion des Documents Client
Objectif
Implémenter la gestion documentaire CRM complète basée sur :
CustomerDocument
avec :
Upload Stockage MinIO/S3 Catégorisation Validation documentaire Historisation Audit RGPD
Architecture cible
Customer ↓ CustomerDocument ↓ StorageService ↓ MinIO / S3 ↓ CRM / Reservations / Compliance
Sprint 3-D.1-A
Modèle Prisma
Étape 1 — Création CustomerDocument
Ajouter dans schema.prisma
model CustomerDocument {
id String
@id
@default(uuid())
tenantId String
customerId String
documentType CustomerDocumentType
category String?
name String
originalFilename String
storagePath String
mimeType String
fileSize Int
checksum String?
version Int
@default(1)
status DocumentStatus
@default(PENDING)
expiresAt DateTime?
verifiedAt DateTime?
verifiedBy String?
uploadedBy String?
metadata Json?
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
deletedAt DateTime?
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
@@index([tenantId])
@@index([customerId])
@@index([documentType])
@@index([status])
@@index([expiresAt])
}
Étape 2 — Enum DocumentType
Ajouter
enum CustomerDocumentType {
IDENTITY_CARD
PASSPORT
DRIVING_LICENSE
VISA
RESIDENCE_PERMIT
CONTRACT
INVOICE
PROOF_OF_ADDRESS
INSURANCE
TAX_DOCUMENT
OTHER
}
Étape 3 — Enum DocumentStatus
Ajouter
enum DocumentStatus {
PENDING
VERIFIED
REJECTED
EXPIRED
ARCHIVED
}
Étape 4 — Relation Customer
Ajouter
Dans :
model Customer
documents CustomerDocument[]
Étape 5 — Migration
Générer
npx prisma migrate dev \
--name customer_documents
Générer
npx prisma generate
Sprint 3-D.1-B
Module
Étape 6 — Création
src/modules/customer-documents ├── application │ │ └── dto │ │ ├── upload-customer-document.dto.ts │ └── customer-document-response.dto.ts │ ├── domain │ │ └── services │ │ └── customer-document.service.ts │ ├── presentation │ │ └── controllers │ │ └── customer-document.controller.ts │ └── customer-document.module.ts
Sprint 3-D.1-C
DTOs
Étape 7 — Upload DTO
Créer
upload-customer-document.dto.ts
Ajouter
export class UploadCustomerDocumentDto {
documentType:
CustomerDocumentType;
category?: string;
expiresAt?: Date;
}
Étape 8 — Response DTO
Créer
customer-document-response.dto.ts
Ajouter
export class CustomerDocumentResponseDto {
id: string;
name: string;
documentType: string;
status: string;
mimeType: string;
fileSize: number;
createdAt: Date;
}
Sprint 3-D.1-D
Validation documentaire
Étape 9 — Types autorisés
Créer
shared/constants document-mime-types.ts
Ajouter
export const ALLOWED_DOCUMENT_TYPES = [ 'application/pdf', 'image/jpeg', 'image/png', 'image/webp' ];
Étape 10 — Taille maximale
Ajouter
export const MAX_DOCUMENT_SIZE = 20 * 1024 * 1024;
Étape 11 — Validation
Vérifier
mimetype size
Rejeter
EXE ZIP JS BAT SH
Sprint 3-D.1-E
CustomerDocumentService
Étape 12 — Création
Créer
customer-document.service.ts
Injection
@Injectable()
export class CustomerDocumentService {
constructor(
private readonly prisma:
PrismaService,
private readonly storageService:
StorageService
) {}
}
Étape 13 — Méthodes
Ajouter
findAll() upload() remove() verify() generateDownloadUrl()
Étape 14 — Upload
Chemin
customers/
{customerId}/
documents/
{uuid}
Upload MinIO
const storagePath =
await storageService
.uploadDocument(
file,
customerId
);
Étape 15 — Enregistrement
Créer
await prisma.customerDocument.create({
data: {
tenantId,
customerId,
documentType,
storagePath,
mimeType:
file.mimetype,
fileSize:
file.size,
status:
'PENDING'
}
});
Étape 16 — URL sécurisée
Générer
generateDownloadUrl()
Utiliser
Presigned URL Expiration 1h
Sprint 3-D.1-F
Historisation CRM
Étape 17 — CustomerHistory
Ajouter
DOCUMENT_UPLOADED DOCUMENT_VERIFIED DOCUMENT_DELETED
Exemple
changedField: 'document'
Étape 18 — Audit
Ajouter
Dans :
AuditLog
Événements
CUSTOMER_DOCUMENT_UPLOAD CUSTOMER_DOCUMENT_VERIFY CUSTOMER_DOCUMENT_DELETE
Sprint 3-D.1-G
Contrôleur
Étape 19 — Création
Créer
customer-document.controller.ts
Déclaration
@ApiTags( 'Customer Documents' ) @Controller( 'customers/:id/documents' ) @UseGuards( JwtAuthGuard ) @ApiBearerAuth()
Étape 20 — GET
Route
GET /customers/{id}/documents
Étape 21 — POST
Route
POST /customers/{id}/documents
Upload
@UseInterceptors(
FileInterceptor(
'file'
)
)
Étape 22 — DELETE
Route
DELETE /customers/{id}/documents/{documentId}
Étape 23 — Download
Ajouter
GET /customers/{id}/documents/{documentId}/download
Sprint 3-D.1-H
Vérification documentaire
Étape 24 — Endpoint
Ajouter
PUT /customers/{id}/documents/{documentId}/verify
Action
Status ↓ VERIFIED
Métadonnées
verifiedAt verifiedBy
Étape 25 — Expiration
Vérifier
Passport Visa Insurance
Automatisation future
Créer alertes :
30 jours avant expiration
Sprint 3-D.1-I
Module
Étape 26 — Création
Créer
customer-document.module.ts
Implémentation
@Module({
imports: [
PrismaModule,
AuthModule,
StorageModule
],
controllers: [
CustomerDocumentController
],
providers: [
CustomerDocumentService
],
exports: [
CustomerDocumentService
]
})
export class CustomerDocumentModule {}
Étape 27 — Swagger
Vérifier
GET /customers/{id}/documents
POST /customers/{id}/documents
DELETE /customers/{id}/documents/{documentId}
GET /customers/{id}/documents/{documentId}/download
PUT /customers/{id}/documents/{documentId}/verify
Étape 28 — Exemple
Upload
Passeport.pdf
Résultat
Document stocké MinIO Status=PENDING Historique CRM créé Audit créé
Préparation Sprint 19
Compatible avec :
Consent ComplianceAudit RetentionPolicy DataClassification
Préparation Sprint 13
Compatible avec :
OCR Document AI Extraction automatique Classification automatique
Définition de terminé
Le Sprint 3-D.1 est terminé lorsque :
✓ CustomerDocument créé ✓ Upload opérationnel ✓ MinIO/S3 intégré ✓ Validation documentaire ✓ Vérification documentaire ✓ AuditLog intégré ✓ Historisation CRM ✓ URLs sécurisées ✓ Swagger documenté
Livrables
CustomerDocument CustomerDocumentModule CustomerDocumentController CustomerDocumentService Document Validation MinIO Integration Secure Download URLs
Sprint 3-D.2 — Gestion Documentaire Enterprise
Objectif
Faire évoluer le système documentaire CRM vers une GED Enterprise complète.
À l'issue de cette étape :
✓ Versioning ✓ OCR ✓ Classification automatique ✓ Extraction de données ✓ Expiration automatique ✓ Workflow de validation ✓ Signature électronique ✓ Conformité RGPD ✓ Préparation ISO27001
Architecture cible
Document Upload ↓ OCR Engine ↓ Classification Engine ↓ Extraction Engine ↓ Validation Workflow ↓ Storage ↓ Compliance
Sprint 3-D.2-A
Extension Prisma
Étape 1 — Versioning documentaire
Ajouter dans CustomerDocument
parentDocumentId String?
documentVersion Int
@default(1)
isLatestVersion Boolean
@default(true)
supersededAt DateTime?
Étape 2 — Relation Version
Ajouter
parentDocument CustomerDocument?
@relation(
"DocumentVersions",
fields:[parentDocumentId],
references:[id]
)
versions CustomerDocument[]
@relation(
"DocumentVersions"
)
Étape 3 — OCR
Ajouter
ocrStatus OcrStatus
@default(PENDING)
ocrText String?
ocrExecutedAt DateTime?
Étape 4 — Classification
Ajouter
classificationScore Float? classificationSource String? detectedDocumentType String?
Étape 5 — Extraction
Ajouter
extractedData Json? extractionStatus String?
Étape 6 — Signature
Ajouter
signatureRequired Boolean
@default(false)
signedAt DateTime?
signatureProvider String?
signatureReference String?
Étape 7 — Enum OCR
Ajouter
enum OcrStatus {
PENDING
PROCESSING
COMPLETED
FAILED
}
Étape 8 — Migration
Générer
npx prisma migrate dev \
--name customer_documents_enterprise
Générer
npx prisma generate
Sprint 3-D.2-B
GED Workflow
Étape 9 — Création DocumentWorkflow
Ajouter
model DocumentWorkflow {
id String
@id
@default(uuid())
tenantId String
name String
documentType String
active Boolean
@default(true)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
steps DocumentWorkflowStep[]
}
Étape 10 — Workflow Steps
Ajouter
model DocumentWorkflowStep {
id String
@id
@default(uuid())
workflowId String
name String
stepOrder Int
validatorRole String?
required Boolean
@default(true)
workflow DocumentWorkflow
@relation(
fields:[workflowId],
references:[id],
onDelete:Cascade
)
@@index([workflowId])
@@index([stepOrder])
}
Étape 11 — Workflow Instance
Ajouter
model CustomerDocumentWorkflow {
id String
@id
@default(uuid())
documentId String
currentStep Int
@default(1)
status WorkflowStatus
@default(PENDING)
startedAt DateTime
@default(now())
completedAt DateTime?
document CustomerDocument
@relation(
fields:[documentId],
references:[id]
)
}
Étape 12 — Enum Workflow
Ajouter
enum WorkflowStatus {
PENDING
IN_PROGRESS
APPROVED
REJECTED
CANCELLED
}
Sprint 3-D.2-C
OCR Module
Étape 13 — Création
src/modules/document-ai
Structure
document-ai ├── domain │ │ └── services │ │ ├── ocr.service.ts │ │ ├── document-classifier.service.ts │ │ ├── extraction.service.ts │ │ └── expiration-monitor.service.ts │ └── document-ai.module.ts
Étape 14 — OCR Service
Méthodes
processDocument() extractText() detectLanguage()
Prévoir
Connecteurs futurs :
Tesseract AWS Textract Google Vision Azure Form Recognizer
Étape 15 — OCR Workflow
Upload ↓ OCR ↓ Classification ↓ Extraction ↓ Validation ↓ Archive
Sprint 3-D.2-D
Classification Automatique
Étape 16 — DocumentClassifier
Méthodes
classify() detectPassport() detectInvoice() detectContract()
Étape 17 — Classification
Exemple
Passeport ↓ IDENTITY_DOCUMENT
Résultat
classificationScore: 0.98
Étape 18 — Mise à jour
Ajouter
detectedDocumentType classificationScore classificationSource
Sprint 3-D.2-E
Extraction de données
Étape 19 — ExtractionService
Méthodes
extractIdentityData() extractInvoiceData() extractContractData()
Étape 20 — Exemple
Passeport
Nom Prénom Nationalité Date expiration Numéro
Sauvegarder
extractedData Json
Étape 21 — Exemple
Facture
Numéro facture Montant Date TVA
Sprint 3-D.2-F
Expiration Automatique
Étape 22 — ExpirationMonitor
Méthodes
checkExpiringDocuments() markExpiredDocuments()
Étape 23 — Workflow
Tous les jours ↓ Expiration < 30 jours ↓ Notification ↓ Alert
Étape 24 — Statut
Mise à jour
EXPIRED
automatiquement.
Sprint 3-D.2-G
Signature Électronique
Étape 25 — Préparation
Ajouter
SignatureProvider
Fournisseurs
DocuSign Yousign Adobe Sign
Étape 26 — Workflow
Document ↓ Signature Request ↓ Signed ↓ Archive
Étape 27 — Endpoints
Ajouter
POST /customers/{id}/documents/{documentId}/sign
GET /customers/{id}/documents/{documentId}/signature
Sprint 3-D.2-H
API GED
Étape 28 — Endpoints
Ajouter
POST /documents/{id}/ocr
POST /documents/{id}/classify
POST /documents/{id}/extract
GET /documents/{id}/workflow
PUT /documents/{id}/approve
PUT /documents/{id}/reject
Étape 29 — Permissions
RBAC
documents.read documents.write documents.verify documents.approve documents.sign
Sprint 3-D.2-I
Audit & Conformité
Étape 30 — AuditLog
Journaliser
DOCUMENT_OCR DOCUMENT_CLASSIFIED DOCUMENT_EXTRACTED DOCUMENT_APPROVED DOCUMENT_REJECTED DOCUMENT_SIGNED DOCUMENT_EXPIRED
Étape 31 — DataClassification
Préparer
Compatible avec :
PII IDENTITY FINANCIAL LEGAL CONFIDENTIAL
Étape 32 — Retention
Préparer
Compatible avec :
RetentionPolicy ComplianceAudit GDPR
Sprint 3-D.2-J
Dashboard GED
Étape 33 — Statistiques
Ajouter
GET /documents/statistics
Retour
{
"totalDocuments": 5234,
"verifiedDocuments": 4987,
"expiredDocuments": 74,
"pendingValidation": 32,
"pendingSignatures": 11
}
Étape 34 — Recherche GED
Ajouter
GET /documents/search
Filtres
Type Statut Date expiration Client OCR Workflow
Préparation Sprint 13
Compatible avec :
KnowledgeDocument Recommendation AI Assistant Document AI
Préparation Sprint 19
Compatible avec :
ComplianceAudit DataClassification RetentionPolicy SecurityIncident
Définition de terminé
Le Sprint 3-D.2 est terminé lorsque :
✓ Versioning ✓ OCR ✓ Classification automatique ✓ Extraction de données ✓ Expiration automatique ✓ Workflow validation ✓ Signature électronique ✓ Audit GED ✓ Conformité préparée
Livrables
DocumentWorkflow DocumentWorkflowStep CustomerDocumentWorkflow OcrService DocumentClassifierService ExtractionService ExpirationMonitorService Enterprise GED API
Sprint 3-E.1 — Gestion des Tags CRM
Objectif
Implémenter un moteur de tags CRM permettant :
Segmentation Classification Automatisation Marketing CRM Analytics Personnalisation
basé sur :
CustomerTag CustomerTagAssignment
Architecture cible
Customer ↓ CustomerTagAssignment ↓ CustomerTag ↓ CRM Segmentation ↓ Campaigns ↓ Automation
Sprint 3-E.1-A
Modèle Prisma
Étape 1 — Création CustomerTag
Ajouter dans schema.prisma
model CustomerTag {
id String
@id
@default(uuid())
tenantId String
name String
code String
description String?
color String?
icon String?
category String?
tagType CustomerTagType
@default(MANUAL)
active Boolean
@default(true)
usageCount Int
@default(0)
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
assignments CustomerTagAssignment[]
@@unique([
tenantId,
code
])
@@index([tenantId])
@@index([tagType])
@@index([active])
}
Étape 2 — Création CustomerTagAssignment
Ajouter
model CustomerTagAssignment {
id String
@id
@default(uuid())
customerId String
tagId String
assignedBy String?
assignedAt DateTime
@default(now())
source String?
@default("MANUAL")
expiresAt DateTime?
metadata Json?
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
tag CustomerTag
@relation(
fields:[tagId],
references:[id],
onDelete:Cascade
)
@@unique([
customerId,
tagId
])
@@index([customerId])
@@index([tagId])
@@index([assignedAt])
}
Étape 3 — Enum TagType
Ajouter
enum CustomerTagType {
MANUAL
DYNAMIC
SYSTEM
MARKETING
LOYALTY
RISK
}
Étape 4 — Relations
Ajouter dans Customer
tags CustomerTagAssignment[]
Étape 5 — Migration
Générer
npx prisma migrate dev \
--name customer_tags
Générer
npx prisma generate
Sprint 3-E.1-B
Module
Étape 6 — Création
src/modules/customer-tags ├── application │ │ └── dto │ │ ├── create-customer-tag.dto.ts │ │ ├── assign-customer-tag.dto.ts │ │ └── customer-tag-response.dto.ts │ ├── domain │ │ └── services │ │ └── customer-tag.service.ts │ ├── presentation │ │ └── controllers │ │ └── customer-tag.controller.ts │ └── customer-tag.module.ts
Sprint 3-E.1-C
DTOs
Étape 7 — CreateCustomerTagDto
Créer
create-customer-tag.dto.ts
Implémentation
export class CreateCustomerTagDto {
name: string;
code: string;
description?: string;
color?: string;
icon?: string;
category?: string;
tagType?: string;
}
Étape 8 — AssignCustomerTagDto
Créer
assign-customer-tag.dto.ts
Implémentation
export class AssignCustomerTagDto {
tagId: string;
expiresAt?: Date;
}
Sprint 3-E.1-D
CustomerTagService
Étape 9 — Méthodes
Ajouter
findTags() createTag() assignTag() removeTag() getCustomerTags() recalculateUsage()
Étape 10 — Création Tag
Vérifier
Code unique par tenant
Création
await prisma.customerTag.create({
data: {
tenantId,
...dto
}
});
Étape 11 — Affectation
Vérifier
Customer Tag Même tenant
Affecter
await prisma.customerTagAssignment.create({
data: {
customerId,
tagId,
assignedBy:
userId
}
});
Étape 12 — Usage Count
Mettre à jour
await prisma.customerTag.update({
where: {
id: tagId
},
data: {
usageCount: {
increment: 1
}
}
});
Étape 13 — Suppression
Supprimer
CustomerTagAssignment
Décrémenter
usageCount
Sprint 3-E.1-E
Tags Dynamiques
Étape 14 — Extension CustomerTag
Ajouter
dynamicRule Json?
Étape 15 — Exemple
VIP
{
"customerScore": {
"gte": 80
}
}
High Revenue
{
"lifetimeValue": {
"gte": 10000
}
}
Étape 16 — Recalcul
Méthode
evaluateDynamicTags()
Déclencheurs
Customer Updated Reservation Created Score Updated
Sprint 3-E.1-F
Tags Système
Étape 17 — Tags par défaut
Seed
VIP FREQUENT CORPORATE HIGH_VALUE INACTIVE BLACKLISTED HIGH_RISK NEWSLETTER LOYALTY
Étape 18 — Attribution automatique
Exemple
Segment = VIP ↓ Tag VIP
Exemple
Risk = HIGH ↓ Tag HIGH_RISK
Sprint 3-E.1-G
Contrôleur
Étape 19 — Création
Créer
customer-tag.controller.ts
Déclaration
@ApiTags('Customer Tags')
@Controller('customers')
Étape 20 — Liste tags
Route
GET /customers/tags
Étape 21 — Création tag
Route
POST /customers/tags
Étape 22 — Affectation
Route
POST /customers/{id}/tags
Étape 23 — Suppression
Route
DELETE /customers/{id}/tags/{tagId}
Étape 24 — Consultation
Ajouter
GET /customers/{id}/tags
Sprint 3-E.1-H
Recherche CRM
Étape 25 — Filtre Tags
Ajouter dans
CustomerQueryDto
Champ
tags?: string[];
Étape 26 — Recherche
Exemple
VIP + NEWSLETTER
Résultat
Clients correspondants
Étape 27 — Segmentation
Exemple
GET /customers/search
tag=VIP
Utilisation
Marketing Campagnes Automatisation
Sprint 3-E.1-I
Audit & Historisation
Étape 28 — CustomerHistory
Journaliser
TAG_ASSIGNED TAG_REMOVED
Étape 29 — AuditLog
Ajouter
CUSTOMER_TAG_CREATED CUSTOMER_TAG_ASSIGNED CUSTOMER_TAG_REMOVED CUSTOMER_DYNAMIC_TAG_UPDATED
Sprint 3-E.1-J
Préparation Sprint 9
Compatible
Campaign CampaignRecipient MarketingSegment MarketingEvent
Préparation Sprint 13
Compatible avec :
AutomationRule Recommendation AiConversation AutomationScenario
Préparation Sprint 20
Compatible avec :
Customer Analytics Predictive Segmentation Lead Scoring AI Recommendations
Définition de terminé
Le Sprint 3-E.1 est terminé lorsque :
✓ CustomerTag créé ✓ CustomerTagAssignment créé ✓ Tags manuels ✓ Tags dynamiques ✓ Segmentation CRM ✓ Recherche par tags ✓ AuditLog intégré ✓ Historisation CRM ✓ Swagger documenté
Livrables
CustomerTag CustomerTagAssignment CustomerTagModule CustomerTagController CustomerTagService Dynamic Tag Engine
Sprint 3-E.2 — Segmentation CRM Avancée & Smart Tags
Objectif
Transformer le moteur de tags CRM en moteur intelligent de segmentation Enterprise.
À l'issue de cette étape :
✓ Tag Rules Engine ✓ Smart Tags IA ✓ Segmentation comportementale ✓ Scoring automatique ✓ Segments prédictifs ✓ Marketing Intelligence ✓ CRM Intelligence Engine
Architecture cible
Customer Data ↓ Behavior Analysis ↓ Scoring Engine ↓ Tag Rules Engine ↓ Smart Segments ↓ Marketing Intelligence ↓ Automation
Sprint 3-E.2-A
Extension Prisma
Étape 1 — Création SmartSegment
Ajouter dans schema.prisma
model SmartSegment {
id String
@id
@default(uuid())
tenantId String
name String
code String
description String?
segmentType SmartSegmentType
active Boolean
@default(true)
ruleDefinition Json
estimatedCustomers Int
@default(0)
lastCalculatedAt DateTime?
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
@@unique([
tenantId,
code
])
@@index([tenantId])
@@index([segmentType])
@@index([active])
}
Étape 2 — Création CustomerScore
Ajouter
model CustomerScore {
id String
@id
@default(uuid())
customerId String
@unique
engagementScore Int
@default(0)
loyaltyScore Int
@default(0)
revenueScore Int
@default(0)
marketingScore Int
@default(0)
riskScore Int
@default(0)
predictiveScore Int
@default(0)
overallScore Int
@default(0)
calculatedAt DateTime
@default(now())
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
}
Étape 3 — Enum SegmentType
Ajouter
enum SmartSegmentType {
BEHAVIORAL
REVENUE
LOYALTY
MARKETING
PREDICTIVE
RISK
AI_GENERATED
}
Étape 4 — Relations
Ajouter dans Customer
score CustomerScore?
Étape 5 — Migration
Générer
npx prisma migrate dev \
--name crm_smart_segments
Générer
npx prisma generate
Sprint 3-E.2-B
Tag Rules Engine
Étape 6 — Création
crm-tag-rules.service.ts
Méthodes
evaluateRules() executeRule() assignTags() removeTags()
Étape 7 — Structure Rule
Exemple
{
"conditions": [
{
"field": "lifetimeValue",
"operator": "gte",
"value": 10000
}
],
"action": {
"tag": "HIGH_VALUE"
}
}
Étape 8 — Opérateurs
eq neq gt gte lt lte contains in notIn
Sprint 3-E.2-C
Scoring Automatique
Étape 9 — Création
customer-scoring.service.ts
Méthodes
calculateOverallScore() calculateEngagement() calculateLoyalty() calculateRevenue() calculateRisk()
Étape 10 — Engagement
Critères
Communications Ouvertures emails Réponses Activité CRM
Score
0 → 100
Étape 11 — Loyalty
Critères
Ancienneté Réservations Lifetime Value VIP
Étape 12 — Revenue
Critères
Total Revenue Average Basket Frequency
Sprint 3-E.2-D
Smart Tags IA
Étape 13 — Création
smart-tag.service.ts
Méthodes
generateSmartTags() predictCustomerCategory() recommendTags()
Étape 14 — Smart Tags
Exemples
HIGH_VALUE FUTURE_VIP AT_RISK LOYAL_CUSTOMER UPSELL_TARGET CHURN_RISK
Étape 15 — Attribution
Exemple
Lifetime Value élevé + Croissance forte ↓ FUTURE_VIP
Sprint 3-E.2-E
Segmentation Comportementale
Étape 16 — BehaviorSegmentService
Créer
behavior-segmentation.service.ts
Segments
Frequent Traveler Weekend Traveler Luxury Traveler Business Traveler Seasonal Traveler Family Traveler
Étape 17 — Analyse
Sources
Reservations Invoices Communications Preferences
Étape 18 — Exemple
80% réservations Vendredi → Dimanche ↓ Weekend Traveler
Sprint 3-E.2-F
Segments Prédictifs
Étape 19 — PredictiveSegmentation
Créer
predictive-segmentation.service.ts
Segments
Future VIP Future Churn Future Corporate Future High Revenue Future Ambassador
Étape 20 — Prévision
Critères
Croissance dépenses Fréquence réservations Engagement Satisfaction
Étape 21 — Exemple
Croissance 30% ↓ Future VIP
Sprint 3-E.2-G
Marketing Intelligence
Étape 22 — Création
marketing-intelligence.service.ts
Méthodes
findCampaignTargets() findUpsellTargets() findRetentionTargets() findReferralCandidates()
Étape 23 — Exemples
Upsell
VIP + Revenue > 5000 ↓ Campagne Premium
Rétention
CHURN_RISK ↓ Campagne Réactivation
Sprint 3-E.2-H
API CRM Intelligence
Étape 24 — Endpoints
Ajouter
GET /customers/segments/smart GET /customers/tags/smart GET /customers/scoring POST /customers/scoring/recalculate POST /customers/segments/recalculate
Étape 25 — Exemple
Réponse
{
"customerId":"123",
"overallScore":87,
"smartTags":[
"VIP",
"LOYAL_CUSTOMER",
"UPSELL_TARGET"
]
}
Sprint 3-E.2-I
Dashboard CRM Intelligence
Étape 26 — KPI
Ajouter
GET /customers/intelligence/dashboard
Retour
{
"futureVip":54,
"churnRisk":23,
"upsellTargets":118,
"loyalCustomers":401
}
Étape 27 — Visualisation
Répartition
Segments Scores Tags Prévisions
Sprint 3-E.2-J
Audit & Automatisation
Étape 28 — AuditLog
Journaliser
SMART_TAG_ASSIGNED SEGMENT_RECALCULATED CUSTOMER_SCORE_UPDATED PREDICTIVE_SEGMENT_ASSIGNED
Étape 29 — Automatisation
Déclencheurs
Reservation Created Invoice Paid Customer Updated Campaign Opened
Actions
Recalculate Scores Recalculate Tags Recalculate Segments
Préparation Sprint 9
Compatible avec :
Campaign CampaignRecipient MarketingSegment MarketingEvent
Préparation Sprint 13
Compatible avec :
Recommendation AutomationRule AutomationScenario AiConversation
Préparation Sprint 20
Compatible avec :
Enterprise Analytics Customer Intelligence Predictive CRM AI Recommendations
Définition de terminé
Le Sprint 3-E.2 est terminé lorsque :
✓ SmartSegment créé ✓ CustomerScore créé ✓ Tag Rules Engine ✓ Smart Tags ✓ Segmentation comportementale ✓ Segments prédictifs ✓ Marketing Intelligence ✓ Dashboard CRM Intelligence ✓ Audit intégré
Livrables
SmartSegment CustomerScore CustomerScoringService SmartTagService BehaviorSegmentationService PredictiveSegmentationService MarketingIntelligenceService CRM Intelligence API
Sprint 3-F.1 — Gestion des Notes CRM
Objectif
Implémenter le système de notes CRM permettant aux équipes :
Commerciales Support Réservations Finance Marketing Administration
de collaborer autour d'un client.
À l'issue de cette étape :
✓ Notes privées ✓ Notes publiques ✓ Historique CRM ✓ Mentions utilisateurs ✓ Audit ✓ Recherche ✓ Timeline CRM
Architecture cible
Customer ↓ CustomerNote ↓ Mentions ↓ Timeline CRM ↓ Audit ↓ Collaboration
Sprint 3-F.1-A
Modèle Prisma
Étape 1 — Création CustomerNote
Ajouter dans schema.prisma
model CustomerNote {
id String
@id
@default(uuid())
tenantId String
customerId String
authorId String
title String?
content String
visibility NoteVisibility
@default(PRIVATE)
noteType CustomerNoteType
@default(GENERAL)
pinned Boolean
@default(false)
edited Boolean
@default(false)
editedAt DateTime?
metadata Json?
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
deletedAt DateTime?
tenant Tenant
@relation(
fields:[tenantId],
references:[id]
)
customer Customer
@relation(
fields:[customerId],
references:[id],
onDelete:Cascade
)
author User
@relation(
fields:[authorId],
references:[id]
)
mentions CustomerNoteMention[]
@@index([tenantId])
@@index([customerId])
@@index([authorId])
@@index([visibility])
@@index([createdAt])
}
Étape 2 — Création CustomerNoteMention
Ajouter
model CustomerNoteMention {
id String
@id
@default(uuid())
noteId String
userId String
readAt DateTime?
createdAt DateTime
@default(now())
note CustomerNote
@relation(
fields:[noteId],
references:[id],
onDelete:Cascade
)
user User
@relation(
fields:[userId],
references:[id]
)
@@unique([
noteId,
userId
])
@@index([userId])
@@index([noteId])
}
Étape 3 — Enum Visibility
Ajouter
enum NoteVisibility {
PRIVATE
INTERNAL
PUBLIC
}
Étape 4 — Enum Type
Ajouter
enum CustomerNoteType {
GENERAL
SALES
SUPPORT
FINANCE
MARKETING
RESERVATION
VIP
RISK
}
Étape 5 — Relation Customer
Ajouter
Dans :
model Customer
notes CustomerNote[]
Étape 6 — Migration
Générer
npx prisma migrate dev \
--name customer_notes
Générer
npx prisma generate
Sprint 3-F.1-B
Module
Étape 7 — Création
src/modules/customer-notes ├── application │ │ └── dto │ │ ├── create-customer-note.dto.ts │ │ ├── update-customer-note.dto.ts │ │ └── customer-note-response.dto.ts │ ├── domain │ │ └── services │ │ └── customer-note.service.ts │ ├── presentation │ │ └── controllers │ │ └── customer-note.controller.ts │ └── customer-note.module.ts
Sprint 3-F.1-C
DTOs
Étape 8 — CreateCustomerNoteDto
Créer
create-customer-note.dto.ts
Implémentation
export class CreateCustomerNoteDto {
title?: string;
content: string;
visibility?: string;
noteType?: string;
pinned?: boolean;
mentions?: string[];
}
Étape 9 — UpdateCustomerNoteDto
Créer
update-customer-note.dto.ts
Implémentation
export class UpdateCustomerNoteDto
extends PartialType(
CreateCustomerNoteDto
) {}
Sprint 3-F.1-D
CustomerNoteService
Étape 10 — Méthodes
Ajouter
findAll() findOne() create() update() remove() createMentions()
Étape 11 — Liste
Trier
Pinned ↓ Date création DESC
Prisma
orderBy: [
{
pinned: 'desc'
},
{
createdAt: 'desc'
}
]
Étape 12 — Création
Vérifier
Customer Tenant
Créer
const note =
await prisma.customerNote.create({
data: {
tenantId,
customerId,
authorId,
...dto
}
});
Étape 13 — Mentions
Exemple
@john @support @manager
Créer
await prisma.customerNoteMention.createMany({
data: [...]
});
Étape 14 — Notifications
Déclencher
IN_APP EMAIL
pour les utilisateurs mentionnés.
Sprint 3-F.1-E
Notes privées
Étape 15 — Visibilité
PRIVATE
Auteur uniquement
INTERNAL
Employés du tenant
PUBLIC
Visible dans CRM global
Étape 16 — Filtrage
Vérifier
Avant lecture :
Visibility Tenant Permissions
Sprint 3-F.1-F
Modification
Étape 17 — Update
Ajouter
edited = true editedAt = new Date()
Étape 18 — Historique
Journaliser
Dans :
CustomerHistory
Événements
NOTE_CREATED NOTE_UPDATED NOTE_DELETED
Étape 19 — Soft Delete
Supprimer
deletedAt: new Date()
Sprint 3-F.1-G
Recherche CRM
Étape 20 — Recherche
Ajouter
GET /customers/{id}/notes
Paramètres
noteType visibility author search
Étape 21 — Recherche texte
Champs
title content
Prisma
contains: search
Sprint 3-F.1-H
Contrôleur
Étape 22 — Création
Créer
customer-note.controller.ts
Déclaration
@ApiTags( 'Customer Notes' ) @Controller( 'customers/:id/notes' ) @UseGuards( JwtAuthGuard ) @ApiBearerAuth()
Étape 23 — Endpoints
Ajouter
GET /customers/{id}/notes
POST /customers/{id}/notes
PUT /customers/{id}/notes/{noteId}
DELETE /customers/{id}/notes/{noteId}
Étape 24 — Mentions
Ajouter
GET /notes/mentions
Retour
Mes mentions
Sprint 3-F.1-I
Timeline CRM
Étape 25 — Préparation
Les notes alimentent :
Customer Timeline
future.
Événements
Notes Documents Tags Communications Réservations
Étape 26 — Notes épinglées
Utilisation
VIP Risques Informations critiques
Sprint 3-F.1-J
Audit & Sécurité
Étape 27 — AuditLog
Journaliser
CUSTOMER_NOTE_CREATED CUSTOMER_NOTE_UPDATED CUSTOMER_NOTE_DELETED CUSTOMER_NOTE_PINNED CUSTOMER_MENTION_CREATED
Étape 28 — Permissions
Ajouter
customer.notes.read customer.notes.write customer.notes.delete customer.notes.manage
Préparation Sprint 9
Compatible avec :
CustomerCommunication Campaign MarketingEvent
Préparation Sprint 13
Compatible avec :
AiConversation Recommendation KnowledgeDocument
Définition de terminé
Le Sprint 3-F.1 est terminé lorsque :
✓ CustomerNote créé ✓ CustomerNoteMention créé ✓ Notes privées ✓ Notes publiques ✓ Mentions utilisateurs ✓ Historisation CRM ✓ AuditLog intégré ✓ Recherche notes ✓ Swagger documenté
Livrables
CustomerNote CustomerNoteMention CustomerNoteModule CustomerNoteController CustomerNoteService CRM Notes API