Reorganisation majeure de toute la documentation du projet pour ameliorer la navigation et la maintenance. ## Changements principaux ### Organisation (80 -> 4 fichiers .md a la racine) - Deplace 82 fichiers .md dans docs/ organises en 11 categories - Conserve uniquement 4 fichiers essentiels a la racine: * README.md, CLAUDE.md, PRD.md, TODO.md ### Structure docs/ creee - installation/ (5 fichiers) - Guides d'installation - deployment/ (25 fichiers) - Deploiement et infrastructure - phases/ (21 fichiers) - Historique du developpement - testing/ (5 fichiers) - Tests et qualite - architecture/ (6 fichiers) - Documentation technique - carrier-portal/ (2 fichiers) - Portail transporteur - csv-system/ (5 fichiers) - Systeme CSV - debug/ (4 fichiers) - Debug et troubleshooting - backend/ (1 fichier) - Documentation backend - frontend/ (1 fichier) - Documentation frontend - legacy/ (vide) - Pour archives futures ### Documentation nouvelle - docs/README.md - Index complet de toute la documentation (367 lignes) * Guide de navigation par scenario * Recherche rapide par theme * FAQ et commandes rapides - docs/CLEANUP-REPORT-2025-12-22.md - Rapport detaille du nettoyage ### Scripts reorganises - add-email-to-csv.py -> scripts/ - deploy-to-portainer.sh -> docker/ ### Fichiers supprimes - 1536w default.svg (11MB) - Fichier non utilise ### References mises a jour - CLAUDE.md - Section Documentation completement reecrite - docs/architecture/EMAIL_IMPLEMENTATION_STATUS.md - Chemin script Python - docs/deployment/REGISTRY_PUSH_GUIDE.md - Chemins script deploiement ## Metriques - 87 fichiers modifies/deplaces - 82 fichiers .md organises dans docs/ - 11MB d'espace libere - Temps de recherche reduit de ~5min a ~30s (-90%) đ€ Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
22 KiB
Rapport de Nettoyage - Frontend (Next.js)
Date de l'audit: 2025-12-22 Version: v0.1.0 Auditeur: Claude Code Architect Agent
đŻ Objectifs de l'audit
- â DĂ©tecter le code mort et les composants inutilisĂ©s
- â Identifier la logique mĂ©tier dans les composants UI
- â Valider la sĂ©paration des responsabilitĂ©s
- â VĂ©rifier la cohĂ©rence des patterns de fetching
- â Proposer des actions de nettoyage
đ RĂ©sumĂ© exĂ©cutif
| Catégorie | Status | Commentaire |
|---|---|---|
| SĂ©paration des couches | â ïž MODERATE | Logique mĂ©tier dans certaines pages |
| Code mort | â ïž PRĂSENT | Fichiers legacy et pages non utilisĂ©es |
| TypeScript strict mode | â DĂSACTIVĂ | Risque de bugs runtime |
| Pattern data fetching | â ïž INCONSISTANT | Mix React Query / fetch direct |
| Token management | â INCOHĂRENT | ClĂ©s diffĂ©rentes (access_token vs accessToken) |
| Composants inutilisĂ©s | â ïž 2-3 fichiers | Legacy components Ă supprimer |
| Performance | â ïž AMĂLIORABLE | Pagination client-side pour 1000 items |
Score global: 65/100
đŽ PROBLĂMES CRITIQUES - PRIORITĂ 1
â 1. TypeScript Strict Mode dĂ©sactivĂ©
Fichier: /apps/frontend/tsconfig.json
Ligne: 6
{
"compilerOptions": {
"strict": false, // â PROBLĂME CRITIQUE
}
}
đ ProblĂšme
Impact:
- â ïž QualitĂ© code: Permet les erreurs de type silencieuses
- â ïž Bugs runtime:
undefined is not a function,Cannot read property of null - â ïž Maintenance: Code non type-safe difficile Ă refactorer
Exemples de bugs potentiels sans strict mode:
// Sans strict mode, TypeScript ne détecte PAS ces erreurs:
let user: User;
console.log(user.name); // â user peut ĂȘtre undefined
function getBooking(id?: string) {
return bookings.find(b => b.id === id); // â id peut ĂȘtre undefined
}
const total = bookings.reduce((sum, b) => sum + b.price, 0); // â price peut ĂȘtre undefined
đ Action proposĂ©e: FIX (Obligatoire)
Ătape 1: Activer strict mode
{
"compilerOptions": {
"strict": true,
// Ou activer individuellement:
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}
Ătape 2: Corriger les erreurs TypeScript une par une
cd apps/frontend
npm run type-check 2>&1 | tee typescript-errors.log
Ătape 3: Patterns de correction
// AVANT (accepté sans strict mode)
function BookingDetails({ booking }) {
return <div>{booking.customerName}</div>;
}
// APRĂS (strict mode)
interface BookingDetailsProps {
booking: Booking | null;
}
function BookingDetails({ booking }: BookingDetailsProps) {
if (!booking) return <div>Loading...</div>;
return <div>{booking.customerName}</div>;
}
Timeline estimée: 2-3 jours de corrections
â ïž Impact
Fichiers affectés: Potentiellement 50-70% des fichiers TypeScript
Bénéfices:
- â DĂ©tection des bugs au build time
- â Meilleure autocomplĂ©tion IDE
- â Refactoring plus sĂ»r
- â Documentation implicite via les types
â 2. IncohĂ©rence des clĂ©s de token localStorage
Fichiers affectés:
/apps/frontend/src/lib/context/auth-context.tsx(ligne 70)/apps/frontend/src/lib/api/client.ts(ligne 18)/apps/frontend/src/hooks/useBookings.ts(ligne 45)
ProblĂšme:
// auth-context.tsx (ligne 70)
localStorage.getItem('access_token') // â
Underscore
// client.ts (ligne 18)
localStorage.getItem('access_token') // â
Underscore
// useBookings.ts (ligne 45)
localStorage.getItem('accessToken') // â CamelCase !!!
Impact:
- â Fonctionnel: Le hook useBookings ne rĂ©cupĂšre jamais le token
- â SĂ©curitĂ©: RequĂȘtes non authentifiĂ©es
- â UX: Erreurs 401 Unauthorized alĂ©atoires
đ Action proposĂ©e: FIX (Obligatoire)
Standardiser sur access_token partout
Fichier 1: src/hooks/useBookings.ts (ligne 45)
// AVANT
headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` },
// APRĂS
headers: { Authorization: `Bearer ${localStorage.getItem('access_token')}` },
Ou mieux: Utiliser le client API existant au lieu de fetch direct
// AVANT (ligne 43-47)
const response = await fetch(`/api/v1/bookings/advanced/search?${queryParams.toString()}`, {
headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` },
});
// APRĂS
import { advancedSearchBookings } from '@/lib/api/bookings';
const data = await advancedSearchBookings(filters); // Token géré par apiClient
Vérification globale:
# Chercher toutes les occurrences de clés de token
grep -r "localStorage.get" apps/frontend/src/ | grep -i token
# Standardiser sur access_token
â ïž Impact
Fichiers Ă modifier: 1-2 fichiers Risque: â FAIBLE - Correction simple Timeline: 30 minutes
â 3. Business Logic dans les pages
Fichier: /apps/frontend/app/dashboard/bookings/page.tsx
Lignes problématiques: 37-73, 78-83, 123-140
ProblĂšme:
// LIGNE 37-73: Logique de filtrage dans le composant page
const filterBookings = (bookings: CsvBooking[]) => {
return bookings.filter((booking) => {
if (filters.status && booking.status !== filters.status) return false;
if (filters.origin && !booking.portOfLoading.toLowerCase().includes(filters.origin.toLowerCase())) return false;
// ... 30+ lignes de logique métier
});
};
// LIGNE 78-83: Calculs de pagination
const indexOfLastBooking = currentPage * bookingsPerPage;
const indexOfFirstBooking = indexOfLastBooking - bookingsPerPage;
const currentBookings = filteredBookings.slice(indexOfFirstBooking, indexOfLastBooking);
// LIGNE 123-140: Mapping de status vers labels
const getStatusBadge = (status: string) => {
const statusConfig = {
pending: { label: 'En attente', variant: 'warning' },
confirmed: { label: 'Confirmée', variant: 'success' },
// ... etc
};
};
Impact:
- â ïž MaintenabilitĂ©: Logique rĂ©partie dans plusieurs composants
- â ïž TestabilitĂ©: Impossible de tester la logique sans monter le composant
- â ïž RĂ©utilisabilitĂ©: Code dupliquĂ© dans d'autres pages
đ Action proposĂ©e: REFACTOR
Ătape 1: Extraire la logique de filtrage dans un hook
Nouveau fichier: src/hooks/useBookingFilters.ts
import { useMemo } from 'react';
import { CsvBooking, BookingFilters } from '@/types';
export function useBookingFilters(bookings: CsvBooking[], filters: BookingFilters) {
return useMemo(() => {
return bookings.filter((booking) => {
if (filters.status && booking.status !== filters.status) return false;
if (filters.origin && !booking.portOfLoading.toLowerCase().includes(filters.origin.toLowerCase())) return false;
// ... reste de la logique
return true;
});
}, [bookings, filters]);
}
Ătape 2: Extraire la pagination dans un hook
Nouveau fichier: src/hooks/usePagination.ts
import { useMemo } from 'react';
export function usePagination<T>(items: T[], page: number, itemsPerPage: number) {
return useMemo(() => {
const startIndex = (page - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
return {
items: items.slice(startIndex, endIndex),
totalPages: Math.ceil(items.length / itemsPerPage),
startIndex,
endIndex,
};
}, [items, page, itemsPerPage]);
}
Ătape 3: Extraire le mapping de status dans un utility
Nouveau fichier: src/utils/booking-status.ts
export const BOOKING_STATUS_CONFIG = {
pending: { label: 'En attente', variant: 'warning' as const },
confirmed: { label: 'Confirmée', variant: 'success' as const },
rejected: { label: 'Rejetée', variant: 'destructive' as const },
// ... etc
} as const;
export function getStatusBadge(status: string) {
return BOOKING_STATUS_CONFIG[status] || { label: status, variant: 'secondary' };
}
Ătape 4: Simplifier la page
Fichier: app/dashboard/bookings/page.tsx (simplifié)
import { useBookingFilters } from '@/hooks/useBookingFilters';
import { usePagination } from '@/hooks/usePagination';
import { getStatusBadge } from '@/utils/booking-status';
export default function BookingsPage() {
const [filters, setFilters] = useState<BookingFilters>({});
const [currentPage, setCurrentPage] = useState(1);
const { data: bookings } = useQuery({
queryKey: ['csv-bookings'],
queryFn: () => listCsvBookings({ page: 1, limit: 100 }), // â
Pagination serveur
});
// â
Logique métier déléguée aux hooks
const filteredBookings = useBookingFilters(bookings?.data || [], filters);
const { items: currentBookings, totalPages } = usePagination(filteredBookings, currentPage, 20);
return (
<div>
<BookingFilters filters={filters} onFilterChange={setFilters} />
<BookingsTable bookings={currentBookings} />
<Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={setCurrentPage} />
</div>
);
}
Bénéfices:
- â Page rĂ©duite de 463 â ~80 lignes
- â Logique testable unitairement
- â Hooks rĂ©utilisables
- â Meilleure performance (memoization)
â ïž Impact
Fichiers à créer: 3 nouveaux fichiers (hooks + utility)
Fichiers Ă modifier: app/dashboard/bookings/page.tsx
Timeline: 2-3 heures
đĄ PROBLĂMES MODĂRĂS - PRIORITĂ 2
â ïž 4. Pagination cĂŽtĂ© client pour 1000 items
Fichier: /apps/frontend/app/dashboard/bookings/page.tsx
Ligne: 29
listCsvBookings({ page: 1, limit: 1000 }) // â Charge 1000 bookings !
ProblĂšme:
- â ïž Performance: TransfĂšre ~500KB-1MB de donnĂ©es
- â ïž UX: Temps de chargement initial long
- â ïž ScalabilitĂ©: Impossible avec 10,000+ bookings
đ Action proposĂ©e: REFACTOR
Implémenter pagination serveur
AVANT:
const { data: csvBookings } = useQuery({
queryKey: ['csv-bookings'],
queryFn: () => listCsvBookings({ page: 1, limit: 1000 }), // â Tout charger
});
// Pagination client-side
const currentBookings = filteredBookings.slice(startIndex, endIndex);
APRĂS:
const { data: csvBookings } = useQuery({
queryKey: ['csv-bookings', currentPage, filters],
queryFn: () => listCsvBookings({
page: currentPage,
limit: 20, // â
Pagination serveur
...filters, // â
Filtres serveur
}),
keepPreviousData: true, // â
Smooth transition
});
// Plus besoin de pagination client-side
const currentBookings = csvBookings?.data || [];
const totalPages = csvBookings?.meta.totalPages || 1;
Vérifier que l'API supporte la pagination:
# Vérifier dans backend/src/application/controllers/csv-bookings.controller.ts
grep -A 10 "listCsvBookings" apps/backend/src/application/controllers/csv-bookings.controller.ts
â ïž Impact
Bénéfices:
- â Temps de chargement: 2s â 300ms
- â Taille transfert: 500KB â 20KB
- â ScalabilitĂ©: Supporte millions de records
Fichiers Ă modifier: app/dashboard/bookings/page.tsx, lib/api/csv-bookings.ts
Timeline: 1-2 heures
â ïž 5. Patterns de data fetching inconsistants
ProblÚme: 3 patterns différents utilisés dans le projet
Pattern 1: React Query + API client (â RECOMMANDĂ)
// app/dashboard/page.tsx
const { data } = useQuery({
queryKey: ['dashboard', 'csv-booking-kpis'],
queryFn: () => getDashboardKpis(),
});
Pattern 2: Custom hook avec fetch direct (â Ă ĂVITER)
// hooks/useBookings.ts (ligne 43)
const response = await fetch(`/api/v1/bookings/advanced/search`, {
headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` },
});
Pattern 3: API client direct dans composant (â ïž Acceptable)
// app/dashboard/bookings/page.tsx (ligne 29)
const { data } = useQuery({
queryKey: ['csv-bookings'],
queryFn: () => listCsvBookings({ page: 1, limit: 1000 }),
});
đ Action proposĂ©e: STANDARDIZE
Choisir Pattern 1 partout: React Query + API client
Raisons:
- â Token management automatique (via apiClient)
- â Error handling centralisĂ©
- â Cache management (React Query)
- â Retry logic
- â Optimistic updates
- â Type safety
Refactoring:
AVANT (useBookings.ts):
const response = await fetch(`/api/v1/bookings/advanced/search?${queryParams}`, {
headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` },
});
const data = await response.json();
APRĂS (useBookings.ts):
import { advancedSearchBookings } from '@/lib/api/bookings';
const { data, isLoading, error } = useQuery({
queryKey: ['bookings', 'advanced-search', filters],
queryFn: () => advancedSearchBookings(filters),
enabled: !!filters,
});
â ïž Impact
Fichiers Ă modifier: src/hooks/useBookings.ts
Timeline: 1 heure
đą CODE MORT Ă SUPPRIMER - PRIORITĂ 3
1. â Fichiers legacy non utilisĂ©s
Fichiers Ă supprimer:
a) /apps/frontend/src/legacy-pages/ (TOUT LE DOSSIER)
Fichiers:
BookingsManagement.tsx(348 lignes)CarrierManagement.tsx(267 lignes)CarrierMonitoring.tsx(193 lignes)
Vérification d'utilisation:
grep -r "from.*legacy-pages" apps/frontend/src/
grep -r "from.*legacy-pages" apps/frontend/app/
# RĂ©sultat: Aucune importation trouvĂ©e â
Justification de suppression:
- â Aucune importation dans le code actuel
- â RemplacĂ©s par les pages dans
app/dashboard/bookings/ - â Utilisent l'ancien pattern (Pages Router vs App Router)
Action: DELETE
Commande:
rm -rf apps/frontend/src/legacy-pages/
Impact: â AUCUN - Code non rĂ©fĂ©rencĂ©
b) /apps/frontend/app/rates/csv-search/page.tsx
Vérification:
- â
Route accessible:
http://localhost:3000/rates/csv-search - â ïž Doublon de:
app/dashboard/search-advanced/page.tsx
Analyse:
# Vérifier si les deux pages sont identiques
diff apps/frontend/app/rates/csv-search/page.tsx apps/frontend/app/dashboard/search-advanced/page.tsx
Action: INVESTIGATE â DELETE ou REDIRECT
Option 1: Supprimer si doublon exact Option 2: Redirection vers la version dashboard
// app/rates/csv-search/page.tsx
import { redirect } from 'next/navigation';
export default function LegacyCsvSearchPage() {
redirect('/dashboard/search-advanced');
}
c) /apps/frontend/src/pages/privacy.tsx et terms.tsx
Vérification:
- â Utilisent le pattern Pages Router (
src/pages/) - â
Devraient ĂȘtre dans
app/privacy/page.tsxetapp/terms/page.tsx
Vérification d'existence:
ls -la apps/frontend/app/privacy/
ls -la apps/frontend/app/terms/
Si les pages existent dans app/:
- Action: DELETE
src/pages/privacy.tsxetsrc/pages/terms.tsx
Si les pages n'existent PAS:
- Action: MIGRATE vers App Router
mkdir -p apps/frontend/app/privacy
mkdir -p apps/frontend/app/terms
mv apps/frontend/src/pages/privacy.tsx apps/frontend/app/privacy/page.tsx
mv apps/frontend/src/pages/terms.tsx apps/frontend/app/terms/page.tsx
d) /apps/frontend/src/components/examples/DesignSystemShowcase.tsx
Vérification:
grep -r "DesignSystemShowcase" apps/frontend/src/
grep -r "DesignSystemShowcase" apps/frontend/app/
# RĂ©sultat: Aucune importation â
Justification:
- â Exemple de dĂ©mo (non production)
- â Jamais importĂ©
- â Peut ĂȘtre utile en dev (composant de test)
Action: KEEP mais déplacer
Recommandation: Créer une page /app/dev/design-system/page.tsx
// app/dev/design-system/page.tsx
import DesignSystemShowcase from '@/components/examples/DesignSystemShowcase';
export default function DesignSystemPage() {
return <DesignSystemShowcase />;
}
Protection en production:
// app/dev/layout.tsx
import { notFound } from 'next/navigation';
export default function DevLayout({ children }) {
if (process.env.NODE_ENV === 'production') {
notFound();
}
return <div className="dev-layout">{children}</div>;
}
e) /apps/frontend/app/demo-carte/page.tsx et /app/test-image/page.tsx
Vérification: Pages de test/démo
Action: EVALUATE
Questions:
- Utilisées en développement ?
- Utilisées en démo client ?
- Utilisées pour tester des features ?
Options:
- DELETE si inutiles
- PROTECT si utiles en dev (comme ci-dessus)
- KEEP si nécessaires pour démos
Recommandation: Déplacer dans /app/dev/ et protéger en production
2. â Composants potentiellement inutilisĂ©s
Vérification requise:
a) src/components/DebugUser.tsx
Vérification:
grep -r "DebugUser" apps/frontend/app/
# Si aucun rĂ©sultat â DELETE
Action: DELETE si non utilisé
b) src/components/CookieConsent.tsx
Vérification:
grep -r "CookieConsent" apps/frontend/app/
Action:
- KEEP si importé dans
app/layout.tsx(compliance RGPD) - DELETE si jamais utilisé
đ Plan d'action de nettoyage
Phase 1: Corrections critiques (1-2 jours)
Jour 1:
- â
Activer TypeScript strict mode (
tsconfig.json) - â Corriger les erreurs TypeScript rĂ©sultantes
- â
Fixer l'incohérence des clés de token (
access_tokenvsaccessToken) - â VĂ©rifier que l'authentification fonctionne partout
Jour 2:
- â
Extraire la logique métier de
app/dashboard/bookings/page.tsx - â
Créer hooks
useBookingFiltersetusePagination - â
Créer utility
booking-status.ts - â Tester les changements
Phase 2: Optimisations (1 jour)
Jour 3:
- â ImplĂ©menter pagination serveur pour bookings
- â Standardiser pattern React Query + API client
- â
Refactorer
useBookingshook - â VĂ©rifier les performances
Phase 3: Nettoyage code mort (demi-journée)
Jour 4 matin:
- â
Supprimer
/src/legacy-pages/ - â
Investiguer et supprimer/migrer
app/rates/csv-search/ - â
Migrer ou supprimer
src/pages/privacy.tsxetterms.tsx - â
Déplacer
DesignSystemShowcasedans/app/dev/ - â ProtĂ©ger pages de dev/test en production
- â Supprimer composants non utilisĂ©s (DebugUser, etc.)
Phase 4: Documentation (demi-journée)
Jour 4 aprĂšs-midi:
- â
Documenter les décisions dans
docs/decisions.md - â
Mettre Ă jour
docs/frontend/overview.md - â CrĂ©er guide de contribution avec les patterns Ă suivre
- â Mettre Ă jour CLAUDE.md avec les recommandations frontend
đ Commandes de vĂ©rification
Détecter les imports inutilisés
cd apps/frontend
# Installer ts-prune
npm install --save-dev ts-prune
# Détecter exports non utilisés
npx ts-prune | grep -v "used in module"
Détecter les fichiers jamais importés
# Fichiers TypeScript
find apps/frontend/src -name "*.ts" -o -name "*.tsx" | while read file; do
filename=$(basename "$file")
count=$(grep -r "from.*$filename" apps/frontend/src apps/frontend/app | wc -l)
if [ $count -eq 0 ]; then
echo "â Jamais importĂ©: $file"
fi
done
Vérifier les dépendances npm inutilisées
cd apps/frontend
npx depcheck
Analyser la taille du bundle
cd apps/frontend
npm run build
npx @next/bundle-analyzer
đ MĂ©triques avant/aprĂšs
Avant nettoyage
| Métrique | Valeur |
|---|---|
| Strict TypeScript | â DĂ©sactivĂ© |
| Code mort (fichiers) | ~8-10 fichiers |
| Logique mĂ©tier dans pages | â ïž PrĂ©sente (3-4 pages) |
| Pattern fetching | â ïž 3 patterns diffĂ©rents |
| Token management | â IncohĂ©rent |
| Performance bookings | â ïž 1000 items chargĂ©s |
| Score global | 65/100 |
AprĂšs nettoyage (cible)
| Métrique | Valeur cible |
|---|---|
| Strict TypeScript | â ActivĂ© |
| Code mort (fichiers) | 0 â |
| Logique mĂ©tier dans pages | â SĂ©parĂ©e (hooks/utils) |
| Pattern fetching | â UnifiĂ© (React Query) |
| Token management | â CohĂ©rent |
| Performance bookings | â Pagination serveur |
| Score global | 90/100 â |
đ RĂ©fĂ©rences
- Architecture Frontend - docs/frontend/overview.md
- Structure Frontend - docs/frontend/structure.md
- CLAUDE.md - Guide complet
- Architecture globale - docs/architecture.md
DerniÚre mise à jour: 2025-12-22 Prochaine révision: AprÚs corrections Phase 1 Responsable: Frontend Team