Ce projet est un monorepo JS, suivant l'architecture React-Express-MySQL telle qu'enseignée à la Wild Code School (v7.1.7) :
sequenceDiagram
box Web Client
participant React as React
participant Fetcher as Fetcher
end
box Web Server
participant Express as Express
participant Module as Module
end
box DB Server
participant DB as MySQL Server
end
React-)Fetcher: event
activate Fetcher
Fetcher-)Express: requête (HTTP)
activate Express
Express-)Module: appel
activate Module
Module-)DB: requête SQL
activate DB
DB--)Module: données
deactivate DB
Module--)Express: json
deactivate Module
Express--)Fetcher: réponse HTTP
deactivate Express
Fetcher--)React: render
deactivate Fetcher
Il est pré-configuré avec un ensemble d'outils pour aider les étudiants à produire du code de qualité industrielle, tout en restant un outil pédagogique :
Assurez-vous de lancer ces commandes dans un terminal Git pour éviter les problèmes de formats de nouvelles lignes :
git config --global core.eol lf
git config --global core.autocrlf false
npm install
..env
) dans les répertoires server
et client
: vous pouvez copier les fichiers .env.sample
comme modèles (ne les supprimez pas).Commande | Description |
---|---|
npm install |
Installe les dépendances pour le client et le serveur |
npm run db:migrate |
Met à jour la base de données à partir d'un schéma défini |
npm run dev |
Démarre les deux serveurs (client et serveur) dans un seul terminal |
npm run check |
Exécute les outils de validation (linting et formatage) |
npm run test |
Exécute les tests unitaires et d'intégration |
my-project/
│
├── server/
│ ├── app/
│ │ ├── modules/
│ │ │ ├── item/
│ │ │ │ ├── itemActions.ts
│ │ │ │ └── itemRepository.ts
│ │ │ └── ...
│ │ ├── app.ts
│ │ ├── main.ts
│ │ └── router.ts
│ ├── database/
│ │ ├── client.ts
│ │ └── schema.sql
│ ├── tests/
│ ├── .env
│ └── .env.sample
│
└── client/
├── src/
│ ├── components/
│ ├── pages/
│ └── App.tsx
├── .env
└── .env.sample
Créer et remplir le fichier .env
dans le dossier server
:
DB_HOST=localhost
DB_PORT=3306
DB_USER=not_root
DB_PASSWORD=password
DB_NAME=my_database
Les variables sont utilisés dans server/database/client.ts
:
const { DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME } = process.env;
import mysql from "mysql2/promise";
const client = mysql.createPool({
host: DB_HOST,
port: DB_PORT as number | undefined,
user: DB_USER,
password: DB_PASSWORD,
database: DB_NAME,
});
export default client;
Créer une table dans server/database/schema.sql
:
CREATE TABLE item (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES user(id)
);
Insérer des données dans server/database/schema.sql
:
INSERT INTO item (title, user_id) VALUES
('Sample Item 1', 1),
('Sample Item 2', 2);
Synchroniser la BDD avec le schema :
npm run db:migrate
Créer une route dans server/app/router.ts
:
// ...
/* ************************************************************************* */
// Define Your API Routes Here
/* ************************************************************************* */
// Define item-related routes
import itemActions from "./modules/item/itemActions";
router.get("/api/items", itemActions.browse);
/* ************************************************************************* */
// ...
Définir une action dans server/app/modules/item/itemActions.ts
:
import type { RequestHandler } from "express";
import itemRepository from "./itemRepository";
const browse: RequestHandler = async (req, res, next) => {
try {
const items = await itemRepository.readAll();
res.json(items);
} catch (err) {
next(err);
}
};
export default { browse };
Accéder aux données dans server/app/modules/item/itemRepository.ts
:
import databaseClient from "../../../database/client";
import type { Result, Rows } from "../../../database/client";
interface Item {
id: number;
title: string;
user_id: number;
}
class ItemRepository {
async readAll() {
const [rows] = await databaseClient.query<Rows>("select * from item");
return rows as Item[];
}
}
export default new ItemRepository();
Ajouter un middleware
// ...
/* ************************************************************************* */
// Define Your API Routes Here
/* ************************************************************************* */
// Define item-related routes
import itemActions from "./modules/item/itemActions";
const foo: RequestHandler = (req, res, next) => {
req.message = "hello middleware";
next();
}
router.get("/api/items", foo, itemActions.browse);
/* ************************************************************************* */
// ...
req.message
sera disponible dans itemActions.browse
.
⚠️ La propriété message
doit être ajoutée dans src/types/express/index.d.ts
:
// to make the file a module and avoid the TypeScript error
export type {};
declare global {
namespace Express {
export interface Request {
/* ************************************************************************* */
// Add your custom properties here, for example:
//
// user?: { ... };
/* ************************************************************************* */
+ message: string;
}
}
}
Opération | Méthode | Chemin d'URL | Corps de la requête | SQL | Réponse (Succès) | Réponse (Erreur) |
---|---|---|---|---|---|---|
Browse | GET | /items | SELECT | 200 (OK), liste des items. | ||
Read | GET | /items/:id | SELECT | 200 (OK), un item. | 404 (Not Found), si id invalide. | |
Add | POST | /items | Données de l'item | INSERT | 201 (Created), id d'insertion. | 400 (Bad Request), si corps invalide. |
Edit | PUT | /items/:id | Données de l'item | UPDATE | 204 (No Content). | 400 (Bad Request), si corps invalide. 404 (Not Found), si id invalide. |
Destroy | DELETE | /items/:id | DELETE | 204 (No Content). | 404 (Not Found), si id invalide. |
Sécurité :
Code :
⚠️ Prérequis : Vous devez avoir installé et configuré Traefik sur votre VPS au préalable. Suivez les instructions ici : VPS Traefik Starter Kit.
Pour le déploiement, ajoutez les secrets suivants dans la section secrets
→ actions
du dépôt GitHub :
SSH_HOST
: Adresse IP de votre VPSSSH_USER
: Identifiant SSH pour votre VPSSSH_PASSWORD
: Mot de passe de connexion SSH pour votre VPSEt une variable publique dans /settings/variables/actions
:
PROJECT_NAME
: Le nom du projet utilisé pour créer le sous-domaine.⚠️ Avertissement : Les underscores ne sont pas autorisés car ils peuvent causer des problèmes avec le certificat Let's Encrypt.
L'URL de votre projet sera https://${PROJECT-NAME}.${subdomain}.wilders.dev/
.
Les étudiants doivent utiliser le modèle fourni dans le fichier *.env.sample*
en suivant la convention <PROJECT_NAME><SPECIFIC_NAME>=<THE_VARIABLE>
.
⚠️ Avertissement: Le
PROJECT_NAME
doit correspondre à celui utilisé dans la variable publique Git.
Pour l'ajouter lors du déploiement, suivez ces deux étapes :
docker-compose.prod.yml
(comme montré dans l'exemple : PROJECT_NAME_SPECIFIC_NAME: ${PROJECT_NAME_SPECIFIC_NAME}
)..env
global dans Traefik (nano ./traefik/data/.env
). Ajoutez la variable avec la valeur correcte et sauvegardez le fichier.Après cela, vous pouvez lancer le déploiement automatique. Docker ne sera pas rafraîchi pendant ce processus.
Pour accéder aux logs de votre projet en ligne (pour suivre le déploiement ou surveiller les erreurs), connectez-vous à votre VPS (ssh user@host
). Ensuite, allez dans votre projet spécifique et exécutez docker compose logs -t -f
.
Nous accueillons avec plaisir les contributions ! Veuillez suivre ces étapes pour contribuer :
git switch -c feature/your-feature-name
).git commit -m 'Add some feature'
).git push origin feature/your-feature-name
).Guide de Contribution :
npm run check
avant de pousser vos modifications.