---
title: "SmartBoot : Un squelette prêt à l'emploi"
weight: 280
---

# SmartBoot : Un squelette prêt à l'emploi

SmartBoot génère la structure complète d'un module Dolibarr augmenté avec SmartMaker (front React + back PHP).

Sources: https://inligit.fr/cap-rel/dolibarr/smartmaker/smartboot.git

## Installation

### Linux

```
git clone https://inligit.fr/cap-rel/dolibarr/smartmaker/smartboot.git && ./smartboot/setup.sh
```

### Windows

> [!NOTE]
> Le script PowerShell est en cours de finalisation.

```
git clone https://inligit.fr/cap-rel/dolibarr/smartmaker/smartboot.git && powershell ./smartboot/setup.ps1
```

Puis suivez les étapes de l'assistant :

```
Is your project name Coucou ?
[y/n] y
ok on continue

please wait during npm install depends ... it could take time :)
```

## Structure générée

Après installation, SmartBoot ajoute à votre module :

```
monmodule/
├── mobile/                          # Application React
│   ├── index.html                   # Point d'entrée (manifest PWA dynamique)
│   ├── vite.config.js               # Configuration Vite + PWA + proxy de dev
│   ├── .env.example                 # Modèle du .env (créé par setup.sh)
│   ├── src/
│   │   ├── main.jsx                 # Point d'entrée React
│   │   ├── App.jsx                  # Composant racine
│   │   ├── appConfig.js             # Configuration globale
│   │   ├── sw.js                    # Service Worker (mode injectManifest)
│   │   ├── api/
│   │   │   └── mapping/             # Mapping backend <-> front, un par feature
│   │   ├── db/
│   │   │   ├── index.js             # Instanciation de Db
│   │   │   └── stores/users/        # indexes.js + useDbUsers.jsx
│   │   ├── components/
│   │   │   ├── app/                 # Router, Provider, Head, Toaster
│   │   │   ├── layouts/
│   │   │   │   ├── AnimationLayout/ # Transitions de pages
│   │   │   │   └── PagesLayout/     # Layout global (thème, scale)
│   │   │   └── pages/
│   │   │       ├── public/          # Pages sans auth (Login, Welcome)
│   │   │       ├── private/         # Pages avec auth (Home, DeviceIdentification)
│   │   │       └── errors/          # Error404Page
│   │   ├── global-state/slices/     # État d'interface uniquement
│   │   ├── hooks/
│   │   │   └── useSmartcommonLabels/  # Libellés smartcommon dans la langue active
│   │   ├── i18n/
│   │   └── utils/
│   │       ├── constants/
│   │       ├── functions/
│   │       └── maps/                # form.jsx et list.jsx
│   └── public/
│       ├── images/                  # Icônes PWA
│       └── locales/<lang>/<ns>.json # Un fichier par langue ET par feature
├── pwa/                             # Build de production
│   ├── api.php                      # Routeur API
│   └── .htaccess                    # Redirection Apache
├── smartmaker-api/
│   ├── Controllers/                 # Vos controllers PHP
│   ├── dmGenericObject.php          # Exemple de mapping Dolibarr
│   └── HomeController.php           # Controller d'exemple
└── smartmaker-api-prepend.php       # Initialisation SmartAuth
```

Cette arborescence n'est pas décorative : elle applique les règles d'organisation décrites dans [Architecture](/front/architecture), notamment le découpage de la couche données en `indexes.js` et hook `useDb<Feature>`, et le découpage des traductions par namespace.

### Traductions par namespace

Le squelette livre cinq namespaces, en français et en anglais : `common`, `welcomePage`, `loginPage`, `deviceIdentificationPage` et `homePage`.

```
const { t } = useTranslation('loginPage');
```

> [!WARNING]
> Un Makefile qui dérive `VITE_LOCALES` doit lister les **sous-dossiers** de `public/locales/`, et non les fichiers `*.json`. Les recettes anciennes cherchaient `locales/*.json` : depuis le passage au multi-namespace, elles ne trouvent plus rien, la liste des langues est vide et l'application reste figée sur la langue de repli.

