Skip to content

Repository files navigation

🛒 Kinka — E-commerce de Mangas

Plateforme e-commerce full-stack pour libraires de mangas — catalogue filtré, panier hybride (localStorage invité / MySQL connecté), tunnel d'achat complet, annonces seconde main, avis, i18n FR/EN. Vanilla JS frontend (no framework), Node/Express/MySQL backend, JWT auth.

Node Express MySQL JWT Vanilla JS Figma

🌐 Démo en direct (UI statique sans backend)

https://abdoulrazack1.github.io/Kinka/page_accueil.html

Kinka — Page d'accueil

Scroll through Kinka — Hero Chainsaw Man → Maisons d'édition → Catégories → Premium

⚠️ La version live sur GitHub Pages affiche l'UI complète (CSS, navigation, mode sombre, i18n) mais sans données dynamiques — le backend Node/Express/MySQL n'est pas déployé. Pour la version complète avec catalogue, panier et auth, suis les instructions d'installation ci-dessous.


💡 Pourquoi Kinka

Use case Comment Kinka le résout
Visiteur ajoute des articles Panier en localStorage — pas de friction d'inscription
Visiteur s'inscrit après Migration auto du panier localStorage → MySQL au login (sans perte)
Vendre du neuf et de l'occasion Catalogue principal + section "Annonces" avec CRUD utilisateur
i18n FR/EN Système de traduction custom, 1800+ chaînes
Auth solide pour DWWM JWT + bcrypt (12 rounds) + rate-limit + auth-guard côté client

Pas une démo — 41 pages HTML, 38 feuilles CSS, 18 scripts JS, 32 endpoints API, mode sombre + responsive complet.


Stack

Front : HTML5 · CSS3 · JavaScript ES6+ (sans framework) · Figma Back : Node.js (Express) · MySQL · JWT (jsonwebtoken) · bcryptjs Outils : Git · Live Server (VS Code, port 5503)

Fonctionnalités

Catalogue

  • Filtres dynamiques multi-critères (catégorie, état, éditeur, prix, auteur) sans rechargement
  • Moteur de recherche instantané (titre, série, auteur, éditeur, description)
  • Pages dédiées : nouveautés, promotions, coups de cœur, coffrets, occasion, par catégorie

Panier & commande

  • Panier hybride : localStorage si visiteur, base MySQL si connecté
  • Tunnel complet : panier → paiement (avec adresse) → confirmation → suivi
  • Calcul automatique du sous-total, des frais de livraison (gratuits dès 50 €) et du TTC
  • Décrémentation transactionnelle des stocks

Compte utilisateur

  • Inscription, connexion, mot de passe oublié, modification du profil
  • Stockage JWT en localStorage + cookie « se souvenir de moi » (30 jours)
  • Pages protégées par auth-guard (panier, paiement, profil, favoris, …)

Favoris : ajout/retrait synchronisé entre localStorage (visiteur) et BDD (connecté)

Annonces seconde main : création/édition/suppression par les utilisateurs

Avis : note + commentaire (une fois par produit)

