No description
  • JavaScript 62.4%
  • CSS 26.3%
  • HTML 9.7%
  • PowerShell 1.4%
  • Dockerfile 0.2%
Find a file
2026-07-24 16:48:27 +02:00
data création de la structure de dossiers 2026-07-20 15:28:03 +02:00
db correction de l'erreur 2026-07-24 16:32:49 +02:00
docs MAJ du README et de la documentation utilisateur 2026-07-24 16:48:27 +02:00
models Refactoring de models/item.js pour convenir à l'architecture MVC 2026-07-24 14:13:25 +02:00
public Ajout de la suppression de l'image d'un item + reset de la recherche et des filtres 2026-07-24 15:00:29 +02:00
routes Refactoring de models/item.js pour convenir à l'architecture MVC 2026-07-24 14:13:25 +02:00
scripts Merge branch 'main' into dev 2026-07-24 16:25:04 +02:00
services Refactoring de models/item.js pour convenir à l'architecture MVC 2026-07-24 14:13:25 +02:00
.dockerignore ajout de la config docker 2026-07-21 13:25:50 +02:00
.env.example création d'un script de publication automatique sur Docker Hub 2026-07-24 15:30:33 +02:00
.gitignore modification du gitignore 2026-07-21 11:15:45 +02:00
CHANGELOG.md Dump de la v1.0 de my-library 2026-07-24 15:11:47 +02:00
config.js Suppression des valeurs par défauts 2026-07-24 14:33:25 +02:00
docker-compose.yml exemple fonctionnel de docker compose 2026-07-24 15:53:45 +02:00
Dockerfile MAJ des dockers pour la publications des images ainsi que les tests 2026-07-24 15:45:46 +02:00
package-lock.json Update des dependencies better-sqlite3 12.11 -> 13.0 et Node 20 -> 22 2026-07-24 14:37:21 +02:00
package.json ajout de la virgule en fin de ligne 2026-07-24 16:26:11 +02:00
PUBLISH.md création d'un script de publication automatique sur Docker Hub 2026-07-24 15:30:33 +02:00
README.md MAJ du README et de la documentation utilisateur 2026-07-24 16:48:27 +02:00
ROADMAP.md Dump de la v1.0 de my-library 2026-07-24 15:11:47 +02:00
server.js externalisation de l'URL du serveur 2026-07-24 14:01:09 +02:00

My Library

My Library est un projet personnel qui a pour but de garder à jour l'avancement dans les animes, les films, les webtoons, etc...

Stack technique

Couche Technologie
Frontend HTML / CSS / JS Vanilla
Backend Node.js + Express
Base de données SQLite (better-sqlite3) + sauvegarde JSON
Auth Token HMAC (mode Propriétaire/Visiteur) avec timingSafeEqual
Services Couche métier entre les routes et les modèles (services/)
UI CSS Vanilla (Mobile First)
Upload Multer (png/jpg, max 5 Mo)

Prérequis & Installation

Prérequis

  • Node.js 22 ou supérieur
  • npm (inclus avec Node.js)

Installation

npm install
cp .env.example .env

Éditez .env :

Variable Rôle Obligatoire
HOST Hôte d'écoute (défaut : localhost) Non
PORT Port d'écoute (défaut : 3000) Non
OWNER_PASSWORD Mot de passe propriétaire Oui
AUTH_SECRET Clé secrète pour le token HMAC Oui
DOCKER_USER Nom d'utilisateur Docker Hub Non
DOCKER_TOKEN Token ou mot de passe Docker Hub Non

Lancement

npm run dev

Ouvrez http://localhost:3000.

Docker

Build local

npm run docker:build
npm run docker:run

Via Docker Hub (pré-buildé)

docker compose -f docker-compose.hub.yml up -d

Une image pré-buildée est disponible sur Docker Hub : primorion/my-library, mise à jour plus ou moins en même temps que le dépôt git.

Schéma de base de données

