# Showroom VO — affichage du stock véhicules sur écran tactile

Application web autonome qui synchronise périodiquement le fichier de stock
PlanetVO (`.txt`, format `PVO 1.18`) depuis votre FTP, et l'affiche sous
forme de catalogue tactile pour vos clients en showroom.

## Architecture

```
vo-showroom/
├── server/                  → backend Node.js
│   ├── server.js            → serveur web + API (mono-site ou multi-sites)
│   ├── ftpSync.js           → connexion FTP + écriture du cache
│   ├── parser.js            → conversion du .txt PlanetVO en JSON
│   ├── tenants.js           → résolution du site courant par sous-domaine
│   ├── tenants.example.json → modèle de configuration multi-sites
│   ├── sync-cron.js         → script à appeler depuis une tâche CRON OVH
│   ├── .env.example         → modèle de configuration (identifiants FTP)
│   └── data/                → cache par site (généré automatiquement)
└── public/                  → frontend (même code pour tous les sites)
```

Le navigateur ne peut pas se connecter directement à un serveur FTP : c'est
le backend Node.js qui va chercher le fichier à intervalle régulier, le
convertit en JSON, et le sert ensuite via une petite API HTTP consommée par
la page web tactile. Les photos, elles, sont déjà hébergées par PlanetVO
(URLs `https://jupiterfiles.planetvo.fr/...`) : l'application les affiche
directement, sans avoir besoin de les télécharger.

### Protéger l'accès (optionnel)

Le fichier `.env` propose `BASIC_AUTH_USER` / `BASIC_AUTH_PASSWORD` : si
vous les renseignez, le site demande un identifiant/mot de passe avant de
s'afficher (utile si vous préférez ne pas laisser le catalogue accessible
à n'importe qui connaissant l'URL). Laissez-les vides pour un accès libre.
Sur la borne elle-même, Chrome peut mémoriser ces identifiants une fois
saisis au premier lancement.

## Installation

```bash
cd server
npm install
cp .env.example .env
```

Éditez `server/.env` avec les identifiants FTP fournis par PlanetVO :

```
FTP_HOST=ftp.planetvo.fr
FTP_USER=...
FTP_PASSWORD=...
FTP_REMOTE_PATH=/planetvo.txt
```

Démarrage local (pour tester avant déploiement) :

```bash
npm start
```

L'application est alors accessible sur `http://localhost:3000`. Pour la
mise en production sur votre hébergement OVH mutualisé, voir la section
suivante — c'est elle qui fait référence pour le déploiement réel.

## Multi-sites (plusieurs concessions)

L'application peut servir plusieurs concessions en parallèle, chacune sur
son propre sous-domaine (ex. `dev.carkiosq.com` pour commencer, puis
`nom-concession.carkiosq.com` pour chaque nouveau site), avec un seul
déploiement et un seul code à maintenir.

### Comment ça marche

- **`server/tenants.json`** liste vos sites. S'il n'existe pas, l'application
  reste en mode mono-site classique (comportement historique, inchangé).
  Copiez `tenants.example.json` pour démarrer :

  ```json
  [
    { "id": "dev", "subdomain": "dev.carkiosq.com", "dealerName": "Altitude 69" }
  ]
  ```

- Chaque site a ses propres identifiants FTP dans `.env`, préfixés par son
  `id` en majuscules :

  ```
  FTP_HOST_DEV=ftp.planetvo.fr
  FTP_USER_DEV=...
  FTP_PASSWORD_DEV=...
  FTP_REMOTE_PATH_DEV=/planetvo.txt
  ```

  Pour un second site `id: "nouvelle-concession"`, on ajoute de la même
  façon `FTP_HOST_NOUVELLE_CONCESSION`, etc.

- À chaque requête, le serveur regarde le nom de domaine appelé
  (`dev.carkiosq.com`, par exemple) et sert automatiquement les données du
  site correspondant — chacun avec son propre cache (`data/dev/`,
  `data/nouvelle-concession/`...), donc aucun mélange possible entre
  concessions. Un domaine non déclaré dans `tenants.json` renvoie une page
  d'erreur claire plutôt que d'afficher le mauvais stock.

