You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

20 KiB

Sommaire

  1. Introduction
  2. Description du projet
  3. La pile technologique
    1. Le serveur
    2. Le site web
    3. La base de données
  4. Le serveur
    1. Les dépendances
    2. Le fonctionnement
  5. Le site web
    1. Les dépendances
    2. Le fonctionnement
  6. La base de données
  7. Installation du projet
    1. Docker Compose
    2. Script Shell
    3. Manuellement
  8. Conclusion

Introduction

Cette documentation est à destination des futurs développeurs travaillant sur Freetube. Elle a pour but d’expliquer le fonctionnement technique de toutes les couches de l’application et à justifier les choix pris pour chaque langage et framework. 

La documentation est une ressource indispensable pour tous ceux voulant comprendre le fonctionnement interne de Freetube. Les parties démontrées ici couvrent toutes les couches de l’application. Par ailleurs des diagrammes UML et schémas de base de données vous sont fournies pour une meilleure compréhension du code. Un indexe est disponible en fin de document. 

Cette documentation est à un but technique, elle rentre volontairement dans les détails du fonctionnement de chaque partie. Elle n’est pas faite pour être lu par un utilisateur, un manuel utilisateur vous a été fournies pour remplir ce besoin.

De plus les documentations externes sont disponible en fin de document et un Swagger est présent sur l'endpoint /api/api-docs pour une documentation de l'API plus approfondie.

Description du projet

Il m’a été demandé de créer une plateforme concurrente à YouTube nommée Freetube. Cette alternative a pour but de mieux remplir les demandes des utilisateurs, pas d’abonnement ni publicité pour consommer ou poster des vidéos sur la plateforme. 

Le cahier des charges du projet demande certaines fonctionnalités à implémenter. Les utilisateurs doivent pourvoir regarder des vidéos sans avoir à se connecter où à créer de compte, ils doivent pouvoir créer un compte et le gérer, pouvoir créer une chaîne la gérer et y poster des vidéos. La fonctionnalité de vidéo privé a aussi été demandé. 

Pour ce projet j’avais la main libre sur la pile technologique à utiliser tout en respectant les demandes d’efficacité d’une plateforme de streaming vidéo.

La pile technologique

Le serveur

Le serveur a été codé en Nodejs, j’ai choisi ce langage car il permet d’implémenter une API REST efficacement grâce à son implémentation native de l’asynchrone indispensable pour une API REST. NodeJS étant basé sur Javascript il n’est pas le plus efficient mais ce n’est pas dérangeant car nous travaillons avec une API, le temps de réponse sera biaisé par la connexion internet de l’utilisateur.

Le site web

Le site web a lui été codé en ReactJS une librairie Javascript permettant de créer des interfaces utilisateur. ReactJS étant lui aussi basé sur Javascript, cela permet une maintenabilité plus simple car les deux parties sont dans le même langages, de plus le site web bénéficie lui aussi de l’implémentation de l’asynchrone. J’ai choisi d’utiliser ReactJS car il permet l’utilisation de components permettant le live reload et évite la duplication de code inutile.

La base de données

La base de données est en PostgreSQL, un langage basé sur SQL largement utilisé pour communiquer avec une base de données. Cependant PostgreSQL possède quelques avantages par rapport à une base de données comme MySQL, il intègre une très bonne gestion du JSON que j’ai beaucoup utilisé dans ce projet et il est Open Source.

Le serveur

Les dépendances

Le serveur NodeJS sert de plateforme entre le site web et la base de données, il doit donc pouvoir recevoir des requêtes HTTP et envoyer des requêtes SQL. Pour les requêtes HTTP j’ai choisis le framework ExpressJS car il est très connu et a donc beaucoup de contenu disponible sur internet. Pour les requêtes SQL j'ai utilisé la librairie pg qui permet de communiquer avec PostgreSQL, cette librairie peux gérer les fermetures de connexion inutile comme les time out ou les oublies. 

Puisque l’API transmet des données sensibles j’ai dû sécuriser les endpoints en vérifiant les données entrantes, pour cela j’ai utilisé express-validator qui permet de créer des middlewares pour vérifier les données. Pour les images et les fichiers vidéo j’ai utilisé multer qui s’intègre très bien avec ExpressJS. Pour l’authentification par Github j’ai choisi de passé par PassportJS qui s’occupe du passage de token entre GitHub et le backend. 

