Pro Registration
Summary
A real-estate professional registers an account by providing their personal details, agency info, SIRET, and carte T (CPI format). The system validates both identifiers synchronously, hashes the password, issues tokens, and fires a Slack notification to admins so the pending CNI review is visible immediately.
State Diagram
stateDiagram-v2 state "Validation en cours" as Validating state "Rejeté (SIRET invalide)" as Rejected_SIRET state "Rejeté (carte T invalide)" as Rejected_CarteT state "Rejeté (email existant)" as Rejected_Conflict state "Compte créé" as Created state "Tokens émis" as TokensIssued state "Slack notifié" as SlackNotified [*] --> Validating: pro submits registration form Validating --> Rejected_SIRET: invalid SIRET (Luhn) Validating --> Rejected_CarteT: invalid carte T format Validating --> Rejected_Conflict: email already exists Validating --> Created: all checks pass Created --> TokensIssued: access + refresh tokens minted TokensIssued --> SlackNotified: notifyProRegistration (fire-and-forget) SlackNotified --> [*]: 201 returned to client Rejected_SIRET --> [*] Rejected_CarteT --> [*] Rejected_Conflict --> [*]
Steps
1. Submit Registration Form (Actor: pro)
The pro sends a POST request to /pro/auth/register with the full registration payload. Rate limited to 3 requests per hour per IP.
Required fields: email, password, firstName, lastName, phone, siret, carteT, address, city, postalCode.
Optional: rcp, agencyName, jobTitle, latitude, longitude.
Triggers: Pro fills out registration form and submits Outcome: Request reaches the API handler
2. Validate SIRET and Carte T (Actor: system)
isValidSiret(siret) runs a Luhn check on the 14-digit SIRET. isValidCarteT(carteT) validates the CPI format (CPI XXXX YYYY 000 ZZZ ZZZ). Email is normalised to lowercase before the uniqueness check.
Triggers: Request passes JSON schema validation Outcome: 400 on failure; proceeds on pass
3. Create Pro Record (Actor: system)
Password is hashed via hashPassword. A Pro row is inserted. The isActive field defaults to true; cniVerifiedAt defaults to null.
Triggers: All validations pass Outcome: Pro record persisted in DB
4. Issue Tokens (Actor: system)
An access token (15 min, HS256, signed with PRO_JWT_SECRET) and a refresh token (7 days, 96-char opaque hex, SHA-256 hashed in DB) are issued. The refresh token is set as an httpOnly cookie (proRefreshToken, sameSite: lax). Device type is recorded as "web" for the initial registration token.
Triggers: Pro record created
Outcome: ProRefreshToken row inserted; tokens returned to client
5. Slack Notification (Actor: system)
notifyProRegistration(pro) posts to #pro-registration (channel env var SLACK_PRO_REGISTRATION_CHANNEL_ID) with the pro’s name, email, agency, SIRET, and a link to their admin fiche. The Slack message ts is stored in pro.slackThreadTs for future thread replies (CNI upload, AI analysis). This is fire-and-forget — errors are logged but do not affect the response.
Triggers: Pro record created
Outcome: Admin team alerted; slackThreadTs persisted
Error States
- Invalid SIRET → 400
INVALID_SIRET - Invalid carte T format → 400
INVALID_CARTE_T - Email already registered → 409
CONFLICT(generic message, does not confirm email existence) - Slack notification failure → logged, not surfaced to client
Related Processes
- login-session — the pro can now authenticate
- cni-upload-analysis — must upload CNI within 72h to avoid gate