Aller au contenu

Front-end Domain Map

Apps

  • front-mobile-app : App investisseur principale (Expo/React Native). iOS + Android + Web
  • app-pdp-financement : App porteur de projet (espace financement). Même stack, scope plus réduit
  • storybook : Storybook pour uimmo et composants partagés

Modules

Module Scope
auth Login, signup, 2FA, auth social, reset password, invitation (token URL)
home Dashboard, propriétés mises en avant, actions rapides, revenus
project Détail d'un bien : overview, documents, news, charts, community
projects Liste des biens, filtres, recherche, projets financés
wallet Solde, top-up, retrait, historique transactions
boostedBalance Fonctionnalité solde boosté (gift balance)
onboarding KYC Lemonway, setup profil investisseur

Structure standard d'un module — s'inspirer de projects/front-mobile-app/src/modules/project/ comme référence :

modules/{feature}/
  screens/{Feature}Screen/
    {Feature}Screen.tsx              → Screen (compose les composants du module)
    index.ts
  components/{ComponentName}/
    {ComponentName}.tsx               → Smart (data fetching, hooks, logique)
    {ComponentName}UI.tsx             → Dumb (props only, présentation)
    {ComponentName}Loading.tsx        → Skeleton
    {ComponentName}UI.stories.tsx
    index.ts
  services/
    queryKeys.ts                      → Query keys scopées au module
    use{DataHook}.ts                  → Hooks React Query
  hooks/          → Hooks custom du module
  store/          → Zustand stores locaux
  types/
  utils/

Pas tous les dossiers sont obligatoires — un module simple peut n'avoir que screens/ et services/.

Quand un module a plusieurs screens avec sous-routes imbriquées, les composants partagés entre ces screens vont dans components/ au niveau du module (pas dupliqués dans chaque screen).

Legacy screens

src/screens/ contient les écrans legacy pas encore migrés vers modules/ : portfolio, purchaseBricks, wallet, marketplace, referral, giftCard, taxation, documents, account (information, security, about)

Nouvelles features = toujours dans src/modules/. Migration en cours.

Routes (Expo Router)

src/app/
  _layout.tsx                 → RootProvider (15+ providers) + RootContent
  (public)/                   → Auth (login, signup, forgot-password, reset-password, invitation)
  (authenticated)/
    _layout.tsx               → Providers authentifiés (user, feature flags, biometric)
    (tabs)/                   → Navigation bottom tabs
      index.tsx               → Home
      properties.tsx          → Liste biens
      portfolio/[tab].tsx     → Portfolio (onglets dynamiques)
      marketplace.tsx         → Marketplace
    account/                  → Paramètres compte (8 écrans)
    wallet/                   → Wallet (top-up, retrait, achat briques)
    onboarding/               → Flow KYC Lemonway
    properties/[id]/          → Détail bien (depuis liste)
    portfolio-project/[id]/   → Détail bien (depuis portfolio)

Groupes () = pas de segment URL. [id] = route dynamique.

Provider stack

Root layout imbrique ~15 providers (ordre = outer → inner). Pas de provider de thème : Uniwind passe par l'import core/theme/global.css en tête de _layout.tsx : Toast > SafeArea > ErrorBoundary > Datadog > ProductTracking > AdvertisingTracking > ReactQuery > GestureHandler > NavigationTracking > OTAUpdates > SessionGate > MandatoryLoader > Maintenance > ForceUpdate > NewVersion

Authenticated layout ajoute : User, FeatureFlags, Biometric, EmailVerification, NavigationModalCloser, FundingProgress, SensitiveAmounts

Impact : un hook n'est utilisable que dans le provider qui le fournit. L'ordre détermine les dépendances.

Packages partagés