CREATE TABLE items (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  cover_image TEXT,
  type TEXT NOT NULL CHECK(type IN ('anime','serie','webtoon','film','video','livre')),
  status TEXT NOT NULL CHECK(status IN ('à regarder','en cours','terminé')) DEFAULT 'à regarder',
  location TEXT,                  -- JSON: [{"name": "...", "url": "..."}]
  rating REAL CHECK(rating >= 0 AND rating <= 100),
  is_favorite INTEGER DEFAULT 0,
  description TEXT,
  metadata TEXT,                  -- JSON selon le type
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE folders (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE folder_items (
  folder_id INTEGER NOT NULL REFERENCES folders(id) ON DELETE CASCADE,
  item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
  PRIMARY KEY (folder_id, item_id)
);

CREATE TABLE tags (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE item_tags (
  item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
  tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
  PRIMARY KEY (item_id, tag_id)
);

-- Index pour la synchronisation
CREATE INDEX IF NOT EXISTS idx_folders_updated_at ON folders(updated_at);
CREATE INDEX IF NOT EXISTS idx_tags_updated_at ON tags(updated_at);

Métadonnées par type (JSON dans metadata)

type metadata
anime, serie {"season": int, "episode": int, "timecode": {"hours": int, "minutes": int, "seconds": int}}
webtoon {"season": int, "chapter": int}
film, video {"timecode": {"hours": int, "minutes": int, "seconds": int}}
livre {"volume": int, "chapter": int, "page": int}

Contrainte : si status = 'en cours'

type Champs obligatoires
anime/serie season + episode
webtoon season + chapter
film/video (timecode optionnel)
livre volume + page (chapter optionnel)

Routes API REST

POST   /api/auth/verify                           Body: { password }

GET    /api/items                                  Query: ?type=&status=&folder_id=&tag=&search=&sort=&order=&page=&limit=
POST   /api/items                                  Body: { title, type, status, location, rating, is_favorite, description, metadata, folder_ids[], tag_ids[] }
GET    /api/items/:id
PUT    /api/items/:id
DELETE /api/items/:id                              → 204 No Content
POST   /api/items/batch-delete                     Body: { ids: [1, 2, 3] }

GET    /api/folders
POST   /api/folders                                Body: { name }
PUT    /api/folders/:id                             Body: { name }
DELETE /api/folders/:id
PUT    /api/folders/:id/items                       Body: { item_ids: [1, 2, 3] }

GET    /api/tags
POST   /api/tags                                   Body: { name }
PUT    /api/tags/:id                                Body: { name }
DELETE /api/tags/:id
POST   /api/items/:id/tags                         Body: { tag_ids: [1, 2] }

POST   /api/upload                                 multipart/form-data → { url: "/uploads/fichier.jpg" }

GET    /api/export?format=json|csv

Arborescence du projet

my-library/
├── config.js                    # Configuration (port, host, auth)
├── server.js                    # Point d'entrée Express
├── package.json
├── .env.example
├── Dockerfile
├── docker-compose.yml
├── docker-compose.hub.yml
├── .dockerignore
├── .gitignore
├── db/
│   ├── schema.js                # Création + migrations des tables SQLite
│   ├── database.js              # Initialisation DB
│   └── backup.js                # Export JSON/CSV
├── routes/
│   ├── items.js                 # CRUD items (délègue à services/)
│   ├── folders.js               # CRUD dossiers
│   ├── tags.js                  # CRUD tags + item_tags
│   ├── upload.js                # Upload d'image
│   ├── export.js                # Export JSON/CSV
│   └── auth.js                  # Authentification propriétaire
├── services/
│   ├── itemService.js           # Logique métier des items
│   └── fileService.js           # Gestion des fichiers (cover)
├── models/
│   ├── item.js
│   ├── folder.js
│   └── tag.js
├── scripts/
│   ├── cleanup-roadmap.js       # Nettoyage ROADMAP → CHANGELOG
│   └── migrate-db.js            # Migration manuelle de la DB
├── public/
│   ├── index.html               # Page principale
│   ├── style.css                # Styles vanilla
│   ├── js/                      # JS client modulaire
│   │   ├── app.js
│   │   ├── api.js
│   │   ├── auth.js
│   │   ├── folders.js
│   │   ├── items.js
│   │   ├── render.js
│   │   └── tags.js
│   └── uploads/                 # Images uploadées
├── data/
│   └── library.db               # Fichier SQLite (généré)
└── docs/
    ├── USER_GUIDE.md            # Guide utilisateur complet
    └── MOBILE.md                # Documentation app mobile

Fonctionnalités

  • Créer des dossiers (animes, films à voir, livres fantasy, etc...)
  • Ajouter des items à un dossier (un item peut être dans plusieurs dossiers)
  • Recherche et filtres (par type, statut, dossier, tag, texte)
  • Upload d'image de couverture (png/jpg, 5 Mo max)
  • Export JSON / CSV
  • Tags libres avec table dédiée
  • Mode Propriétaire/Visiteur — consultation seule vs accès complet (auth via token HMAC avec timingSafeEqual)
  • Raccourcis clavier/ (recherche), N (ajout), Échap (fermer)
  • Mode sombre — automatique selon le système, sauvegardé dans le navigateur
  • Sélection multiple — supprimer en lot
  • Docker — build et lancement via npm run docker:*
  • Configuration — via .env (host, port, mot de passe, secret)
  • Couche service — logique métier extraite des routes (services/)
  • Migrations automatiques — la DB se met à jour au démarrage (db/schema.js)
  • Comparaison sécuriséecrypto.timingSafeEqual pour le mot de passe et le token

Roadmap & Changelog

Le fichier ROADMAP.md liste les bugs, modifications et fonctionnalités à venir. Les entrées terminées (marquées Fait) sont déplacées vers CHANGELOG.md via la commande :

npm run roadmap:cleanup        # bump mineur (v1.0 → v1.1)
npm run roadmap:cleanup major  # bump majeur  (v1.1 → v2.0)

La version du ROADMAP est incrémentée à chaque nettoyage et la date est enregistrée dans l'en-tête. Le CHANGELOG conserve l'historique de toutes les entrées déplacées.