InfoTools
CRM Web
Extranet CRM développé en Laravel pour les commerciaux d'InfoTools. Permet de gérer les rendez-vous, consulter les produits et suivre l'historique d'achats des clients.
Contexte InfoTools
La société Info-Tools développe et vend différents logiciels. Cet extranet est destiné à ses commerciaux pour gérer leur activité de démarchage et de suivi client depuis le terrain.
Périmètre du projet
Base de données
| Table | Description | Clés |
|---|---|---|
users | Commerciaux authentifiés | — |
appointments | Rendez-vous clients | user_id |
products | Catalogue produits | — |
clients | Clients InfoTools | — |
purchases | Achats par client | user_id, client_id, product_id |
audit_logs | Journalisation des actions | user_id, entity_type |
Stack technique
Architecture MVC avec Laravel, API REST sécurisée via Sanctum et interface Blade avec Tailwind CSS.
Architecture
Le projet suit l'architecture MVC native de Laravel. Les routes web sont séparées des routes API. L'authentification web utilise les sessions, l'API utilise les tokens Sanctum.
// Structure des routes
routes/
├── web.php ← Dashboard, RDV, Produits, Clients (session)
├── api.php ← API REST sécurisée (Sanctum token)
└── auth.php ← Login / Register / Reset password
app/Http/Controllers/
├── AppointmentController.php
├── ClientController.php
├── ProductController.php
└── Api/
├── ProductController.php
└── PurchaseController.php
Modèles & Relations
hasMany AppointmenthasMany Purchase
hasMany Purchase
hasMany Purchase
belongsTo UserbelongsTo ClientbelongsTo Product
Technologies utilisées
| Technologie | Usage | Version |
|---|---|---|
| Laravel | Framework PHP MVC | 12.x |
| PHP | Langage serveur | 8.4 |
| MySQL | Base de données relationnelle | 5.7+ |
| Laravel Sanctum | Authentification API par token | inclus |
| Tailwind CSS | Framework CSS utilitaire | 3.x |
| Vite | Bundler assets JS/CSS | 5.x |
| Blade | Moteur de templates Laravel | natif |
Dashboard
Page d'accueil personnalisée après connexion. Affiche les KPIs du commercial connecté et ses prochains rendez-vous.
Contenu affiché
Implémentation
// web.php
Route::get('/dashboard', function (Request $request) {
$nextAppointments = Appointment::where('user_id', $request->user()->id)
->where('starts_at', '>=', now())
->orderBy('starts_at')
->take(3)
->get();
return view('dashboard', compact('nextAppointments'));
})->middleware(['auth', 'verified'])->name('dashboard');
Rendez-vous
CRUD complet sur les rendez-vous. Chaque commercial ne voit et ne modifie que ses propres données.
Routes disponibles
Validation des champs
| Champ | Règles | Obligatoire |
|---|---|---|
client_name | string, max:255 | Oui |
starts_at | date, futur recommandé | Oui |
notes | string, nullable | Non |
Isolation des données
Chaque requête filtre automatiquement par user_id = auth()->id(). Un commercial ne peut pas accéder aux RDV d'un autre. Le contrôleur vérifie également l'ownership avant toute modification avec abort_unless().
Catalogue Produits
Page de consultation du catalogue InfoTools. Accessible à tous les commerciaux authentifiés.
Produits disponibles
| Produit | Prix | Description |
|---|---|---|
| InfoTools CRM Web | 59,00 € | Portail CRM pour commerciaux |
| InfoTools CRM Manager | 129,00 € | CRM complet pour managers |
| Module Facturation | 39,00 € | Gestion et suivi des factures |
| Module Gestion de stock | 49,00 € | Produits + stock entrées/sorties |
| Audit & Traçabilité | 19,00 € | Journalisation des actions |
| Dimensionnement Infrastructure | 399,00 € | Étude CPU/RAM/stockage |
| Mise en place Infrastructure | 799,00 € | Installation serveur + réseau |
| Maintenance & Support | 149,00 €/mois | Support + correctifs |
Implémentation
// ProductController.php
public function index()
{
$products = Product::orderBy('name')->get();
return view('products.index', compact('products'));
}
Les produits sont insérés via le DatabaseSeeder en utilisant le ProductFactory qui pioche dans un catalogue prédéfini de 8 produits représentatifs d'InfoTools.
Clients & Achats
Répertoire des clients avec historique d'achats filtré. Chaque commercial ne voit que les achats qu'il a lui-même enregistrés.
Routes disponibles
Protection IDOR
// ClientController.php
public function purchases(Client $client, Request $request)
{
$purchases = $client->purchases()
->where('user_id', $request->user()->id) // ← IDOR protection
->with('product')
->orderByDesc('purchased_at')
->get();
return view('clients.purchases', compact('client', 'purchases'));
}
Données affichées — Achats
| Colonne | Source |
|---|---|
| Date | purchases.purchased_at |
| Produit | product.name (relation eager load) |
| Quantité | purchases.quantity |
| Notes | purchases.notes |
API REST
API sécurisée par tokens Sanctum. Destinée aux applications mobiles et à l'application lourde C# du projet InfoTools.
Authentification
// Requête
{
"email": "commercial@infotools.fr",
"password": "password"
}
// Réponse
{
"token": "1|abc123..."
}
Endpoints protégés
Toutes ces routes nécessitent le header Authorization: Bearer {token}
Throttling
Le endpoint /api/login est limité à 10 tentatives par minute via le middleware throttle:10,1. Retourne HTTP 429 en cas de dépassement.
Mesures de sécurité
Plusieurs couches de sécurité ont été implémentées conformément aux exigences du cahier des charges.
Protections implémentées
user_id = auth()->id(). Un commercial ne peut jamais accéder aux données d'un autre, même en connaissant l'URL.audit_logs avec user_id, action, entity_type, entity_id et un champ meta JSON.FormRequest ou $request->validate(). Les tentatives d'injection ou de XSS retournent HTTP 422.Guide d'installation
Procédure complète pour déployer l'application en local ou sur le serveur SISR.
Prérequis
PHP 8.4+, Composer, Node.js 18+, MySQL 5.7+
Laravel Herd (Windows/Mac) ou Laravel Valet (Mac/Linux)
Installation locale
git clone https://github.com/whizpixel/web-ap.git
cd web-ap
composer install
npm install
cp .env.example .env
php artisan key:generate
Renseigner DB_DATABASE, DB_USERNAME, DB_PASSWORD dans le .env
php artisan migrate:fresh --seed
# Terminal 1
php artisan serve
# Terminal 2
npm run dev
Comptes de test
Le seeder crée 2 commerciaux avec des données fictives. Récupérer leurs emails via :
php artisan tinker
>>> App\Models\User::all(['id', 'name', 'email'])
Mot de passe pour tous les comptes seedés : password
Migration sur serveur SISR
Modifier le .env avec les credentials du serveur MySQL SISR, puis exécuter :
php artisan migrate --force
php artisan db:seed --force