Réalisations par membre
Mohamed Amine Hidaoui
<?php
require_once "includes/auth.php";
require_once "config/db.php";
// ── INSERT ou UPDATE ─────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$id = !empty($_POST['id']) ? (int)$_POST['id'] : null;
$rdv_id = !empty($_POST['rdv_id']) ? (int)$_POST['rdv_id'] : null;
$date_consultation = trim($_POST['date_consultation'] ?? '');
$diagnostic = trim($_POST['diagnostic'] ?? '');
$traitement = trim($_POST['traitement'] ?? '');
if ($rdv_id && $date_consultation && $diagnostic && $traitement) {
if (!$id) {
$pdo->prepare("
INSERT INTO consultations (rdv_id, date_consultation, diagnostic, traitement)
VALUES (?, ?, ?, ?)
")->execute([$rdv_id, $date_consultation, $diagnostic, $traitement]);
} else {
$pdo->prepare("
UPDATE consultations
SET rdv_id = ?, date_consultation = ?, diagnostic = ?, traitement = ?
WHERE id = ?
")->execute([$rdv_id, $date_consultation, $diagnostic, $traitement, $id]);
}
}
header("Location: compte_rendu_medical.php");
exit;
}
// ── Liste des consultations avec toutes les jointures ────────────
$consultations = $pdo->query("
SELECT
c.id, c.date_consultation, c.diagnostic, c.traitement, c.rdv_id,
a.nom AS animal_nom, a.espece,
v.nom AS vet_nom
FROM consultations c
JOIN rdv r ON c.rdv_id = r.id
JOIN animaux a ON r.animal_id = a.id
JOIN veterinaires v ON r.veterinaire_id = v.id
ORDER BY c.date_consultation DESC
")->fetchAll();
<?php
require_once "includes/auth.php";
require_once "config/db.php";
// ── INSERT ou UPDATE ─────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (empty($_POST['id'])) {
$pdo->prepare("INSERT INTO factures (consultation_id, montant, statut, date_facture) VALUES (?,?,?,?)")
->execute([$_POST['consultation_id'], $_POST['montant'], $_POST['statut'], $_POST['date_facture']]);
} else {
$pdo->prepare("UPDATE factures SET consultation_id=?, montant=?, statut=?, date_facture=? WHERE id=?")
->execute([$_POST['consultation_id'], $_POST['montant'], $_POST['statut'], $_POST['date_facture'], $_POST['id']]);
}
header("Location: service_facturation.php");
exit;
}
// ── Liste des factures avec jointures multi-tables ────────────────
$data = $pdo->query("
SELECT f.*,
a.nom AS animal_nom, a.espece,
p.nom AS proprio_nom, p.prenom AS proprio_prenom,
v.nom AS vet_nom
FROM factures f
JOIN consultations c ON f.consultation_id = c.id
JOIN rdv r ON c.rdv_id = r.id
JOIN animaux a ON r.animal_id = a.id
JOIN proprietaires p ON a.proprietaire_id = p.id
JOIN veterinaires v ON r.veterinaire_id = v.id
ORDER BY f.date_facture DESC
")->fetchAll();
// ── Statuts avec classes CSS dynamiques ─────────────────────────
$statusCls = match($f['statut']) {
'Payée' => 'status-payee',
'Non payée' => 'status-attente',
default => 'status-annulee'
};
<?php
// planning_public.php — Page publique sans authentification requise
// Pas de require auth.php, pas de menu intranet
require_once "config/db.php";
// Récupération des RDV avec animaux et vétérinaires
$stmt = $pdo->query("
SELECT r.id, r.date_rdv, r.statut,
a.nom AS animal_nom, a.espece AS animal_espece,
v.nom AS vet_nom, v.specialite
FROM rdv r
JOIN animaux a ON r.animal_id = a.id
JOIN veterinaires v ON r.veterinaire_id = v.id
ORDER BY r.date_rdv ASC
");
$events = [];
while ($r = $stmt->fetch()) {
// Couleur conditionnelle selon le statut du RDV
$color = match($r['statut']) {
'Terminé' => '#1a62b0',
'Annulé' => '#b92c21',
default => '#1a8a49' // Programmé
};
$events[] = [
'id' => $r['id'],
'title' => $r['animal_nom'] . ' (' . $r['animal_espece'] . ')',
'start' => $r['date_rdv'],
'color' => $color,
'extendedProps' => [
'statut' => $r['statut'],
'veterinaire' => $r['vet_nom'],
'specialite' => $r['specialite'],
]
];
}
// Injection PHP → JS pour FullCalendar
// const events = <?= json_encode($events, JSON_UNESCAPED_UNICODE) ?>;
<?php
require_once "includes/auth.php";
require_once "config/db.php";
// Compteurs pour les statistiques du tableau de bord
$veterinaires = $pdo->query("SELECT COUNT(*) FROM veterinaires") ->fetchColumn();
$proprietaires = $pdo->query("SELECT COUNT(*) FROM proprietaires")->fetchColumn();
$animaux = $pdo->query("SELECT COUNT(*) FROM animaux") ->fetchColumn();
$nom = htmlspecialchars($_SESSION['user']['nom'] ?? '');
$prenom = htmlspecialchars($_SESSION['user']['prenom'] ?? '');
?>
<!-- Hero banner avec image de fond et overlay sombre -->
<div class="hero-dashboard mb-4">
<div class="hero-content">
<h2>👋 Bienvenue, <?= $prenom ?> <?= $nom ?></h2>
<p>Tableau de bord — Clinique vétérinaire Lisa Horse</p>
</div>
</div>
<!-- Cartes de statistiques (vétérinaires, propriétaires, animaux) -->
<div class="row">
<div class="col-md-4 mb-3">
<div class="card stat-card">
<div class="stat-icon">🩺</div>
<h6>Vétérinaires</h6>
<h2><?= $veterinaires ?></h2>
</div>
</div>
<!-- ... propriétaires, animaux -->
</div>
// Conclusion
Développement des pages fonctionnelles les plus complexes (comptes rendus médicaux, facturation, planning public FullCalendar, tableau de bord). Responsable de la documentation technique et du diagramme de classes UML (Win Design, 7 classes).
Orchestration de jointures SQL sur 5 tables (factures, consultations, RDV, animaux, propriétaires). Intégration de FullCalendar avec injection PHP→JS pour le planning public, sans authentification ni Bootstrap personnalisé.
Utilisation de requêtes PDO préparées avec jointures multi-tables. Pattern INSERT/UPDATE unifié via un seul formulaire PHP. Sérialisation JSON des événements PHP vers JavaScript (json_encode). Séparation stricte public/intranet sur le planning.
Ajouter des totaux de CA dynamiques sur le dashboard. Implémenter une génération PDF des factures. Sécuriser les suppressions avec tokens CSRF. Compléter les commentaires PHPDoc pour la maintenabilité.
Kevin Leger (LK)
<?php
require_once "../config/db.php";
session_start();
// Vérification des identifiants à la soumission du formulaire
if ($_POST) {
$stmt = $pdo->prepare("SELECT * FROM utilisateurs WHERE email=?");
$stmt->execute([$_POST['email']]);
$user = $stmt->fetch();
// password_verify() compare le mdp saisi au hash bcrypt en BDD
if ($user && password_verify($_POST['password'], $user['mot_de_passe'])) {
$_SESSION['user'] = $user;
header("Location: ../dashboard.php");
exit;
}
$error = "Identifiants incorrects";
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Connexion - Clinique vétérinaire Lisa Horse</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family:'Poppins',sans-serif;
background: url("../assets/img/accueil-clinique-val-europe.jpg") center/cover no-repeat;
height: 100vh;
}
.overlay { position:absolute; inset:0; background:rgba(0,0,0,0.6); }
.card { border-radius: 20px; }
</style>
</head>
<body>
<div class="overlay"></div>
<div class="d-flex justify-content-center align-items-center vh-100 position-relative">
<form method="post" class="card p-4 shadow-lg" style="width:380px;">
<h3 class="text-center mb-3">🐎 Clinique vétérinaire Lisa Horse</h3>
<p class="text-center mb-3">Accès à l'intranet</p>
<?php if(isset($error)): ?>
<div class="alert alert-danger"><?= $error ?></div>
<?php endif; ?>
<input class="form-control mb-3" name="email" placeholder="Adresse email" required>
<input class="form-control mb-3" type="password" name="password" placeholder="Mot de passe" required>
<button class="btn btn-success w-100 py-2">🔐 Se connecter</button>
</form>
</div>
</body></html>
<?php
// animaux.php — Gestion des animaux (CRUD complet)
require_once "includes/auth.php";
require_once "config/db.php";
// ── 1. Traitement du formulaire (INSERT ou UPDATE) ───────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$id = !empty($_POST['id']) ? (int)$_POST['id'] : null;
$nom = trim($_POST['nom'] ?? '');
$espece = trim($_POST['espece'] ?? '');
$race = trim($_POST['race'] ?? '');
$sexe = trim($_POST['sexe'] ?? '');
$date_naissance = trim($_POST['date_naissance'] ?? '') ?: null; // NULL si vide
$proprietaire_id = !empty($_POST['proprietaire_id']) ? (int)$_POST['proprietaire_id'] : null;
if ($nom && $proprietaire_id) {
if (!$id) {
// ── Création d'un nouvel animal ──────────────────────
$pdo->prepare("
INSERT INTO animaux (nom, espece, race, sexe, date_naissance, proprietaire_id)
VALUES (?, ?, ?, ?, ?, ?)
")->execute([$nom, $espece, $race, $sexe, $date_naissance, $proprietaire_id]);
} else {
// ── Mise à jour d'un animal existant ─────────────────
$pdo->prepare("
UPDATE animaux
SET nom=?, espece=?, race=?, sexe=?, date_naissance=?, proprietaire_id=?
WHERE id=?
")->execute([$nom, $espece, $race, $sexe, $date_naissance, $proprietaire_id, $id]);
}
}
header("Location: animaux.php");
exit;
}
// ── 4. Liste animaux avec jointure propriétaires ─────────────────
$data = $pdo->query("
SELECT a.id, a.nom, a.espece, a.race, a.sexe, a.date_naissance, a.proprietaire_id,
p.nom AS prop_nom, p.prenom AS prop_prenom
FROM animaux a
LEFT JOIN proprietaires p ON a.proprietaire_id = p.id
ORDER BY a.nom ASC
")->fetchAll();
<?php
require_once "includes/auth.php";
require_once "config/db.php";
// Ajout ou modification d'un RDV selon la présence de l'ID
if ($_POST) {
if (empty($_POST['id'])) {
$pdo->prepare("INSERT INTO rdv (animal_id, veterinaire_id, date_rdv, statut) VALUES (?,?,?,?)")
->execute([$_POST['animal_id'], $_POST['veterinaire_id'], $_POST['date_rdv'], $_POST['statut']]);
} else {
$pdo->prepare("UPDATE rdv SET animal_id=?, veterinaire_id=?, date_rdv=?, statut=? WHERE id=?")
->execute([$_POST['animal_id'], $_POST['veterinaire_id'], $_POST['date_rdv'], $_POST['statut'], $_POST['id']]);
}
header("Location: rdv.php"); exit;
}
// Récupération de tous les RDV avec jointures (animal, vétérinaire, propriétaire)
$data = $pdo->query("
SELECT rdv.*,
a.nom AS animal_nom, a.espece AS animal_espece,
v.nom AS vet_nom,
p.nom AS prop_nom, p.prenom AS prop_prenom
FROM rdv
LEFT JOIN animaux a ON rdv.animal_id = a.id
LEFT JOIN veterinaires v ON rdv.veterinaire_id = v.id
LEFT JOIN proprietaires p ON a.proprietaire_id = p.id
ORDER BY rdv.date_rdv DESC
")->fetchAll();
// Badges colorés selon le statut via match PHP 8
$badge = match($r['statut']) {
'Terminé' => 'badge-termine',
'Programmé' => 'badge-programme',
'Annulé' => 'badge-annule',
default => ''
};
<!-- index.php — Page d'accueil publique de la clinique -->
<section class="hero">
<!-- Overlay sombre pour améliorer la lisibilité du texte -->
<div class="overlay"></div>
<div class="content">
<h1>🐴 Clinique vétérinaire Lisa Horse</h1>
<p class="lead mt-3">Gestion & planning des soins équins</p>
<div class="mt-4">
<!-- Accès intranet : redirige vers login si non connecté -->
<a href="auth/login.php" class="btn btn-success btn-custom">
🔐 Intranet
</a>
<!-- Planning public : aucune authentification requise -->
<a href="planning_public.php" class="btn btn-primary btn-custom">
📅 Voir le planning
</a>
</div>
</div>
<!-- Copyright avec année dynamique -->
<div class="footer">
© <?= date('Y') ?> Clinique vétérinaire Lisa Horse
</div>
</section>
// Conclusion
Développeur principal de l'intranet PHP. A pris en charge l'architecture de l'application (includes, config, auth), le système d'authentification avec sessions PHP, et les pages CRUD animaux et rendez-vous. Responsable aussi de la page d'accueil publique.
Mise en place d'un système d'authentification sécurisé avec password_verify() et gestion de session. Conception d'un formulaire PHP unique gérant à la fois l'ajout et la modification (INSERT/UPDATE conditionnel). Gestion du type DATETIME pour les RDV.
Utilisation de PDO avec requêtes préparées (protection injection SQL). Sessions PHP sécurisées avec vérification de hash bcrypt. Détection de l'action (ajout/modif) via la présence ou absence de l'ID caché dans le formulaire. Redirection POST/GET pour éviter la re-soumission.
Remplacer les suppressions GET par des formulaires POST avec tokens CSRF. Ajouter une gestion des rôles (admin, secrétaire, vétérinaire). Implémenter une recherche/filtrage dans les tableaux. Compléter les commentaires de débogage.
Sofiane Fodil (SF)
<?php
require_once "includes/auth.php";
require_once "config/db.php";
// Ajout ou modification d'un propriétaire selon la présence de l'ID
if ($_POST) {
if (empty($_POST['id'])) {
$pdo->prepare("INSERT INTO proprietaires (nom, prenom, telephone, email, adresse) VALUES (?,?,?,?,?)")
->execute([$_POST['nom'], $_POST['prenom'], $_POST['telephone'], $_POST['email'], $_POST['adresse']]);
} else {
$pdo->prepare("UPDATE proprietaires SET nom=?, prenom=?, telephone=?, email=?, adresse=? WHERE id=?")
->execute([$_POST['nom'], $_POST['prenom'], $_POST['telephone'], $_POST['email'], $_POST['adresse'], $_POST['id']]);
}
header("Location: proprietaires.php"); exit;
}
// Chargement du propriétaire ciblé pour pré-remplir le formulaire d'édition
$edit = null;
if (isset($_GET['edit'])) {
$e = $pdo->prepare("SELECT * FROM proprietaires WHERE id=?");
$e->execute([$_GET['edit']]);
$edit = $e->fetch();
}
// Suppression d'un propriétaire par son ID
if (isset($_GET['delete'])) {
$pdo->prepare("DELETE FROM proprietaires WHERE id=?")->execute([$_GET['delete']]);
header("Location: proprietaires.php"); exit;
}
// Récupération de tous les propriétaires triés par nom
$data = $pdo->query("SELECT * FROM proprietaires ORDER BY nom")->fetchAll();
<?php
require_once "includes/auth.php"; // Vérifie l'authentification avant toute action
require_once "config/db.php";
// Traitement du formulaire d'ajout ou de modification
if ($_POST) {
if (empty($_POST['id'])) {
// Aucun ID fourni → création d'un nouveau vétérinaire
$pdo->prepare("INSERT INTO veterinaires(nom,specialite,telephone) VALUES(?,?,?)")
->execute([$_POST['nom'], $_POST['specialite'], $_POST['telephone']]);
} else {
// ID présent → mise à jour du vétérinaire existant
$pdo->prepare("UPDATE veterinaires SET nom=?, specialite=?, telephone=? WHERE id=?")
->execute([$_POST['nom'], $_POST['specialite'], $_POST['telephone'], $_POST['id']]);
}
header("Location: veterinaires.php");
exit;
}
// Récupération de tous les vétérinaires triés alphabétiquement
$data = $pdo->query("SELECT * FROM veterinaires ORDER BY nom ASC")->fetchAll();
// Rendu HTML : tableau avec badge spécialité et actions édition/suppression
// htmlspecialchars() sur chaque sortie pour prévenir les failles XSS
?>
<table>
<thead>
<tr>
<th>Nom du vétérinaire</th>
<th>Spécialité</th>
<th>Téléphone</th>
<th style="text-align:right;">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $r): ?>
<tr>
<td style="font-weight:600;"><?= htmlspecialchars($r['nom']) ?></td>
<td>
<span style="background:#eff6ff; color:#3b82f6; padding:4px 10px; border-radius:20px;">
<?= htmlspecialchars($r['specialite']) ?>
</span>
</td>
<td><?= htmlspecialchars($r['telephone']) ?></td>
<td style="text-align:right;">
<a href="?edit=<?= $r['id'] ?>" title="Modifier">✏️</a>
<!-- Confirmation côté client avant suppression définitive -->
<a href="?delete=<?= $r['id'] ?>" title="Supprimer"
onclick="return confirm('Supprimer ce vétérinaire ?')">🗑️</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
/* ── ZONE DE CONTENU PRINCIPAL ───────────────────────────────────
flex: 1 = prend tout l'espace restant après la sidebar.
overflow-y: auto = scroll vertical si le contenu est trop long.
─────────────────────────────────────────────────────────────── */
.main-content {
flex: 1;
padding: 30px;
overflow-y: auto;
}
/* ── BARRE LATÉRALE (SIDEBAR) ────────────────────────────────────
Colonne fixe à gauche, toujours aussi haute que l'écran.
─────────────────────────────────────────────────────────────── */
.sidebar {
width: 240px;
background: #111827;
min-height: 100vh;
}
.sidebar a {
color: #cbd5e1;
display: block;
padding: 10px;
border-radius: 6px;
text-decoration: none;
margin: 4px 0;
transition: all .15s;
}
.sidebar a:hover {
background: #1f2937;
color: #fff;
}
/* ── BANDEAU HÉRO ────────────────────────────────────────────────
position: relative est indispensable pour que l'overlay (::after)
et le texte se positionnent correctement par-dessus l'image.
─────────────────────────────────────────────────────────────── */
.hero-banner {
height: 260px;
background: url("assets/img/colvert_sport_banner.jpg") center center / cover no-repeat;
position: relative;
border-radius: 18px;
overflow: hidden;
margin-bottom: 30px;
}
.hero-banner::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to right, rgba(0,0,0,0.65), rgba(0,0,0,0.25));
}
// Conclusion
Responsable de la couche données : conception du schéma relationnel (7 tables, PK/FK), rédaction et test des requêtes SQL complexes (jointures, champs calculés), et développement des pages CRUD propriétaires, vétérinaires et consultations. Co-responsable de l'harmonisation CSS globale.
Conception d'un modèle relationnel cohérent sur 7 tables avec contraintes référentielles. Rédaction des requêtes SQL avancées (taux de paiement, CA total, âge animal calculé). Harmonisation du style CSS sur l'ensemble des pages de l'intranet sans introduire de régressions.
Utilisation de requêtes préparées PDO pour toutes les opérations. Variables CSS et classes réutilisables pour garantir la cohérence visuelle. Schéma relationnel vérifié avec PhpMyAdmin avant implémentation. Suppression sécurisée avec confirmation JavaScript.
Ajouter des vues SQL pour simplifier les requêtes récurrentes. Mettre en place des contraintes ON DELETE CASCADE ou RESTRICT selon les entités. Compléter les requêtes de reporting (taux d'occupation, statistiques par espèce). Optimiser les index pour les performances.
Corey Defranc (CD)
<?php
// config/db.php — Point de connexion centralisé PDO
// Inclus par toutes les pages via require_once "config/db.php"
$pdo = new PDO(
"mysql:host=localhost;dbname=lisa_horse;charset=utf8mb4",
"root",
"",
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
// ATTR_ERRMODE_EXCEPTION : toute erreur SQL lève une exception
// FETCH_ASSOC : résultats retournés sous forme de tableaux associatifs
?>
// Structure de l'application web — Clinique Lisa Horse
// Architecture mise en place avec Kevin Leger
Lisa Horse/
├── index.php // Accueil public (hero + boutons)
├── planning_public.php // Calendrier public FullCalendar
├── dashboard.php // Tableau de bord intranet
├── animaux.php // CRUD animaux
├── rdv.php // CRUD rendez-vous
├── proprietaires.php // CRUD propriétaires
├── veterinaires.php // CRUD vétérinaires
├── compte_rendu_medical.php // CRUD consultations
├── service_facturation.php // CRUD factures
│
├── auth/
│ ├── login.php // Formulaire de connexion
│ ├── login_ex.php // Gestion erreurs login
│ └── logout.php // Destruction de session
│
├── includes/
│ ├── auth.php // Vérification session (require_once)
│ ├── header.php // <head> + Bootstrap + fonts
│ ├── menu.php // Sidebar navigation
│ ├── hero_banner.php // Bandeau hero réutilisable
│ └── footer.php // Pied de page commun
│
├── config/
│ └── db.php // Connexion PDO centralisée
│
├── assets/
│ ├── style.css // CSS global (sidebar, layout)
│ └── img/ // Images (hero, bannières)
│
└── lisa_horse.sql // Script SQL BDD (7 tables)
// Conclusion
Analyste et co-architecte de l'application. A participé à la conception du diagramme de classes UML (7 classes, associations, multiplicités, visibilité +/-) sur Win Design, et à la mise en place de la structure globale PHP (includes, config, auth) avec Kevin Leger.
Modélisation UML rigoureuse en respectant la notation standard (visibilité, multiplicités, associations vs compositions). Organisation de l'architecture PHP pour permettre la réutilisation des includes sur toutes les pages sans redondance de code.
Conception UML sur Win Design avec relecture croisée Mohamed Amine. Pattern includes/ centralisé : header, menu, footer, hero_banner et auth inclus systématiquement via require_once. Fichier db.php unique garantissant une connexion PDO cohérente dans tout le projet.
Étendre le diagramme UML avec les diagrammes de séquence (authentification, CRUD). Exporter l'architecture vers un autoloader PSR-4 pour un code plus maintenable. Ajouter un diagramme d'activité pour les flux métier principaux.
| Entité | Attribut | Type SQL | Taille | Contraintes | Description |
|---|---|---|---|---|---|
| UTILISATEUR | id_utilisateur | INT | - | PK | Identifiant unique du personnel |
| nom_user | VARCHAR | 50 | Requis | Nom du membre du personnel | |
| prenom_user | VARCHAR | 50 | Requis | Prénom du membre du personnel | |
| identifiant | VARCHAR | 50 | Unique, Requis | Login de connexion | |
| mot_de_passe | VARCHAR | 255 | Requis | Mot de passe haché | |
| role | VARCHAR | 30 | Requis | Admin / Vétérinaire / Secrétaire | |
| PROPRIETAIRE | id_proprietaire | INT | - | PK | Identifiant unique du client |
| nom_prop | VARCHAR | 50 | Requis | Nom de famille | |
| prenom_prop | VARCHAR | 50 | Requis | Prénom | |
| telephone | VARCHAR | 15 | Requis | Numéro de contact | |
| VARCHAR | 100 | Requis | Adresse courriel | ||
| ville | VARCHAR | 50 | Requis | Ville de résidence | |
| ANIMAL | id_animal | INT | - | PK | Identifiant unique de l'animal |
| nom_animal | VARCHAR | 50 | Requis | Nom (ex: Bella) | |
| type_animal | VARCHAR | 30 | Requis | Cheval, Chien, Chat | |
| race | VARCHAR | 50 | Optionnel | Ex: Pur-sang, Labrador | |
| sexe | CHAR | 1 | Requis | M ou F | |
| date_naissance | DATE | AAAA-MM-JJ | Requis | Date de naissance | |
| id_proprietaire | INT | - | FK → PROPRIETAIRE | Lien vers le propriétaire | |
| RENDEZ_VOUS | id_rdv | INT | - | PK | Identifiant unique du RDV |
| date_heure | DATETIME | AAAA-MM-JJ HH:MM | Requis | Date et heure prévues | |
| motif | VARCHAR | 255 | Requis | Raison de la visite | |
| id_animal | INT | - | FK → ANIMAL | Animal concerné | |
| id_utilisateur | INT | - | FK → UTILISATEUR | Vétérinaire en charge | |
| CONSULTATION | id_consultation | INT | - | PK | Identifiant unique de la consultation |
| date_consult | DATE | AAAA-MM-JJ | Requis | Date effective | |
| compte_rendu | TEXT | - | Requis | Détail médical et observations | |
| id_animal | INT | - | FK → ANIMAL | Animal ausculté | |
| id_utilisateur | INT | - | FK → UTILISATEUR | Vétérinaire rédacteur | |
| FACTURE | id_facture | INT | - | PK | Identifiant unique de la facture |
| date_facture | DATE | AAAA-MM-JJ | Requis | Date d'émission | |
| montant | DECIMAL | 10,2 | Requis | Montant en euros | |
| statut | VARCHAR | 20 | Requis | Payée / En attente / Annulée | |
| id_proprietaire | INT | - | FK → PROPRIETAIRE | Client facturé | |
| VETERINAIRE | id_veterinaire | INT | - | PK | Identifiant unique du vétérinaire |
| nom | VARCHAR | 100 | Requis | Nom (ex: Dr Leroux) | |
| specialite | VARCHAR | 50 | Requis | Ex: Équin, Chirurgie | |
| telephone | VARCHAR | 15 | Requis | Contact professionnel |
Bilan du projet
✅ Points forts
- Séparation claire entre la partie publique et l'intranet sécurisé
- Code HTML5/CSS3 lisible et homogène, sans framework externe
- Requêtes SQL avec jointures multi-tables et champs calculés
- Organisation Kanban efficace via Trello (4 colonnes)
- Collaboration en temps réel via Live Share (LAN partagé)
- Application fonctionnelle déployée localement sous WAMP 64
⚡ Axes d'amélioration
- Présentation finale à finaliser et peaufiner
- Commentaires du code à compléter (PHPDoc)
- Débogage de certaines pages encore en cours
- Sécurisation des suppressions avec tokens CSRF
- Gestion des rôles utilisateurs (admin, vétérinaire, secrétaire)
- Tests unitaires et fonctionnels à ajouter