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:
162
ARCHITECTURE.md
Normal file
162
ARCHITECTURE.md
Normal 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
|
||||
Reference in New Issue
Block a user