Bonjour, bonsoir

Je suis en train de réaliser une app react native et je me pose pas mal de questions sur comment organiser mon projet, j'aimerais respecter une structure assez clean, mais je suis un peu perdu avec tout ce que j'ai pu lire sur internet, j'ai pas mal de fonctionnalités donc je veux quelque chose d'assez carré.

J'ai pensé à une structure mélangeant à la fois la vertical slice archi et la clean archi (avec les Domain, Application, Infrastructure), mais ça pose question à la fois sur les principes DRY, KISS et SOLID et simplement sur où mettre mon frontend, toute la complexité de l'histoire c'est que je veux utiliser Expo Router, avec des tabs, il y aurait aussi des drawers.

Je dois donc créer un dossier nommé comme ceci : (tabs), où mettre mes autres écrans ? Par rapport à la logique métier etc..

/src
├── /modules
│   ├── /application
│   │   ├── /auth
│   │   │   ├── loginUseCase.ts
│   │   │   ├── signupUseCase.ts
│   │   │   └── logoutUseCase.ts
│   │   ├── /profile
│   │   │   ├── updateAvatarUseCase.ts
│   │   │   ├── changePasswordUseCase.ts
│   │   │   ├── deleteAccountUseCase.ts
│   │   │   ├── addBoatUseCase.ts
│   │   │   └── updateBioUseCase.ts
│   │   ├── /boats
│   │   │   ├── createBoatUseCase.ts
│   │   │   ├── updateBoatUseCase.ts
│   │   │   └── deleteBoatUseCase.ts
│   ├── /domain
│   │   ├── /auth
│   │   │   └── authRepository.ts
│   │   ├── /profile
│   │   │   └── profileRepository.ts
│   │   ├── /boats
│   │   │   └── boatRepository.ts
│   ├── /infrastructure
│   │   ├── /auth
│   │   │   └── authRepositorySupabase.ts
│   │   ├── /profile
│   │   │   └── profileRepositorySupabase.ts
│   │   ├── /boats
│   │   │   └── boatRepositorySupabase.ts

Un exemple de la structure que je comlpte utiliser, déjà qu'en pensez-vous ?

Je suis preneur de vos suggestions / idées d'optimisation pour mieux structurer mon code, j'ai cherché sur internet, mais je n'ai pas trouvé de documentation suffisamment pertinente qui expliquerait ça.
Ce que j'ai retenu c'est qu'il n'existe pas de bonnes ou de mauvaises structure, ce qui rend la tâche d'autant plus complexe.

C'est quelque chose qui doit être maintenu facilement dans le temps, j'aimerais pouvoir y intégrer des tests ainsi que de la validation, avec Zod par exemple

à chaque fois que j'ajoute une nouvelle pierre je suis perdu sur où la placer casser ma structure.

les fichiers Supabase contiendront les "requêtes" pour parler au SDK de supabase, et les repository toutes la partie modelisations DTO etc..

et mes usecase jouant le rôle de "controller" reception de requête par le front etc..

Merci pour vos réponses

3 réponses


Smith john
Réponse acceptée

ca semble plutot pas mal, ton archi. pour le dossier (tabs), tu peux le gerer simplement je pense en appelant simplement tes vues, un peu comme cela.

app                            
├── _layout.tsx                
├── (tabs)                      
│   ├── _layout.tsx
│   ├── index.tsx               # Vue principale
│   ├── profile.tsx             # Vue du profil
│   └── settings.tsx            # Vue des paramètres
modules
├── /application                
│   ├── /auth                   
│   │   ├── loginUseCase.ts     
│   │   ├── signupUseCase.ts    
│   │   └── logoutUseCase.ts    
│   ├── /profile                
│   │   ├── updateAvatarUseCase.ts 
│   │   └── changePasswordUseCase.ts 
│   └── /boats                 
│       ├── createBoatUseCase.ts 
│       └── deleteBoatUseCase.ts 
├── /domain                    
│   ├── /auth                   
│   │   ├── AuthEntity.ts       # Entité Auth
│   │   └── AuthRepository.ts   # Interface du repository d'authentification
│   ├── /profile               
│   │   ├── ProfileEntity.ts    # Entité Profile
│   │   └── ProfileRepository.ts # Interface du repository de profil
│   └── /boats                  
│       ├── BoatEntity.ts       # Entité Boat
│       └── BoatRepository.ts   # Interface du repository des bateaux
├── /infrastructure             
│   ├── /auth                   
│   │   └── AuthRepositorySupabase.ts 
│   ├── /profile               
│   │   └── ProfileRepositorySupabase.ts 
│   └── /boats                  
│       └── BoatRepositorySupabase.ts
├── /hooks                      
│   ├── useAuth.ts              
│   ├── useProfile.ts           
│   └── useBoats.ts             
├── /components                 
│   ├── Button.tsx              
│   ├── Input.tsx               
│   └── ProfileCard.tsx         
├── /views                      
│   ├── ProfileView.tsx        
│   └── SettingsView.tsx       
├── /tests                      # Tests unitaires et d'intégration
│   ├── /application            # Tests des cas d'utilisation
│   │   ├── loginUseCase.test.ts
│   │   ├── signupUseCase.test.ts
│   │   └── updateAvatarUseCase.test.ts
│   ├── /components             # Tests des composants
│   │   ├── Button.test.tsx
│   │   └── ProfileCard.test.tsx
│   └── /hooks                  # Tests des hooks
│       ├── useAuth.test.ts
│       └── useProfile.test.ts
└── /utils                     
        ├── api.ts                 
        └── formatDate.ts          
Laznet
Auteur
Réponse acceptée

J'ai trouvé répones à ma question tout seul, mais je la publie ici si jamais quelqu'un passe ici :

On peut utiliser zod pour à la fois mapper nos données (donc un DTO) et en même les valider, zod peut tranformer les données, il exploitera notre entity comme "model interne" et transformera nos données entrante vers nos données interne :

Dans ce code je souhaite transformer email en adresseEmail et _id en id

l'idée derrière est de ne pas être dépendant de la structure du back et d'avoir ma propre structure, (donc en cas de changement de backend, pas besoin de changer tous le code)

import { z } from 'zod';

// Schéma Zod pour valider et transformer les données venant de Supabase
const userSchema = z.object({
  _id: z.string(), // Nom du champ venant du backend
  email: z.string().email(), // Validation que 'email' est une adresse valide
}).transform(data => ({
  id: data._id,            // Transformation du champ _id en id
  adresseEmail: data.email, // Transformation du champ email en adresseEmail
}));

// Exemple de données venant de Supabase
const userFromSupabase = {
  _id: 'user123',   // Identifiant venant de Supabase
  email: 'user@example.com', // Email venant de Supabase
};

// Valider et transformer les données avec Zod
const parsedUser = userSchema.parse(userFromSupabase);

// Créer une instance de l'entité User avec les données transformées
const userEntity = new User(parsedUser.id, parsedUser.adresseEmail);

console.log(userEntity); // Affiche l'instance de l'entité User
Laznet
Auteur

Je te remercie pour ta réponse, c'est un peu plus clair :)

Donc dans views ce serait les vues qui ne s'afficheraient pas dans le tabs (les vues type details) et si à temre j'ai besoin de définir différents tabs je pourrais utiliser la structure recommandé par Expo Router

donc parfait :)

Laznet
Auteur

Seule petite interrogation, à quel endroit je pourrais implémenter mon mapping de donnée (similaire à un DTO) j'ai compris que entity représente mon "model", mais si demain je souhaite changer de back j'aimerais être indépendant de supabase.

Je veux bien tes conseils à ce sujet