Un moteur de blog technique moderne — Symfony 8 · PHP 8.4 · React 19 · Tailwind CSS v4
Blog de développement pour publier des articles, des retours de bugs et des récits de parcours, avec back-office EasyAdmin, sitemap SEO dynamique, monitoring de sécurité et upload d'images.
Fonctionnalités · Stack · Installation · Fixtures · Admin · Architecture
DevJournal est un moteur de blog technique full-stack pensé pour partager du contenu de développeur : articles de fond, retours d'expérience sur des bugs résolus, et récits de parcours professionnel. Le projet combine un back-end Symfony 8 / PHP 8.4 robuste avec un front-end React 19 intégré via Vite, le tout stylé avec Tailwind CSS v4.
Il met l'accent sur trois axes souvent négligés dans les projets « vitrine » :
- Le SEO technique — sitemap XML dynamique, slugs propres, temps de lecture calculé, données structurées.
- La sécurité applicative — journalisation des événements de sécurité, blocage d'IP/comptes, monitoring des tentatives de connexion.
- L'expérience d'administration — un back-office EasyAdmin 5 complet avec tableau de bord statistique.
💡 Ce dépôt sert aussi de démonstration de savoir-faire full-stack : conception d'entités Doctrine, cycle de vie des entités (lifecycle callbacks), intégration front/back moderne, et bonnes pratiques de sécurité.
- Trois types de contenus typés via une énumération PHP :
Article📝,Bug / Retour d'expérience🐛,Parcours🚀 — chacun avec son badge coloré et son icône. - Slugs automatiques générés à partir du titre (via
AsciiSlugger), garantis uniques. - Temps de lecture calculé automatiquement à partir du contenu.
- Compteur de vues par article.
- Système de tags en relation Many-to-Many, avec pages d'archives par tag.
- Articles mis en avant (featured) avec positionnement personnalisable.
- Upload d'image de couverture géré par VichUploaderBundle.
- Formulaire de contact avec validation et anti-spam basique (stockage IP).
- Sitemap XML dynamique (
/sitemap.xml) listant accueil, pages par type, tags, articles publiés et page contact — avecpriority,changefreqetlastmod. - Cache HTTP sur le sitemap (
s-maxage=3600). - Contenus riches (Markdown → HTML via
league/commonmark).
- Journal des événements de sécurité (
SecurityEventLog) : connexions réussies/échouées, blocages, accès admin refusés, activités suspectes. - Blocage d'IP et de comptes dès la première tentative échouée, avec page de blocage dédiée.
- Indexation optimisée (index Doctrine sur
event_type,ip_address,created_at).
- Back-office EasyAdmin 5 thématisé (
$_ DevJournal). - Tableau de bord avec statistiques : nombre d'articles, publiés/brouillons, tags, total des vues, derniers articles, plus consultés.
- Gestion des utilisateurs avec rôles, blocage de compte et vérification email.
| Domaine | Technologies |
|---|---|
| Back-end | PHP 8.4, Symfony 8.1, Doctrine ORM 3.6 |
| Front-end | React 19, Redux, React Router, Tailwind CSS v4, Vite 8 |
| Intégration | pentatrion/vite-bundle, Symfony UX (Turbo, Stimulus) |
| Base de données | MySQL / MariaDB (compatible via Doctrine DBAL) |
| Admin | EasyAdmin 5 |
| Uploads | VichUploaderBundle |
| Sécurité | symfony/security-bundle, rate-limiter |
| Contenu | league/commonmark (Markdown → HTML) |
| Emails | symfony/mailer + verify-email-bundle |
| Outils dev | Maker Bundle, Fixtures Bundle, PHPUnit 13, Web Profiler |
Avant de commencer, assure-toi d'avoir installé :
- PHP ≥ 8.4 avec les extensions
ctype,iconv,pdo_mysql - Composer 2.x
- Node.js ≥ 20 et npm
- MySQL 8 ou MariaDB 10.6+
- (Optionnel) Symfony CLI pour le serveur de dev local
git clone https://github.com/Amar1921/devjournal.git
cd devjournalcomposer installnpm installCopie le fichier d'environnement et adapte-le :
cp .env.exemple .env.localÉdite .env.local pour renseigner ta connexion base de données et tes variables :
# .env.local
APP_ENV=dev
APP_SECRET=change_me
# Base de données (adapte user/password/dbname)
DATABASE_URL="mysql://app_user:app_password@127.0.0.1:3306/devjournal?serverVersion=8.0&charset=utf8mb4"
# Mailer (exemple)
MAILER_DSN=smtp://localhost:1025
# Email admin (pour la page de blocage et les alertes)
ADMIN_EMAIL=admin@amarsyll.pro# Créer la base
php bin/console doctrine:database:create
# Jouer les migrations (schéma versionné)
php bin/console doctrine:migrations:migrate🔧 Alternative rapide en dev (sans migrations) :
php bin/console doctrine:schema:update --force
php bin/console doctrine:fixtures:loadVoir la section Fixtures pour le détail de ce qui est généré.
# En mode développement (hot-reload)
npm run dev
# OU pour un build de production
npm run build# Avec Symfony CLI (recommandé)
symfony serve -d
# OU avec le serveur PHP intégré
php -S localhost:8000 -t public/L'application est accessible sur http://localhost:8000 🎉 Le back-office se trouve sur http://localhost:8000/admin.
Le projet fournit des fixtures pour peupler la base avec un jeu de données réaliste, idéal pour tester ou faire une démo :
php bin/console doctrine:fixtures:loadphp bin/console doctrine:fixtures:load --no-interactionLes fixtures génèrent :
- 1 utilisateur administrateur — identifiants par défaut :
- Email :
admin@amarsyll.pro - Mot de passe :
admin1234
- Email :
- ~20 tags techniques (Symfony, React, Doctrine, Vite, JWT, DevOps…).
- 50+ articles répartis sur les trois types (
Article,Bug,Parcours) :- dates de publication réparties sur ~18 mois,
- ~80 % publiés / 20 % en brouillon,
- quelques articles mis en avant (featured),
- 2 à 4 tags aléatoires par article,
- contenu HTML riche (titres, listes, blocs de code).
🔐 Pense à changer le mot de passe admin avant tout déploiement en production.
Le back-office est protégé par le rôle ROLE_ADMIN et accessible sur /admin.
Utilise le compte admin créé par les fixtures (ou crée le tien) :
# Créer un utilisateur admin manuellement (exemple via Maker ou tinker)
php bin/console make:userPour promouvoir un utilisateur existant en admin, tu peux mettre à jour son champ roles en base (["ROLE_ADMIN"]) ou passer par une petite commande dédiée.
| Section | Actions |
|---|---|
| Tableau de bord | Stats globales (articles, vues, brouillons, tags), derniers articles, plus consultés |
| Articles | CRUD complet, publication, mise en avant, upload de couverture, gestion des tags |
| Tags | Création et édition (slug auto-généré) |
| Utilisateurs | Rôles, blocage de compte, statut de vérification |
Le tableau de bord affiche notamment le total cumulé des vues via une requête DQL d'agrégation, et met en valeur les 5 articles les plus récents et les plus consultés.
Post ─────────┬──── ManyToMany ────── Tag
│
├──── ManyToOne ────── User (author)
│
└──── UploadableField ── coverImage (VichUploader)
User ───────── implements UserInterface, PasswordAuthenticatedUserInterface
SecurityEventLog ──── ManyToOne (nullable) ── User
ContactMessage ────── (autonome)
- Énumération typée (
PostType) avec méthodes métier :label(),badgeClasses()(classes Tailwind),icon()etchoices()pour les formulaires — le type est mappé directement en base viaenumType. - Lifecycle callbacks Doctrine sur
Post(PrePersist/PreUpdate) : génération du slug, gestion automatique depublishedAt,createdAt,updatedAt. - Index de base de données explicites pour les performances (
idx_post_published,idx_event_type, etc.). - Sécurité :
Usergère les rôles, le blocage de compte (isBlocked), la vérification email, et unplainPasswordnon persisté pour les formulaires admin. - SEO :
SitemapControllerconstruit un sitemap complet et cacheable en une seule passe. - Intégration Vite/Symfony : deux points d'entrée (
app.jspublic etadmin/index.jsx), manifest activé, minification CSS, alias@versassets/.
devjournal/
├── assets/ # Front-end (React, JS, CSS)
│ ├── app.js # Point d'entrée public
│ └── admin/index.jsx # Point d'entrée admin
├── config/ # Configuration Symfony
├── migrations/ # Migrations Doctrine versionnées
├── public/ # Racine web (build Vite → public/build)
├── src/
│ ├── Controller/ # Contrôleurs (Blog, Sitemap, Security…)
│ │ └── Admin/ # DashboardController + CRUD EasyAdmin
│ ├── Entity/ # Post, Tag, User, SecurityEventLog, ContactMessage
│ ├── Enum/ # PostType
│ ├── Repository/ # Repositories Doctrine
│ ├── Service/ # SecurityMonitorService…
│ └── DataFixtures/ # AppFixtures
├── templates/ # Vues Twig
├── composer.json
├── package.json
├── vite.config.js
└── tailwind.config.js
# Lancer la suite de tests PHPUnit
php bin/phpunit
# Avec couverture (si Xdebug/PCOV activé)
php bin/phpunit --coverage-html var/coverage| Commande | Description |
|---|---|
symfony serve -d |
Démarrer le serveur de dev en arrière-plan |
npm run dev |
Serveur Vite avec hot-reload |
npm run build |
Build de production des assets |
php bin/console doctrine:migrations:migrate |
Appliquer les migrations |
php bin/console doctrine:fixtures:load |
Recharger les données de démo |
php bin/console cache:clear |
Vider le cache Symfony |
php bin/console debug:router |
Lister toutes les routes |
Quelques points d'attention pour un déploiement propre (typiquement sur un VPS Ubuntu avec Apache/Nginx + PHP-FPM) :
# 1. Optimiser l'autoloader et passer en prod
composer install --no-dev --optimize-autoloader
APP_ENV=prod APP_DEBUG=0
# 2. Compiler les assets
npm ci && npm run build
# 3. Vider et préchauffer le cache
php bin/console cache:clear --env=prod
php bin/console cache:warmup --env=prod
# 4. Jouer les migrations
php bin/console doctrine:migrations:migrate --no-interaction --env=prod- Configure le DocumentRoot sur le dossier
public/. - Active HTTPS (Let's Encrypt).
- Renseigne un vrai
MAILER_DSNet unADMIN_EMAIL. - Change
APP_SECRETet le mot de passe admin.
- Flux RSS/Atom des articles publiés
- Données structurées JSON-LD (Article, BreadcrumbList)
- Recherche full-text côté public
- Système de commentaires modérés
- Cache d'application (Redis) sur les pages les plus consultées
- Tests fonctionnels du back-office
Amar Syll — Développeur full-stack (Symfony / React)
- 🌐 Portfolio : amarsyll.pro
- 💼 GitHub : @Amar1921
- ✉️ Contact : amar91syll@gmail.com
Projet sous licence propriétaire. Tous droits réservés. Pour toute demande d'utilisation ou de collaboration, contacte l'auteur.
Construit avec ❤️ et beaucoup de ☕ — Symfony · React · Tailwind