01 — Introduction

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.

Projet BTS SIO · Mission 2

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.

Laravel 12 PHP 8.4 MySQL Tailwind CSS Sanctum API Blade Vite

Périmètre du projet

Rendez-vous
Création, modification et suppression de rendez-vous clients avec tableau de bord personnalisé.
Produits
Catalogue des produits InfoTools avec nom, prix et description consultable par les commerciaux.
Clients & Achats
Répertoire clients avec historique d'achats filtré par commercial (protection IDOR).

Base de données

Table Description Clés
usersCommerciaux authentifiés
appointmentsRendez-vous clientsuser_id
productsCatalogue produits
clientsClients InfoTools
purchasesAchats par clientuser_id, client_id, product_id
audit_logsJournalisation des actionsuser_id, entity_type
02 — Technique

Stack technique

Architecture MVC avec Laravel, API REST sécurisée via Sanctum et interface Blade avec Tailwind CSS.

Architecture

Modèle MVC Laravel

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

User

hasMany Appointment
hasMany Purchase

Client

hasMany Purchase

Product

hasMany Purchase

Purchase

belongsTo User
belongsTo Client
belongsTo Product

Technologies utilisées

TechnologieUsageVersion
LaravelFramework PHP MVC12.x
PHPLangage serveur8.4
MySQLBase de données relationnelle5.7+
Laravel SanctumAuthentification API par tokeninclus
Tailwind CSSFramework CSS utilitaire3.x
ViteBundler assets JS/CSS5.x
BladeMoteur de templates Laravelnatif
03 — Fonctionnalités

Dashboard

Page d'accueil personnalisée après connexion. Affiche les KPIs du commercial connecté et ses prochains rendez-vous.

application-web.test/dashboard
Dashboard Rendez-vous Produits Clients
RDV à venir 6
Prochain RDV Société Dupont · 18/03/2026
Accès rapide Mes RDV · Produits · Clients

Contenu affiché

KPI — RDV à venir
Nombre de rendez-vous futurs du commercial connecté, avec affichage du prochain RDV (nom client + date).
Accès rapide
Liens directs vers les principales sections : Mes RDV, Produits, Clients.
Planning des RDV
Liste des 6 prochains rendez-vous avec nom, date, notes et bouton de modification.
Bouton + Nouveau RDV
Accès direct au formulaire de création d'un rendez-vous depuis le header.

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');
04 — Fonctionnalités

Rendez-vous

CRUD complet sur les rendez-vous. Chaque commercial ne voit et ne modifie que ses propres données.

Routes disponibles

GET /appointments Liste de tous les RDV du commercial
GET /appointments/create Formulaire de création
POST /appointments Enregistrement d'un nouveau RDV
GET /appointments/{id}/edit Formulaire de modification
PUT /appointments/{id} Mise à jour du RDV
DELETE /appointments/{id} Suppression du RDV

Validation des champs

ChampRèglesObligatoire
client_namestring, max:255Oui
starts_atdate, futur recommandéOui
notesstring, nullableNon

Isolation des données

Filtrage par user_id

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().

05 — Fonctionnalités

Catalogue Produits

Page de consultation du catalogue InfoTools. Accessible à tous les commerciaux authentifiés.

Produits disponibles

ProduitPrixDescription
InfoTools CRM Web59,00 €Portail CRM pour commerciaux
InfoTools CRM Manager129,00 €CRM complet pour managers
Module Facturation39,00 €Gestion et suivi des factures
Module Gestion de stock49,00 €Produits + stock entrées/sorties
Audit & Traçabilité19,00 €Journalisation des actions
Dimensionnement Infrastructure399,00 ۃtude CPU/RAM/stockage
Mise en place Infrastructure799,00 €Installation serveur + réseau
Maintenance & Support149,00 €/moisSupport + correctifs

Implémentation

// ProductController.php
public function index()
{
    $products = Product::orderBy('name')->get();
    return view('products.index', compact('products'));
}
Données de test

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.

06 — Fonctionnalités

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

GET /clients Liste de tous les clients
GET /clients/{id}/purchases Historique d'achats d'un client (filtré par commercial)

Protection IDOR

Filtrage par user_id sur les achats
Un commercial connecté ne peut voir que les achats qu'il a lui-même créés pour un client. Même si l'URL est connue, les achats d'un autre commercial n'apparaissent jamais.
// 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

ColonneSource
Datepurchases.purchased_at
Produitproduct.name (relation eager load)
Quantitépurchases.quantity
Notespurchases.notes
07 — Technique

API REST

API sécurisée par tokens Sanctum. Destinée aux applications mobiles et à l'application lourde C# du projet InfoTools.

Authentification

POST /api/login Retourne un token Sanctum
// 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}

GET /api/products Liste des produits
POST /api/purchases Créer un achat
GET /api/clients/{id}/purchases Achats d'un client (IDOR protégé)
DELETE /api/purchases/{id} Supprimer un achat

Throttling

Limitation de débit

Le endpoint /api/login est limité à 10 tentatives par minute via le middleware throttle:10,1. Retourne HTTP 429 en cas de dépassement.

08 — Sécurité

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

Protection IDOR
Chaque requête sur les données sensibles (appointments, purchases) filtre par user_id = auth()->id(). Un commercial ne peut jamais accéder aux données d'un autre, même en connaissant l'URL.
Authentification Sanctum
L'API utilise des tokens personnels Sanctum. L'interface web utilise les sessions Laravel avec protection CSRF sur tous les formulaires.
Throttling API
Le login API est limité à 10 requêtes/minute. Empêche les attaques par force brute sur les credentials.
Audit Logs
Chaque action sensible (création/suppression d'achat) génère une entrée dans la table audit_logs avec user_id, action, entity_type, entity_id et un champ meta JSON.
Validation serveur
Tous les champs sont validés côté serveur via FormRequest ou $request->validate(). Les tentatives d'injection ou de XSS retournent HTTP 422.
09 — Déploiement

Guide d'installation

Procédure complète pour déployer l'application en local ou sur le serveur SISR.

Prérequis

Environnement

PHP 8.4+, Composer, Node.js 18+, MySQL 5.7+

Recommandé

Laravel Herd (Windows/Mac) ou Laravel Valet (Mac/Linux)

Installation locale

1
Cloner le dépôt
git clone https://github.com/whizpixel/web-ap.git
cd web-ap
2
Installer les dépendances
composer install
npm install
3
Configurer l'environnement
cp .env.example .env
php artisan key:generate

Renseigner DB_DATABASE, DB_USERNAME, DB_PASSWORD dans le .env

4
Migrer et seeder la base
php artisan migrate:fresh --seed
5
Lancer les serveurs
# Terminal 1
php artisan serve

# Terminal 2
npm run dev

Comptes de test

Credentials seedés

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

Déploiement serveur étudiant

Modifier le .env avec les credentials du serveur MySQL SISR, puis exécuter :

php artisan migrate --force
php artisan db:seed --force