- Le nom de la concession (`dealerName`) s'affiche automatiquement dans la
  barre du haut et l'écran de veille — pas besoin de dupliquer le code
  frontend par site.

- **`sync-cron.js` synchronise tous les sites en une seule tâche CRON** :
  pas besoin de créer une tâche planifiée par concession dans le Manager
  OVH, une seule suffit (voir section suivante).

### Côté OVH

1. **DNS** : dans la zone DNS de `carkiosq.com` (Manager OVH → *Domaines* →
   `carkiosq.com` → *Zone DNS*), ajoutez un enregistrement pour chaque
   sous-domaine (ex. `dev`) pointant vers votre hébergement mutualisé —
   OVH propose généralement un enregistrement CNAME tout prêt vers votre
   hébergement pour ce cas d'usage.
2. **Multisite** : dans le Manager OVH, section *Hébergements* → votre
   offre → *Multisite*, associez chaque sous-domaine à votre hébergement
   Node.js (même application, un seul dossier `www/`).
3. Le reste (déploiement du code, `.env`, tâche CRON) est identique à la
   section précédente, à ceci près que `.env` contient maintenant les
   identifiants FTP de toutes vos concessions, et que `tenants.json` est
   déployé aux côtés du code.

## Déploiement sur OVH mutualisé

Un point important distingue l'hébergement mutualisé d'un VPS : votre
application n'y tourne pas comme un process permanent que vous pilotez —
OVH gère lui-même le cycle de vie du process Node, et il n'y a pas de
minuteur interne fiable en tâche de fond. Le projet est donc découpé en
deux parties indépendantes, adaptées à ce fonctionnement :

- **`server.js`** — le site web lui-même (API + interface tactile). Il ne
  fait que *lire* le cache `data/vehicles.json` à chaque requête, il ne
  déclenche plus la synchro FTP tout seul.
- **`sync-cron.js`** — un script autonome qui se lance, effectue une seule
  synchro FTP, écrit `vehicles.json`, puis se termine immédiatement. C'est
  ce script qu'OVH doit exécuter à intervalle régulier.

### Étapes

1. **Créer l'hébergement Node.js** dans le Manager OVH (section
   *Hébergements web* → votre offre → onglet *Multisite/Node.js* selon
   l'offre). OVH indique la version de Node disponible et la structure de
   dossier attendue (généralement un déploiement par Git, ou dépôt de
   fichiers via FTP/SSH dans `www/`). Suivez l'assistant OVH pour ce point
   précis — l'interface évolue régulièrement, mieux vaut se fier à celle du
   moment plutôt qu'à une capture d'écran figée.

2. **Déposer le projet** (dossier `server/` et `public/`) dans l'espace de
   l'hébergement, puis `npm install` dans `server/` (via SSH si votre offre
   le permet, sinon en local + upload de `node_modules`).

3. **Configurer `.env`** (copié depuis `.env.example`) avec vos identifiants
   FTP PlanetVO. Laissez `ENABLE_INTERNAL_SCHEDULER=false`.