Pour la gestion de l’authentification j’ai utilisé Json Web Token qui permet de générer et de vérifier des tokens d’authentifications. Pour l’encryption des mots de passe Bcrypt a été utilisé.

Le fonctionnement

Chaque endpoints et diviser en trois parties distinctes, la définition de la route, qui va définir l’URL à appeler, les middlewares qui vont effectuer les vérifications et modifications des données avant leur utilisation, et les controllers qui vont faire les actions (appels de base données, déplacement de fichier...). Des diagrammes UML expliquant les routes unes-à-unes est disponible dans le dossier “Diagramme_UML”.

Chaque endpoints qui doivent être protégées par l’utilisation d’un compte utilisent le middleware “auth.middleware.js” pour vérifier la validité d’un token.

Le site web

Les dépendances

Le site web ne doit faire aucun calcul, tout passe donc par des requête HTTP, j'ai donc utilisé la librairie fetch intégré à NodeJS dans sa version 22. 

Pour l’hébergement j’ai choisi NGINX car il permet de d’héberger un site et de faire des redirections, il m’a permis de rediriger les requêtes vers l’API en passant par la route “/api/” ce qui évite d’exposer des ports inutilement. 

NGINX permet aussi de mettre en place l’HTTPS avec des certificats SSL ce qui chiffre les requêtes du site et de l'API. 

Le site fonctionnant avec ReactJS nécessite l’utilisation de Vite pour le développement et le déploiement. 

Freetube est un site multi-page et doit utiliser un système de routage. Pour cela j’ai utilisé React Router 7 car il est très utilisé et donc très bien documenté.

Pour la partie style du site web, j'ai utilisé TailwindCSS dans sa version 4.0. Tailwind permet de créer des classes CSS directement depuis le JSX et prend en charge le responsive grâce a des breakpoints. Il est notamment plus léger que ses concurrents car il créer ses classes CSS au moment du build contrairement, par exemple, a Bootstrap qui à besoin d'un fichier contenant toue les classes CSS de la librairie pour fonctionner.

Le fonctionnement

Les éléments du site sont divisés en plusieurs parties, les pages sont dans le dossier “/src/pages” et servent à accueillir et à mettre en forme les composants et à appeler les services.  

Les composants dans le dossier “/src/components” servent à diviser le code et à éviter la duplication, un composant peut être appelé plusieurs fois sur plusieurs pages différentes. Les composants ne font pas d'appel aux services, les événements liés aux composants sont passer en paramètre de ces dernier. 

Les modales sont dans le dossier “/src/modals” et sont toujours afficher au-dessus de la vue principale. Comme les composants elles ne fonts aucun appels aux services, les événements liés aux modales sont passer en paramètre de ces derniers. Elles sont toujours appelées en fin de fichier. 

Les services présent dans le dossier “/src/services” sont les seuls fichiers faisant appel à l’API (à l’exception du fichier AuthContext.jsx). Les services sont organisés de la même manière que les endpoints. Un service peut être appelé plusieurs fois dans plusieurs pages. 

Les routes utilisées par React Router sont présente dans le fichier “/src/routes/route.jsx”. Les routes ayant besoin d’un compte sont protégées par “ProtectedRoute” et rédigeront automatiquement à la page de connexion. React Router n’étant pas directement compatible avec le système de NGINX une configuration supplémentaire est nécessaire, elle est détaillée dans le fichier “/nginx/default.conf”.

La base de données

La structure de la base de données est créée automatiquement par le serveur au lancement, chaque modification effectuée doit être modifié dans le fichier /backend/src/utils/database.js dans la fonction initDb().  

La base de données étant relationnelle, elle repose sur beaucoup de clé étrangère détaillés dans le schéma fourni. A savoir que les enfants se détruisent automatiquement si le lien parent est supprimé grâce à la condition “ON CASCADE” présente dans chacun des liens.  

Le port de la base de données (5432 par defaut) ne doit jamais être exposé sans pare-feu, seul le serveur doit y avoir accès. Pour cela PostgreSQL propose deux fichiers de configuration. pg_hba créer des règles internes en fonction de l’utilisateur, la base cible et l’IP du client et postgres.conf qui permet de définir un schéma d’IP autorisé. A savoir que si le projet et lancé via Docker seul localhost peut avoir accès à cette base de données.

Installation et lancement