### Proxy de développement

Si votre Dolibarr n'est pas servi par le serveur de développement Vite, renseignez la cible dans `mobile/.env` :

```
VITE_DEV_PROXY_TARGET=https://dolibarr.local/custom/monmodule/pwa
```

C'est le répertoire qui **contient** `api.php`, sans slash final. Variable absente ou vide : aucun proxy n'est enregistré. Le pourquoi est expliqué dans [PWA](/front/pwa), section "Origine du front et origine de l'API".

### Lint en deux passes

`npm run lint` exécute `oxlint` puis `eslint .`. La première passe est native et rapide, la seconde couvre ce que la première ne traite pas. `eslint-plugin-oxlint` désactive côté ESLint les règles déjà vérifiées par oxlint.

## Manifest PWA dynamique

SmartBoot configure automatiquement le manifest PWA de manière dynamique via SmartAuth. Le fichier `index.html` pointe vers `api.php/manifest.webmanifest` au lieu d'un fichier statique :

```
<link rel="manifest" href="api.php/manifest.webmanifest">
<link rel="icon" type="image/png" href="api.php/icon/64">
<link rel="apple-touch-icon" href="api.php/icon/192">
```

Et dans `vite.config.js`, le manifest statique est désactivé :

```
VitePWA({
  // ...
  manifest: false, // Servi dynamiquement par SmartAuth
})
```

> [!IMPORTANT]
> Ce lien est relatif : il suppose que le front et l'API sont servis depuis la même origine, ce qui est le cas une fois la PWA déployée dans `pwa/`. En développement, avec `vite dev` sur le port 5173 et Dolibarr sur un autre hôte, il faut proxifier `api.php`. Voir [PWA](/front/pwa), section "Origine du front et origine de l'API".

Voir [PWA](/front/pwa) pour les constantes Dolibarr, les deux modes de Service Worker et le démarrage hors ligne.

## Layouts et gardes de routes

SmartBoot ne fournit que deux layouts visuels :

| Layout | Rôle |
| --- | --- |
| `PagesLayout` | Layout global : applique le thème, le dark mode et le scale |
| `AnimationLayout` | Gère les transitions animées entre pages (Framer Motion) |

L'authentification et l'identification d'appareil sont gérées par le composant `<RouteGuard>` de smartcommon (4 modes : `requireGuest`, `requireAuth`, `requireDeviceIdentification`, `requireDeviceIdentified`). Voir [Composants avancés -> RouteGuard](/front/composants-avances#routeguard) pour la documentation détaillée.

### Exemple de Router (skel SmartBoot)

```
import { Routes, Route, RouteGuard } from '@cap-rel/smartcommon';

import {
  LoginPage, HomePage, Error404Page, PagesLayout,
  WelcomePage, DeviceIdentificationPage, AnimationLayout,
} from 'src/components';

export const Router = () => (
  <Routes>
    <Route element={<PagesLayout />}>
      {/* Pages publiques : un utilisateur authentifie est renvoye vers / */}
      <Route element={<RouteGuard requireGuest />}>
        <Route path="/welcome" element={<WelcomePage />} />
        <Route path="/login" element={<LoginPage />} />
      </Route>

      {/* Authentifie, identification d'appareil encore a faire */}
      <Route element={<RouteGuard requireDeviceIdentification />}>
        <Route path="/device-identification" element={<DeviceIdentificationPage />} />
      </Route>

      {/* Authentifie + appareil identifie : toutes les pages privees */}
      <Route element={<RouteGuard requireDeviceIdentified />}>
        {/* AnimationLayout est monte UNE fois ici, jamais page par page */}
        <Route element={<AnimationLayout />}>
          <Route path="/" element={<HomePage />} />
          {/* Ajouter vos routes privees ici */}
        </Route>
      </Route>

      <Route path="*" element={<Error404Page />} />
    </Route>
  </Routes>
);
```