4. **Créer la tâche CRON** dans le Manager OVH (*Hébergements* → votre
   offre → *Tâches planifiées (CRON)* → *Ajouter une tâche*) — une seule
   tâche suffit même avec plusieurs concessions, `sync-cron.js` les
   synchronise toutes à la suite :
   - Commande : chemin absolu vers `node`, suivi du chemin absolu vers
     `sync-cron.js` (OVH affiche le chemin absolu de votre espace, du type
     `/homez.XXX/votre_login/www/server/sync-cron.js`).
   - Fréquence : la granularité minimale dépend de votre offre (certaines
     offres mutualisées OVH ne descendent pas sous 1h entre deux
     exécutions, d'autres permettent plus fin) — réglez au plus proche de
     10-15 min si le manager le permet, sinon au minimum disponible.
   - OVH limite chaque tâche CRON à 3600 secondes d'exécution : très
     largement suffisant ici (la synchro dure quelques secondes).

5. **Vérifiez** dans les logs CRON du Manager OVH (*Statistiques et logs*)
   que la tâche s'exécute avec un `exitcode: 0`, et que `data/vehicles.json`
   se met bien à jour.

6. Pointez le navigateur de la borne (en mode kiosque, voir plus bas) vers
   l'URL de votre hébergement OVH.

> Alternative VPS : si vous changez d'avis pour un VPS OVH plus tard, il
> suffit de repasser `ENABLE_INTERNAL_SCHEDULER=true` dans `.env` et de
> supprimer la tâche CRON — le minuteur interne (`ftpSync.startScheduler`)
> reprend le relais automatiquement, sans autre changement de code.

## Déploiement en mode kiosque sur l'écran tactile

Sur la machine reliée à l'écran, ouvrez Chrome en mode kiosque pointé vers
l'URL de l'application — locale ou distante selon l'option choisie :

```bash
chrome --kiosk --incognito --noerrdialogs --disable-pinch https://dev.carkiosq.com
```

Pour que Chrome se relance automatiquement avec le PC de la borne, deux
options :

- **Windows** : ajoutez un raccourci vers cette commande dans le dossier
  "Démarrage" de l'utilisateur.
- **Linux** : ajoutez un script de démarrage pour Chrome (`.xinitrc` ou
  service systemd). Le site étant hébergé chez OVH, seul le navigateur a
  besoin de démarrer sur cette machine — pas de serveur Node local à gérer.

## ⚠️ Fiabilité du mapping des champs PlanetVO

Le fichier `.txt` PlanetVO n'a pas de spécification publique pour ce format
texte à tabulations (à la différence de son export CSV documenté). Le
mapping des 228 colonnes a été **reconstruit par analyse du fichier réel**
que vous avez fourni, en croisant les valeurs sur l'ensemble des véhicules.

Dans `server/parser.js`, chaque champ utilisé est annoté :

- **[FIABLE]** : confirmé par recoupement (formats de date cohérents, codes
  qui varient logiquement — énergie ES/GO/EL/HY, boîte BVM/BVA/BVRD —, prix
  cohérents avec le kilométrage et la garantie, dimensions qui correspondent
  aux fiches techniques réelles des modèles BMW/MINI du fichier...).
- **[INCERTAIN]** : estimation raisonnable mais non confirmée à 100 % (ex.
  cylindrée, nombre de rapports, certaines dimensions). Ces champs sont
  affichés dans la fiche détail mais peuvent être retirés facilement si vous
  constatez une incohérence.

**Recommandation avant mise en production** : vérifiez au minimum le champ
prix (`FIELD.PRICE_CENTS`, colonne 39) sur quelques véhicules en comparant
avec votre interface PlanetVO, puisque c'est le seul champ visible par vos
clients qui aurait un impact direct s'il était mal interprété. Si PlanetVO
vous transmet un jour la documentation officielle du format, il suffit de
corriger les index dans `parser.js` — le reste de l'application n'a pas à
être modifié.

## API disponible

- `GET /api/vehicles?brand=&energy=&gearbox=&q=&minPrice=&maxPrice=&sort=`
  → liste filtrée
- `GET /api/vehicles/:reference` → détail d'un véhicule
- `GET /api/meta` → marques/énergies/boîtes disponibles + bornes de prix
- `GET /api/status` → horodatage de la dernière synchro FTP (succès/échec)
- `POST /api/sync` → force une synchronisation immédiate

## Fonctionnalités de l'interface tactile

- Grille de véhicules avec photo, prix, kilométrage, énergie, garantie
- Recherche texte + filtres marque/énergie + tri (prix, kilométrage, année)
- Fiche détail plein écran avec galerie photo (swipe/flèches) et
  caractéristiques complètes
- **Écran de veille** : après 90 s d'inactivité, diaporama photo en boucle
  invitant les clients à toucher l'écran (se referme au premier contact)
- Rafraîchissement automatique de l'affichage toutes les minutes (sans
  recharger la page) pour refléter les mises à jour du stock

## Personnalisation rapide

- Délai avant écran de veille : `IDLE_TIMEOUT_MS` dans `public/js/app.js`
- Fréquence de synchro FTP : réglée dans la tâche CRON du Manager OVH (pas
  dans le code — voir section déploiement)
- Couleurs / typographies : variables CSS en haut de `public/css/style.css`