Légal & support : CGU, CGV, politique de retour, FAQ, contact (formulaire branché à l'API)

Mode sombre : toggle persistant + respect du prefers-color-scheme système

i18n : système de traduction FR/EN (1800+ chaînes)

Structure du projet

Kinka/
├── README.md                       ← ce fichier
├── .gitignore                      ← exclut node_modules, .env, builds
├── .vscode/                        ← config Live Server (port 5503)
│
├── client/                         ← Front
│   ├── pages/                      ← 42 pages HTML
│   │   ├── page_accueil.html       ← homepage avec carrousel
│   │   ├── page_catalogue.html     ← catalogue filtré
│   │   ├── page_detail_produit.html← fiche produit (+ onglet avis)
│   │   ├── page_annonces.html      ← annonces entre membres
│   │   ├── page_admin.html         ← back-office
│   │   └── …
│   └── assets/
│       ├── css/                    ← feuilles de style (1 par page + partagées)
│       ├── images/                 ← logos, bannières, visuels
│       └── js/                     ← scripts frontend
│           ├── kinka-api-client.js ← client API + auth + cookies + toast
│           ├── kinka-cards.js      ← rendu des cartes produit
│           ├── admin.js            ← logique du back-office
│           ├── avis.js             ← avis clients
│           └── …
│
├── server/                         ← Backend Node.js (MVC)
│   ├── src/
│   │   ├── server.js               ← point d'entrée : middlewares + montage des routes
│   │   ├── routes/                 ← déclaration des URL (chemin + middlewares)
│   │   ├── controllers/            ← logique applicative
│   │   ├── models/                 ← accès aux données : tout le SQL vit ici
│   │   ├── views/emails/           ← gabarits des emails envoyés par le serveur
│   │   ├── services/               ← dépendances externes (SMTP, API Jikan)
│   │   ├── middleware/             ← auth JWT, rôle admin, validation
│   │   └── config/db.js            ← pool MySQL (mysql2/promise)
│   ├── scripts/
│   │   ├── seed_big.js             ← jeu de données de démonstration
│   │   ├── sync_mangas_jikan.js    ← import depuis MyAnimeList
│   │   ├── sync_covers_mangadex.js ← une couverture par tome
│   │   └── make_admin.js           ← promotion d'un compte en administrateur
│
├── database/
│   ├── schema.sql                  ← structure seule
│   ├── seed.sql                    ← données de démonstration
│   └── migrations/                 ← évolutions du schéma
│
├── docs/                           ← documentation et captures d'écran
└── .env.example                    ← copier en .env

Démarrage rapide

Prérequis

  • Node.js ≥ 18 (pour fetch natif)
  • MySQL ≥ 8 ou MariaDB ≥ 10.5
  • VS Code avec extension Live Server (recommandé pour le front)

1. Cloner le projet

git clone https://github.com/Abdoulrazack1/Kinka.git
cd Kinka

2. Installer le backend

npm install

3. Créer la base de données

Dans MySQL :

CREATE DATABASE kinka_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Puis importer le schéma :

mysql -u root -p kinka_db < kinka_db.sql

4. Configurer l'environnement

cp .env.example .env

Éditer .env avec vos valeurs :

PORT=3000

DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=kinka_db
DB_USER=root
DB_PASS=ton_mot_de_passe

# Générer une clé robuste avec :
#   node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"
JWT_SECRET=remplacer_par_une_cle_aleatoire_longue
JWT_EXPIRES_IN=7d

CLIENT_URL=http://127.0.0.1:5503

5. Importer les données initiales

npm run seed:big                       # Jeu de données de démonstration
node server/scripts/create_demo_user.js  # Compte démo : demo@kinka.fr / demo1234

(Optionnel : npm run sync pour ajouter ~100 mangas depuis MyAnimeList via Jikan)

6. Lancer le backend

npm start            # Production
npm run dev          # Développement (rechargement auto avec nodemon)

Vérifier :

GET http://localhost:3000/api/health
→ { "success": true, "message": "Kinka API en ligne 🎌", "version": "2.0.0" }

7. Lancer le front

Ouvrir le projet dans VS Code et clic-droit sur page_accueil.htmlOpen with Live Server. Le front sera servi sur http://127.0.0.1:5503.

Démarrage : npm run dev sert à la fois l'API et le site sur http://localhost:3000 — front et API sur la même origine, sans configuration d'hôte virtuel. Le site reste servable par Apache : le .htaccess à la racine redirige vers client/ et bloque l'accès web à server/, database/ et docs/.

Compte de démonstration

Après node server/scripts/create_demo_user.js :

Email Mot de passe Plan
demo@kinka.fr demo1234 Premium

Endpoints de l'API

Méthode Route Auth Description
GET /api/health Vérification du serveur
POST /api/auth/register Inscription
POST /api/auth/login Connexion
POST /api/auth/forgot Demande de réinitialisation
POST /api/auth/reset Enregistrer le nouveau mot de passe
GET /api/auth/me Profil courant
PUT /api/auth/me Modifier le profil
PUT /api/auth/password Changer le mot de passe
DELETE /api/auth/me Supprimer le compte
GET /api/produits Liste filtrée + paginée
GET /api/produits/search?q= Recherche (titre, série, auteur…)
GET /api/produits/:id Détail d'un produit
GET /api/editeurs Maisons d'édition + nb de titres
GET /api/editeurs/:slug Fiche d'une maison d'édition
GET /api/panier Mon panier
POST /api/panier Ajouter un article
PUT /api/panier/:id Modifier la quantité
DELETE /api/panier/:id Retirer un article
DELETE /api/panier Vider le panier
GET /api/favoris Mes favoris
POST /api/favoris Ajouter un favori
DELETE /api/favoris/:id Retirer un favori
DELETE /api/favoris Vider les favoris
GET /api/commandes Historique commandes
GET /api/commandes/:id Détail d'une commande
POST /api/commandes Passer une commande (transaction)
GET /api/annonces Liste des annonces (occasion)
GET /api/annonces/mes-annonces Mes annonces publiées
GET /api/annonces/:id Détail d'une annonce
POST /api/annonces Publier une annonce
PUT /api/annonces/:id Modifier une annonce
DELETE /api/annonces/:id Supprimer une annonce
GET /api/avis?produit_id= Avis d'un produit
POST /api/avis Publier ou modifier un avis
DELETE /api/avis/:produit_id Supprimer mon avis
GET /api/mangas/search?q= Recherche Jikan (sans BDD)
GET /api/mangas/:mal_id Fiche Jikan par identifiant MAL
POST /api/mangas/sync 🔒 Sync mangas populaires
POST /api/mangas/sync-one 🔒 Importer un manga par mal_id
POST /api/newsletter Inscription newsletter
POST /api/contact Envoyer un message de contact

Légende : — public · ✓ connecté · 🔒 administrateur

Back-office

Toutes ces routes exigent un compte administrateur.

Méthode Route Description
GET /api/admin/stats Chiffres du tableau de bord
GET /api/admin/produits Catalogue (recherche, filtres)
POST /api/admin/produits Créer une fiche produit
PUT /api/admin/produits/:id Modifier une fiche produit
DELETE /api/admin/produits/:id Supprimer une fiche produit
GET /api/admin/commandes Toutes les commandes
GET /api/admin/commandes/:id Détail + historique des statuts
PATCH /api/admin/commandes/:id Statut, transporteur, numéro de suivi
GET /api/admin/avis File de modération des avis
PATCH /api/admin/avis/:id Publier ou retirer un avis
DELETE /api/admin/avis/:id Supprimer un avis
GET /api/admin/annonces Annonces entre membres
PATCH /api/admin/annonces/:id Changer le statut d'une annonce
DELETE /api/admin/annonces/:id Supprimer une annonce
GET /api/admin/contact Messages reçus
PATCH /api/admin/contact/:id Marquer traité / rouvrir
DELETE /api/admin/contact/:id Supprimer un message (spam)
GET /api/admin/newsletter Inscrits à la newsletter
GET /api/admin/newsletter/export Export CSV des inscrits
GET /api/admin/utilisateurs Comptes clients
PATCH /api/admin/utilisateurs/:id Changer le rôle d'un compte
GET /api/admin/logs Journal des actions d'administration

Toutes les réponses suivent le format :

{ "success": true,  "data":  { } }
{ "success": false, "error": "Message" }
{ "success": false, "errors": { "champ": "Message" } }

Les routes protégées attendent un header :

Authorization: Bearer <token_jwt>

Utilisation côté front

Toute page HTML inclut les scripts dans cet ordre (gérés par auth-guard et panier hybride) :

<script src="../assets/js/kinka-api-client.js"></script>
<script src="../assets/js/kinka-auth-guard.js"></script>
<script src="../assets/js/kinka-cards.js"></script>
<script src="../assets/js/authentification.js"></script>
<script src="../assets/js/panier.js"></script>
<script src="../assets/js/favoris.js"></script>
<script src="../assets/js/darkmode.js"></script>
<script src="../assets/js/recherche.js"></script>
<script src="../assets/js/translate.js"></script>

Exemples d'utilisation :

// Connexion (avec « se souvenir de moi »)
const user = await KinkaAPI.auth.login('demo@kinka.fr', 'demo1234', true);

// Catalogue filtré
const mangas = await KinkaAPI.produits.getAll({ categorie: 'Shônen', promo: '1' });

// Panier
await KinkaAPI.panier.add('one-piece-105', 1);

// Toast (XSS-safe, défini globalement)
showToast('Ajouté au panier !', 'success');

Pour pointer vers une autre URL d'API, définir avant le chargement du client :

<script>window.KINKA_API_URL = 'https://api.kinka.fr/api';</script>
<script src="../assets/js/kinka-api-client.js"></script>

Sécurité

  • Mots de passe hachés avec bcrypt (12 rounds)
  • Authentification par JWT (HS256, 7 jours par défaut)
  • Rate limiting : 100 req/min sur /api, 10 req/15 min sur /api/auth, 600/min sur les couvertures. Le limiteur ne couvre volontairement pas les pages et les assets : un affichage demande une trentaine de fichiers, et un plafond global rendait le site inaccessible au bout de trois pages visitées.
  • Politique de mot de passe : 8 à 72 caractères, au moins deux familles de caractères, pas de répétition d'un seul caractère. Appliquée à l'inscription, au changement depuis le profil et à la réinitialisation — le contrôle côté client (kinkaFaiblesseMotDePasse) n'est qu'un confort, le serveur tranche.
  • Champ leurre anti-robot (site_web) sur l'inscription et le contact : invisible et hors du parcours clavier, il fait refuser toute requête qui le remplit. Le message de contact suspect reçoit une réponse de succès ordinaire mais n'est pas enregistré.
  • Validation systématique des entrées (middleware/validate.js)
  • Requêtes paramétrées (mysql2) → pas d'injection SQL
  • XSS : échappement HTML dans toutes les fonctions de rendu (_esc, _e)
  • CORS configurable via CLIENT_URL
  • Bannière de consentement RGPD (cookies)
  • Auth-guard côté client pour les pages sensibles (kinka-auth-guard.js) : redirige vers la connexion en mémorisant la destination. Le panier et la page Premium restent ouverts aux visiteurs ; la connexion n'est exigée qu'au paiement.

Accessibilité

Les deux thèmes respectent le niveau WCAG AA (contraste 4,5:1 pour le texte courant, 3:1 pour les grands titres), vérifié par mesure sur 16 pages × 2 thèmes.

Le rose de marque #e03b8b ne satisfait ce seuil dans aucun de ses deux rôles : 4,14:1 en texte sur fond sombre, 4,06:1 en aplat sous du texte blanc. Aucune valeur unique ne convient — assombrir améliore l'aplat et dégrade le texte. Deux déclinaisons sont donc appliquées, générées depuis les feuilles du projet :

Rôle Couleur Ratio
le rose est le texte #ef5a9f (sombre) / #c62372 (clair) 5,31:1 / 4,90:1
le rose porte du texte blanc #d12d7d 4,79:1

Le jeton --pink lui-même est inchangé : bordures, icônes et usages décoratifs gardent la teinte d'origine. Les surcharges vivent dans darkmode.css et contraste-clair.css.

La mise en page ne déborde plus horizontalement de 320 à 1280 px (18 pages vérifiées). La cause était presque toujours la même : un élément de grille garde min-width: auto et impose la largeur minimale de son contenu à sa piste.

Qualité du code

npm run lint          # ESLint + contrôle des scripts inline
npm run lint:inline   # uniquement le JS écrit dans les pages HTML
npm run format        # Prettier

lint:inline existe parce qu'ESLint ne lit que les fichiers .js : les ~1600 lignes de JavaScript écrites directement dans les <script> des pages n'étaient vérifiées par rien. C'est précisément là que se trouvaient les deux pannes les plus visibles de l'audit (une IIFE et un setTimeout non refermés, qui rendaient muet tout le script de la page Contact et de la page Paiement). Le script échoue avec un code de sortie non nul, il est donc utilisable en CI.

Bonnes pratiques de production

  • Remplacer JWT_SECRET par une clé forte générée aléatoirement (64 octets)
  • Restreindre CLIENT_URL à votre domaine de production (au lieu de *)
  • Activer HTTPS (les cookies sont en SameSite=Lax ; passer en Strict + Secure derrière HTTPS)
  • Mettre en place un vrai service d'envoi d'emails pour /auth/forgot (le code actuel logge en console)
  • Pré-générer les indexes (déjà inclus pour categorie, promo, nouveaute, bestseller, commandes.user_id)
  • Brancher un reverse proxy (nginx) devant le Node + servir le statique depuis nginx

Auteur

Abdoulrazack Abdillahi Mahamoudabdoul.abdillahi@gmail.com

Projet réalisé dans le cadre de la formation Développeur Web et Web Mobile (DWWM).

About

Manga e-commerce (DWWM project) -- vanilla JS frontend, Node/Express/MySQL backend, hybrid cart (localStorage / MySQL), JWT auth.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages