Files
peakskills/README.md
Julien Froidefond 03d49aa16a fix: improve skill category syncing and data structure
- 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.
2025-08-26 13:21:08 +02:00

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>;
};
```