Repo : gitlab.lorva.dev/root/lorva-website (remote origin)
Branche principale : master
Déploiement : runner GitLab → SSH → lorva-public (10.10.30.10)
URL publique : https://lorva.dev
Le site est constitué de deux composants déployés en Docker Compose sur la VM lorva-public :
| Composant | Image | Rôle |
|---|---|---|
lorva-web |
nginx:alpine + HTML statique |
Serveur web public |
lorva-mailer |
node:22-alpine |
API backend (support + release notes) |
Le service web proxyifie les requêtes /api/* vers lorva-mailer:3000. Toutes les autres requêtes sont servies statiquement par nginx.
/html/assets/global.css
#09090f, surface rgba(255,255,255,0.03)-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI'--bg, --surface, --border, --text, --muted, --fainthtml.fr
.lang-fr masqué par défaut ; affiché quand html.fr est présentlocalStorage (clé lang)<script> inline en <head> (évite le flash de mauvaise langue)backdrop-filter: blur(12px)lorva-mailer (Node.js)lorva-web (réseau Docker internal)| Variable | Valeur par défaut | Usage |
|---|---|---|
SMTP_HOST |
mail.btjp.fr |
Serveur SMTP (Stalwart) |
SMTP_PORT |
465 |
Port SMTPS |
SMTP_SECURE |
true |
TLS |
SMTP_USER |
— | Compte SMTP |
SMTP_PASS |
— | Mot de passe SMTP |
MAIL_FROM |
[email protected] |
Expéditeur |
MAIL_TO |
[email protected] |
Destinataire des tickets |
ALLOWED_ORIGIN |
https://lorva.dev |
CORS whitelist |
GITLAB_TOKEN |
— | Token lecture API GitLab lorva.dev |
GITHUB_TOKEN |
— | Token lecture API GitHub (LanProbe) |
Fichier /nginx.conf copié dans l'image web :
location /api/ {
proxy_pass http://lorva-mailer:3000;
}
location / {
try_files $uri $uri/ $uri/index.html =404;
}
Les sous-pages (ex. /klibri/support) sont résolues via $uri/index.html — chaque section est un dossier avec son propre index.html.
html/
├── assets/
│ └── global.css # CSS commun à toutes les pages
├── index.html # Page d'accueil LORVA
├── legal/
│ └── index.html # Mentions légales (EN + FR)
├── klibri/
│ ├── index.html # Page produit Klibri
│ ├── support/
│ │ └── index.html # Formulaire de support Klibri
│ ├── privacy/
│ │ └── index.html # Politique de confidentialité Klibri
│ └── assets/
│ ├── klibri-icon.png
│ ├── klibri-screen-iphone.png
│ └── klibri-screen-ipad.png
├── taskori/
│ ├── index.html # Page produit Taskori
│ ├── support/
│ │ └── index.html # Formulaire de support Taskori
│ └── privacy/
│ └── index.html # Politique de confidentialité Taskori
├── lanprobe/
│ ├── index.html # Page produit LanProbe
│ └── assets/
│ └── lanprobe-icon.png
├── privacy/
│ ├── klibri/index.html # Alias legacy
│ └── taskori/index.html # Alias legacy
└── support/
└── klibri/index.html # Alias legacy
/)Cards produits en grille CSS (auto-fill, minmax(280px, 1fr)) :
iOS, lien App Store, liens Support + PrivacySaaS, lien vers taskori.app, badge "Coming soon"Open Source, lien vers releases GitHub/klibri)iOS / Freeid6768134637)/api/releases/klibri)/taskori)https://taskori.app/lanprobe)github.com/Ops-Lorva/lanprobe/releases/api/releases/lanprobe)/klibri/support, /taskori/support)POST /api/support (fetch JSON)app transmis au backend pour identifier le produit dans l'objet de l'email/klibri/privacy, /taskori/privacy)/legal)lang-en / lang-frlorva-mailer)POST /api/supportEnvoie un email de support.
Body JSON :
{
"name": "John Doe",
"email": "[email protected]",
"topic": "bug",
"message": "...",
"app": "Klibri"
}
Validations :
name, email, message, appEmail généré :
"Klibri Support" <[email protected]>MAIL_TO[Klibri] Support request — bugRéponses : { ok: true } / { ok: false, error: "..." } + HTTP 400/500
GET /api/releases/klibriRécupère les releases depuis l'API GitLab privée gitlab.lorva.dev.
GET https://gitlab.lorva.dev/api/v4/projects/43/releasesPRIVATE-TOKEN: <GITLAB_TOKEN>### English et ### Français (ou Francais) sont extraites séparément pour renvoyer notes_en et notes_frnotes_fr = notes_enRéponse JSON :
[
{
"version": "1.0.4",
"date": "2026-05-01",
"notes_en": ["Fixed PDF rendering on iPad", "..."],
"notes_fr": ["Correction du rendu PDF sur iPad", "..."]
}
]
Côté client (page Klibri) : la première release est auto-ouverte, les autres sont repliées. Les dates sont formatées en JS selon la langue active (Jan 1, 2026 / 1 jan. 2026).
GET /api/releases/lanprobeRécupère les release notes depuis le CHANGELOG.md du repo (format Keep a Changelog), comme pour Klibri.
GET https://raw.githubusercontent.com/Ops-Lorva/lanprobe/main/CHANGELOG.mdlorva-mailer## [x.y.z] - date ; au sein de chaque bloc, les sections ### English / ### Français -> notes_en / notes_fr (puces multi-lignes fusionnées, markdown nettoyé)Réponse JSON :
[
{
"version": "1.1.4",
"date": "2026-06-01",
"notes_en": ["..."],
"notes_fr": ["..."]
}
]
Note : depuis 2026-06-01, LanProbe est bilingue EN/FR comme Klibri, et la source est le CHANGELOG.md du repo (plus les GitHub releases auto-générées).
GET /healthzRetourne { ok: true }. Utilisé pour les health checks Docker.
.gitlab-ci.ymlPipeline déclenché uniquement sur la branche master, en 2 stages :
Stage build :
docker build --push -t $CI_REGISTRY_IMAGE/web:latest .
docker build --push -t $CI_REGISTRY_IMAGE/mailer:latest ./mailer
Les deux images sont poussées vers le registry GitLab de gitlab.lorva.dev.
Stage deploy :
DEPLOY_SSH_KEY[email protected] (VM lorva-public)gitlab-ci-deploy) est autorisée sur [email protected] via NetBox : enregistrée sur la machine lorva-public dans netbox.lorva.dev et poussée dans authorized_keys par netbox-sync-lorva (cron */15, conteneur sur lorva-infra). Ne jamais éditer authorized_keys à la main.docker login sur le registry GitLabcd /docker/lorva && docker compose pulldocker compose up -d --remove-orphansImage web (./Dockerfile) :
FROM nginx:alpine
COPY html /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
Image mailer (./mailer/Dockerfile) :
FROM node:22-alpine
WORKDIR /app
COPY package.json .
RUN npm install --production
COPY index.js .
USER node
EXPOSE 3000
CMD ["node", "index.js"]
| Variable | Usage |
|---|---|
DEPLOY_SSH_KEY |
Clé SSH privée pour accès [email protected] (pubkey gitlab-ci-deploy autorisée via NetBox -> netbox-sync) |
CI_REGISTRY_USER / CI_REGISTRY_PASSWORD |
Auth registry GitLab (auto-injectées) |
CI_REGISTRY / CI_REGISTRY_IMAGE |
URL registry (auto-injectées) |
SMTP_USER / SMTP_PASS |
Injectées dans docker-compose via .env sur l'hôte |
GITLAB_TOKEN |
Token read-only API GitLab lorva.dev (projet 43 = Klibri) |
GITHUB_TOKEN |
Token read-only GitHub API (LanProbe) |
lorva-public)Fichier /docker/lorva/docker-compose.yml :
lorva-web : réseau web (Traefik) + internal
172.32.0.40lorva.dev et www.lorva.dev, entrypoint websecure, TLS Let's Encrypt via resolver le (DNS-01)lorva-mailer : réseau web + internal (pas de label Traefik, non exposé directement)internal : internal: true (isolé de l'extérieur)Mécanisme entièrement côté client, sans JavaScript côté serveur :
<head> avant le CSS : si localStorage.lang === 'fr', ajoute la classe fr sur <html> immédiatement (pas de flash).lang-fr { display: none !important } par défaut ; html.fr .lang-en { display: none !important } et html.fr .lang-fr { display: revert !important } activent la version FRsetLang(lang, btn) qui met à jour la classe et localStorageLes textes FR et EN coexistent dans le même DOM — seule la visibilité CSS change.
lorva-public sur infra LORVA OVH KS-16)[email protected][email protected]| Chemin | Description |
|---|---|
/home/benjamin/projects/LORVA/lorva-website/ |
Racine du repo |
html/ |
Sources HTML statiques (copiées dans l'image nginx) |
html/assets/global.css |
CSS partagé entre toutes les pages |
mailer/index.js |
Toute la logique API (support + releases) |
mailer/package.json |
Dépendances : express ^4.19.2, nodemailer ^6.9.13 |
nginx.conf |
Config nginx (proxy /api/ + serve statique) |
docker-compose.yml |
Définition des services web + mailer |
Dockerfile |
Image nginx (web) |
mailer/Dockerfile |
Image Node.js (mailer) |
.gitlab-ci.yml |
Pipeline CI/CD (build + deploy SSH) |
/docker/lorva/ |
Répertoire de déploiement sur lorva-public (10.10.30.10) |