- TypeScript 68%
- CSS 21.6%
- Nunjucks 9.1%
- Dockerfile 0.9%
- JavaScript 0.3%
- Other 0.1%
|
|
||
|---|---|---|
| prisma | ||
| public | ||
| src | ||
| themes | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| next.config.mjs | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.mjs | ||
| README.md | ||
| tsconfig.json | ||
Cursus
Cursus est une application web auto-hébergée pour créer, héberger et exporter un CV. On édite son CV en ligne (enregistrement automatique), on le publie à une URL publique, et on l'exporte en PDF A4 au rendu identique quel que soit le navigateur — la génération est faite côté serveur par un Chromium headless.
Le logo reprend la case de l'élément Cu (n°29) du tableau périodique — clin d'œil à Cursus.
Fonctionnalités
- ✍️ Éditeur en ligne avec enregistrement automatique (aucun bouton « Enregistrer ») et interface en barre latérale.
- 🌐🔒 CV public et CV privé : chaque section / contact / élément a une visibilité Public, Privé ou Public et privé.
- 🎨 7 thèmes intégrés + thèmes « fichiers » : déposez un dossier (
theme.json+template.njk+styles.css) dansthemes/et il apparaît au runtime, sans recompiler (voirthemes/README.md). - 🖨️ Export PDF déterministe (A4, marges par thème) identique à l'écran, généré par Playwright/Chromium.
- 📄 Aperçu paginé sur le web : la page s'affiche comme le PDF (feuilles A4 empilées), avec respect de l'option « ne pas couper un bloc ».
- 🖼️ Photo avec recadrage / zoom / rotation avant upload.
- 🔁 Export / Import JSON du CV complet.
- 🧩 Sections repliables, champs contextuels selon le type de section, couleur d'accent et taille de texte réglables.
Prérequis
- Docker et Docker Compose v2 (
docker compose …). - Rien d'autre : Node, la base SQLite et le Chromium d'export PDF sont embarqués dans l'image.
Déploiement avec Docker Compose (pas à pas)
1. Récupérer le projet
git clone https://forge.lequen.fr/jlequen/Cursus.git cursus
cd cursus
2. Créer le fichier de configuration .env
cp .env.example .env
Puis éditez .env et renseignez au minimum :
| Variable | À mettre |
|---|---|
AUTH_SECRET |
Un secret long et aléatoire — générez-le avec la commande ci-dessous |
ADMIN_EMAIL |
L'email de connexion à l'éditeur |
ADMIN_PASSWORD |
Le mot de passe initial de ce compte |
PUBLIC_BASE_URL |
L'URL publique finale (ex. https://cv.mon-domaine.fr) |
APP_PORT |
Le port exposé sur l'hôte (par défaut 63546) |
Générer un AUTH_SECRET solide :
openssl rand -base64 32
⚠️
.envcontient vos secrets et n'est pas versionné (il est dans.gitignore). Ne le committez jamais.
3. Construire et lancer
docker compose up -d --build
Au premier démarrage, le conteneur applique les migrations, crée le compte admin (à partir de ADMIN_EMAIL / ADMIN_PASSWORD) puis démarre l'app. Suivez les logs :
docker compose logs -f
4. Accéder à l'application
- CV public : http://localhost:63546/
- Éditeur : http://localhost:63546/admin → connectez-vous avec
ADMIN_EMAIL/ADMIN_PASSWORD.
(Remplacez le port si vous avez changé APP_PORT.)
Le CV est vide au départ : tout se remplit dans l'éditeur, ou via Import JSON.
5. Mettre à jour, arrêter, redémarrer
# Récupérer une nouvelle version puis reconstruire
git pull
docker compose up -d --build
# Arrêter (les données sont conservées dans le volume)
docker compose down
# Voir les logs
docker compose logs -f
Mise en production derrière un reverse proxy
Le conteneur écoute en interne sur le port 3000 et est exposé sur l'hôte via APP_PORT (63546 par défaut). Placez un reverse proxy (Nginx, Caddy, Traefik…) devant, en TLS, qui transmet vers http://127.0.0.1:63546, et réglez PUBLIC_BASE_URL sur l'URL HTTPS publique.
Configuration (variables d'environnement)
| Variable | Défaut | Rôle |
|---|---|---|
APP_PORT |
63546 |
Port exposé sur l'hôte |
ADMIN_EMAIL |
admin@example.com |
Login de l'éditeur (créé au 1er démarrage) |
ADMIN_PASSWORD |
changeme-please |
Mot de passe initial (à changer !) |
AUTH_SECRET |
— | Secret de signature des sessions JWT (obligatoire) |
PUBLIC_BASE_URL |
http://localhost:3000 |
URL publique (liens canoniques / rendu PDF) |
DATABASE_URL |
file:/app/data/cv.db |
Base SQLite (sur le volume persistant) |
THEMES_DIR |
/app/themes |
Dossier des thèmes fichiers (monté en volume) |
CHROMIUM_PATH |
/usr/bin/chromium |
Chromium headless pour l'export PDF (fourni par l'image) |
Le mot de passe n'est créé qu'au premier démarrage. Pour le changer ensuite, utilisez Compte → Changer le mot de passe dans l'éditeur (modifier
ADMIN_PASSWORDaprès coup n'a pas d'effet).
Données & sauvegarde
- Toutes les données (base SQLite + photos uploadées) vivent dans le volume Docker
cv-data— elles survivent àdown/up/--build. - Sauvegarde rapide du contenu : éditeur → Compte → Exporter en JSON. Restauration via Importer.
- Sauvegarde du volume complet :
docker run --rm -v cv-data:/data -v "$PWD":/backup alpine \
tar czf /backup/cv-data-backup.tar.gz -C /data .
Thèmes
Deux possibilités :
- Thèmes intégrés (déjà livrés) : sélectionnables dans Apparence → Thème.
- Thèmes fichiers : déposez un dossier dans
themes/(monté en volume), rechargez la page — aucun rebuild. Format et variables documentés dansthemes/README.md.
Sécurité
- Changez
AUTH_SECRETetADMIN_PASSWORDavant toute mise en ligne. .env, la base de données (*.db,/data) et les sauvegardes (/backups) sont exclus du dépôt (.gitignore) : aucun secret ni donnée personnelle n'est versionné.- Servez l'application en HTTPS derrière un reverse proxy.
Développement local (sans Docker)
npm install
cp .env.example .env # adaptez DATABASE_URL en local si besoin
npx prisma migrate deploy
npm run seed
npm run dev # http://localhost:3000
L'export PDF en local nécessite un Chromium/Chrome installé ; pointez CHROMIUM_PATH dessus.
Stack technique
- Next.js 15 (App Router) · React 19 · TypeScript · Tailwind CSS v4
- Prisma + SQLite
- Playwright (Chromium headless) pour l'export PDF A4 déterministe
- Nunjucks (+
marked/sanitize-html) pour les thèmes fichiers - Authentification par session JWT (
jose) + bcrypt