- Enhanced skill category syncing by ensuring id and name properties are included, boosting data integrity. - Cleaned up admin exports related to skill categories for better maintainability.
167 lines
4.4 KiB
Markdown
167 lines
4.4 KiB
Markdown
# PeakSkills - Architecture et Organisation du Code
|
|
|
|
## Structure du Projet
|
|
|
|
```
|
|
peakSkills/
|
|
├── app/ # Pages Next.js et routes API
|
|
├── clients/ # Clients HTTP pour les appels externes
|
|
│ ├── base/ # Client HTTP de base
|
|
│ └── domains/ # Clients par domaine métier
|
|
├── components/ # Composants React
|
|
│ ├── ui/ # Composants UI réutilisables
|
|
│ └── [feature]/ # Composants spécifiques aux features
|
|
├── services/ # Services métier
|
|
├── lib/ # Types et utilitaires partagés
|
|
├── hooks/ # Hooks React personnalisés
|
|
├── scripts/ # Scripts utilitaires
|
|
│ └── migrations/ # Scripts de migration
|
|
├── data/ # Données statiques
|
|
└── styles/ # Styles globaux
|
|
```
|
|
|
|
## Règles de Structure
|
|
|
|
### 1. Clients HTTP (`clients/`)
|
|
|
|
- Toute la logique d'appels HTTP doit être encapsulée dans des clients dédiés
|
|
- Chaque domaine métier a son propre client (ex: `auth-client.ts`, `skills-client.ts`)
|
|
- Les clients utilisent le client de base (`http-client.ts`) pour les appels
|
|
- Les clients ne contiennent que la logique d'appel, pas de logique métier
|
|
|
|
Exemple :
|
|
|
|
```typescript
|
|
// clients/domains/skills-client.ts
|
|
export class SkillsClient {
|
|
constructor(private httpClient: HttpClient) {}
|
|
|
|
async getSkills(): Promise<Skill[]> {
|
|
return this.httpClient.get("/api/skills");
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Services Backend (`services/`)
|
|
|
|
- SEULE couche autorisée à faire des requêtes PostgreSQL
|
|
- Contiennent toute la logique métier et d'accès aux données
|
|
- Implémentent une interface claire
|
|
- Organisés par domaine métier
|
|
- Gèrent les transactions
|
|
- Valident les données
|
|
- Utilisent le pool de connexion de database.ts
|
|
|
|
Exemple :
|
|
|
|
```typescript
|
|
// services/skills-service.ts
|
|
export interface ISkillsService {
|
|
getSkillsByCategory(category: string): Promise<Skill[]>;
|
|
}
|
|
|
|
export class SkillsService implements ISkillsService {
|
|
constructor(private pool: Pool) {}
|
|
|
|
async getSkillsByCategory(category: string): Promise<Skill[]> {
|
|
const query = `
|
|
SELECT s.*, c.name as category_name
|
|
FROM skills s
|
|
JOIN skill_categories c ON s.category_id = c.id
|
|
WHERE c.id = $1
|
|
`;
|
|
|
|
const result = await this.pool.query(query, [category]);
|
|
return result.rows;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Composants (`components/`)
|
|
|
|
- Composants UI réutilisables dans `ui/`
|
|
- Composants spécifiques dans leur dossier feature
|
|
- Export via `index.ts`
|
|
- Utilisation de TypeScript (`.tsx`)
|
|
|
|
### 4. Pages (`app/`)
|
|
|
|
- Structure selon le routing Next.js
|
|
- Utilisation des composants
|
|
- Pas de logique métier directe
|
|
|
|
### 5. Types (`lib/`)
|
|
|
|
- Types partagés dans `types.ts`
|
|
- Types spécifiques dans `[domain]-types.ts`
|
|
- Interfaces commencent par "I"
|
|
|
|
## Bonnes Pratiques
|
|
|
|
1. **Séparation des Responsabilités**
|
|
- Les composants gèrent l'UI
|
|
- Les services gèrent la logique métier
|
|
- Les clients gèrent les appels HTTP
|
|
|
|
2. **Typage**
|
|
- Tout doit être typé
|
|
- Utiliser des interfaces pour les contrats
|
|
- Éviter `any`
|
|
|
|
3. **Organisation du Code**
|
|
- Un fichier = une responsabilité
|
|
- Export via `index.ts`
|
|
- Documentation en français
|
|
|
|
4. **Tests**
|
|
- Tests unitaires à côté du code
|
|
- Tests d'intégration dans `__tests__`
|
|
- Mocks dans `__mocks__`
|
|
|
|
## Patterns à Éviter
|
|
|
|
❌ Ne pas mettre de logique métier dans les composants
|
|
❌ Ne pas faire d'appels HTTP directs
|
|
❌ Ne pas dupliquer les types
|
|
❌ Ne pas mélanger les responsabilités
|
|
|
|
## Exemples
|
|
|
|
### ✅ Bon Pattern
|
|
|
|
```typescript
|
|
// components/skills/SkillList.tsx
|
|
export const SkillList = () => {
|
|
const { skills } = useSkills(); // Hook personnalisé
|
|
return <div>{skills.map(skill => <SkillCard skill={skill} />)}</div>;
|
|
};
|
|
|
|
// hooks/useSkills.ts
|
|
export const useSkills = () => {
|
|
const skillsService = useSkillsService();
|
|
const [skills, setSkills] = useState<Skill[]>([]);
|
|
|
|
useEffect(() => {
|
|
skillsService.getSkills().then(setSkills);
|
|
}, []);
|
|
|
|
return { skills };
|
|
};
|
|
```
|
|
|
|
### ❌ Mauvais Pattern
|
|
|
|
```typescript
|
|
// components/skills/SkillList.tsx
|
|
export const SkillList = () => {
|
|
const [skills, setSkills] = useState<Skill[]>([]);
|
|
|
|
useEffect(() => {
|
|
// ❌ Appel HTTP direct dans le composant
|
|
fetch('/api/skills').then(res => res.json()).then(setSkills);
|
|
}, []);
|
|
|
|
return <div>{skills.map(skill => <SkillCard skill={skill} />)}</div>;
|
|
};
|
|
```
|