Ces instructions sont prévues pour un serveur tournant sous Ubuntu 24.04/Debian 12. Par conséquent certaines commandes peuvent être incompatible avec votre système, cependant cotre système d'exploitation fournis des commandes alternatives.

Freetube peut être installé de trois manière différentes :

  • Docker Compose
  • Script Shell
  • Manuellement

Installation avec Docker Compose

Installer Docker et Docker Compose

De part la documentation officielle de Docker

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Paramétrages NGINX

Quelque modification doivent être faites pour le fonctionnement de NGINX

server {
	#------------------------------ ici -------------------------------
	server_name <url du serveur>;
	#------------------------------------------------------------------
	listen 80;
	return 301 https://$host$request_uri;
}

server {
	#------------------------------ ici -------------------------------
	server_name <url du serveur>;
	#------------------------------------------------------------------
	listen 443 ssl;
	
	root /usr/share/nginx/html;
	index index.html index.htm;
	
	client_max_body_size 500M;
	
	ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
	ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
	
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers HIGH:!aNULL:!MD5;
	
	location /api/ {
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '$http_origin' always;
		add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
		add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
		add_header 'Access-Control-Allow-Credentials' 'true' always;
		add_header 'Access-Control-Max-Age' 1728000 always;
		add_header 'Content-Type' 'text/plain; charset=utf-8' always;
		add_header 'Content-Length' 0 always;
		return 204;
		}
	
		proxy_pass http://resit_backend:8000;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header Origin $http_origin;
		proxy_buffering off;
		
		add_header 'Access-Control-Allow-Origin' '$http_origin' always;
		add_header 'Access-Control-Allow-Credentials' 'true' always;
		
		proxy_read_timeout 300s;
		proxy_send_timeout 300s;
	}
	
	location ~* ^/(?!api/).*\.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
		add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
		add_header Pragma "no-cache";
		add_header Expires "0";
		try_files $uri =404;
	}
	
	location / {
		add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
		try_files $uri $uri/ /index.html;
	}

}

Création de clé d'API Gmail

Rendez-vous sur Gmail et allez dans le panel d'administration de votre compte Dans la barre de recherche tapez Mot de passe des applications Créer un mot de passe et gardez le de côté il servira pour les variables d'environnements

Création Application OAuth Github

Rendez-vous sur Github et allez dans les paramètres de votre compte En bas du menu à gauche, cliquez sur Paramètres de développeur puis cliquez sur Application OAuth Créez une nouvelle application et gardez les clé de côté, elle serviront pour les variables d'environnements

Mise en place des variables d'environnements

A la racine du projet créer un fichier .env

touch .env

A l'aide de l'éditeur de votre choix entrez dans le fichier

nano .env

Rentrez les informations dans ce format /!\ les valeurs non-entourées de chevrons ne doivent pas être modifié.

POSTGRES_USER=<utilisateur_de_la_base>
POSTGRES_PASSWORD=<mot_de_passe>
POSTGRES_DB=<nom_de_la_base>
POSTGRES_HOST=db

BACKEND_PORT=8000

JWT_SECRET=<votre_clé_JWT>

LOG_FILE=/var/log/freetube/access.log

GMAIL_USER=<adresse e-mail>
GMAIL_PASSWORD=<mot_de_passe_créer_precedemment>

FRONTEND_URL=<URL_HTTPS_de_votre_nginx>

GITHUB_ID=<ID_github>

GITHUB_SECRET=<secret_github>


#### Lancement

