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.
This commit is contained in:
Julien Froidefond
2025-08-26 13:21:08 +02:00
parent 9d11a725d7
commit 03d49aa16a
8 changed files with 491 additions and 0 deletions

162
ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,162 @@
# Architecture PeakSkills
## Principes Fondamentaux
### 1. Services (Backend)
- ✅ TOUTES les requêtes PostgreSQL DOIVENT être dans les services/
- ✅ Les services sont la SEULE couche autorisée à communiquer avec la base de données
- ✅ Chaque service doit avoir une interface claire
- ✅ Les services doivent gérer les transactions
- ✅ Les services doivent logger les erreurs
- ✅ Les services doivent valider les données avant insertion
- ❌ AUCUNE requête SQL en dehors des services
### 2. Routes API (Backend)
- ✅ Les routes API doivent UNIQUEMENT utiliser les services
- ✅ Les routes doivent gérer la validation des entrées
- ✅ Les routes doivent retourner des réponses typées
- ❌ AUCUNE requête SQL directe dans les routes
### 3. Clients HTTP (Frontend)
- ✅ Les appels HTTP doivent être dans clients/domains/
- ✅ Chaque domaine a son propre client
- ✅ Les clients doivent typer leurs réponses
- ❌ AUCUNE logique métier dans les clients
### 4. Components (Frontend)
- ✅ UI réutilisable dans components/ui/
- ✅ Composants feature dans leur dossier dédié
- ✅ Export via index.ts
- ❌ AUCUN appel direct aux services
## Exemple d'Architecture
### Service (Backend)
```typescript
// services/skills-service.ts
export class SkillsService {
constructor(private pool: Pool) {}
async getSkillsByCategory(categoryId: string): Promise<Skill[]> {
const client = await this.pool.connect();
try {
await client.query("BEGIN");
const result = await client.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
`,
[categoryId]
);
await client.query("COMMIT");
return result.rows;
} catch (error) {
await client.query("ROLLBACK");
logger.error("Failed to get skills by category", { error, categoryId });
throw new DatabaseError("Failed to get skills");
} finally {
client.release();
}
}
}
```
### Route API
```typescript
// app/api/skills/[categoryId]/route.ts
import { SkillsService } from "@/services/skills-service";
export async function GET(
request: Request,
{ params: { categoryId } }: { params: { categoryId: string } }
) {
try {
const skillsService = new SkillsService(pool);
const skills = await skillsService.getSkillsByCategory(categoryId);
return Response.json(skills);
} catch (error) {
return Response.error();
}
}
```
### Client HTTP (Frontend)
```typescript
// clients/domains/skills-client.ts
export class SkillsClient {
constructor(private httpClient: HttpClient) {}
async getSkillsByCategory(categoryId: string): Promise<Skill[]> {
return this.httpClient.get(`/api/skills/${categoryId}`);
}
}
```
### Composant (Frontend)
```typescript
// components/skills/SkillList.tsx
export const SkillList = ({ categoryId }: { categoryId: string }) => {
const { skills, loading } = useSkills(categoryId);
if (loading) return <Spinner />;
return (
<div>
{skills.map(skill => (
<SkillCard key={skill.id} skill={skill} />
))}
</div>
);
};
```
### Hook (Frontend)
```typescript
// hooks/useSkills.ts
export const useSkills = (categoryId: string) => {
const skillsClient = useSkillsClient();
const [skills, setSkills] = useState<Skill[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
skillsClient
.getSkillsByCategory(categoryId)
.then(setSkills)
.finally(() => setLoading(false));
}, [categoryId]);
return { skills, loading };
};
```
## Validation de l'Architecture
Pour s'assurer que l'architecture est respectée :
1. **Review de Code**
- Vérifier qu'aucune requête SQL n'est en dehors des services
- Vérifier que les composants n'accèdent pas directement aux services
- Vérifier que les types sont correctement utilisés
2. **Tests**
- Tests unitaires pour les services
- Tests d'intégration pour les routes API
- Tests de composants pour le frontend
3. **Monitoring**
- Logger les erreurs de service
- Monitorer les performances des requêtes
- Tracer les appels API