Kinka

🛒 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

Panier & commande

Compte utilisateur

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

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.html → Open 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é

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

Auteur

Abdoulrazack Abdillahi Mahamoud — abdoul.abdillahi@gmail.com

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