Pour lancer le groupe de conteneur
```bash
docker compose up -d # pour détacher de la session

Installation via le Script Shell

Ajout des autorisations

Pour ajouter les autorisations nécessaire au lancement du script

chmod +x ./deploy.sh

Création de clé d'API Gmail

Rendez-vous sur Gmail et allez dans le panel d'administration de votre compte Dans la barre de recherche tapez Mot de passe des applications Créer un mot de passe et gardez le de côté il servira pour les variables d'environnements

Création Application OAuth Github

Rendez-vous sur Github et allez dans les paramètres de votre compte En bas du menu à gauche, cliquez sur Paramètres de développeur puis cliquez sur Application OAuth Créez une nouvelle application et gardez les clé de côté, elle serviront pour les variables d'environnements

Lancer l'installation

Lancer le script et répondez au question

./deploy.sh

Lancer le projet

cd backend && npm run start
cd frontend && npx vite build

systemctl enable --now nginx # Pour un démarrage automatique au lancement de la machine
systemctl enable --now postgresql

Installation manuelle

Création de clé d'API Gmail

Rendez-vous sur Gmail et allez dans le panel d'administration de votre compte Dans la barre de recherche tapez Mot de passe des applications Créer un mot de passe et gardez le de côté il servira pour les variables d'environnements

Création Application OAuth Github

Rendez-vous sur Github et allez dans les paramètres de votre compte En bas du menu à gauche, cliquez sur Paramètres de développeur puis cliquez sur Application OAuth Créez une nouvelle application et gardez les clé de côté, elle serviront pour les variables d'environnements

Mise en place des variables d'environnements

A la racine du projet créer un fichier .env

touch .env

A l'aide de l'éditeur de votre choix entrez dans le fichier

nano .env

Rentrez les informations dans ce format /!\ les valeurs non-entourées de chevrons ne doivent pas être modifié.

POSTGRES_USER=<utilisateur_de_la_base>
POSTGRES_PASSWORD=<mot_de_passe>
POSTGRES_DB=<nom_de_la_base>
POSTGRES_HOST=db

BACKEND_PORT=8000

JWT_SECRET=<votre_clé_JWT>

LOG_FILE=/var/log/freetube/access.log

GMAIL_USER=<adresse e-mail>
GMAIL_PASSWORD=<mot_de_passe_créer_precedemment>

FRONTEND_URL=<URL_HTTPS_de_votre_nginx>

GITHUB_ID=<ID_github>

GITHUB_SECRET=<secret_github>

Installation des paquets

Pour installer PostgreSQL/NGINX

apt install nginx postgresql

Pour installer NodeJS de part la documentation officielle

# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"

# Download and install Node.js:
nvm install 22

# Verify the Node.js version:
node -v # Should print "v22.19.0".
nvm current # Should print "v22.19.0".

# Verify npm version:
npm -v # Should print "10.9.3".

Installations des dépendances NodeJS

Pour le serveur

cd backend && npm i --production 

Pour le site web

cd frontend && npm i --production
npx vite build # pour la construction du site

Configuration de NGINX

Dans /etc/nginx/conf.d/ ajouter le fichier freetube.conf avec cette configuration

server {
	server_name <url du serveur>;
	listen 80;
	return 301 https://$host$request_uri;
}

server {
	server_name <url du serveur>;
	listen 443 ssl;
	
	root /usr/share/nginx/html;
	index index.html index.htm;
	
	client_max_body_size 500M;
	
	ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
	ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
	
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers HIGH:!aNULL:!MD5;
	
	location /api/ {
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '$http_origin' always;
		add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
		add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
		add_header 'Access-Control-Allow-Credentials' 'true' always;
		add_header 'Access-Control-Max-Age' 1728000 always;
		add_header 'Content-Type' 'text/plain; charset=utf-8' always;
		add_header 'Content-Length' 0 always;
		return 204;
		}
	
		proxy_pass http://resit_backend:8000;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header Origin $http_origin;
		proxy_buffering off;
		
		add_header 'Access-Control-Allow-Origin' '$http_origin' always;
		add_header 'Access-Control-Allow-Credentials' 'true' always;
		
		proxy_read_timeout 300s;
		proxy_send_timeout 300s;
	}
	
	location ~* ^/(?!api/).*\.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
		add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
		add_header Pragma "no-cache";
		add_header Expires "0";
		try_files $uri =404;
	}
	
	location / {
		add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
		try_files $uri $uri/ /index.html;
	}

}

Création de la base de données

Pour créer l'utilisateur PostgreSQL

CREATE ROLE "<nom_utilisateur>" WITH PASSWORD "<mot_de_passe>";

Pour créer la base

CREATE DATABASE "<nom_de_la_base>" OWNER "<nom_utilisateur";

Créer le fichier de log

Pour créer le fichier de log

mkdir -p /var/log/freetube/
touch /var/log/freetube/access.log

Activer les services

Pour activer et lancer les services

systemctl enable --now postgresql
systemctl enable --now nginx

Lancement

Pour lancer Freetube

cd backend
npm run start

Conclusion

Documentations externes

NodeJS ReactJS Vite ExpressJS NGINX PostgreSQL Multer TailwindCSS v4.0 PassportJS Swagger