Guidelines de développement
Afin de faciliter les migrations de votre projet merci de respecter les guidelines décrites ci-dessous.
L’objectif est de maintenir la codebase de votre projet proprement structurée et standardisée, en particulier les dossiers app et server.
Le setup par défaut du serveur et de l’application React est externalisé dans la dépendance @fasstech/oip-starter-utils, dont l’équipe OIP assure l’évolution et la maintenabilité. Pour en savoir plus sur l’API de OIP Starter Utils, veuillez vous référer à la documentation.
En complément des fichiers liés aux vues, les dossiers app et server accueilleront également votre logique métier.
Attention : veillez à respecter la structure existante des dossiers app et server. De nombreux fichiers présents dans ces répertoires sont indispensables au bon fonctionnement global de l’OAV. Ne supprimez ni ne renommez ces fichiers, ni leurs déclarations.
En complément de cette documentation, des commentaires intégrés dans le code vous aideront à identifier ces fichiers et vous guideront sur les éventuelles modifications possibles selon vos besoins.
Vous pouvez adapter les fichiers suivants selon vos besoins, en respectant la structure existante et les commentaires associés :
- Les dossiers app et server
- Les fichiers de configuration des vues dans le dossier viewsConfig
- Les composants des vues dans views/[view]/client
- Les resolvers liés aux vues dans views/[view]/server/graphql/resolver
- Les logiques partagées client/serveur des vues dans views/_common
- Les fichiers de configuration généraux (ex. vite.config.js)
Lisibilité et maintenabilité du code
Pour garantir un code clair, cohérent et maintenable, nous vous recommandons de suivre les bonnes pratiques suivantes :
- Écrivez votre code en anglais
- Utilisez des noms courts, explicites et cohérents pour les variables, fonctions et fichiers
- Respectez les conventions suivantes :
- kebab-case pour les noms de fichiers et dossiers
- camelCase pour les variables et fonctions
- PascalCase ou UPPER_SNAKE_CASE pour les constantes
- Structurez votre code de manière simple et lisible
- Adoptez la philosophie KISS : Keep It Simple, Stupid !
Fichier package.json, les recommandations
Concernant l'installation de dépendances, veuillez toujours privilégier la définition de versions fixes dans le fichier package.json
{
"name": "oip-starter",
...
"dependencies": {
"my-package": "1.0.0", // ✅ version fixe
"dummy": "^1.0.0" // 🚫 version minimale
}
}Par ailleurs, afin d’optimiser la qualité et la taille de votre image Docker, veillez à bien catégoriser vos dépendances lors de leur installation :
- Toutes les dépendances frontend doivent être installées en tant que devDependencies
- Les dépendances backend de développement doivent également être installées en devDependencies
- Les dépendances backend nécessaires à l’exécution (runtime) du serveur doivent être installées en tant que dependencies
- Les dépendances de développement communes au frontend et au backend doivent être installées en devDependencies
# installer une dev dependency
$ npm install -D my-package
# installer une main dependency
$ npm install my-packageEmplacement du fichier de configuration OIP
Le fichier de configuration OIP se trouve à la racine du dossier server
Chemin : server/oip.config.mjs
Ajouter des logiques d'initialisation au server
Pour tout ajout de logiques d'initialisation au server, veuillez éditer le fichier server/index.mjs
Exemple :
import { Something } from 'something';
...
// init your business logic here
Something.start();Ajouter une route ou un middleware
Vous pouvez ajouter des routes ou des middlewares au serveur via le fichier routes.mjs situé à la racine du dossier server
Exemple :
import express from 'express';
const router = express.Router();
// a custom middleware on /api
router.use('/api', (req, res, next) => {
console.log('My beautiful API');
next();
});
// a custom endpoint on /api
router.get('/api/test', (req, res) => {
res.send({ message: 'Dans la vie, il y a des cactus!' })
});
export default router;Dans le cas d'ajout d'un nouvel endpoint, n'oubliez pas de le déclarer dans le fichier de configuration de vite :
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
...
server: {
port: 8000,
proxy: {
...
// custom endpoint /api
'/api': {
target: `http://localhost:${env.PORT}`,
changeOrigin: true
}
}
}
};
});Initialiser et définir l'entité Project à partir du contexte client
Pour définir l'entité Project et créer des entités/propriétés selon les besoins de votre projet lors de la récupération du contexte grâce au token passé en URL, vous devez modifier le fichier server/controllers/project/project.mjs et sa fonction initProjectFromContext
import { Entities } from '@fasstech/oip-core';
export const initProjectFromContext = async (context) => {
// setup your init logic project here
const { externalId } = context;
let project = await Entities('Project').get({ externalId });
if (project) {
return project;
}
project = await Entities('Project').create({ externalId });
project = await Entities('Project').save(project);
return project;
};Pour plus de détails, se référer à ce chapitre
Étendre le process
Pour étendre le type par défaut de l'objet process, se référer à ce chapitre
Ajouter des handlers personnalisés
Pour ajouter des handlers personnalisés à processHandlers, se référer à ce chapitre
Ajouter des types GraphQL
Pour l'ajout de types, queries ou mutations graphQL, se référer à ce chapitre
Lecture et écriture des valeurs des propriétés OIP
Toujours passer par les getter et setter exposés par l'OIP Core pour lire ou définir la valeur d'une propriété OIP.
✅ Exemple :
import * as R from 'ramda';
import {
getCustomerFirstName,
getCustomerLastName,
setCustomerFirstName,
setCustomerLastName,
} from '@fasstech/oip-core/entities';
// lecture
const firstName = getCustomerFirstName(customer);
const lastName = getCustomerLastName(customer);
// écriture
setCustomerFirstName('Lucky', customer);
setCustomerLastName('Luke', customer);
// écriture avec ramda
R.compose(
setCustomerFirstName('Lucky'),
setCustomerLastName('Luke')
)(customer);Dans le cas contraire, si la migration se fait via un script, les propriétés lues ou modifiées sans utiliser les getters/setters OIP ne seront pas prises en charge par le script de migration.
🚫 Interdit :
import * as R from 'ramda';
// ⚠️ INTERDIT ⚠️
// lecture (js natif)
const { firstName, lastName } = customer;
// lecture via ramda
const firstName = R.prop('firstName', customer);
const lastName = R.prop('lastName', customer);
// écriture (js natif)
customer.firstName = 'Joe';
customer.lastName = 'Dalton';Configurer la mécanique CORS
La configuration de la mécanique CORS est disponible à partir de la version 3.4.0 de la dépendance OIP Starter Utils.
Le server utilise la dépendance npm cors pour la configuration de la mécanique CORS.
La configuration par défaut est l'équivalent de :
{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}Si vous souhaitez modifier la configuration par défaut, vous pouvez passer un objet corsOptions en paramètre de la méthode startServer appelée par défaut dans le fichier server/index.mjs
Exemple :
import { start as startServer } from '@fasstech/oip-starter-utils/server';
const config = {
// ...
corsOptions: {
origin: (origin, callback) => {
if (!origin || WHITE_LIST.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Origin not allowed!'));
}
},
credentials: true,
methods: 'GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE',
allowedHeaders: ['Origin', 'Content-Type', 'Accept', 'Authorization'],
preflightContinue: false
}
};
const { app } = await startServer(config);Pour la liste complète et le détail des options de configuration acceptèes, veuillez vous référer à la documentation de la dépendance npm cors
Charger l'application front-end depuis un domaine différent
Cette fonctionnalité n'est supportée qu'à partir de la version 3.4.0 de la dépendance OIP Starter Utils.
Dans le cas où l’application front-end doit être chargée depuis un domaine différent — par exemple, depuis un front-end client — vous pouvez utiliser la variable d’environnement SERVER_URL pour renseigner l’URL du serveur de l’OAV à l’application React.
Assurez-vous que la variable __SERVER_URL__ est correctement définie dans le fichier vite.config.js, par exemple :
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
// ...
define: {
__API_KEY__: JSON.stringify(env.API_KEY),
__API_USER_ID__: JSON.stringify(env.API_USER_ID),
__SERVER_URL__: JSON.stringify(env.SERVER_URL || '')
},
}
}Enfin, côté serveur, n’oubliez pas de configurer la mécanique CORS afin d’autoriser l’origine du front-end client.
Veillez également à configurer correctement les attributs du cookie de session pour qu’ils puissent être envoyé dans un contexte de requêtes cross-site.