Blog Next.js 16 avec Prisma 7, PostgreSQL, Tailwind CSS v4 et React 19.
- Node.js 20+
- PostgreSQL 15+ (local ou via Docker)
git clone <repo-url>
cd blog
npm install# Connexion Prisma pour les migrations
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/blog"
# Connexion directe pour le runtime (doit être une URL postgres:// standard)
POSTGRES_URL="postgresql://postgres:postgres@localhost:5432/blog"
# Clés de signature JWT (valeurs quelconques en dev)
SESSION_SECRET="une-cle-secrete-longue-et-aleatoire"
JWT_SECRET="une-autre-cle-secrete"
# Better Auth (requis même si inutilisé pour le login)
BETTER_AUTH_SECRET="encore-une-cle-secrete"
BETTER_AUTH_URL="http://localhost:3000/"npx prisma generateGénère le client dans
app/generated/prisma/— ce dossier n'est pas commité.
npx prisma migrate dev --name initnpx prisma db seedCrée 2 admins, 3 blogueurs et 6 articles.
| Mot de passe | Rôle | |
|---|---|---|
admin@blog.fr |
admin1234 |
Admin |
superadmin@blog.fr |
super5678 |
Admin |
claire@blog.fr |
claire1234 |
Blogueur |
david@blog.fr |
david1234 |
Blogueur |
emma@blog.fr |
emma1234 |
Blogueur |
npm run devOuvrir http://localhost:3000.
- Docker Desktop ou Docker Engine + Docker Compose
docker compose up --buildCela démarre :
- PostgreSQL sur le port
5432 - L'application Next.js sur le port
3000
Les migrations et le seed sont appliqués automatiquement au démarrage.
# Démarrer en arrière-plan
docker compose up -d --build
# Voir les logs
docker compose logs -f app
# Arrêter
docker compose down
# Arrêter et supprimer les données (base incluse)
docker compose down -v
# Relancer uniquement l'app (sans rebuild)
docker compose restart app
# Ouvrir un shell dans le conteneur app
docker compose exec app sh
# Lancer Prisma Studio depuis le conteneur
docker compose exec app npx prisma studioapp/
├── actions/ # Server Actions
│ ├── auth.ts # login(), logout()
│ ├── post.ts # createPost(), editPost()
│ ├── about.ts # saveAbout() — admin seulement
│ └── profile.ts # updateProfile()
├── api/
│ ├── auth/
│ │ ├── login/ # POST — retourne un JWT (custom)
│ │ ├── register/ # POST — crée un Author (custom)
│ │ └── [...all]/ # better-auth (vestigial)
│ ├── about/ # GET/POST — contenu de la page À propos
│ └── posts/ # GET/POST — liste et création de posts
├── components/
│ ├── Header.tsx
│ ├── LogoutButton.tsx
│ ├── AboutEditor.tsx
│ ├── EditPostForm.tsx
│ └── ProfileForm.tsx
├── lib/
│ ├── session.ts # getSession(), createSession() — server-only
│ ├── jwt.ts # signToken(), decodeToken()
│ ├── prisma.ts # client Prisma singleton
│ ├── auth.ts # better-auth config (vestigial)
│ └── auth-client.ts# better-auth client (vestigial)
├── blog/
│ ├── page.tsx # Liste des articles (ISR)
│ ├── [id]/ # Article complet (ISR)
│ ├── create/ # Créer un article
│ └── edit/[id]/ # Modifier un article
├── about/ # Page À propos (ISR, éditeur admin intégré)
├── profil/ # Profil utilisateur
│ └── edit/ # Modifier son profil
├── login/ # Connexion (custom JWT)
└── signup/ # Inscription (better-auth)
prisma/
├── schema.prisma
├── seed.ts
└── migrations/
- Authentification : le login utilise un système JWT custom (
app/lib/session.ts). Le cookiesessionest httpOnly et signé avecSESSION_SECRET. - Mots de passe : stockés en clair dans la table
Author(pas de hachage). À ne pas utiliser en production sans ajout de bcrypt. - ISR :
/blog,/blog/[id]et/aboututilisent l'ISR on-demand. Les pages sont régénérées uniquement quand un article est créé/modifié ou que le contenu About est sauvegardé. - Client Prisma : généré dans
app/generated/prisma/avec@prisma/adapter-pg(driver adapter natif, pas le client standard).