Apparence
UserProfile
Données personnelles (PII) de l'utilisateur et ses paramètres de facturation. Isolé dans une sous-collection pour faciliter les exports/suppressions RGPD et appliquer des règles Firestore distinctes.
- Path Firestore :
users/{userId}/profile/main - Doc unique, ID fixe
main - Source TS :
klapy-crm/src/types/index.ts
Interface
ts
interface UserProfile {
first_name?: string;
last_name?: string;
commercial_name?: string;
phone?: string;
siret?: string;
address?: Address;
logo_url?: string;
professions?: Profession[];
/** @deprecated remplacé par `professions`, lu en fallback via readProfileProfessions() */
videographer_type?: string;
tva_rate?: number;
tva_exempt?: boolean;
tva_mention?: string;
quote_prefix?: string;
invoice_prefix?: string;
payment_conditions?: string;
validity_days?: number;
footer_text?: string;
general_conditions?: string;
updated_at: Timestamp;
}Champs
| Champ | Notes |
|---|---|
commercial_name | Nom affiché sur les devis et factures, peut différer du nom légal |
siret | 14 chiffres, pas validé à l'écriture, à valider en UI |
address | Adresse postale, voir sous-objet ci-dessous |
logo_url | URL Firebase Storage du logo, affiché en haut des PDF |
professions | Métiers de l'utilisateur (multi-valué). Énumération unifiée Profession, partagée avec Contact.trades |
videographer_type | Déprécié. Ancien champ string mono-valué. Lu en fallback (readProfileProfessions()) puis effacé au prochain enregistrement du profil |
tva_rate | Taux par défaut appliqué aux nouvelles lignes (ex. 20) |
tva_exempt | Si true, mention « TVA non applicable, art. 293 B du CGI » |
tva_mention | Mention légale custom utilisée si tva_exempt |
quote_prefix | Préfixe des numéros de devis (ex. DEV-) |
invoice_prefix | Préfixe des numéros de facture (ex. FACT-) |
payment_conditions | Conditions de règlement par défaut, texte libre |
validity_days | Validité par défaut des nouveaux devis, en jours |
footer_text | Pied de page imprimé sur tous les documents |
general_conditions | CGV en texte libre, imprimées en bas de chaque devis |
Sous-objet Address
ts
interface Address {
street?: string;
city?: string;
postal_code?: string;
country?: string;
}Tous les champs sont optionnels. Stocké en inline, jamais en document Firestore séparé.
Pourquoi cette sous-collection ?
La séparation UserAccount ↔ UserProfile n'est pas cosmétique : elle permet à la Cloud Function exportUserData de zipper le profil en un seul read, à deleteUserAccount de supprimer toutes les PII en une opération, et à firestore.rules de définir des règles plus strictes sur le profil que sur le compte. Ne jamais déplacer un champ de l'un à l'autre sans réviser les rules et les Cloud Functions RGPD.
Constantes liées
PROFESSION
Énumération unifiée des métiers, partagée entre :
UserProfile.professions— les métiers que l'utilisateur exerce lui-mêmeContact.trades— les métiers techniques d'un collaborateur
49 valeurs, regroupées par famille :
| Famille | Valeurs |
|---|---|
| Écriture / pré-prod | screenwriter, script_supervisor, casting_director, location_scout |
| Vidéaste / réalisation | videographer, director, producer, assistant_director, production_assistant, production_agency, live_director, event_planner |
| Image | cameraman, focus_puller, camera_assistant, dop, photographer, drone_pilot, gaffer, grip, dit |
| Post-production | editor, colorist, motion_designer, vfx_artist, animator, three_d_artist, subtitler |
| Son | sound_engineer, sound_mixer, sound_designer, composer, voice_over_artist |
| Plateau / talents | mua, stylist, set_designer |
| Design / illustration | graphic_designer, web_designer, illustrator, painter |
| Marketing / contenu | copywriter, content_creator, social_media_manager, marketing_manager |
| Musique | musician, dj, singer |
| Tech / autres | developer, other |
Pourquoi unifié ?
Avant : deux énumérations distinctes (VIDEOGRAPHER_TYPE côté profil utilisateur, CONTACT_TRADE côté contacts). Désormais une seule liste — un utilisateur peut être editor, un contact collaborateur aussi. Le helper readProfileProfessions(profile) lit profile.professions ?? mapLegacy(profile.videographer_type) et retourne toujours un Profession[].
Migration de données
Les profils créés avant l'unification continuent d'avoir un videographer_type: string. Le client lit en fallback via readProfileProfessions(), puis écrit professions: [...] + videographer_type: null au premier enregistrement du profil. Tant qu'il reste des profils legacy non sauvegardés, ne pas supprimer la mapping LEGACY_VIDEOGRAPHER_TYPE_TO_PROFESSION ni le champ videographer_type de firestore.rules.
Voir aussi
UserAccount: compte parentContact: utilise la même énumérationPROFESSIONviatradesCompany: utilise aussi le sous-objetAddress- Cloud Functions :
exportUserData,deleteUserAccount - RGPD (à rédiger)