> [!WARNING]
> **Pas de `<BrowserRouter>` ici.** Le `<Provider>` de SmartCommon en monte déjà un. En ajouter un second produit l'erreur `You cannot render a <Router> inside another <Router>`. Une PWA servie sous un sous-chemin, ou qui utilise des liens profonds par hash, passe `config.router: "hash"` et `config.basename` au `Provider` plutôt que de monter son propre routeur.

> [!NOTE]
> `Routes` et `Route` sont réexportés par SmartCommon : une page ne doit jamais importer `react-router-dom` directement. Pour naviguer, utilisez `useNavigation()`.

> [!TIP]
> Avant la migration vers smartcommon, SmartBoot fournissait quatre layouts custom (`PrivatePagesLayout`, `PublicPagesLayout`, `PreDeviceIdentificationLayout`, `PostDeviceIdentificationLayout`). Ils ont été remplacés par `<RouteGuard>` qui centralise la logique dans smartcommon et permet d'évoluer sans toucher au skel.

## Pages générées (LoginPage, DeviceIdentificationPage)

Les pages publiques de connexion et d'identification utilisent les composants high-level `<LoginComponent>` et `<DeviceIdentificationComponent>` de smartcommon. Le skel ne fait que les habiller (wrapper visuel, vagues de fond, liens register/forgot-password) et brancher `onSuccess`/`onError` sur le store local.
- `<LoginComponent>` inclut **gratuitement le flux QR pair smartAuth** (scan -> claim -> poll). Voir [détails](/front/composants-avances#logincomponent).
- `<DeviceIdentificationComponent>` lit `useApi().user.deviceOptions` pour afficher soit un input simple (premier device), soit un radio + input (pairing). Voir [détails](/front/composants-avances#deviceidentificationcomponent).

## AboutModal

SmartBoot intègre l`'AboutModal` de smartcommon (vérification automatique des mises à jour PWA via [usePWAUpdate](/front/hooks#usepwaupdate)) :

```
import { AboutModal } from '@cap-rel/smartcommon';
import { APP_VERSION } from 'src/utils';

<AboutModal
  open={showAbout}
  onClose={() => setShowAbout(false)}
  appName="Mon Application"
  version={APP_VERSION}
/>
```

Ce composant affiche :
- Le nom de l'application et la version (`APP_VERSION` issu de `VITE_APP_VERSION`)
- Des champs libres optionnels via la prop `fields`
- Un bouton "Vérifier les mises à jour" qui relance le Service Worker

Voir [Composants avancés -> AboutModal](/front/composants-avances#aboutmodal) pour les libellés et slots.

## Controller d'exemple

SmartBoot génère un `HomeController.php` d'exemple avec un mapping `dmGenericObject.php` :

```
// smartmaker-api/HomeController.php
class HomeController
{
    public function index($arr = null)
    {
        global $db, $langs;

        $ret = [
            'statusCode' => 200,
            'generic_message' => "",
            'lastupdate'  => "",
            'home'  => "",
        ];

        return ([$ret, 200]);
    }
}
```

## Composants montés par défaut

Le squelette monte déjà, dans `App.jsx`, trois composants transverses de SmartCommon. Vous n'avez rien à ajouter :

| Composant | Rôle |
| --- | --- |
| `<UpdatePrompt>` | propose le rechargement quand une nouvelle version est prête |
| `<InstallPrompt>` | propose l'installation de la PWA sur l'appareil |
| `<ViewportProvider>` | expose le palier d'affichage (mobile, tablette, bureau) |

> [!NOTE]
> `InstallPrompt` n'a pas de bundle de traductions : ses libellés par défaut sont en anglais. Le squelette lui passe ses propres `labels`, à traduire dans vos namespaces. Voir [PWA](/front/pwa), section "Proposer l'installation".

## Étapes suivantes

Vous pouvez maintenant passer au développement :

- [Développement PHP (back)](/howto/devback) - Routes et controllers
- [Développement React (front)](/howto/devfront) - Interface utilisateur
- [Architecture](/front/architecture) - organisation des fichiers, à lire avant d'ajouter votre première fonctionnalité
