Outils pour utilisateurs

Outils du site


ujusum:3-codage:2-sprints:3-sprint-3

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

ujusum/3-codage/2-sprints/3-sprint-3.1781050774.txt.gz · Dernière modification : 2026/06/10 02:19 de 83.202.252.200

DokuWiki Appliance - Powered by TurnKey Linux