Package Contenu
@bricks-common/uimmo Design system : 74+ composants (Text, Button, BottomSheetModal, SafeAreaBox, Icon...), helpers (cn, useModals, useCloseModal, triggerHapticFeedback, LinearGradient, SafeAreaView)
@bricks-common/api-communication Endpoints API, validators, types branded, ErrorCode. 28 domaines. Partagé front/back
@bricks-common/helpers Helpers purs partagés (array, date, string, number, object). NE PAS importer formatCurrency/formatPercentage côté front
@bricks-common-front/helpers Helpers front : schemaResolver, useCurrencyFormatter, usePercentageFormatter, Datadog, productTracking, i18n
@bricks-common-front/theme Thème Uniwind : spacing, colors, shadows, fonts, z-index. Génère uniwind-theme.css

Tokens du design system (source de vérité pour les valeurs disponibles) :

Token Fichier
Spacing projects/common/front/theme/src/spacing.ts
Colors projects/common/front/theme/src/colors/*.ts
Border radius projects/common/front/theme/src/border-radius.ts
Shadows projects/common/front/theme/src/shadow.ts
Fonts / Typography projects/common/front/theme/src/fonts.ts
Z-index projects/common/front/theme/src/z-index.ts
Breakpoints projects/common/front/theme/src/breakpoints.ts

Data flow

  1. API : customAxios + processHttpResult (valide la réponse, affiche toast erreur, log Datadog)
  2. Query keys : centralisées dans allStaticQueryKeys (par domaine)
  3. Hooks API : src/api/{domain}/use{Action}.ts ou src/modules/{module}/services/use{Action}.ts
  4. Endpoints : définis dans @bricks-common/api-communication, partagés avec le backend
  5. Auth : token JWT dans MMKV, vérifié dans RootContent pour guard routes
  6. Persistence queries : AsyncStorage (survit au restart app)

Import aliases (front-mobile-app)

Tous les aliases mobile-app sont prefixes @invest-* pour eviter les collisions avec app-pdp-financement.

Alias Cible
@invest-modules/* src/modules/* (le plus courant)
@invest-core/* src/core/* (providers, theme, i18n, api, config, storage, customerIO, biometric, date, logger)
@invest-shared/* src/shared/* (hooks, utils, services, components)
@invest-components/* src/shared/components/* (raccourci vers les composants partages)
@invest-assets/* assets/*
@invest-legacy/* src/legacy/* (ecrans pas encore migres vers modules/)

Priorité d'import : module local → @invest-modules@invest-shared / @invest-core@bricks-common

PDP (app-pdp-financement) : @modules, @shared (code sous src/), @assets / @pdp-assetsassets/ a la racine du projet (convention Expo, hors src).

PDP — groupes de modules

Une aire de l'app (= un route group app/(…)) est un groupe de modules, pas un module plat. Ex. modules/financing-management/ regroupe un sous-module par feature (home/, requests/, news/, documents/, users/…) + un shell/ qui porte le cadre partagé : utils/ (dont useNavItems, source unique des onglets), providers/SelectedProjectProvider, components/ (NavBar, Sidebar, ProjectsDropdown), et les écrans utilitaires non-feature dans screens/ (MoreScreen, HelpScreen). Les features dépendent de shell/ (jamais entre elles) ; les _layout.tsx câblent shell/ + les navigators Expo (Stack/Tabs, qui restent dans les route files). users/ (BRI-1785) : page Utilisateurs (liste + invitations + rôles) entre Documents et Compte ; tab toujours enabled (pas de requiresFinancedProject) ; invite/relance stubbées jusqu'à BRI-1784. Page publique invitation (BRI-1865) : /(public)/invitation?token= sous modules/auth/screens/InvitationScreen — validate + submit stubbés jusqu'à BRI-1784 ; session gate gère le post-accept.

modules/financing-request/ suit le même moule en variante wizard : un sous-module par step (presentation/, documents/, borrower/, analysis/, offer/, finalization/, signature/) + un shell/. La racine d'un groupe ne contient que les sous-modules (steps/features) + shell/ — jamais de components//services//types//store//utils/ à plat. Le transverse partagé du groupe vit sous shell/ : shell/providers/ (ProjectProvider), shell/components/ (chrome consommée par les _layout.tsx comme ProjectHeader+ProjectStepsBar, building blocks partagés comme BackToFunnelBanner, et FinancingStepContainer — layout steps 1–3 + signature avec side brut optionnel et FAB → Modal locale sous 2xl ; CTAs portal dans StepsBar uniquement ≥2xl), shell/services/ (logique de groupe non rattachée à un step — ici useValidateStep/useInvalidateStep, la progression du wizard), shell/utils/ (projectSteps, source unique de progression). Chaque step porte sa propre archi de module (<step>/components/, <step>/services/ + son queryKeys.ts, <step>/providers/, <step>/utils/) : un service consommé par un seul step vit dans <step>/services/. Au niveau module, pas de découpage par typologie hors services/ : hooks, types et utils vivent à plat dans <step>/utils/ (pas de hooks/ ni types/ séparés). Pas de dépendance entre steps : un service partagé monte dans shell/, jamais importé d'un autre step. Ce qui dépasse le groupe (utilisé aussi par auth, financing-management, app shell…) remonte au niveau app : primitives projet (useGetProject, useCreateProject, projectsStorage, clé project de @shared/services/queryKeys) dans @shared/services/, type Project dans @shared/types/, composants génériques (FormField, ProjectHeroBase, CheckboxCard, SelectCategoryModal, SelectDateModal) dans @shared/components/. App modules/shell ne doit pas importer les steps financing-request/*.

La coquille de l'app entière vit dans modules/shell/ (top-level, frère des groupes, pas un group-shell niché) : providers/ (toute la stack root câblée par app/_layout.tsx — Theme, ReactQuery, Datadog, CustomerIO, ProductTracking, SessionGate, MandatoryLoader, Maintenance, User, UserTracking ; authenticated ajoute ApporteurAffairesProvider — fake toggle DEV jusqu'au rôle API), screens/MaintenanceScreen, screens/NewProjectScreen (route authentifiée /new — AuthLayout + form de création 0 projet ; form partagé components/NewProjectForm aussi monté par components/modals/NewProjectModal depuis le dropdown / HomeHeader), components/InfoBanner, services/ (useMaintenanceChecker, useGetInfoBanner + leur queryKeys.ts). Importé via @modules/shell/…. Distinction de couche : modules/shell/ = chrome/infra qui wrappe toutes les routes (y compris (public)) ; shared/ reste le réutilisable générique cross-groupe (utils api/config/storage/theme/i18n, primitives projet, composants génériques).

Dans financing-management, l'index /(financing-management) redirige vers projects[0]/dashboard, ou vers /new si la liste est vide. L'option « Tous les projets » du dropdown est masquée via showAllProjectsOption={false} (le scope kind: 'all' reste supporté pour deep links / guards screens). Création d'un projet supplémentaire → openModal(NewProjectModal).

Concepts clés

  • Modules vs Screens : src/modules/ = architecture cible. src/screens/ = legacy. Toujours créer dans modules
  • Smart/Dumb : Screen complexe = Screen.tsx (smart, hooks, logique) + ScreenUI.tsx (dumb, props only, Storybook)
  • Uniwind : Système TailwindCSS-like pour React Native. Classes via className. cn() pour merge avec résolution de conflits
  • processHttpResult : Valide la réponse API contre le validator de l'endpoint, affiche notification erreur, retourne données typées
  • Montants : Toujours en centimes (cents). Les formatters (useCurrencyFormatter) divisent par 100 pour l'affichage
  • Feature flags : Fetchés via API, fournis par FeatureFlagsProvider. Vérifier le hook FF avant toute logique conditionnelle
  • Observabilité : Datadog. Erreurs auto-reportées via processHttpResult et ErrorBoundaryProvider. Sur web, beforeSend drop le bruit navigateur opaque (Script error., Outlook hosted webview, ResizeObserver, MetaMask, abort réseau) — shouldDiscardBrowserNoiseLog
  • Design system : Vit dans Figma. Composants uimmo matchent les noms Figma. Toujours vérifier uimmo avant de créer un nouveau primitif UI

Maintenance

Quand tu modifies la structure des modules, les routes, ou les providers : mettre à jour ce fichier.