- 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.
163 lines
4.1 KiB
Markdown
163 lines
4.1 KiB
Markdown
# 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
|