# Fichier: python_cheats/cheatsheets/Nexus.txt
# Cheatsheet Nexus Repository Manager - Guide Complet Débutant


[OK] INTRODUCTION - QU'EST-CE QUE NEXUS ? (EXPLICATION SIMPLE)

# === ANALOGIE POUR COMPRENDRE ===

# Imaginez Nexus comme une BIBLIOTHÈQUE INTELLIGENTE pour votre code:
# 
# 1. BIBLIOTHÈQUE PERSONNELLE (Hosted Repository)
#    Vous écrivez vos propres livres (code) et les rangez ici
#    Exemple: Votre équipe crée une librairie "authentification-utils"
#    -> Vous la stockez dans Nexus pour la réutiliser dans tous vos projets
#
# 2. PHOTOCOPIEUSE DE BIBLIOTHÈQUE EXTERNE (Proxy Repository)
#    Au lieu d'aller chercher un livre à la bibliothèque municipale à chaque fois,
#    vous en faites une copie et la gardez chez vous
#    Exemple: Au lieu de télécharger React depuis npmjs.org à chaque build,
#    -> Nexus le télécharge UNE FOIS et le garde en cache
#    -> Vos builds suivants sont 10x plus rapides!
#
# 3. CATALOGUE UNIFIÉ (Group Repository)
#    Un seul endroit pour chercher, que ce soit vos livres OU les copies
#    Exemple: Au lieu de configurer 3 sources différentes,
#    -> Vous configurez JUSTE le "group" qui cherche partout automatiquement


# === POURQUOI UTILISER NEXUS ? ===

# PROBLÈME SANS NEXUS:
# - Vous téléchargez React depuis Internet -> 50 secondes
# - Votre collègue télécharge React depuis Internet -> 50 secondes
# - Le serveur CI télécharge React depuis Internet -> 50 secondes
# - Vous refaites un build -> RE-télécharge React -> 50 secondes
# -> TEMPS PERDU + BANDE PASSANTE GASPILLÉE

# SOLUTION AVEC NEXUS:
# - Première fois: télécharge React depuis Internet -> 50 secondes
# - Nexus garde React en cache
# - Tous les autres builds: téléchargent depuis Nexus -> 2 secondes!
# - Même si npmjs.org tombe en panne, vous avez votre copie!


# === VOCABULAIRE ESSENTIEL ===

# ARTEFACT (Artifact):
#   Un "fichier" que vous voulez stocker
#   Exemples: un fichier .jar Java, un package .whl Python, une image Docker
#   -> C'est comme un "livre" dans notre analogie bibliothèque

# REPOSITORY (Dépôt):
#   Un "conteneur" qui stocke des artefacts
#   Comme une étagère de bibliothèque spécialisée
#   -> Une étagère pour les livres Java, une pour les livres Python, etc.

# COMPOSANT (Component):
#   Un artefact avec ses métadonnées (nom, version, auteur)
#   Exemple: "react" version "18.2.0"
#   -> C'est comme la fiche de catalogage d'un livre

# BLOB STORE:
#   L'endroit physique sur le disque dur où sont stockés les fichiers
#   -> C'est comme la salle d'archives physique de la bibliothèque

# FORMAT:
#   Le "type" de packages que le repository accepte
#   Exemples: maven2 (Java), npm (JavaScript), pypi (Python), docker, etc.
#   -> Comme les sections de bibliothèque: romans, BD, magazines, etc.


# === LES 3 TYPES DE REPOSITORIES EXPLIQUÉS ===

# 1. HOSTED REPOSITORY (Hébergé)
#    = Votre bibliothèque PERSONNELLE
#    
#    Utilisation: Stocker VOS créations
#    Exemple concret:
#    - Votre équipe développe "company-auth-lib" version 1.0
#    - Vous l'uploadez dans le hosted repository "maven-releases"
#    - Tous vos projets peuvent maintenant l'utiliser
#    
#    Commande Maven pour l'utiliser:
#    <dependency>
#      <groupId>com.votreentreprise</groupId>
#      <artifactId>company-auth-lib</artifactId>
#      <version>1.0</version>
#    </dependency>
#    -> Maven va chercher dans Nexus au lieu d'Internet!

# 2. PROXY REPOSITORY (Proxy/Cache)
#    = Photocopieuse de bibliothèque EXTERNE
#    
#    Utilisation: Cacher les packages publics (React, Django, etc.)
#    Exemple concret:
#    - Vous créez un proxy vers npmjs.org (le dépôt officiel npm)
#    - La première fois que vous faites "npm install react":
#      -> Nexus télécharge depuis npmjs.org (lent)
#      -> Nexus GARDE une copie locale
#    - Les fois suivantes:
#      -> Nexus sert SA copie (ultra rapide!)
#    
#    Avantages:
#    [OK] Builds 10x plus rapides
#    [OK] Fonctionne même si npmjs.org est down
#    [OK] Économise la bande passante Internet
#    [OK] Sécurité: scan une seule fois les packages

# 3. GROUP REPOSITORY (Groupe)
#    = Catalogue UNIFIÉ de toutes vos sources
#    
#    Utilisation: UN SEUL point d'accès pour tout
#    Exemple concret:
#    - Vous avez:
#      * "maven-releases" (hosted) avec vos librairies internes
#      * "maven-snapshots" (hosted) avec vos versions de dev
#      * "maven-central" (proxy) qui cache Maven Central
#    
#    - Vous créez un GROUP "maven-public" qui contient les 3
#    
#    - Dans votre projet, vous configurez JUSTE:
#      <repository>
#        <url>http://nexus/repository/maven-public/</url>
#      </repository>
#    
#    - Quand Maven cherche une dépendance:
#      1. Il cherche dans "maven-releases" (vos trucs) -> Pas trouvé
#      2. Il cherche dans "maven-snapshots" (vos dev) -> Pas trouvé
#      3. Il cherche dans "maven-central" (proxy public) -> TROUVÉ!
#    
#    -> Vous n'avez rien à changer dans votre config!


# === EXEMPLE DE VIE RÉELLE ===

# Scénario: Vous développez une application web React + Java

# AVANT NEXUS (situation chaotique):
# - Backend Java: télécharge 50 librairies depuis Maven Central -> 5 minutes
# - Frontend React: télécharge 200 packages npm -> 3 minutes
# - Votre CI fait 20 builds par jour -> 160 minutes gaspillées!
# - Maven Central a une panne -> TOUS vos builds cassent
# - Vous avez développé "utils-backend.jar" -> copier/coller entre projets

# APRÈS NEXUS (situation organisée):
# - Installation Nexus une seule fois
# - Configuration (15 minutes):
#   * Créer proxy Maven vers Maven Central
#   * Créer proxy npm vers npmjs.org
#   * Créer hosted "company-releases" pour vos librairies
#   * Créer groups pour unifier tout ça
# 
# - Premier build:
#   * Backend: télécharge 50 librairies -> 5 minutes (Nexus les cache)
#   * Frontend: télécharge 200 packages -> 3 minutes (Nexus les cache)
# 
# - Builds suivants:
#   * Backend: utilise le cache Nexus -> 30 secondes!
#   * Frontend: utilise le cache Nexus -> 20 secondes!
# 
# - Vous uploadez "utils-backend.jar" dans Nexus
#   * Tous vos projets peuvent l'utiliser comme une dépendance normale
#   * Versioning automatique (1.0, 1.1, 2.0, etc.)
# 
# - Maven Central a une panne?
#   * Pas de problème! Nexus a tout en cache
# 
# -> Économie: 140 minutes par jour = 11 heures par mois!


# === VERSIONS ===

# Nexus Repository OSS (Open Source - GRATUIT)
# [OK] Tous les formats essentiels (Maven, npm, Docker, PyPI, etc.)
# [OK] Repositories hosted, proxy, group
# [OK] Gestion utilisateurs basique
# [OK] API REST complète
# [X] Pas de clustering/HA
# [X] Pas de support officiel
# -> PARFAIT pour petites/moyennes équipes

# Nexus Repository Pro (PAYANT)
# [OK] Tout ce que OSS a
# [OK] High Availability (clustering)
# [OK] Staging repositories
# [OK] Support officiel Sonatype
# [OK] Fonctionnalités avancées de sécurité
# [OK] Métriques Prometheus
# -> Pour grandes entreprises


# === CAS D'USAGE TYPIQUES ===

# 1. STARTUP/PETITE ÉQUIPE:
#    - Installer Nexus OSS sur un serveur
#    - Créer proxy npm + Maven
#    - Héberger packages internes
#    -> Builds plus rapides, organisation du code

# 2. ENTREPRISE MOYENNE:
#    - Nexus OSS ou Pro
#    - Proxies pour tous les formats utilisés
#    - Repositories par équipe/projet
#    - Intégration CI/CD
#    -> Contrôle complet des dépendances

# 3. GRANDE ENTREPRISE:
#    - Nexus Pro avec HA
#    - Plusieurs instances par région
#    - Sécurité stricte (LDAP, SSO)
#    - Scan de vulnérabilités
#    -> Compliance et sécurité

# 4. PROJET OPEN SOURCE:
#    - Héberger releases publiques
#    - CI/CD automatisé
#    - Distribution facile aux utilisateurs
#    -> Maven Central, npm registry, etc.


# === FORMATS SUPPORTÉS (EXPLIQUÉS) ===

# Maven (Java):
#   Packages Java (.jar, .war)
#   Utilisé par: Java, Kotlin, Scala, Groovy
#   Exemple: Spring Boot, Apache Commons

# npm (JavaScript):
#   Packages JavaScript/TypeScript
#   Utilisé par: Node.js, React, Vue, Angular
#   Exemple: react, lodash, express

# Docker:
#   Images de conteneurs
#   Utilisé par: Applications containerisées
#   Exemple: nginx, postgres, vos apps

# PyPI (Python):
#   Packages Python (.whl, .tar.gz)
#   Utilisé par: Django, Flask, pandas
#   Exemple: requests, numpy, django

# NuGet (.NET):
#   Packages C#/.NET
#   Utilisé par: .NET Framework, .NET Core
#   Exemple: Newtonsoft.Json, Entity Framework

# Et beaucoup d'autres: RubyGems, apt, yum, Helm, etc.


[OK] INSTALLATION

# === PRÉREQUIS ===

# Java 8 ou 11 requis (OpenJDK recommandé)
java -version

# Minimum 4 Go RAM recommandé (8 Go pour production)
# Espace disque: dépend de vos besoins (100 Go+ recommandé)


# === MÉTHODE 1: INSTALLATION MANUELLE (LINUX) ===

# Télécharger Nexus OSS
cd /opt
sudo wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz

# Extraire
sudo tar -xvzf latest-unix.tar.gz

# Renommer pour simplicité
sudo mv nexus-3.* nexus
sudo mv sonatype-work nexus-data

# Créer utilisateur dédié (sécurité)
sudo useradd -r -m -U -d /opt/nexus -s /bin/bash nexus

# Donner permissions
sudo chown -R nexus:nexus /opt/nexus
sudo chown -R nexus:nexus /opt/nexus-data

# Configurer pour démarrer avec utilisateur nexus
sudo nano /opt/nexus/bin/nexus.rc
# Ajouter: run_as_user="nexus"

# Créer service systemd
sudo nano /etc/systemd/system/nexus.service

# Contenu du service:
[Unit]
Description=Nexus Repository Manager
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus/bin/nexus start
ExecStop=/opt/nexus/bin/nexus stop
User=nexus
Restart=on-abort
TimeoutSec=600

[Install]
WantedBy=multi-user.target

# Activer et démarrer
sudo systemctl daemon-reload
sudo systemctl enable nexus
sudo systemctl start nexus

# Vérifier statut
sudo systemctl status nexus

# Logs
tail -f /opt/nexus-data/log/nexus.log


# === MÉTHODE 2: INSTALLATION AVEC DOCKER ===

# Pull image officielle
docker pull sonatype/nexus3

# Créer volume pour persistance
docker volume create nexus-data

# Démarrer conteneur
docker run -d \
  --name nexus \
  -p 8081:8081 \
  -p 8082:8082 \
  -v nexus-data:/nexus-data \
  sonatype/nexus3

# Avec docker-compose (recommandé)
# docker-compose.yml
version: '3.8'
services:
  nexus:
    image: sonatype/nexus3
    container_name: nexus
    restart: always
    ports:
      - "8081:8081"
      - "8082:8082"
      - "5000:5000"
    volumes:
      - nexus-data:/nexus-data
    environment:
      - INSTALL4J_ADD_VM_PARAMS=-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g

volumes:
  nexus-data:

# Démarrer
docker-compose up -d

# Voir logs
docker logs -f nexus

# Récupérer mot de passe admin initial
docker exec -it nexus cat /nexus-data/admin.password


# === MÉTHODE 3: INSTALLATION WINDOWS ===

# 1. Télécharger depuis: https://www.sonatype.com/products/repository-oss-download
# 2. Extraire le ZIP dans C:\nexus
# 3. Ouvrir CMD en administrateur
cd C:\nexus\bin
nexus.exe /install

# Démarrer service
nexus.exe /start

# Arrêter service
nexus.exe /stop

# Désinstaller service
nexus.exe /uninstall


# === ACCÈS INITIAL ===

# URL par défaut
http://localhost:8081

# Utilisateur par défaut: admin
# Mot de passe initial dans:
# Linux: /opt/nexus-data/admin.password
# Docker: docker exec nexus cat /nexus-data/admin.password
# Windows: C:\nexus-data\admin.password

cat /opt/nexus-data/admin.password


[OK] CONFIGURATION INITIALE

# === PREMIÈRE CONNEXION ===

# 1. Aller sur http://localhost:8081
# 2. Cliquer "Sign in" en haut à droite
# 3. Username: admin
# 4. Password: contenu de admin.password
# 5. Setup wizard va démarrer:
#    - Changer le mot de passe admin
#    - Activer anonymous access (optionnel)
#    - Configurer les repositories


# === CONFIGURATION MÉMOIRE ===

# Éditer fichier JVM options
# Linux: /opt/nexus/bin/nexus.vmoptions
# Windows: C:\nexus\bin\nexus.vmoptions

-Xms2703m                    # Heap initial
-Xmx2703m                    # Heap maximum
-XX:MaxDirectMemorySize=2703m  # Mémoire directe

# Pour serveur avec 8 Go RAM:
-Xms4g
-Xmx4g
-XX:MaxDirectMemorySize=4g

# Redémarrer après modification
sudo systemctl restart nexus


# === CONFIGURATION REVERSE PROXY (NGINX) ===

# /etc/nginx/sites-available/nexus
server {
    listen 80;
    server_name nexus.example.com;

    location / {
        proxy_pass http://localhost:8081;
        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;
    }
}

# Activer
sudo ln -s /etc/nginx/sites-available/nexus /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx


# === CONFIGURATION HTTPS ===

# Avec Let's Encrypt
sudo certbot --nginx -d nexus.example.com

# Configuration Nexus pour HTTPS
# Administration > System > Capabilities > HTTP Settings
# Base URL: https://nexus.example.com


[OK] CONCEPTS CLÉS - TYPES DE REPOSITORIES

# === HOSTED REPOSITORY ===
# Dépôt hébergé localement sur votre Nexus
# Pour stocker VOS artefacts/packages
# Exemple: vos librairies Java internes, vos packages npm privés

# Création:
# Settings (roue dentée) > Repository > Repositories > Create repository
# Type: maven2 (hosted) / npm (hosted) / docker (hosted), etc.

# Configuration typique:
Name: maven-releases              # Nom du dépôt
Version policy: Release           # Release ou Snapshot
Deployment policy: Disable redeploy  # Empêche écrasement
Blob store: default              # Stockage physique


# === PROXY REPOSITORY ===
# Cache des dépôts externes (Maven Central, npm registry, PyPI)
# Accélère les builds en cachant localement
# Réduit la bande passante externe

# Création:
# Create repository > maven2 (proxy) / npm (proxy), etc.

# Configuration typique:
Name: maven-central-proxy
Remote storage: https://repo1.maven.org/maven2/
Blob store: default
Maximum component age: 1440        # Minutes (24h)
Maximum metadata age: 1440


# === GROUP REPOSITORY ===
# Groupe plusieurs repositories en un seul point d'accès
# Simplifie la configuration des clients
# Ordre de recherche configurable

# Création:
# Create repository > maven2 (group) / npm (group), etc.

# Configuration typique:
Name: maven-public
Member repositories:
  - maven-releases (hosted)
  - maven-snapshots (hosted)
  - maven-central-proxy (proxy)


# === SCHÉMA TYPIQUE ===
# 
#         [maven-public] (GROUP)
#                |
#     +----------+----------+
#     |          |          |
# [releases] [snapshots] [central-proxy]
# (hosted)   (hosted)     (proxy -> Maven Central)


[OK] FORMATS SUPPORTÉS

# Nexus supporte de nombreux formats de packages:
# - Maven (Java)
# - npm (JavaScript/Node.js)
# - PyPI (Python)
# - Docker (Conteneurs)
# - NuGet (.NET)
# - RubyGems (Ruby)
# - apt (Debian/Ubuntu)
# - yum (RedHat/CentOS)
# - Helm (Kubernetes)
# - Raw (fichiers quelconques)
# - Et beaucoup d'autres...


[OK] MAVEN REPOSITORIES

# === CRÉER REPOSITORIES MAVEN ===

# 1. Hosted Release
Settings > Repositories > Create repository > maven2 (hosted)
Name: maven-releases
Version policy: Release
Layout policy: Strict
Deployment policy: Disable redeploy

# 2. Hosted Snapshots
Name: maven-snapshots
Version policy: Snapshot
Layout policy: Strict
Deployment policy: Allow redeploy

# 3. Proxy Maven Central
Create repository > maven2 (proxy)
Name: maven-central
Remote storage: https://repo1.maven.org/maven2/

# 4. Group
Create repository > maven2 (group)
Name: maven-public
Group members: maven-releases, maven-snapshots, maven-central


# === CONFIGURER MAVEN (pom.xml) ===

<!-- Ajouter dans pom.xml -->
<project>
  <!-- ... -->
  
  <!-- Repositories pour téléchargement -->
  <repositories>
    <repository>
      <id>nexus</id>
      <name>Nexus Repository</name>
      <url>http://localhost:8081/repository/maven-public/</url>
    </repository>
  </repositories>
  
  <!-- Distribution Management pour upload -->
  <distributionManagement>
    <repository>
      <id>nexus-releases</id>
      <name>Releases</name>
      <url>http://localhost:8081/repository/maven-releases/</url>
    </repository>
    <snapshotRepository>
      <id>nexus-snapshots</id>
      <name>Snapshots</name>
      <url>http://localhost:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
  </distributionManagement>
</project>


# === CONFIGURER SETTINGS.XML ===

<!-- ~/.m2/settings.xml -->
<settings>
  <!-- Mirrors -->
  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://localhost:8081/repository/maven-public/</url>
    </mirror>
  </mirrors>
  
  <!-- Authentification -->
  <servers>
    <server>
      <id>nexus-releases</id>
      <username>deployment-user</username>
      <password>your-password</password>
    </server>
    <server>
      <id>nexus-snapshots</id>
      <username>deployment-user</username>
      <password>your-password</password>
    </server>
  </servers>
  
  <!-- Profiles -->
  <profiles>
    <profile>
      <id>nexus</id>
      <repositories>
        <repository>
          <id>central</id>
          <url>http://localhost:8081/repository/maven-public/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>true</enabled></snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>central</id>
          <url>http://localhost:8081/repository/maven-public/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>true</enabled></snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  
  <activeProfiles>
    <activeProfile>nexus</activeProfile>
  </activeProfiles>
</settings>


# === DEPLOYER ARTEFACT MAVEN ===

# Avec Maven
mvn clean deploy

# Upload manuel via Nexus UI
# Browse > Upload > Repository: maven-releases
# GAV Parameters:
#   Group ID: com.example
#   Artifact ID: my-library
#   Version: 1.0.0
# Upload JAR file


# === TÉLÉCHARGER ARTEFACT ===

# Dans pom.xml
<dependency>
  <groupId>com.example</groupId>
  <artifactId>my-library</artifactId>
  <version>1.0.0</version>
</dependency>

# Maven télécharge automatiquement depuis Nexus


[OK] NPM REPOSITORIES

# === CRÉER REPOSITORIES NPM ===

# 1. Hosted (vos packages privés)
Create repository > npm (hosted)
Name: npm-private

# 2. Proxy (cache npmjs.org)
Create repository > npm (proxy)
Name: npm-proxy
Remote storage: https://registry.npmjs.org

# 3. Group
Create repository > npm (group)
Name: npm-all
Members: npm-private, npm-proxy


# === CONFIGURER NPM CLIENT ===

# Voir configuration actuelle
npm config list

# Configurer registry Nexus
npm config set registry http://localhost:8081/repository/npm-all/

# Pour scope spécifique (@mycompany)
npm config set @mycompany:registry http://localhost:8081/repository/npm-private/

# Authentification
npm login --registry=http://localhost:8081/repository/npm-all/
# Username: votre-user
# Password: votre-password
# Email: your@email.com

# Vérifier authentification
cat ~/.npmrc


# === FICHIER .NPMRC (PROJET) ===

# .npmrc dans la racine du projet
registry=http://localhost:8081/repository/npm-all/
@mycompany:registry=http://localhost:8081/repository/npm-private/
email=your@email.com
always-auth=true


# === PUBLIER PACKAGE NPM ===

# 1. Créer package.json avec scope
{
  "name": "@mycompany/my-package",
  "version": "1.0.0",
  "description": "My private package"
}

# 2. Login
npm login --registry=http://localhost:8081/repository/npm-private/

# 3. Publier
npm publish --registry=http://localhost:8081/repository/npm-private/

# Ou avec .npmrc configuré:
npm publish


# === INSTALLER DEPUIS NEXUS ===

# Package public (via proxy)
npm install express

# Package privé
npm install @mycompany/my-package

# Vérifier d'où vient le package
npm view express dist.tarball


# === UTILISER YARN AVEC NEXUS ===

# Configurer registry
yarn config set registry http://localhost:8081/repository/npm-all/

# Installer packages
yarn install

# Publier
yarn publish --registry http://localhost:8081/repository/npm-private/


[OK] DOCKER REPOSITORIES

# === CRÉER REPOSITORIES DOCKER ===

# 1. Hosted (vos images)
Create repository > docker (hosted)
Name: docker-hosted
HTTP port: 5000              # Port d'accès
Enable Docker V1 API: non    # Utiliser V2

# 2. Proxy (cache Docker Hub)
Create repository > docker (proxy)
Name: docker-proxy
Remote storage: https://registry-1.docker.io
Docker Index: Use Docker Hub
HTTP port: 5001

# 3. Group
Create repository > docker (group)
Name: docker-all
HTTP port: 5002
Members: docker-hosted, docker-proxy


# === CONFIGURER DOCKER CLIENT ===

# Éditer /etc/docker/daemon.json
{
  "insecure-registries": [
    "localhost:5000",
    "localhost:5001",
    "localhost:5002"
  ]
}

# Redémarrer Docker
sudo systemctl restart docker

# Login
docker login localhost:5000
# Username: votre-user
# Password: votre-password


# === POUSSER IMAGE DOCKER ===

# 1. Créer/tagger image
docker build -t my-app:1.0 .

# 2. Tagger pour Nexus
docker tag my-app:1.0 localhost:5000/my-app:1.0

# 3. Pousser
docker push localhost:5000/my-app:1.0


# === TIRER IMAGE DOCKER ===

# Depuis Nexus hosted
docker pull localhost:5000/my-app:1.0

# Depuis Nexus proxy (cache Docker Hub)
docker pull localhost:5001/nginx:latest

# Depuis group (cherche dans hosted puis proxy)
docker pull localhost:5002/nginx:latest


# === AVEC NOM DE DOMAINE ===

# Configuration nginx pour registry.example.com
server {
    listen 443 ssl;
    server_name registry.example.com;
    
    ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
    
    location / {
        proxy_pass http://localhost:5000;
        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 "https";
    }
}

# Utilisation
docker login registry.example.com
docker tag my-app:1.0 registry.example.com/my-app:1.0
docker push registry.example.com/my-app:1.0


[OK] PYPI REPOSITORIES

# === CRÉER REPOSITORIES PYPI ===

# 1. Hosted
Create repository > pypi (hosted)
Name: pypi-private

# 2. Proxy
Create repository > pypi (proxy)
Name: pypi-proxy
Remote storage: https://pypi.org

# 3. Group
Create repository > pypi (group)
Name: pypi-all
Members: pypi-private, pypi-proxy


# === CONFIGURER PIP ===

# Fichier ~/.pip/pip.conf (Linux/Mac)
[global]
index-url = http://localhost:8081/repository/pypi-all/simple
trusted-host = localhost

# Fichier %APPDATA%\pip\pip.ini (Windows)
[global]
index-url = http://localhost:8081/repository/pypi-all/simple
trusted-host = localhost

# Ou en ligne de commande
pip install --index-url http://localhost:8081/repository/pypi-all/simple package_name

# Variable d'environnement
export PIP_INDEX_URL=http://localhost:8081/repository/pypi-all/simple
export PIP_TRUSTED_HOST=localhost


# === PUBLIER PACKAGE PYTHON ===

# 1. Créer package
# setup.py
from setuptools import setup

setup(
    name='mypackage',
    version='1.0.0',
    packages=['mypackage'],
)

# 2. Build
python setup.py sdist bdist_wheel

# 3. Installer twine
pip install twine

# 4. Configurer .pypirc
# ~/.pypirc
[distutils]
index-servers =
    nexus

[nexus]
repository = http://localhost:8081/repository/pypi-private/
username = your-username
password = your-password

# 5. Upload
twine upload --repository nexus dist/*


# === INSTALLER DEPUIS NEXUS ===

# Package public (via proxy)
pip install requests

# Package privé
pip install mypackage

# Avec requirements.txt
# requirements.txt
--index-url http://localhost:8081/repository/pypi-all/simple
--trusted-host localhost

requests==2.28.0
mypackage==1.0.0


[OK] RAW REPOSITORIES

# Les Raw repositories permettent de stocker n'importe quel fichier
# Utile pour: scripts, configs, binaires, archives, etc.

# === CRÉER RAW REPOSITORY ===

Create repository > raw (hosted)
Name: raw-files


# === UPLOADER FICHIER ===

# Via UI
Browse > raw-files > Upload component
Upload file: script.sh

# Via curl
curl -u admin:password \
  --upload-file script.sh \
  http://localhost:8081/repository/raw-files/scripts/script.sh


# === TÉLÉCHARGER FICHIER ===

# Via navigateur
http://localhost:8081/repository/raw-files/scripts/script.sh

# Via curl
curl -u user:password \
  http://localhost:8081/repository/raw-files/scripts/script.sh \
  -o script.sh

# Via wget
wget --user=user --password=password \
  http://localhost:8081/repository/raw-files/scripts/script.sh


[OK] GESTION DES UTILISATEURS

# === CRÉER UTILISATEUR ===

# Administration > Security > Users > Create local user
ID: developer1
First name: John
Last name: Doe
Email: john@example.com
Status: Active
Password: ********

# Roles à assigner:
# - nx-admin: Administrateur complet
# - nx-anonymous: Accès anonyme
# - nx-deploy: Déploiement d'artefacts
# - nx-read: Lecture seule


# === CRÉER RÔLE PERSONNALISÉ ===

# Administration > Security > Roles > Create role
Type: Nexus role
Role ID: developer-read-only
Role name: Developer Read Only
Role description: Read-only access for developers

# Privilèges:
# - nx-repository-view-*-*-browse
# - nx-repository-view-*-*-read


# === PRIVILÈGES COURANTS ===

# Lecture
nx-repository-view-maven2-*-read
nx-repository-view-npm-*-read

# Upload/Déploiement
nx-repository-view-maven2-maven-releases-edit
nx-repository-view-npm-npm-private-edit

# Administration
nx-all


# === AUTHENTIFICATION LDAP ===

# Administration > Security > LDAP
Name: Company LDAP
LDAP server: ldap://ldap.example.com
Search base: dc=example,dc=com
Authentication method: Simple Authentication
Username: cn=admin,dc=example,dc=com
Password: ********

# User mapping
User ID attribute: uid
Email attribute: mail


# === TOKENS API ===

# Créer token pour utilisateur
# User menu (coin supérieur droit) > User Token
Generate: Access user token

# Utiliser token
curl -u 'username:token' http://localhost:8081/repository/...


[OK] GESTION DES PERMISSIONS

# === CONTENT SELECTORS ===

# Permettent de filtrer l'accès à certains artefacts
# Administration > Security > Content Selectors > Create selector

Name: company-artifacts
Description: Artifacts from company namespace
Expression: format == "maven2" and path =^ "/com/example/"

# Utiliser dans privilège:
# Create privilege > Content Selector
# Name: company-artifacts-read
# Content Selector: company-artifacts
# Repository: maven-releases
# Actions: read


# === PRIVILÈGES PAR REPOSITORY ===

# Limiter accès à repository spécifique
Create privilege > Repository View
Name: maven-releases-read
Repository: maven-releases
Actions: read, browse

# Assigner à rôle
Edit role > Add privilege > maven-releases-read


[OK] BLOB STORES

# Blob stores = stockage physique des artefacts

# === CRÉER BLOB STORE ===

# Administration > Repository > Blob Stores > Create blob store
Type: File
Name: fast-ssd-storage
Path: /mnt/fast-ssd/nexus-blobs

# Ou pour S3 (Nexus Pro)
Type: S3
Bucket: my-nexus-bucket
Region: us-east-1


# === ASSIGNER BLOB STORE À REPOSITORY ===

# Lors création repository:
Blob store: fast-ssd-storage

# Note: Ne peut pas être changé après création!


# === COMPACTER BLOB STORE ===

# Libère espace après suppression d'artefacts
# Administration > Repository > Blob Stores
# Select blob store > Compact blob store

# Ou via API
curl -X POST -u admin:password \
  http://localhost:8081/service/rest/v1/blobstores/default/compact


# === STRATÉGIES DE STOCKAGE ===

# Séparer par type:
# - maven-blobs: pour repositories Maven
# - docker-blobs: pour images Docker
# - npm-blobs: pour packages npm

# Séparer par performance:
# - hot-storage: SSD pour artefacts récents
# - cold-storage: HDD pour archives


[OK] CLEANUP POLICIES

# Supprimer automatiquement vieux artefacts

# === CRÉER CLEANUP POLICY ===

# Administration > Repository > Cleanup Policies > Create cleanup policy

Name: delete-old-snapshots
Format: maven2
Criteria:
  - Component Age: 30 days
  - Component Usage: Last downloaded before 60 days


# === ASSIGNER À REPOSITORY ===

# Edit repository > Cleanup
Cleanup Policies: delete-old-snapshots


# === EXEMPLES DE POLICIES ===

# Supprimer snapshots > 7 jours
Name: short-lived-snapshots
Component Age: 7 days

# Supprimer artefacts non téléchargés depuis 180 jours
Name: unused-artifacts
Last Downloaded: 180 days

# Supprimer tout sauf N dernières versions
Name: keep-latest-only
Component Age: 30 days
AND Last Blob Updated: 90 days


# === EXÉCUTER CLEANUP ===

# Manuel:
# Administration > System > Tasks > Create task
# Type: Admin - Cleanup repositories using their policies
# Schedule: Manual / On demand

# Automatique (scheduled):
# Schedule: Daily at 2:00 AM


[OK] TASKS (TÂCHES PLANIFIÉES)

# === TÂCHES COURANTES ===

# Administration > System > Tasks > Create task

# 1. Cleanup Blob Store
Type: Admin - Compact blob store
Blob store: default
Schedule: Weekly on Sunday at 2:00 AM

# 2. Cleanup Repositories
Type: Admin - Cleanup repositories using their policies
Schedule: Daily at 1:00 AM

# 3. Rebuild Index
Type: Repair - Rebuild repository search
Repository: maven-releases
Schedule: Monthly

# 4. Database Backup
Type: Admin - Export databases for backup
Location: /opt/nexus-backups
Schedule: Daily at 3:00 AM

# 5. Docker Cleanup
Type: Admin - Remove Docker images using cleanup policy
Repository: docker-hosted
Schedule: Daily at 4:00 AM


# === TYPES DE SCHEDULES ===

Manual: Exécution à la demande
Once: Une seule fois à date/heure précise
Hourly: Toutes les heures
Daily: Tous les jours à heure précise
Weekly: Jour de semaine spécifique
Monthly: Jour du mois spécifique
Advanced (Cron): Expression cron personnalisée


# === EXEMPLES CRON ===

# Tous les jours à 2h30
0 30 2 * * ?

# Tous les lundis à 3h
0 0 3 ? * MON

# Premier jour du mois à minuit
0 0 0 1 * ?

# Toutes les 4 heures
0 0 */4 * * ?


[OK] SAUVEGARDE ET RESTAURATION

# === SAUVEGARDE MANUELLE ===

# 1. Arrêter Nexus
sudo systemctl stop nexus

# 2. Sauvegarder dossiers importants
tar -czf nexus-backup-$(date +%Y%m%d).tar.gz \
  /opt/nexus-data/db \
  /opt/nexus-data/etc \
  /opt/nexus-data/keystores

# 3. Sauvegarder blobs (optionnel, peut être très volumineux)
tar -czf nexus-blobs-backup-$(date +%Y%m%d).tar.gz \
  /opt/nexus-data/blobs

# 4. Redémarrer Nexus
sudo systemctl start nexus


# === SAUVEGARDE AVEC DOCKER ===

# Arrêter conteneur
docker stop nexus

# Sauvegarder volume
docker run --rm \
  -v nexus-data:/data \
  -v $(pwd):/backup \
  ubuntu tar czf /backup/nexus-backup.tar.gz /data

# Redémarrer
docker start nexus


# === SAUVEGARDE AUTOMATIQUE (SCRIPT) ===

#!/bin/bash
# backup-nexus.sh

BACKUP_DIR="/backups/nexus"
NEXUS_DATA="/opt/nexus-data"
DATE=$(date +%Y%m%d-%H%M%S)
RETENTION_DAYS=30

# Créer dossier backup
mkdir -p $BACKUP_DIR

# Sauvegarder DB et config (sans arrêter Nexus)
tar -czf $BACKUP_DIR/nexus-config-$DATE.tar.gz \
  $NEXUS_DATA/db \
  $NEXUS_DATA/etc \
  $NEXUS_DATA/keystores

# Supprimer sauvegardes anciennes
find $BACKUP_DIR -name "nexus-config-*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed: nexus-config-$DATE.tar.gz"

# Ajouter à crontab
# 0 2 * * * /usr/local/bin/backup-nexus.sh


# === RESTAURATION ===

# 1. Arrêter Nexus
sudo systemctl stop nexus

# 2. Sauvegarder données actuelles (sécurité)
mv /opt/nexus-data /opt/nexus-data.old

# 3. Créer nouveau dossier
mkdir /opt/nexus-data

# 4. Extraire backup
tar -xzf nexus-backup-20241120.tar.gz -C /

# 5. Restaurer permissions
sudo chown -R nexus:nexus /opt/nexus-data

# 6. Redémarrer
sudo systemctl start nexus


# === EXPORT DATABASE (TASK) ===

# Administration > System > Tasks > Create task
# Type: Admin - Export databases for backup
Location: /opt/nexus-backups/db-export
Schedule: Daily at 3:00 AM

# Fichiers créés:
# - component.bak
# - config.bak
# - security.bak


[OK] MONITORING ET LOGS

# === LOGS NEXUS ===

# Logs principaux
tail -f /opt/nexus-data/log/nexus.log

# Logs de requêtes
tail -f /opt/nexus-data/log/request.log

# Logs audit
tail -f /opt/nexus-data/log/audit/audit.log

# Avec Docker
docker logs -f nexus


# === NIVEAUX DE LOG ===

# Éditer /opt/nexus-data/etc/logback/logback.xml

<!-- Niveau global -->
<root level="INFO">
  <appender-ref ref="logfile"/>
</root>

<!-- Logger spécifique -->
<logger name="org.sonatype.nexus" level="DEBUG"/>


# === MÉTRIQUES SYSTÈME ===

# Administration > System > Support > System Information
# Affiche:
# - Version Nexus
# - Utilisation mémoire JVM
# - Espace disque
# - Threads actifs
# - Blob stores


# === HEALTHCHECK ===

# Endpoint de health check
curl http://localhost:8081/service/rest/v1/status

# Réponse si OK:
{
  "available": true,
  "healthy": true,
  "state": "DB_AVAILABLE"
}

# Vérifier writable
curl http://localhost:8081/service/rest/v1/status/writable


# === PROMETHEUS METRICS (Nexus Pro) ===

# Activer dans Administration > System > Capabilities
# Enable: Prometheus Metrics

# Endpoint metrics
http://localhost:8081/service/metrics/prometheus


[OK] API REST

# === AUTHENTICATION ===

# Basic Auth
curl -u admin:password http://localhost:8081/service/rest/v1/repositories

# Avec token
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:8081/service/rest/v1/repositories


# === LISTER REPOSITORIES ===

# GET /service/rest/v1/repositories
curl -u admin:password \
  http://localhost:8081/service/rest/v1/repositories | jq

# Réponse:
[
  {
    "name": "maven-releases",
    "format": "maven2",
    "type": "hosted",
    "url": "http://localhost:8081/repository/maven-releases"
  }
]


# === CRÉER REPOSITORY ===

# POST /service/rest/v1/repositories/maven/hosted
curl -X POST -u admin:password \
  -H "Content-Type: application/json" \
  http://localhost:8081/service/rest/v1/repositories/maven/hosted \
  -d '{
    "name": "maven-test",
    "online": true,
    "storage": {
      "blobStoreName": "default",
      "strictContentTypeValidation": true,
      "writePolicy": "ALLOW_ONCE"
    },
    "maven": {
      "versionPolicy": "RELEASE",
      "layoutPolicy": "STRICT"
    }
  }'


# === RECHERCHER COMPOSANTS ===

# GET /service/rest/v1/search
curl -u admin:password \
  "http://localhost:8081/service/rest/v1/search?repository=maven-releases&q=junit"

# Recherche avec paramètres
curl -u admin:password \
  "http://localhost:8081/service/rest/v1/search?repository=maven-releases&name=junit&version=4.13.2"


# === UPLOADER COMPOSANT ===

# Maven
curl -u admin:password \
  --upload-file my-lib-1.0.0.jar \
  http://localhost:8081/repository/maven-releases/com/example/my-lib/1.0.0/my-lib-1.0.0.jar

# Raw
curl -u admin:password \
  --upload-file script.sh \
  http://localhost:8081/repository/raw-files/scripts/script.sh


# === SUPPRIMER COMPOSANT ===

# DELETE /service/rest/v1/components/{id}
# 1. Récupérer l'ID
COMPONENT_ID=$(curl -s -u admin:password \
  "http://localhost:8081/service/rest/v1/search?repository=maven-releases&name=my-lib" | \
  jq -r '.items[0].id')

# 2. Supprimer
curl -X DELETE -u admin:password \
  http://localhost:8081/service/rest/v1/components/$COMPONENT_ID


# === LISTER USERS ===

# GET /service/rest/v1/security/users
curl -u admin:password \
  http://localhost:8081/service/rest/v1/security/users | jq


# === CRÉER USER ===

# POST /service/rest/v1/security/users
curl -X POST -u admin:password \
  -H "Content-Type: application/json" \
  http://localhost:8081/service/rest/v1/security/users \
  -d '{
    "userId": "developer1",
    "firstName": "John",
    "lastName": "Doe",
    "emailAddress": "john@example.com",
    "password": "SecurePass123!",
    "status": "active",
    "roles": ["nx-deploy"]
  }'


# === CHANGER MOT DE PASSE ===

# PUT /service/rest/v1/security/users/{userId}/change-password
curl -X PUT -u admin:password \
  -H "Content-Type: text/plain" \
  http://localhost:8081/service/rest/v1/security/users/developer1/change-password \
  -d 'NewSecurePass123!'


# === LISTER BLOB STORES ===

# GET /service/rest/v1/blobstores
curl -u admin:password \
  http://localhost:8081/service/rest/v1/blobstores | jq


# === SCRIPTS (Nexus 3.x) ===

# Créer script
curl -X POST -u admin:password \
  -H "Content-Type: application/json" \
  http://localhost:8081/service/rest/v1/script \
  -d '{
    "name": "list-repos",
    "type": "groovy",
    "content": "repository.repositoryManager.browse().collect { [name: it.name, type: it.type] }"
  }'

# Exécuter script
curl -X POST -u admin:password \
  -H "Content-Type: text/plain" \
  http://localhost:8081/service/rest/v1/script/list-repos/run


[OK] INTÉGRATIONS CI/CD

# === GITLAB CI ===

# .gitlab-ci.yml
variables:
  NEXUS_URL: "http://nexus.example.com:8081"
  NEXUS_REPO: "maven-releases"

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - mvn clean package

deploy:
  stage: deploy
  script:
    - mvn deploy -DaltDeploymentRepository=nexus::default::${NEXUS_URL}/repository/${NEXUS_REPO}
  only:
    - main


# === JENKINS ===

# Jenkinsfile
pipeline {
    agent any
    
    environment {
        NEXUS_URL = 'http://nexus.example.com:8081'
        NEXUS_CREDENTIALS = credentials('nexus-credentials')
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
        
        stage('Deploy to Nexus') {
            steps {
                sh '''
                    mvn deploy \
                    -DaltDeploymentRepository=nexus::default::${NEXUS_URL}/repository/maven-releases
                '''
            }
        }
    }
}


# === GITHUB ACTIONS ===

# .github/workflows/deploy.yml
name: Deploy to Nexus

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'
      
      - name: Configure Maven settings
        uses: s4u/maven-settings-action@v2
        with:
          servers: |
            [{
              "id": "nexus",
              "username": "${{ secrets.NEXUS_USERNAME }}",
              "password": "${{ secrets.NEXUS_PASSWORD }}"
            }]
      
      - name: Deploy to Nexus
        run: mvn deploy


# === DOCKER BUILD & PUSH ===

# build-and-push.sh
#!/bin/bash

IMAGE_NAME="my-app"
VERSION="1.0.0"
NEXUS_REGISTRY="registry.example.com"

# Build
docker build -t ${IMAGE_NAME}:${VERSION} .

# Tag
docker tag ${IMAGE_NAME}:${VERSION} ${NEXUS_REGISTRY}/${IMAGE_NAME}:${VERSION}
docker tag ${IMAGE_NAME}:${VERSION} ${NEXUS_REGISTRY}/${IMAGE_NAME}:latest

# Login
echo $NEXUS_PASSWORD | docker login -u $NEXUS_USERNAME --password-stdin ${NEXUS_REGISTRY}

# Push
docker push ${NEXUS_REGISTRY}/${IMAGE_NAME}:${VERSION}
docker push ${NEXUS_REGISTRY}/${IMAGE_NAME}:latest


[OK] GRADLE AVEC NEXUS

# === CONFIGURER GRADLE ===

# build.gradle
repositories {
    maven {
        url "http://localhost:8081/repository/maven-public/"
        credentials {
            username = "${nexusUsername}"
            password = "${nexusPassword}"
        }
    }
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
            groupId = 'com.example'
            artifactId = 'my-library'
            version = '1.0.0'
        }
    }
    
    repositories {
        maven {
            name = 'nexus'
            url = "http://localhost:8081/repository/maven-releases/"
            credentials {
                username = "${nexusUsername}"
                password = "${nexusPassword}"
            }
        }
    }
}


# === FICHIER GRADLE.PROPERTIES ===

# ~/.gradle/gradle.properties
nexusUsername=deployment-user
nexusPassword=your-password


# === PUBLIER AVEC GRADLE ===

# Build et publier
./gradlew publish

# Publier release
./gradlew publishMavenPublicationToNexusRepository


[OK] NUGET (.NET)

# === CRÉER REPOSITORY NUGET ===

Create repository > nuget (hosted)
Name: nuget-hosted

Create repository > nuget (proxy)
Name: nuget-proxy
Remote storage: https://api.nuget.org/v3/index.json

Create repository > nuget (group)
Name: nuget-all
Members: nuget-hosted, nuget-proxy


# === CONFIGURER NUGET CLIENT ===

# Ajouter source Nexus
nuget sources add \
  -name nexus \
  -source http://localhost:8081/repository/nuget-all/index.json \
  -username admin \
  -password password

# Lister sources
nuget sources list

# Installer package
nuget install Newtonsoft.Json -Source nexus


# === PUBLIER PACKAGE NUGET ===

# 1. Créer package
dotnet pack MyProject.csproj -o ./nupkgs

# 2. Push vers Nexus
nuget push ./nupkgs/MyProject.1.0.0.nupkg \
  -Source http://localhost:8081/repository/nuget-hosted/ \
  -ApiKey admin:password

# Ou avec dotnet
dotnet nuget push ./nupkgs/MyProject.1.0.0.nupkg \
  --source http://localhost:8081/repository/nuget-hosted/ \
  --api-key admin:password


# === CONFIGURER VISUAL STUDIO ===

# Tools > Options > NuGet Package Manager > Package Sources
# Add:
# Name: Nexus
# Source: http://localhost:8081/repository/nuget-all/index.json


[OK] HELM REPOSITORIES

# === CRÉER REPOSITORY HELM ===

Create repository > helm (hosted)
Name: helm-hosted

Create repository > helm (proxy)
Name: helm-proxy
Remote storage: https://charts.helm.sh/stable


# === CONFIGURER HELM CLIENT ===

# Ajouter repository
helm repo add nexus http://localhost:8081/repository/helm-hosted/ \
  --username admin \
  --password password

# Lister repositories
helm repo list

# Mettre à jour
helm repo update


# === PUBLIER CHART HELM ===

# 1. Package chart
helm package my-chart/

# 2. Upload via curl
curl -u admin:password \
  --upload-file my-chart-1.0.0.tgz \
  http://localhost:8081/repository/helm-hosted/


# === INSTALLER CHART ===

# Depuis Nexus
helm install my-release nexus/my-chart

# Avec version spécifique
helm install my-release nexus/my-chart --version 1.0.0


[OK] APT/YUM REPOSITORIES

# === APT REPOSITORY (DEBIAN/UBUNTU) ===

# Créer repository
Create repository > apt (hosted)
Name: apt-releases
Distribution: bionic

# Uploader .deb
curl -u admin:password \
  --upload-file package.deb \
  http://localhost:8081/repository/apt-releases/

# Configurer client
echo "deb http://localhost:8081/repository/apt-releases/ bionic main" | \
  sudo tee /etc/apt/sources.list.d/nexus.list

# Installer
sudo apt update
sudo apt install package


# === YUM REPOSITORY (RHEL/CENTOS) ===

# Créer repository
Create repository > yum (hosted)
Name: yum-releases

# Uploader .rpm
curl -u admin:password \
  --upload-file package.rpm \
  http://localhost:8081/repository/yum-releases/

# Configurer client
sudo tee /etc/yum.repos.d/nexus.repo << EOF
[nexus]
name=Nexus Repository
baseurl=http://localhost:8081/repository/yum-releases/
enabled=1
gpgcheck=0
EOF

# Installer
sudo yum install package


[OK] SÉCURITÉ

# === SSL/TLS ===

# Générer certificat auto-signé
keytool -genkeypair \
  -keystore keystore.jks \
  -storepass password \
  -keypass password \
  -alias nexus \
  -keyalg RSA \
  -keysize 2048 \
  -validity 365 \
  -dname "CN=nexus.example.com, OU=IT, O=Example, L=City, ST=State, C=US" \
  -ext "SAN=DNS:nexus.example.com,IP:192.168.1.100"

# Copier keystore
sudo cp keystore.jks /opt/nexus-data/etc/ssl/

# Éditer nexus.properties
# /opt/nexus-data/etc/nexus.properties
application-port-ssl=8443
nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-https.xml,${jetty.etc}/jetty-requestlog.xml
ssl.etc=${karaf.data}/etc/ssl

# Éditer jetty-https.xml
# /opt/nexus/etc/jetty/jetty-https.xml
<Set name="KeyStorePath">/opt/nexus-data/etc/ssl/keystore.jks</Set>
<Set name="KeyStorePassword">password</Set>
<Set name="KeyManagerPassword">password</Set>
<Set name="TrustStorePath">/opt/nexus-data/etc/ssl/keystore.jks</Set>
<Set name="TrustStorePassword">password</Set>


# === RÉINITIALISER MOT DE PASSE ADMIN ===

# 1. Arrêter Nexus
sudo systemctl stop nexus

# 2. Supprimer fichier security
rm /opt/nexus-data/admin.password

# 3. Réinitialiser DB (ATTENTION: perte config sécurité)
rm -rf /opt/nexus-data/db/security

# 4. Redémarrer
sudo systemctl start nexus

# 5. Nouveau mot de passe dans:
cat /opt/nexus-data/admin.password


# === AUTHENTIFICATION 2FA (Nexus Pro) ===

# Administration > Security > Realms
# Enable: Duo Security Realm

# Configuration Duo
Integration key: YOUR_INTEGRATION_KEY
Secret key: YOUR_SECRET_KEY
API hostname: api-xxx.duosecurity.com


# === CONTENT VALIDATION ===

# Activer validation stricte des contenus
# Edit repository > Storage
Strict Content Type Validation: Enabled

# Empêche upload de fichiers avec mauvais type MIME


# === FIREWALL (IQ Server - Nexus Pro) ===

# Analyse vulnérabilités des composants
# Administration > Capabilities > Firewall
Enable: Repository Firewall


[OK] MIGRATION

# === MIGRER DEPUIS ARTIFACTORY ===

# 1. Exporter repositories Artifactory
# 2. Créer repositories équivalents dans Nexus
# 3. Utiliser outil de migration ou scripts

# Script de migration (exemple)
#!/bin/bash

ARTIFACTORY_URL="https://artifactory.example.com"
NEXUS_URL="http://localhost:8081"
REPO_NAME="libs-release"

# Liste artefacts
curl -u user:password \
  "${ARTIFACTORY_URL}/api/storage/${REPO_NAME}?list&deep=1" | \
  jq -r '.files[].uri' | \
while read artifact; do
  # Download from Artifactory
  curl -u user:password \
    "${ARTIFACTORY_URL}/${REPO_NAME}${artifact}" \
    -o temp.jar
  
  # Upload to Nexus
  curl -u admin:password \
    --upload-file temp.jar \
    "${NEXUS_URL}/repository/${REPO_NAME}${artifact}"
  
  rm temp.jar
done


# === MIGRER VERS NOUVELLE VERSION NEXUS ===

# 1. Sauvegarder données actuelles
sudo systemctl stop nexus
tar -czf nexus-data-backup.tar.gz /opt/nexus-data

# 2. Télécharger nouvelle version
cd /opt
sudo wget https://download.sonatype.com/nexus/3/nexus-3.XX.X-unix.tar.gz

# 3. Extraire
sudo tar -xzf nexus-3.XX.X-unix.tar.gz
sudo mv nexus-3.XX.X nexus-new

# 4. Pointer vers anciennes données
sudo rm -rf /opt/nexus-new/sonatype-work
sudo ln -s /opt/nexus-data /opt/nexus-new/sonatype-work

# 5. Changer symlink
sudo rm /opt/nexus
sudo ln -s /opt/nexus-new /opt/nexus

# 6. Redémarrer
sudo systemctl start nexus


[OK] TROUBLESHOOTING (DÉPANNAGE)

# === NEXUS NE DÉMARRE PAS ===

# Vérifier logs
tail -f /opt/nexus-data/log/nexus.log

# Vérifier si port déjà utilisé
sudo netstat -tlnp | grep 8081
sudo lsof -i :8081

# Vérifier permissions
sudo chown -R nexus:nexus /opt/nexus
sudo chown -R nexus:nexus /opt/nexus-data

# Vérifier mémoire disponible
free -h

# Augmenter mémoire JVM
# Éditer /opt/nexus/bin/nexus.vmoptions
-Xms4g
-Xmx4g


# === ERREUR "OutOfMemoryError" ===

# Augmenter heap
# /opt/nexus/bin/nexus.vmoptions
-Xms4096m
-Xmx4096m
-XX:MaxDirectMemorySize=4096m

# Redémarrer
sudo systemctl restart nexus


# === REPOSITORY INACCESSIBLE ===

# Vérifier statut repository
# Administration > Repository > Repositories
# Status doit être "Online"

# Forcer online
curl -X PUT -u admin:password \
  -H "Content-Type: application/json" \
  http://localhost:8081/service/rest/v1/repositories/maven-releases \
  -d '{"online": true}'

# Rebuild index
# Administration > System > Tasks
# Create task > Repair - Rebuild repository search


# === ESPACE DISQUE PLEIN ===

# Vérifier utilisation
df -h /opt/nexus-data

# Nettoyer blobs
# Administration > Repository > Blob Stores > Compact

# Supprimer anciens artefacts
# Activer Cleanup Policies

# Vérifier taille des repositories
du -sh /opt/nexus-data/blobs/*


# === ERREUR 401 UNAUTHORIZED ===

# Vérifier credentials
curl -u username:password \
  http://localhost:8081/service/rest/v1/status

# Vérifier rôles utilisateur
# Administration > Security > Users > Edit user

# Réinitialiser mot de passe
# Administration > Security > Users > Change password


# === ERREUR 403 FORBIDDEN ===

# Vérifier permissions repository
# Administration > Security > Privileges

# Vérifier Content Selector
# Administration > Security > Content Selectors

# Assigner bon privilège au rôle


# === BUILDS LENTS ===

# 1. Vérifier proxy repositories sont UP
# 2. Augmenter timeout remote
# Edit proxy repository > Remote Connection
# Connection timeout: 60 seconds
# Connection retries: 3

# 3. Vérifier cache
# Negative cache enabled: Yes
# Negative cache TTL: 1440 minutes

# 4. Utiliser group repository

# 5. Augmenter threads
# /opt/nexus-data/etc/nexus.properties
nexus.analytics.collection.enabled=false


# === DATABASE CORRUPTION ===

# Utiliser backup
sudo systemctl stop nexus
rm -rf /opt/nexus-data/db
tar -xzf nexus-data-backup.tar.gz -C /
sudo systemctl start nexus

# Ou rebuild database
# Administration > System > Tasks
# Admin - Reconcile component database from blob store


# === DOCKER LOGIN FAILED ===

# Vérifier insecure-registries
cat /etc/docker/daemon.json

# Ajouter realm Docker Bearer Token
# Administration > Security > Realms
# Add: Docker Bearer Token Realm

# Vérifier port repository
# Repository doit avoir HTTP port configuré


# === PROXY REPOSITORY NE CACHE PAS ===

# Vérifier connexion internet
curl -I https://repo1.maven.org/maven2/

# Vérifier proxy HTTP (si derrière firewall)
# Administration > System > HTTP
HTTP proxy: proxy.company.com
Port: 8080

# Vérifier remote URL
# Edit proxy repository > Remote storage
# Tester: View > Health check


[OK] BONNES PRATIQUES

# === ORGANISATION DES REPOSITORIES ===

# 1. Structure recommandée
# maven-releases (hosted) - artifacts stables
# maven-snapshots (hosted) - dev builds
# maven-central (proxy) - cache Maven Central
# maven-public (group) - point d'entrée unique

# 2. Séparer par environnement
# maven-dev-releases
# maven-staging-releases
# maven-prod-releases

# 3. Utiliser groupes
# Client configure seulement le group
# Ordre: hosted > proxy


# === NOMMAGE ===

# Format: <format>-<type>-<env>
# Exemples:
# maven-releases-prod
# npm-private-dev
# docker-hosted-staging


# === SÉCURITÉ ===

# 1. Changer mot de passe admin immédiatement
# 2. Créer utilisateurs avec permissions minimales
# 3. Utiliser HTTPS en production
# 4. Activer anonymous access seulement si nécessaire
# 5. Utiliser tokens API plutôt que mots de passe
# 6. Activer audit logging
# 7. Sauvegarder régulièrement


# === PERFORMANCE ===

# 1. Allouer suffisamment de RAM (8 Go+ production)
# 2. Utiliser SSD pour blob stores
# 3. Activer cleanup policies
# 4. Compacter blob stores régulièrement
# 5. Monitorer espace disque
# 6. Optimiser negative cache TTL


# === BACKUP ===

# 1. Sauvegarder quotidiennement
# 2. Tester restaurations régulièrement
# 3. Sauvegarder séparément DB et blobs
# 4. Stocker backups hors serveur
# 5. Rotation des backups (retention policy)


# === MAINTENANCE ===

# 1. Mettre à jour régulièrement
# 2. Monitorer logs d'erreurs
# 3. Vérifier santé des repositories
# 4. Nettoyer artefacts obsolètes
# 5. Vérifier intégrité database
# 6. Documenter configuration


# === CI/CD ===

# 1. Utiliser tokens API dans pipelines
# 2. Ne pas hardcoder credentials
# 3. Utiliser group repositories
# 4. Versionner artifacts
# 5. Cleanup automatique en CI


[OK] SCRIPTS UTILES

# === SCRIPT DE SANTÉ ===

#!/bin/bash
# nexus-health-check.sh

NEXUS_URL="http://localhost:8081"

# Check status
STATUS=$(curl -s ${NEXUS_URL}/service/rest/v1/status | jq -r '.available')

if [ "$STATUS" == "true" ]; then
    echo "[OK] Nexus is healthy"
    exit 0
else
    echo "[X] Nexus is down"
    exit 1
fi


# === SCRIPT BACKUP AUTOMATIQUE ===

#!/bin/bash
# nexus-daily-backup.sh

BACKUP_DIR="/backups/nexus"
NEXUS_DATA="/opt/nexus-data"
DATE=$(date +%Y%m%d)
RETENTION=7

mkdir -p $BACKUP_DIR

# Backup config et DB
tar -czf $BACKUP_DIR/nexus-$DATE.tar.gz \
  $NEXUS_DATA/db \
  $NEXUS_DATA/etc \
  $NEXUS_DATA/keystores

# Cleanup old backups
find $BACKUP_DIR -name "nexus-*.tar.gz" -mtime +$RETENTION -delete

# Log
echo "$(date): Backup completed" >> /var/log/nexus-backup.log


# === SCRIPT NETTOYAGE ESPACE DISQUE ===

#!/bin/bash
# nexus-cleanup.sh

# Compact tous les blob stores
curl -X POST -u admin:password \
  http://localhost:8081/service/rest/v1/blobstores/default/compact

# Run cleanup tasks
curl -X POST -u admin:password \
  http://localhost:8081/service/rest/v1/tasks/*/run

echo "Cleanup completed"


# === SCRIPT MIGRATION MASSE ===

#!/bin/bash
# migrate-artifacts.sh

SOURCE_REPO="old-releases"
TARGET_REPO="new-releases"
NEXUS_URL="http://localhost:8081"

# List et migrate
curl -s -u admin:password \
  "${NEXUS_URL}/service/rest/v1/search?repository=${SOURCE_REPO}" | \
  jq -r '.items[].downloadUrl' | \
while read url; do
  artifact=$(basename $url)
  path=$(echo $url | sed "s|.*/${SOURCE_REPO}/||")
  
  # Download
  curl -s -u admin:password -o /tmp/$artifact $url
  
  # Upload to target
  curl -u admin:password \
    --upload-file /tmp/$artifact \
    "${NEXUS_URL}/repository/${TARGET_REPO}/${path}"
  
  rm /tmp/$artifact
  echo "Migrated: $path"
done


# === SCRIPT LISTE COMPOSANTS ===

#!/bin/bash
# list-components.sh

REPO_NAME=$1
NEXUS_URL="http://localhost:8081"

if [ -z "$REPO_NAME" ]; then
  echo "Usage: $0 <repository-name>"
  exit 1
fi

curl -s -u admin:password \
  "${NEXUS_URL}/service/rest/v1/components?repository=${REPO_NAME}" | \
  jq -r '.items[] | "\(.name):\(.version)"'


# === SCRIPT VÉRIFICATION VULNÉRABILITÉS ===

#!/bin/bash
# check-vulnerabilities.sh

REPO_NAME=$1

curl -s -u admin:password \
  "http://localhost:8081/service/rest/v1/vulnerabilities?repositoryName=${REPO_NAME}" | \
  jq '.items[] | {component: .componentName, cve: .cveId, severity: .severity}'


# === SCRIPT STATISTIQUES REPOSITORIES ===

#!/bin/bash
# repo-stats.sh

NEXUS_URL="http://localhost:8081"

echo "Repository Statistics"
echo "===================="

curl -s -u admin:password \
  ${NEXUS_URL}/service/rest/v1/repositories | \
  jq -r '.[] | "\(.name) (\(.format)) - \(.type)"'

echo ""
echo "Blob Store Usage"
echo "================"

curl -s -u admin:password \
  ${NEXUS_URL}/service/rest/v1/blobstores | \
  jq -r '.[] | "\(.name): \(.totalSizeInBytes/1024/1024/1024 | floor)GB"'


[OK] DOCKER-COMPOSE COMPLET AVEC NGINX

# docker-compose.yml - Setup complet production

version: '3.8'

services:
  # Nexus Repository
  nexus:
    image: sonatype/nexus3:latest
    container_name: nexus
    restart: always
    environment:
      - INSTALL4J_ADD_VM_PARAMS=-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g
    volumes:
      - nexus-data:/nexus-data
    networks:
      - nexus-net
    # Ports internes seulement (via nginx)
    expose:
      - "8081"
      - "5000"
      - "5001"
      - "5002"

  # Nginx Reverse Proxy
  nginx:
    image: nginx:alpine
    container_name: nexus-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "5000:5000"   # Docker hosted
      - "5001:5001"   # Docker proxy
      - "5002:5002"   # Docker group
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
      - nginx-cache:/var/cache/nginx
    depends_on:
      - nexus
    networks:
      - nexus-net

  # PostgreSQL (optionnel - pour audit externe)
  postgres:
    image: postgres:14-alpine
    container_name: nexus-postgres
    restart: always
    environment:
      POSTGRES_DB: nexus_audit
      POSTGRES_USER: nexus
      POSTGRES_PASSWORD: nexuspassword
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - nexus-net

  # Prometheus (monitoring)
  prometheus:
    image: prom/prometheus:latest
    container_name: nexus-prometheus
    restart: always
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"
    networks:
      - nexus-net

  # Grafana (visualisation)
  grafana:
    image: grafana/grafana:latest
    container_name: nexus-grafana
    restart: always
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    networks:
      - nexus-net

volumes:
  nexus-data:
    driver: local
  postgres-data:
    driver: local
  prometheus-data:
    driver: local
  grafana-data:
    driver: local
  nginx-cache:
    driver: local

networks:
  nexus-net:
    driver: bridge


# nginx.conf
events {
    worker_connections 1024;
}

http {
    client_max_body_size 0;
    chunked_transfer_encoding on;

    upstream nexus {
        server nexus:8081;
    }

    upstream docker-hosted {
        server nexus:5000;
    }

    upstream docker-proxy {
        server nexus:5001;
    }

    upstream docker-group {
        server nexus:5002;
    }

    # Cache configuration
    proxy_cache_path /var/cache/nginx/nexus levels=1:2 keys_zone=nexus_cache:10m max_size=1g inactive=60m;

    # Main Nexus UI
    server {
        listen 80;
        server_name nexus.example.com;

        # Redirect to HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name nexus.example.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            proxy_pass http://nexus;
            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 "https";
            
            # Cache static assets
            proxy_cache nexus_cache;
            proxy_cache_valid 200 60m;
            add_header X-Cache-Status $upstream_cache_status;
        }
    }

    # Docker Hosted
    server {
        listen 5000 ssl http2;
        server_name docker.example.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;

        location / {
            proxy_pass http://docker-hosted;
            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 "https";
        }
    }

    # Docker Group
    server {
        listen 5002 ssl http2;
        server_name docker-all.example.com;

        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;

        location / {
            proxy_pass http://docker-group;
            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 "https";
        }
    }
}


# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'nexus'
    metrics_path: '/service/metrics/prometheus'
    static_configs:
      - targets: ['nexus:8081']
    basic_auth:
      username: admin
      password: password


[OK] KUBERNETES DEPLOYMENT

# nexus-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nexus


# nexus-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nexus-data-pvc
  namespace: nexus
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
  storageClassName: standard


# nexus-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nexus
  namespace: nexus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nexus
  template:
    metadata:
      labels:
        app: nexus
    spec:
      containers:
      - name: nexus
        image: sonatype/nexus3:latest
        ports:
        - containerPort: 8081
          name: web
        - containerPort: 5000
          name: docker-hosted
        - containerPort: 5001
          name: docker-proxy
        - containerPort: 5002
          name: docker-group
        env:
        - name: INSTALL4J_ADD_VM_PARAMS
          value: "-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g"
        volumeMounts:
        - name: nexus-data
          mountPath: /nexus-data
        resources:
          requests:
            memory: "4Gi"
            cpu: "1000m"
          limits:
            memory: "8Gi"
            cpu: "2000m"
        livenessProbe:
          httpGet:
            path: /service/rest/v1/status
            port: 8081
          initialDelaySeconds: 180
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /service/rest/v1/status
            port: 8081
          initialDelaySeconds: 60
          periodSeconds: 10
      volumes:
      - name: nexus-data
        persistentVolumeClaim:
          claimName: nexus-data-pvc


# nexus-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nexus-service
  namespace: nexus
spec:
  type: LoadBalancer
  ports:
  - name: web
    port: 8081
    targetPort: 8081
  - name: docker-hosted
    port: 5000
    targetPort: 5000
  - name: docker-proxy
    port: 5001
    targetPort: 5001
  - name: docker-group
    port: 5002
    targetPort: 5002
  selector:
    app: nexus


# nexus-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nexus-ingress
  namespace: nexus
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - nexus.example.com
    secretName: nexus-tls
  rules:
  - host: nexus.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nexus-service
            port:
              number: 8081


# Déployer
kubectl apply -f nexus-namespace.yaml
kubectl apply -f nexus-pvc.yaml
kubectl apply -f nexus-deployment.yaml
kubectl apply -f nexus-service.yaml
kubectl apply -f nexus-ingress.yaml

# Vérifier
kubectl get pods -n nexus
kubectl logs -f -n nexus deployment/nexus

# Récupérer mot de passe initial
kubectl exec -n nexus deployment/nexus -- cat /nexus-data/admin.password


[OK] TERRAFORM CONFIGURATION

# main.tf - Déployer Nexus sur AWS

provider "aws" {
  region = "us-east-1"
}

# Security Group
resource "aws_security_group" "nexus" {
  name        = "nexus-sg"
  description = "Security group for Nexus"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 8081
    to_port     = 8081
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 5000
    to_port     = 5002
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# EBS Volume
resource "aws_ebs_volume" "nexus_data" {
  availability_zone = "us-east-1a"
  size              = 100
  type              = "gp3"
  
  tags = {
    Name = "nexus-data"
  }
}

# EC2 Instance
resource "aws_instance" "nexus" {
  ami           = "ami-0c55b159cbfafe1f0"  # Ubuntu 20.04
  instance_type = "t3.large"
  key_name      = "your-key-pair"
  
  vpc_security_group_ids = [aws_security_group.nexus.id]
  
  user_data = <<-EOF
              #!/bin/bash
              apt-get update
              apt-get install -y openjdk-11-jdk docker.io docker-compose
              
              # Install Nexus with Docker
              mkdir -p /opt/nexus-data
              docker run -d \
                --name nexus \
                -p 8081:8081 \
                -p 5000:5000 \
                -p 5001:5001 \
                -p 5002:5002 \
                -v /opt/nexus-data:/nexus-data \
                sonatype/nexus3
              EOF
  
  tags = {
    Name = "nexus-server"
  }
}

# Attach EBS
resource "aws_volume_attachment" "nexus_data_attachment" {
  device_name = "/dev/sdf"
  volume_id   = aws_ebs_volume.nexus_data.id
  instance_id = aws_instance.nexus.id
}

# Output
output "nexus_public_ip" {
  value = aws_instance.nexus.public_ip
}

output "nexus_url" {
  value = "http://${aws_instance.nexus.public_ip}:8081"
}


[OK] ANSIBLE PLAYBOOK

# nexus-playbook.yml

---
- name: Install and Configure Nexus Repository
  hosts: nexus_servers
  become: yes
  vars:
    nexus_version: "3.60.0-02"
    nexus_user: nexus
    nexus_home: /opt/nexus
    nexus_data: /opt/nexus-data
    nexus_port: 8081

  tasks:
    - name: Install Java
      apt:
        name: openjdk-11-jdk
        state: present
        update_cache: yes

    - name: Create Nexus user
      user:
        name: "{{ nexus_user }}"
        system: yes
        create_home: yes
        home: "{{ nexus_home }}"
        shell: /bin/bash

    - name: Download Nexus
      get_url:
        url: "https://download.sonatype.com/nexus/3/nexus-{{ nexus_version }}-unix.tar.gz"
        dest: /tmp/nexus.tar.gz

    - name: Extract Nexus
      unarchive:
        src: /tmp/nexus.tar.gz
        dest: /opt
        remote_src: yes
        owner: "{{ nexus_user }}"
        group: "{{ nexus_user }}"

    - name: Create symlink
      file:
        src: "/opt/nexus-{{ nexus_version }}"
        dest: "{{ nexus_home }}"
        state: link
        owner: "{{ nexus_user }}"
        group: "{{ nexus_user }}"

    - name: Configure run as user
      lineinfile:
        path: "{{ nexus_home }}/bin/nexus.rc"
        line: 'run_as_user="{{ nexus_user }}"'
        create: yes

    - name: Create systemd service
      template:
        src: nexus.service.j2
        dest: /etc/systemd/system/nexus.service

    - name: Start Nexus service
      systemd:
        name: nexus
        state: started
        enabled: yes
        daemon_reload: yes

    - name: Wait for Nexus to start
      wait_for:
        port: "{{ nexus_port }}"
        delay: 30
        timeout: 300

    - name: Get admin password
      slurp:
        src: "{{ nexus_data }}/admin.password"
      register: admin_password
      ignore_errors: yes

    - name: Display admin password
      debug:
        msg: "Admin password: {{ admin_password.content | b64decode }}"
      when: admin_password is succeeded


# nexus.service.j2
[Unit]
Description=Nexus Repository Manager
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart={{ nexus_home }}/bin/nexus start
ExecStop={{ nexus_home }}/bin/nexus stop
User={{ nexus_user }}
Restart=on-abort
TimeoutSec=600

[Install]
WantedBy=multi-user.target


# Exécuter playbook
ansible-playbook -i inventory.ini nexus-playbook.yml


[OK] MONITORING AVANCÉ

# === CONFIGURER PROMETHEUS + GRAFANA ===

# 1. Activer métriques Nexus (Nexus Pro)
# Administration > Capabilities > Prometheus Metrics
# Enable capability

# 2. Configuration Prometheus
# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'nexus'
    metrics_path: '/service/metrics/prometheus'
    static_configs:
      - targets: ['localhost:8081']
    basic_auth:
      username: 'admin'
      password: 'password'


# 3. Démarrer Prometheus
docker run -d \
  -p 9090:9090 \
  -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
  prom/prometheus


# 4. Dashboards Grafana
# Importer dashboard ID: 13785 (Nexus Repository Manager)


# === MÉTRIQUES IMPORTANTES ===

# Mémoire JVM
nexus_jvm_memory_used_bytes

# Requests HTTP
nexus_http_requests_total

# Taille blob stores
nexus_blob_store_total_size_bytes

# Composants par repository
nexus_repository_component_count

# Téléchargements
nexus_repository_download_total


# === ALERTING (Alertmanager) ===

# alertmanager.yml
global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  receiver: 'email'

receivers:
  - name: 'email'
    email_configs:
      - to: 'admin@example.com'
        from: 'alertmanager@example.com'
        smarthost: 'smtp.example.com:587'
        auth_username: 'alerts@example.com'
        auth_password: 'password'


# alert.rules.yml
groups:
  - name: nexus
    interval: 30s
    rules:
      - alert: NexusDown
        expr: up{job="nexus"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Nexus is down"
          
      - alert: HighMemoryUsage
        expr: nexus_jvm_memory_used_bytes / nexus_jvm_memory_max_bytes > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Nexus memory usage > 90%"
          
      - alert: DiskSpaceLow
        expr: nexus_blob_store_available_space_bytes < 10737418240
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Blob store has less than 10GB free"


[OK] HIGH AVAILABILITY (HA)

# Nexus OSS ne supporte pas HA nativement
# Nexus Pro supporte clustering

# === SETUP HA (NEXUS PRO) ===

# 1. Architecture recommandée
# - Load Balancer (HAProxy/Nginx)
# - 3+ Nexus nodes
# - Shared storage (NFS/S3)
# - Database externe (PostgreSQL)

# 2. HAProxy configuration
# haproxy.cfg
frontend nexus_front
    bind *:8081
    default_backend nexus_back

backend nexus_back
    balance roundrobin
    option httpchk GET /service/rest/v1/status
    server nexus1 10.0.1.10:8081 check
    server nexus2 10.0.1.11:8081 check
    server nexus3 10.0.1.12:8081 check


# === RÉPLICATION ACTIVE-PASSIVE (OSS) ===

# Solution pour OSS: réplication manuelle

# 1. Serveur primaire: nexus-primary
# 2. Serveur secondaire: nexus-secondary (standby)
# 3. Script réplication

#!/bin/bash
# replicate-nexus.sh

PRIMARY_DATA="/opt/nexus-data"
SECONDARY_HOST="nexus-secondary"
SECONDARY_DATA="/opt/nexus-data"

# Sync avec rsync
rsync -avz --delete \
  --exclude 'log/*' \
  --exclude 'tmp/*' \
  $PRIMARY_DATA/ \
  $SECONDARY_HOST:$SECONDARY_DATA/

# Exécuter toutes les heures
# crontab: 0 * * * * /usr/local/bin/replicate-nexus.sh


[OK] COMPARAISON NEXUS VS ALTERNATIVES

# === NEXUS VS ARTIFACTORY ===

Nexus:
[OK] Open source gratuit (OSS)
[OK] Interface simple
[OK] Bon support Docker
[OK] Moins cher (Pro)
[X] Pas de HA natif (OSS)
[X] Moins de formats supportés

Artifactory:
[OK] HA natif
[OK] Plus de formats
[OK] Meilleure performance
[OK] Support Kubernetes natif
[X] Plus cher
[X] Pas de version gratuite complète


# === NEXUS VS GITHUB PACKAGES ===

Nexus:
[OK] Self-hosted (contrôle total)
[OK] Tous les formats
[OK] Pas de limites
[X] Maintenance requise

GitHub Packages:
[OK] Managed service
[OK] Intégration GitHub
[X] Limites stockage/transfert
[X] Formats limités


# === NEXUS VS CLOUD STORAGE (S3) ===

Nexus:
[OK] Metadata et recherche
[OK] Proxy/cache
[OK] Contrôle d'accès granulaire
[OK] Versioning intelligent

S3:
[OK] Simple
[OK] Peu cher
[X] Pas de metadata
[X] Pas de proxy/grouping


[OK] RESSOURCES ET DOCUMENTATION

# Documentation officielle
https://help.sonatype.com/repomanager3

# REST API documentation
https://help.sonatype.com/repomanager3/integrations/rest-and-integration-api

# Docker Hub
https://hub.docker.com/r/sonatype/nexus3

# Community
https://community.sonatype.com

# GitHub
https://github.com/sonatype/nexus-public

# Blog
https://blog.sonatype.com

# Formation
https://learn.sonatype.com


[OK] CHECKLIST DÉPLOIEMENT PRODUCTION

[ ] Serveur dimensionné (8 Go+ RAM, SSD)
[ ] Java 11 installé
[ ] Nexus installé et démarré
[ ] Mot de passe admin changé
[ ] HTTPS configuré (certificat SSL)
[ ] Reverse proxy configuré (Nginx/Apache)
[ ] Firewall configuré (ports 8081, 443)
[ ] Backup automatique configuré
[ ] Monitoring configuré (Prometheus/Grafana)
[ ] Logs rotation configurée
[ ] Cleanup policies activées
[ ] Utilisateurs et rôles créés
[ ] Repositories créés (hosted, proxy, group)
[ ] Anonymous access désactivé (si requis)
[ ] Audit logging activé
[ ] Documentation créée (accès, repos, etc.)
[ ] Plan de disaster recovery testé
[ ] Intégration CI/CD testée
[ ] Performance testée (load testing)
[ ] Espace disque monitoring configuré
[ ] Alerting configuré
[ ] Procédure restauration documentée


[OK] EXEMPLES COMPLETS D'USAGE

# === PROJET JAVA MAVEN ===

# 1. Configuration Maven
# pom.xml
<repositories>
  <repository>
    <id>nexus</id>
    <url>https://nexus.example.com/repository/maven-public/</url>
  </repository>
</repositories>

<distributionManagement>
  <repository>
    <id>nexus-releases</id>
    <url>https://nexus.example.com/repository/maven-releases/</url>
  </repository>
</distributionManagement>

# ~/.m2/settings.xml
<servers>
  <server>
    <id>nexus-releases</id>
    <username>ci-user</username>
    <password>${env.NEXUS_PASSWORD}</password>
  </server>
</servers>

# 2. Build et deploy
mvn clean deploy


# === PROJET NODE.JS ===

# 1. Configuration npm
# .npmrc
registry=https://nexus.example.com/repository/npm-all/
@mycompany:registry=https://nexus.example.com/repository/npm-private/
//nexus.example.com/repository/npm-private/:_auth=dXNlcjpwYXNzd29yZA==

# 2. Install dépendances
npm install

# 3. Publish package privé
npm publish


# === PROJET PYTHON ===

# 1. Configuration pip
# ~/.pip/pip.conf
[global]
index-url = https://nexus.example.com/repository/pypi-all/simple
trusted-host = nexus.example.com

# 2. Install
pip install -r requirements.txt

# 3. Publish
twine upload --repository nexus dist/*


# === PROJET DOCKER ===

# 1. Login
docker login registry.example.com

# 2. Build et tag
docker build -t my-app:1.0 .
docker tag my-app:1.0 registry.example.com/my-app:1.0

# 3. Push
docker push registry.example.com/my-app:1.0

# 4. Pull
docker pull registry.example.com/my-app:1.0


# === PROJET .NET ===

# 1. Configuration NuGet
# nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nexus" value="https://nexus.example.com/repository/nuget-all/index.json" />
  </packageSources>
</configuration>

# 2. Restore
dotnet restore

# 3. Publish
dotnet nuget push bin/Release/MyApp.1.0.0.nupkg \
  --source nexus \
  --api-key user:password


[OK] SCÉNARIO RÉEL: STARTUP E-COMMERCE "SHOPFAST"

# [ENTREPRISE] NEXUS EN PRODUCTION - CAS RÉEL COMPLET
## Startup E-COMMERCE "SHOPFAST" - Application du Monde Réel

---

## [LISTE] CONTEXTE DE L'ENTREPRISE

### Équipe & Infrastructure
```
ShopFast (15 développeurs, ~2M€ ARR)
├── Backend (5 devs)      -> Java/Spring Boot/Maven
├── Frontend (5 devs)     -> React 18/TypeScript/npm
├── Mobile (3 devs)       -> React Native
└── DevOps (2)            -> K8s/Docker/GitLab CI
```

Stack technique
- **Backend**: Java 11, Spring Boot 3.1, Maven 3.8
- **Frontend**: React 18, TypeScript, Vite, npm
- **Mobile**: React Native, Expo
- **Database**: PostgreSQL 14
- **Cache**: Redis 7
- **Queue**: RabbitMQ
- **CI/CD**: GitLab CI -> Kubernetes
- **Container Registry**: Nexus Docker

---

## [ROUGE] 6 PROBLÈMES CRITIQUES AVANT NEXUS

### [X] Problème 1 : Temps de build catastrophiques

#### La réalité quotidienne
```
Backend:   250 dépendances Maven  -> 8 min/build
Frontend:  1200+ packages npm    -> 5 min/build
Mobile:    800 packages + assets -> 6 min/build
CI/CD:     50 builds/jour        -> 650 min perdues = 11h/jour [ATTENTION]

Coûts: bande passante gaspillée, développeurs bloqués
```

#### Pourquoi c'est si lent ?

**Processus ACTUEL (sans Nexus):**

1. **Dev pousse du code** -> GitLab CI démarre le pipeline
2. **Stage BUILD** -> Maven/npm télécharge TOUTES les dépendances depuis Internet
   - Maven doit contacter Maven Central Repository (serveur à Boston)
   - npm doit contacter registry.npmjs.org (serveur AWS)
   - Latence réseau: 100-500ms par requête
   - 250 dépendances = 250 × 500ms = 2 minutes JUSTE pour les requêtes réseau
   - Puis extraction + indexation + compilation = 6 minutes supplémentaires

3. **Téléchargement des JAR/packages**
   - Spring Boot starter-web: 3.2 MB
   - Hibernate: 4.5 MB
   - React, TypeScript, ESLint, etc: 300+ MB
   - Total par build: ~500-1000 MB à télécharger

4. **Exemple réel - Frontend:**
```
npm install
├── 1. Contact npmjs.org (~200ms)
├── 2. Parse package.json (~100ms)
├── 3. Résoudre dépendances (1200 packages) -> récursif (~2000ms)
├── 4. Télécharger tous les packages (~200 MB) -> bande passante! (~3 min)
├── 5. Extraire + valider checksums (~30s)
└── Total: ~5 minutes
```

**Impact pour l'entreprise:**
- 50 builds/jour × 5 min = 250 min/jour juste pour les dépendances
- 5 développeurs attendant = 5 × 250 min = 1250 minutes perdues/jour
- Coût: 1250 min / 60 = **21 heures/jour de temps développeur gaspillées**
- Par mois: 21h × 22 jours = **462 heures = €57,750** (à 125€/h)
- Par an: **€693,000** [SKULL]

### [X] Problème 2 : Builds cassent aléatoirement

#### Les incidents réels documentés

**Cas 1: npmjs.org en maintenance (Août 2023)**
```
Chronologie:
09:00 -> npmjs.org commence maintenance (annoncée sur Twitter)
09:05 -> Premier dev essaie: npm ci -> TIMEOUT
09:10 -> Tous les builds frontend crashent
09:15 -> Slack: "npm est down, on peut pas faire de hotfix"
09:30 -> Autre dev relance le build (espoir...)
09:35 -> TOUJOURS down
11:00 -> npmjs back online

Coût:
- 2 heures de downtime totale
- 5 devs frontend bloqués = 10 heures de productivité perdue
- Hotfix de sécurité RETARDÉ = risque de sécurité
```

**Cas 2: Maven Central timeout**
```
Problème: Maven Central est lent (serveurs souvent surchargés)

Scénario typique:
14:20 -> mvn clean compile
14:25 -> Maven télécharge dépendance N°37 (timeout 30s)
14:25 -> Retry automatique (timeout 30s)
14:26 -> Retry automatique (timeout 30s)
14:26 -> BUILD FAILURE "Connection timeout"

Dev pense: "Mon internet est cassé?"
Reality: Maven Central était juste lent

Solution actuelle: relancer (gambling...)
```

**Cas 3: Dépendance supprimée (npm unpublish)**
```
Incident réel: NPM pac left-pad dépublishe son package (2016)
v
Tous les projets JS dépendant cassent IMMÉDIATEMENT
v
Des milliers d'apps en production cassent

Message build:
ERR! 404 Not Found - GET https://registry.npmjs.org/left-pad
ERR! 404 'left-pad' is not in the npm registry.

Problème: Votre app dépend d'une dépendance qui dépend de left-pad
-> Vous ne pouvez pas faire un build jusqu'à ce que left-pad soit rétabli

Temps d'arrêt: 11+ heures avant rétablissement
```

#### Impact psychologique
- Développeurs = démotivés ("pourquoi ça change à chaque fois?")
- Productivité = imprévisible
- Déploiement urgent = impossible

### [X] Problème 3 : Chaos des versions

#### Le problème du caret (^) et tilde (~)

**Chez ShopFast, chaque développeur a une version différente:**

```json
Dev A - package.json:
{
  "dependencies": {
    "react": "^18.2.0"
  }
}
// ^ = compatible with 18.x.x
// npm install peut télécharger 18.2.0, 18.2.5, 18.3.1, etc (dépend du moment)

Dev B - package.json:
{
  "dependencies": {
    "react": "^18.2.0"
  }
}
// Même ligne! Mais au même moment, npm central retourne 18.3.1

Production - package-lock.json:
{
  "react": "18.1.0"
}
// Lockfile créé il y a 3 mois avec version différente
```

**Résultat:**
- Dev A a React 18.3.1 localement -> code fonctionne
- Dev B a React 18.2.0 localement -> code fonctionne
- Production a React 18.1.0 -> code CASSE!

**Exemple réel: Hook API change**
```javascript
// React 18.1.0 (production)
useState() // return array [state, setter]

// React 18.3.1 (dev local)
useState() // retourne objet {state, setState} (hypothétiquement)

// Code développé:
const [user, setUser] = useState({name: "John"})
// Fonctionne sur 18.3.1
// CASSE sur 18.1.0
```

**Bugs observés:**
- "Fonctionne sur ma machine, pas en prod" (classique)
- Reproduction impossible par autres devs
- Heures perdues à debugger des problèmes de version
- Tests en staging passent (plus haute version)
- Déploiement production -> CRASH

#### Cascades de versions
```
Maven Central cas similaire:
Spring Boot 3.1.5 -> dépend de Spring 6.0.2
Dev A: Spring 6.0.3 -> incompatible avec Spring Security 6.0.1
Dev B: Spring 6.0.1 -> incompatible avec Spring Data 6.0.2

Chacun a compilation locale OK, mais CROSS-PROJECT = chaos
```

### [X] Problème 4 : Librairies internes mal gérées

#### Le copier-coller horror show

**Situation actuelle chez ShopFast:**

```
shopfast-commons v1.2 (librairie partagée) contient:
├── DateUtils.java (utilitaires dates)
├── StringUtils.java (utilitaires strings)
├── ValidationUtils.java (validations métier)
└── ShopfastException.java (exception custom)

Problème: Pas de vrai "publish", juste du copier-coller
```

**Comment c'est utilisé (le chaos):**

```
shopfast-backend/
├── src/commons/  
│   ├── DateUtils.java (copie de shopfast-commons v1.2)
│   └── ... (copie de 20 fichiers)

shopfast-frontend/
├── src/utils/
│   └── DateUtils.ts (réécrit en TypeScript)
│   └── ... (différent de la version Java!)

shopfast-mobile/
├── src/commons/
│   └── DateUtils.ts (copie de frontend, mais modifiée!)
```

**Cascade de changements:**
```
Jour 1: Bug trouvé dans DateUtils.java
├── Fix dans shopfast-commons v1.2
├── Dev A met à jour backend -> recopie les fichiers (version ?)
├── Dev B met à jour frontend -> oublie de mettre à jour
├── Mobile Dev -> n'en sait rien

Résultat:
├── Backend v1.2 (fixé)
├── Frontend v1.0 (ancien, bug intact)
├── Mobile v1.1 (random, probablement cassé)

Bugs: Impossible à tracer, Dépendances cassées, Déploiement chaotique
```

**Problème de maintenance:**

```
Modification simple: ajouter paramètre à ValidationUtils
┌─ Modifier shopfast-commons/ValidationUtils.java
├─ Recompiler shopfast-commons
├─ Recopier dans shopfast-backend
├─ Recopier dans shopfast-frontend (TypeScript!)
├─ Recopier dans shopfast-mobile
└─ Tester dans 4 projets en parallèle

Une simple modif = 4 PRs, 4 reviews, 4 tests, 4 déploiements
Temps: 2-3 jours pour une modification!
```

**À l'échelle:**
- 15 fonctions utilitaires
- Modifiées en moyenne 2 fois/mois chacune
- 3 projets affectés
- = **90 synchronisations manuelles/mois** [!]
- = **180 heures/mois** de travail "busy work"

### [X] Problème 5 : Aucun contrôle de sécurité

#### Vulnerabilités qui passent inaperçues

**Exemple réel: CVE dans commons-lang3**

```
Timeline réelle (2023):
├── 07-01: CVE-2023-12345 découvert dans commons-lang3:3.12.0
│   Problème: Injection de code via StringUtils.evaluateExpression()
│   Severité: CRITICAL
│
├── ShopFast utilise commons-lang3:3.12.0 dans 8 projets
│   (indirect, via Spring, via other libs)
│
├── ShopFast ne le sait PAS
│   Pas de scanning automatique
│   Pas d'alerte
│
├── 07-15: Attaquant découvre ShopFast
│   Scanne repos GitHub public (oups, c'est vrai!)
│   Identifie commons-lang3:3.12.0 dans pom.xml
│   Envoie exploit payload
│
├── 07-16: Hacker access production database
│   Vole 100k de données client
│
└── 07-20: ShopFast découvre le breach
   (2 semaines après CVE publique!)
```

**Coût du breach:**
```
- GDPR fine: €20,000 base
- Client notification: €50,000
- Forensics + incident response: €80,000
- Reputation damage: €500,000+ (client churn)
- Total: €650,000+ de dommage
```

**Pourquoi c'est arrivé:**
- Pas de inventory des dépendances
- Pas de scanning automatique
- Pas de alertes sur CVEs
- Mise à jour = processus manuel (lent)
- Compliance impossible

#### Audit trail invisible

```
Actuel (sans Nexus):
- Dépendances téléchargées depuis Internet (direct)
- Pas de log où elles viennent
- Pas de trace qui a téléchargé quoi
- Pas de checksum verification
- Compliance audit: IMPOSSIBLE

Question: "Est-ce que vous avez openssl 1.0.2 quelque part?"
Réponse: "Aucune idée, il faudrait checker 50 projets manuellement..."
```

### [X] Problème 6 : Onboarding terrible

#### Le jour 1 du nouveau développeur

```
09:00 - "Bienvenue à ShopFast!"
         "Voici ton laptop, clone le repo backend"

09:05 - Nouveau dev: git clone https://github.com/shopfast/backend
        v 2 min (ok, pas mal)

09:07 - Nouveau dev: mvn clean compile
        Maven télécharge... 
        [HOURGLASS_WITH_FLOWING_SAND] 1 min: downloading dependencies
        [HOURGLASS_WITH_FLOWING_SAND] 2 min: still downloading...
        [HOURGLASS_WITH_FLOWING_SAND] 3 min: ...
        [HOURGLASS_WITH_FLOWING_SAND] 5 min: ...
        [HOURGLASS_WITH_FLOWING_SAND] 8 min: BUILD SUCCESS!

09:15 - Wow 8 minutes juste pour compiler?

09:16 - Nouveau dev: npm ci (pour le frontend)
        npm télécharge...
        [HOURGLASS_WITH_FLOWING_SAND] 5 min later...
        
09:21 - Nouveau dev: docker pull node:18
        Docker télécharge...
        [HOURGLASS_WITH_FLOWING_SAND] 2 min...

09:23 - Nouveau dev: "C'est toujours comme ça?"
         Dev senior: "Oui, c'est normal, notre bande passante est lente"
         
         Nouveau dev (internally): "[REFLEXION] Peut-être que ShopFast n'est pas...
                                   un bon endroit pour travailler"

         Le contexte: Startup=agile, efficacité = priorité
                      First impression = "désorganisé"

09:45 - Premier problème: npm timeout
        Nouveau dev relance (attente 5 min de plus)
        Nouveau dev thinks: "C'est instable aussi?"

09:50 - Nouveau dev has pas même commencé à coder
         Déjà 45 minutes perdues
         Motivation: [BAISSE][BAISSE][BAISSE]
```

**Statistique réelle:**

```
Industrie: Onboarding dev devrait prendre 2-4 heures
ShopFast actuel: 15 minutes JUSTE sur les builds
         = 37% du temps d'onboarding AVANT même de toucher du code

Churn rate: Startups avec onboarding lent = 30% churn rate first month
ShopFast: Probablement 15-20% turnover unnecessary
```

#### L'expérience vs la réalité

```
Marketing: "ShopFast est une startup tech moderne!"
Reality: 15 min attendant des builds

Marketing: "On valorise la productivité!"
Reality: 462 heures/mois gaspillées dans les builds

Marketing: "Sécurité est notre priorité!"
Reality: 0 scanning automatique des vulnérabilités

Le message: Contradiction = mauvais leadership perception
```

---

## [OK] SOLUTION : ARCHITECTURE NEXUS

### Qu'est-ce que Nexus? (Explications simples)

**Nexus = Supermarché d'artefacts logiciels**

```
Sans Nexus:
Dev -> "J'ai besoin de React 18.2.0"
   v
   Requête directe à npmjs.org (à Boston)
   v
   Téléchargement 50 MB (lent!)
   v
   Plus tard: différente version téléchargée (chaos!)

Avec Nexus:
Dev -> "J'ai besoin de React 18.2.0"
   v
   Demande à Nexus LOCAL (même serveur!)
   v
   Nexus: "Oui j'ai (cache local)" OU "Je te le cherche"
   v
   Réponse instantanée (< 1 seconde au lieu de 5 minutes)
   v
   Toujours la même version (cache)
```

**Nexus a 3 rôles:**

```
1⃣ PROXY (cache)
   Nexus <-> npmjs.org / Maven Central / Docker Hub
   Rôle: Télécharge une fois, cache pour toujours
   Bénéfice: Vitesse + fiabilité + offline

2⃣ REPOSITORY PRIVÉ (hébergement)
   Chez vous: shopfast-commons, shopfast-ui-components
   Rôle: Publiez vos propres artefacts
   Bénéfice: Contrôle, sécurité, versioning

3⃣ GROUPE (orchestration)
   Nexus groupe = maven-public = 3 repos en 1
   Rôle: Point d'entrée unique pour vos builds
   Bénéfice: Simplifie config, maintient flexible
```

### Jour-1 : Installation & Configuration

**Infrastructure requise:**
- 8 vCPU, 16 Go RAM, 500 Go SSD
- Ubuntu 22.04 LTS + Docker
- HTTPS avec Let's Encrypt
- Disque séparé pour blobstore

#### Pourquoi un disque séparé pour blobstore?

**Blobstore = là où sont stockés TOUS les artefacts**

```
Structure disque:
/nexus-data/
├── db/              (métadonnées, index)
└── blobs/           <- ICI = tous les JAR, packages npm, images Docker!
    ├── default/
    │   ├── maven-central/
    │   │   ├── commons-lang-3.13.0.jar (3.5 MB)
    │   │   ├── spring-boot-3.1.5.jar (10 MB)
    │   │   └── ... (250 packages × 5-20 MB)
    │   ├── npm-registry/
    │   │   ├── react/18.2.0/ (3 MB)
    │   │   ├── typescript/5.2.2/ (2 MB)
    │   │   └── ... (1200 packages × 1-100 MB)
    │   └── docker/
    │       ├── openjdk:11-jre-slim (200 MB)
    │       ├── node:18-alpine (150 MB)
    │       └── ... (50 images × 100-500 MB)

Total: 100-500 GB potentiel
```

**Pourquoi disque séparé?**

```
Scenario 1: Blobstore sur même disque que OS
├── /dev/sda: 500 GB total
├── OS + applications: 50 GB
├── Blobstore: 450 GB
└── Problem: Disque PLEIN -> Nexus crash -> TOUT cassé!

Scenario 2: Blobstore sur disque séparé (CORRECT)
├── /dev/sda: OS + Nexus app (100 GB)
├── /dev/sdb: Blobstore uniquement (2 TB) <- SSD rapide!
└── Benefit: Gérer stockage indépendant, upgrade facile

Performance:
├── Disque lent: npm ci = 30 sec (au lieu de 20s)
├── SSD rapide: npm ci = 20 sec (optimal)
└── Différence importante à l'échelle (50 builds × 10s = 8 min/jour)
```

**Étapes d'installation:**

1. Déployer Nexus (docker-compose)
2. Configurer TLS via reverse-proxy
3. Intégrer LDAP d'entreprise
4. Créer repos & policies
5. Backup initial

#### Étape détaillée 1: Créer les repositories

**Pourquoi 3 repos Maven au lieu d'un?**

```
[X] MAUVAIS: Un seul repo "everything"
maven-everything/
├── Contient: spring-boot, commons-lang, shopfast-commons, etc
├── Problème: Impossible de distinguer "externe vs interne"
├── Problème: Impossible de restreindre "qui peut publier quoi"
└── Problème: Impossible d'appliquer policies différentes

[OK] BON: Trois repos spécialisés

maven-central (PROXY):
├── Url: https://repo1.maven.org/maven2
├── Rôle: Cache Maven Central Repository
├── Qui publie: PERSONNE (read-only)
├── Retention: Garder indéfiniment
└── Policy: Delete only if corrupted

maven-releases (HOSTED):
├── Rôle: Librairies internes STABLES
├── Exemple: shopfast-commons:1.5.3
├── Qui publie: DevOps/Tech Leads uniquement
├── Version policy: Release (pas de -SNAPSHOT)
├── Redeploy: DISABLE (une fois publié = immuable!)
└── Retention: Garder indéfiniment (audit trail)

maven-snapshots (HOSTED):
├── Rôle: Versions en DÉVELOPPEMENT
├── Exemple: shopfast-commons:1.5.3-SNAPSHOT
├── Qui publie: Tous les devs
├── Version policy: Snapshot
├── Redeploy: ALLOW (on peut remplacer version développement)
└── Retention: Delete if > 30 days old (auto-cleanup)

maven-public (GROUP):
├── Aggrégates: [maven-releases, maven-snapshots, maven-central]
├── Order: IMPORTANT!
│   1. maven-releases     (on check ici d'abord)
│   2. maven-snapshots    (puis ici)
│   3. maven-central      (puis Maven Central)
├── Bénéfice: DevOps config une fois, tout le monde utilise cette URL
└── Magic: "dependance trouvée? Retourne d'où elle vient"
```

**Configuration visuelle du groupe:**

```
maven-public (group)
│
├─ Priorité 1: maven-releases (releases stables ShopFast)
│  └─ com.shopfast:shopfast-commons:1.5.3 [OK]
│
├─ Priorité 2: maven-snapshots (versions dev ShopFast)
│  └─ com.shopfast:shopfast-commons:1.5.4-SNAPSHOT [OK]
│
└─ Priorité 3: maven-central (repos Maven public)
   └─ org.springframework:spring-boot:3.1.5 [OK]
   └─ com.fasterxml.jackson:jackson-databind:2.15.2 [OK]

Quand Maven cherche "dependance X":
1. Check maven-releases
2. Si pas trouvé, check maven-snapshots
3. Si pas trouvé, check maven-central
4. Si pas trouvé, ERREUR (dépendance inexistante)
```

#### Étape détaillée 2: Comprendre le proxy

**Proxy = cache intelligent**

```
REQUÊTE 1 - Dev A: "Donne-moi spring-boot-starter-web:3.1.5.jar"
  ├─ Nexus check: "C'est dans mon cache?"
  ├─ Réponse: NON (première fois)
  ├─ Nexus contacte Maven Central: "T'as ce fichier?"
  ├─ Maven Central: "Oui" + envoie 5 MB
  ├─ Nexus: Stocke en cache local (/blobs/maven-central/...)
  └─ Nexus renvoie à Dev A en 1 sec (ultra rapide)

REQUÊTE 2 - Dev B: "Donne-moi spring-boot-starter-web:3.1.5.jar"
  ├─ Nexus check: "C'est dans mon cache?"
  ├─ Réponse: OUI! (même fichier qu'avant)
  ├─ Nexus: Renvoie directement depuis /blobs/
  └─ Temps: < 0.5 sec (réseau local!)

REQUÊTE 3 - CI/CD pipeline 50: "Donne-moi spring-boot-starter-web:3.1.5.jar"
  ├─ Nexus check: Cache? OUI!
  ├─ Nexus: Renvoie directement
  └─ Temps: < 0.5 sec (cache déjà chaud)

RÉSULTAT:
├─ Requête 1: 5 secondes (Nexus télécharge de Maven Central)
├─ Requête 2: 0.5 secondes (cache local)
├─ Requête 3: 0.5 secondes (cache local)
├─ Requête 4-50: 0.5 secondes (cache local)
│
└─ Total 50 requêtes: ~30 secondes
   (au lieu de 50 × 5 sec = 250 secondes!)
```

**Avantage du cache:**

```
Scénario réel:
50 builds/jour × 250 dépendances = 12,500 téléchargements/jour

SANS Nexus:
12,500 × 0.5 sec = 6,250 secondes = 1.7 heures téléchargement par jour
Bande passante: 12,500 × 10 MB = 125 GB/jour (!!)

AVEC Nexus:
12,500 × 0.05 sec = 625 secondes = 10 minutes par jour
Bande passante: 250 × 10 MB = 2.5 GB/jour (cache chaud après jour 1)

Économie: 96% bande passante, 90% temps!
```

#### Étape détaillée 3: Workflow des versions SNAPSHOT vs RELEASE

**Le défi du développement continu**

```
Scénario: shopfast-commons est une dépendance critique
          5 projets la dépendent
          Besoin de: tester en cours dev AVANT release

Solution: DEUX types de versions
```

**SNAPSHOT = Brouillon (Work In Progress)**

```
Version: 1.5.3-SNAPSHOT

Caractéristiques:
├─ Suffixe "-SNAPSHOT" = "ceci n'est pas final"
├─ Peut être remplacée (overwrite allowed)
├─ Timestamp: 1.5.3-SNAPSHOT-20240115.142530
├─ Stockée: maven-snapshots repo
└─ Durée de vie: 30 jours (auto-delete par policy)

Workflow SNAPSHOT:
Jour 1, 10:00 - Dev travaille sur nouvelle feature
├─ Modifie DateUtils.java
├─ mvn versions:set -DnewVersion=1.5.3-SNAPSHOT
├─ mvn clean test (compile + teste)
├─ mvn deploy
│  └─ Uploadé dans maven-snapshots/
│     1.5.3-SNAPSHOT-20240115.100000.jar

Jour 1, 14:00 - Autre dev a besoin des changements
├─ Met à jour pom.xml:
│  <version>1.5.3-SNAPSHOT</version>
├─ mvn clean compile
│  └─ Télécharge 1.5.3-SNAPSHOT-20240115.100000.jar [OK]
├─ Code test, compile OK [OK]

Jour 1, 15:00 - Premier dev re-modifie DateUtils
├─ Même chose: mvn deploy
│  └─ Uploadé 1.5.3-SNAPSHOT-20240115.150000.jar (NEW version!)
│
Jour 1, 15:05 - Autre dev relance build
├─ Maven check: "1.5.3-SNAPSHOT outdated?"
├─ Oui! Version plus récente disponible
├─ Télécharge nouvelle version 1.5.3-SNAPSHOT-20240115.150000.jar

Avantage: Collaboration fluide, itération rapide
Inconvénient: Version change constamment (instabilité)
```

**RELEASE = Version finale (Production)**

```
Version: 1.5.3 (PAS de -SNAPSHOT)

Caractéristiques:
├─ Pas de suffixe = "ceci est FINAL et immutable"
├─ Redeploy: DISABLED (impossible de remplacer!)
├─ Stockée: maven-releases repo
└─ Durée de vie: FOREVER (audit trail légal)

Workflow RELEASE:
Jour 3 - Feature terminée, testée, revue
├─ Dev merge PR
├─ mvn versions:set -DnewVersion=1.5.3
│  └─ Enlève le -SNAPSHOT
├─ mvn clean test -Denv=staging
│  └─ Tests complets en environment similaire production
├─ mvn deploy
│  └─ Uploadé dans maven-releases/
│     1.5.3.jar (VERSION FINAL!)

Jour 4 - Tous les projets peuvent l'utiliser
├─ Backend pom.xml:
│  <dependency>
│    <groupId>com.shopfast</groupId>
│    <artifactId>shopfast-commons</artifactId>
│    <version>1.5.3</version>  <- Fixed version!
│  </dependency>
├─ Frontend pom.xml (même)
├─ Mobile pom.xml (même)
│
└─ Garanties:
   [OK] Même version partout
   [OK] Impossible de modifier (immutable)
   [OK] Reproductible à 100% (même en 1 an!)
   [OK] Audit trail: qui a publié, quand, comment

Jour 365 - Compliance audit
├─ Question: "Quelle version du commons-commons utilisait-on?"
├─ Réponse (depuis Nexus): "Vous aviez 1.5.3 de 2024-01-03"
├─ Proof: Nexus repo + metadata + build logs
└─ Compliance: [OK] Passé!
```

**Décision: Quand passer SNAPSHOT -> RELEASE?**

```
SNAPSHOT = Toujours:
├─ Durant développement
├─ Feature branches
├─ Tests internes uniquement

RELEASE = Quand:
├─ Feature terminée et testée
├─ Code review approved
├─ Tests réussis en staging complet
├─ Prêt pour autres projets/production
└─ "Never touch this code again"
```

---

---

## [CONSTRUCTION] ARCHITECTURE COMPLÈTE DES REPOSITORIES

### Pourquoi pas UN seul repo géant?

**Tentations naturelles:**
```
"Créons un mega repo que tout le monde partage!"

nexus-giant/
├─ react/18.2.0/
├─ spring-boot/3.1.5/
├─ shopfast-commons/1.5.3/
├─ docker images/
├─ python packages/
└─ CHAOS -> impossible à gérer!

Problèmes:
├─ Impossible distinguer "externe vs interne"
├─ Impossible restreindre permissions ("qui peut publier?")
├─ Impossible appliquer policies différentes
├─ Backup = tout ou rien
├─ Une repo down = TOUS les builds cassent!
```

### [PACKAGE] MAVEN (Backend Java) - Architecture en détail

#### Repository Types expliqués

**1. maven-central (TYPE: PROXY)**

```
┌─────────────────────────────────────────┐
│         Maven Central Repository        │
│        (repo1.maven.org)                │
│  - 2+ millions de dépendances publiques │
│  - Maintenu par Sonatype               │
│  - Mirror worldwide                     │
└─────────────────────┬───────────────────┘
                      │ (réseau Internet)
                      v
┌──────────────────────────────────────────┐
│  Nexus Proxy: maven-central              │
│  ├─ Télécharge une fois depuis Maven     │
│  ├─ Cache localement (/blobs/maven-...)  │
│  └─ Servit à tous les builds après ça   │
└──────────────────────┬───────────────────┘
                      │ (réseau local!)
        ┌─────────────┼─────────────┐
        v             v             v
    Build A      Build B      Build C
    (35s)        (35s)        (35s)
    
Sans proxy:
    Build A (5min) -> Build B (5min) -> Build C (5min) = 15 min
    
Avec proxy:
    Build A (5min cache) -> Build B (35s) -> Build C (35s) = 6min
```

**Exemple réel: Spring Boot dépendance**

```
Première fois:
Dev A: mvn clean compile
└─ Maven demande: "T'as org.springframework.boot:spring-boot-starter-web:3.1.5?"
   └─ Nexus: "Non, je vais chercher"
      └─ Contact Maven Central (Boston, USA)
         ├─ Latency: 100-500ms
         ├─ Download: 3.2 MB
         ├─ Stocke dans /blobs/maven-central/spring-boot/...
         └─ Renvoie à Dev A en 5 min

Deuxième fois (même jour):
Dev B: mvn clean compile
└─ Maven demande: "T'as org.springframework.boot:spring-boot-starter-web:3.1.5?"
   └─ Nexus: "Oui! C'est dans mon cache!"
      └─ Renvoie directement depuis /blobs/
         ├─ Latency: < 1ms (réseau local!)
         ├─ Même fichier: Oui (checksum verify)
         └─ Dev B reçoit en 35 secondes (80% plus rapide!)
```

**2. maven-releases (TYPE: HOSTED)**

```
Hosted = "Nous avons nos propres artefacts dedans"

Purpose: Librairies internes STABLES

Exemple: shopfast-commons:1.5.3

┌─────────────────────────┐
│ shopfast-commons v1.5.3 │ <- RELEASE (immutable!)
│ ├─ DateUtils.java      │
│ ├─ StringUtils.java    │
│ └─ ... (compiled JAR)  │
└──────────┬──────────────┘
           │
    ┌──────┴───────┐
    │ RELEASED = IMMUTABLE
    │ (redeploy DISABLED!)
    │
    │ Signification:
    │ ├─ Une fois uploadé = personne ne peut changer
    │ ├─ Pas d'accidents (oups je reversi!)
    │ ├─ Audit trail = parfait
    │ └─ Compliance = [OK]

Stockage:
/nexus-data/blobs/default/maven-releases/
├─ com/shopfast/commons/1.5.3/
│  ├─ shopfast-commons-1.5.3.jar (42 KB)
│  ├─ shopfast-commons-1.5.3.pom (2 KB)
│  └─ shopfast-commons-1.5.3-sources.jar (20 KB)
└─ (immuable après publication)

Politique de rétention:
├─ Jamais auto-delete
├─ Garder pour historique/audit
└─ Disk: manageable (releases < snapshots)
```

**3. maven-snapshots (TYPE: HOSTED)**

```
Hosted = "Nous avons nos propres artefacts dedans"

Purpose: Librairies internes EN DÉVELOPPEMENT

Exemple: shopfast-commons:1.5.3-SNAPSHOT

Caractéristiques:
├─ Suffixe "-SNAPSHOT" = Work In Progress
├─ CAN être remplacée (redeploy ALLOWED)
├─ Version timestamped: 1.5.3-SNAPSHOT-20240115.142530-1
├─ Auto-cleanup: > 30 jours = DELETE
└─ Stockage temporaire

Workflow détaillé:

Jour 1, 10:00 - Dev 1 travaille
  ├─ Modifie DateUtils.java
  ├─ Commit + mvn deploy
  └─ Nexus uploadé:
     /nexus-data/blobs/.../maven-snapshots/com/shopfast/commons/1.5.3-SNAPSHOT/
     ├─ shopfast-commons-1.5.3-SNAPSHOT-20240115.100000-1.jar
     └─ metadata/
        └─ maven-metadata.xml (pointe à version la plus récente)

Jour 1, 10:15 - Dev 2 utilise la version:
  ├─ pom.xml: <version>1.5.3-SNAPSHOT</version>
  ├─ mvn clean compile
  ├─ Maven check Nexus: "Quoi de neuf?"
  ├─ Nexus: "Oui! 1.5.3-SNAPSHOT-20240115.100000-1"
  └─ Télécharge et utilise

Jour 1, 14:00 - Dev 1 re-déploie (bug fix):
  ├─ Modifie DateUtils.java (encore!)
  ├─ mvn deploy
  └─ Nexus uploadé:
     /nexus-data/blobs/.../maven-snapshots/com/shopfast/commons/1.5.3-SNAPSHOT/
     ├─ shopfast-commons-1.5.3-SNAPSHOT-20240115.140000-2.jar (VERSION DIFFÉRENTE!)
     ├─ shopfast-commons-1.5.3-SNAPSHOT-20240115.100000-1.jar (ancienne)
     └─ metadata/
        └─ maven-metadata.xml (update pointant à version 2)

Jour 1, 14:15 - Dev 2 relance build:
  ├─ mvn clean compile
  ├─ Maven check Nexus: "Version plus récente?"
  ├─ Nexus: "OUI! Version -2 existe!"
  ├─ Force téléchargement nouvelle version
  └─ Utilise latest snapshot

Cleanup policy (après 30 jours):
├─ Nexus check: "Ce snapshot n'a pas été téléchargé depuis 30 jours?"
├─ Oui -> SUPPRIME
└─ Raison: C'est du brouillon, pas utile garder longtemps
```

**4. maven-public (TYPE: GROUP)**

```
Group = "Agrégateur virtual de plusieurs repos"

Configuration:
maven-public (group) = [
  1. maven-releases (priorité haute)
  2. maven-snapshots (priorité moyenne)
  3. maven-central (priorité basse)
]

Logique recherche:
Quand Maven cherche: org.springframework.boot:spring-boot:3.1.5

┌─ Check maven-releases
│  ├─ "C'est une release interne ShopFast?"
│  └─ Non -> Continue
│
├─ Check maven-snapshots
│  ├─ "C'est une version dev ShopFast?"
│  └─ Non -> Continue
│
└─ Check maven-central
   ├─ "C'est une lib publique?"
   └─ OUI! Spring framework trouvé! -> Retour

Avantage: Un SEUL URL utilisé partout
  pom.xml:
  <url>https://nexus.shopfast.com/repository/maven-public/</url>

  -> Nexus cache l'implémentation (repos multiples)
  -> Devs n'ont pas besoin connaître la structure

Flexibilité: Modifier ordre/repos = transparent pour tous!
  Admin change order? Mais l'URL reste identique
  -> Aucun dev pom.xml à modifier [OK]
```

### [PACKAGE] NPM (Frontend/Mobile) - Architecture similaire

```
npm-registry (PROXY)
├─ Proxies: https://registry.npmjs.org
├─ Cache: react, typescript, lodash, etc
└─ 1200+ packages × 1-100 MB

npm-private (HOSTED)
├─ Nos packages: @shopfast/ui-components
├─ Scoped sous @shopfast
└─ 50+ packages internes

npm-group (GROUP)
├─ Aggregates: [npm-private, npm-registry]
├─ Order: Local first (@shopfast), puis npm.org
└─ Single URL: tous les projects utilisent npm-group
```

**Exemple npm workflow:**

```
package.json:
{
  "dependencies": {
    "react": "^18.2.0",              <- Cherche dans npm-registry (proxy)
    "@shopfast/ui-components": "^2.4.0"  <- Cherche dans npm-private
  }
}

npm ci:
├─ npm demande: "react@^18.2.0?"
│  ├─ Check npm-private: Non
│  ├─ Check npm-registry: OUI (cached depuis avant)
│  └─ Utilise version cache
│
├─ npm demande: "@shopfast/ui-components@^2.4.0?"
│  ├─ Check npm-private: OUI! (nos composants)
│  └─ Utilise version locale
│
└─ Total: ~1200 packages en 20 secondes (cache!)
```

### [DOCKER] DOCKER (Containers) - Architecture

```
docker-hosted (HOSTED)
├─ Images internes: shopfast-backend:2.3.1
├─ Exposed sur port 5000
└─ Login requis (credentials)

docker-proxy (PROXY)
├─ Proxies: https://registry-1.docker.io (Docker Hub)
├─ Cache: openjdk:11, node:18, nginx, etc
├─ Exposed sur port 5001
└─ Bande passante: énorme (images = 100-500 MB)

docker-group (GROUP)
├─ Aggregates: [docker-hosted, docker-proxy]
├─ Exposed sur port 5002
└─ Single endpoint: tous les pulls utilisent ce port

Workflow:
docker pull nexus.shopfast.com:5002/openjdk:11
├─ Docker demande à port 5002 (docker-group)
├─ Nexus check docker-hosted: Non trouvé
├─ Nexus check docker-proxy: OUI! (cached depuis Docker Hub)
└─ Retour image localement (< 1 sec!)
```

**Problème des images Docker (très lourd):**

```
Docker Hub direct:
openjdk:11-jre-slim = 200 MB
50 builds/jour × 200 MB = 10 GB bande passante

Avec Nexus proxy:
Build 1: 200 MB download (premier cache)
Build 2-50: Network local (< 1 sec)
Total bande passante: 200 MB (96% savings!)

Économie: 9.8 GB/jour = 294 GB/mois = €1000+/mois!
```

---

## [GRAPHIQUE] PROJET 1 : SHOPFAST-BACKEND (Spring Boot) - Explications détaillées

### Pourquoi ce fichier pom.xml exactement?

**pom.xml = "Recette" du projet Java**

```
Analogie: Recette de cuisine
├─ Ingrédients = dépendances
├─ Quantité = version
├─ Source = où acheter
└─ Instructions = comment compiler

Sans pom.xml:
"Faut 250 dépendances, bon courage à les trouver/compiler manuellement"

Avec pom.xml:
"Voici la recette, Maven se charge de tout"
```

#### Partie 1: Basic Info

```xml
<groupId>com.shopfast</groupId>
<artifactId>shopfast-backend</artifactId>
<version>2.3.1</version>
```

**Signification:**
- `groupId` = Identifiant "compagnie/namespace"
  - Comme un domain: com.shopfast.backend
  - Évite conflits: deux libs different companies peuvent avoir même "artifactId"
  
- `artifactId` = Nom unique du projet
  - Com.shopfast + shopfast-backend = unique identifier
  
- `version` = Version current du projet
  - 2.3.1 = Semantic Versioning (MAJOR.MINOR.PATCH)
  - MAJOR=2: Changements incompatibles
  - MINOR=3: Nouvelles features compatibles
  - PATCH=1: Bug fixes uniquement

**Identifiant complet:** `com.shopfast:shopfast-backend:2.3.1`

#### Partie 2: Repositories configuration (CRITIQUE!)

```xml
<repositories>
  <repository>
    <id>maven-public</id>
    <name>Nexus Maven Public</name>
    <url>https://nexus.shopfast.com/repository/maven-public/</url>
```

**Signification:**
```
Sans cette config:
  Maven utilise par défaut: Maven Central Only
  └─ Contacts repo1.maven.org directement
  └─ LENT + instable + pas de control

Avec cette config:
  Maven utilise: https://nexus.shopfast.com/repository/maven-public/
  └─ Contacts Nexus LOCAL
  └─ RAPIDE + fiable + control total

Details:
├─ <id>: Identifiant unique dans ce pom (référencé ailleurs)
├─ <name>: Nom lisible (juste pour affichage)
├─ <url>: Où Maven télécharge les dépendances
└─ <releases>/<snapshots>: Autorise ce type version
```

**Sans cette section: Problèmes!**

```
Dev installe ton projet:
mvn clean compile
ERROR: Could not find org.springframework.boot:spring-boot-starter-web:3.1.5

"Quoi?? C'est censé être un projet Spring Boot!"

Raison: Maven cherche qu'à Maven Central (default)
       Mais Nexus cache = pas remplacé Maven Central
       -> Dépendance trouvée mais trop lente/timeout

Solution: Ajouter <repositories> section
         -> Maven utilise Nexus au lieu de Maven Central
         -> Trouvé en cache! [OK]
```

#### Partie 3: Distribution Management (Publication)

```xml
<distributionManagement>
  <repository>
    <id>nexus-releases</id>
    <url>https://nexus.shopfast.com/repository/maven-releases/</url>
  </repository>
  <snapshotRepository>
    <id>nexus-snapshots</id>
    <url>https://nexus.shopfast.com/repository/maven-snapshots/</url>
  </snapshotRepository>
</distributionManagement>
```

**Signification: "Où publier ce project?"**

```
Sans cette section:
  mvn deploy
  ERROR: No distributionManagement element found
  
  Maven: "J'ai compris, je dois copier l'artefact quelque part"
  "Mais où?? Donne-moi une adresse!"

Avec cette section:
  mvn deploy
  ├─ Check version: 2.3.1 (pas -SNAPSHOT)
  ├─ Oui -> Publie dans maven-releases (URLs ci-dessus)
  └─ Si c'était 2.3.1-SNAPSHOT -> Publie dans maven-snapshots

Details:
├─ <id>: Référence (doit matcher <id> dans <repositories>)
├─ <url>: Adresse Nexus exacte pour uploads
└─ Maven utilise credentials ci-dessous pour authentifier
```

**Exemple réel:**

```
Dev local publie shopfast-backend:2.3.1
mvn deploy
├─ Check: 2.3.1 (pas SNAPSHOT)
├─ Oui -> Nexus URL = nexus-releases
├─ Maven authentifie avec credentials (username/password)
├─ Upload artefact vers:
│  https://nexus.shopfast.com/repository/maven-releases/
│  com/shopfast/shopfast-backend/2.3.1/shopfast-backend-2.3.1.jar
└─ Nexus: "Artefact reçu! Stored at /blobs/..."

Résultat:
├─ Tous les devs peuvent l'utiliser
├─ Fichier immutable (redeploy disabled)
└─ Audit trail: qui a publié quand
```

#### Partie 4: Dependencies

```xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
```

**Signification: "J'ai besoin de Spring Boot Web"**

```
Maven parse this:
├─ Find dans maven-public:
│  org.springframework.boot:spring-boot-starter-web
│  (sans version: use parent BOM version)
├─ Check cache Nexus: "Already have it?"
├─ Si non: Télécharge depuis maven-central proxy
├─ Si oui: Utilise cache
└─ Compile avec cette dépendance

Spring Boot Starter optimise:
├─ "spring-boot-starter-web" = bundle de libs
├─ Includes: Spring Core, Spring Web, Tomcat, JSON, etc
└─ Benefit: Une dépendance = 20 sub-dependencies automatiques!
```

**Dépendance interne ShopFast:**

```xml
<dependency>
  <groupId>com.shopfast</groupId>
  <artifactId>shopfast-commons</artifactId>
  <version>1.5.2</version>
</dependency>
```

**Différence:**
```
groupId=org.springframework
└─ Lib externe (Maven Central)
  └─ Trouvée via maven-central proxy

groupId=com.shopfast
└─ Lib interne (ShopFast)
  └─ Trouvée via maven-releases (hosted!)
  └─ Nous l'avons publiée
  └─ Immutable version 1.5.2
```

### Pipeline CI/CD expliqué (Docker + GitLab)

**Quand Dev pousse du code, que se passe t'il?**

```
Step 1: Dev local
├─ git commit -am "Fix payment bug"
├─ git push origin develop
└─ Notification -> GitLab

Step 2: GitLab reçoit push
├─ Check .gitlab-ci.yml (recette du pipeline)
├─ Démarre runner (machine pour exécuter jobs)
└─ Envoie: "BUILD!", "TEST!", "PACKAGE!", "DEPLOY!"
```

#### Job 1: BUILD

```yaml
build:
  stage: build
  image: nexus.shopfast.com:5002/maven:3.8-openjdk-11
  script:
    - mvn clean compile
```

**Ce qu'il se passe:**

```
1. GitLab Lance un runner (machine Linux vierge)

2. Pull image Docker:
   image: nexus.shopfast.com:5002/maven:3.8-openjdk-11
   └─ Cette image = contient Maven + OpenJDK installés
   └─ AU LIEU d'utiliser Maven Hub (lent)
   └─ Utilise Nexus cache (ultra rapide!)
   
   Docker pull process:
   ├─ Docker daemon demande: "T'as maven:3.8-openjdk-11?"
   ├─ Contacts nexus.shopfast.com:5002 (docker-group)
   ├─ Nexus check: "C'est dans mon cache?"
   ├─ Oui (cached depuis Dev A hier)
   └─ Retour image en 5 secondes! [OK]

3. Configure Maven cache:
   MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
   └─ Utilise cache local du runner
   └─ Entre jobs: cache persiste (GitLab feature)
   └─ Si dépendance déjà téléchargée -> skip!

4. Exécute: mvn clean compile
   ├─ "clean": Remove old build artifacts
   ├─ "compile": Java -> bytecode
   └─ Maven télécharge:
      ├─ org.springframework.boot:spring-boot-starter-web:3.1.5
      ├─ org.postgresql:postgresql:42.6.0
      ├─ com.shopfast:shopfast-commons:1.5.2
      └─ 250+ other deps
      
   Téléchargement:
   ├─ PREMIÈRE fois: tous téléchargés depuis Nexus (30 sec)
   ├─ Fois suivante: cache local runner (< 5 sec!)
   ├─ Total: 30 secondes pour compile
   └─ SANS Nexus: 8 minutes!

5. SUCCESS!
   └─ Fichiers compilés prêts (target/classes/)
```

#### Job 2: TEST

```yaml
test:
  stage: test
  script:
    - mvn test
```

**Ce qu'il se passe:**

```
1. Même runner continue (cache persiste!)
   
2. Exécute: mvn test
   ├─ Exécute tous les tests trouvés
   ├─ 1500+ tests unitaires
   ├─ Reutilise dépendances (cache already warm!)
   └─ Temps: 2 minutes

3. Génère rapport:
   target/surefire-reports/TEST-*.xml
   └─ Metrics: nombre tests, réussis, échoués
   └─ GitLab parse ce rapport
   └─ Affiche résultats jolis graphiques

4. Si test FAIL:
   ├─ Job marque FAILED
   ├─ Pipeline s'arrête
   ├─ Dev reçoit notification
   ├─ Dev fix le code localement
   ├─ Repush -> Pipeline relancé
   └─ Cycle rapide!
```

#### Job 3: PACKAGE (Build JAR)

```yaml
package:
  stage: package
  script:
    - mvn package -DskipTests
```

**Ce qu'il se passe:**

```
1. Exécute: mvn package -DskipTests
   ├─ -DskipTests: Skip tests (déjà exécutés, économise 2min)
   ├─ Compile + dépendances assemblé ensemble
   └─ Crée: target/shopfast-backend-2.3.1.jar
   
   Contenu du JAR:
   ├─ Votre code (classes compilés)
   ├─ Spring Boot libs
   ├─ PostgreSQL driver
   ├─ Tout compilé en UN fichier
   └─ Executable standalone!

2. Artefacts uploadés:
   target/*.jar
   └─ GitLab stocke pour download
   └─ Utilisé plus tard par docker build
```

#### Job 4: DOCKER BUILD & PUSH

```yaml
docker-build:
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login nexus.shopfast.com:5000 -u $NEXUS_USER -p $NEXUS_PASSWORD
    - docker build -t nexus.shopfast.com:5000/shopfast-backend:2.3.1 .
    - docker push nexus.shopfast.com:5000/shopfast-backend:2.3.1
```

**Ce qu'il se passe:**

```
1. Configure docker daemon (dind = Docker In Docker)
   ├─ Permet runner d'exécuter docker commands
   └─ Isolé = sûr

2. Login à Nexus:
   docker login nexus.shopfast.com:5000 -u $NEXUS_USER -p $NEXUS_PASSWORD
   ├─ Credentials from GitLab CI variables (secret!)
   ├─ Auth vers docker-hosted port 5000
   └─ Authorized pour push

3. Build image Docker:
   docker build -t nexus.shopfast.com:5000/shopfast-backend:2.3.1 .
   ├─ Exécute Dockerfile
   ├─ Utilise JAR compilé (target/...)
   ├─ Base image: FROM nexus.shopfast.com:5002/openjdk:11-jre-slim
   │  └─ Cette image = aussi depuis Nexus cache!
   │  └─ Déjà téléchargée par runner Build job
   │  └─ < 1 sec pull!
   ├─ Créé nouvelle image Docker
   └─ Tag: nexus.shopfast.com:5000/shopfast-backend:2.3.1

4. Push vers Nexus:
   docker push nexus.shopfast.com:5000/shopfast-backend:2.3.1
   ├─ Envoie image vers docker-hosted (port 5000)
   ├─ Nexus stocke dans /blobs/docker/...
   └─ Prête pour Kubernetes à déployer!

Résultat:
├─ Image building: 1 minute
├─ Image dans Nexus: 2.3.1 version immutable
└─ Kubernetes peut la déployer rapidement
```

#### Job 5: DEPLOY

```yaml
deploy-staging:
  stage: deploy
  script:
    - kubectl set image deployment/shopfast-backend 
        shopfast-backend=nexus.shopfast.com:5000/shopfast-backend:2.3.1 
        -n staging
```

**Ce qu'il se passe:**

```
1. Kubernetes command exécutée
   ├─ "Update deployment shopfast-backend"
   ├─ "Nouvelle image: nexus.shopfast.com:5000/shopfast-backend:2.3.1"
   └─ Dans namespace "staging"

2. Kubernetes actions:
   ├─ Pull nouvelle image depuis Nexus
   │  └─ Récupère depuis docker-hosted (5000)
   │  └─ Ultra rapide (< 5 sec, déjà en cache!)
   ├─ Stop ancien container
   ├─ Start nouveau container (image 2.3.1)
   └─ Verify health: nouveaux containers répondent?

3. Result:
   ├─ Staging env = new version deployed
   ├─ Prêt pour QA tests
   └─ Si OK -> Peut deployer production
```

### Résultat: Pipeline entier

```
Pas de Nexus:
├─ BUILD (8 min):  Download 250 deps from Maven Central
├─ TEST (2 min):   Same runner, cache helps
├─ PACKAGE (3 min):  Create JAR
├─ DOCKER (5 min): Pull base image from Docker Hub (200 MB!)
└─ DEPLOY (2 min): Pull image from Docker Hub (slow!)
   TOTAL: 20 minutes

Avec Nexus:
├─ BUILD (30 sec):  Download 250 deps from Nexus cache
├─ TEST (2 min):    Same cache
├─ PACKAGE (3 min): Create JAR
├─ DOCKER (1 min):  Pull base image from Nexus (instant!)
└─ DEPLOY (5 sec):  Pull image from Nexus (instant!)
   TOTAL: 6 minutes (5× plus rapide!)

Par jour (50 builds):
SANS Nexus: 50 × 20 min = 1000 min = 16.7 heures!
AVEC Nexus: 50 × 6 min = 300 min = 5 heures!
Saved: 11.7 heures = €1460/jour! [RAPIDE]
```

### [PACKAGE] NPM (Frontend/Mobile)

| Nom | Type | Rôle | URL |
|-----|------|------|-----|
| `npm-registry` | Proxy | Cache npmjs.org | `registry.npmjs.org` |
| `npm-private` | Hosted | Composants React partagés (@shopfast/*) | - |
| `npm-group` | Group | **Point d'entrée unique** | `npm-group` |

**Configuration .npmrc:**
```
registry=https://nexus.shopfast.com/repository/npm-group/
@shopfast:registry=https://nexus.shopfast.com/repository/npm-private/
//nexus.shopfast.com/repository/npm-group/:_authToken=${NPM_AUTH}
always-auth=true
```

### [DOCKER] DOCKER (Conteneurs)

| Nom | Type | Rôle | Port |
|-----|------|------|------|
| `docker-hosted` | Hosted | Images ShopFast | 5000 |
| `docker-proxy` | Proxy | Cache Docker Hub | 5001 |
| `docker-group` | Group | **Point d'entrée unique** | 5002 |

**Daemon config (`/etc/docker/daemon.json`):**
```json
{
  "insecure-registries": ["nexus.shopfast.com:5002"],
  "registry-mirrors": ["https://nexus.shopfast.com:5002"]
}
```

### [FICHIER] RAW (Scripts partagés)

| Nom | Type | Rôle |
|-----|------|------|
| `scripts-shared` | Hosted | Migration DB, scripts deploy, ansible |

---

## [SYNC] SCHÉMA ARCHITECTURE GLOBALE

```
                    ┌─────────────────────────┐
                    │  Développeurs & CI/CD   │
                    │  (15 devs + 50 builds)  │
                    └────────────┬────────────┘
                                 │
                  ┌──────────────┼──────────────┐
                  │              │              │
                  [BLACK_DOWN-POINTING_TRIANGLE]              [BLACK_DOWN-POINTING_TRIANGLE]              [BLACK_DOWN-POINTING_TRIANGLE]
        ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
        │ Maven Public │ │ NPM Group    │ │ Docker Group │
        │ (group)      │ │ (group)      │ │ (group)      │
        └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
               │                │                │
        ┌──────┴──────┐  ┌──────┴──────┐  ┌──────┴──────┐
        │      │      │  │      │      │  │      │      │
        [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]  [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]  [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]      [BLACK_DOWN-POINTING_TRIANGLE]
    Release Snapshot Central Private Registry Proxy Hosted
   (hosted) (hosted) (proxy) (hosted) (proxy) (proxy) (hosted)
        │      │      │      │        │      │      │
        └─┬────┘      │      │        │      │      │
          │           │      │        │      │      └─ shopfast images
          │      npm.js  shopfast   Docker Hub
       maven
     releases
```

---

## [GRAPHIQUE] PROJET 1 : SHOPFAST-BACKEND (Spring Boot)

### Structure & pom.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.shopfast</groupId>
    <artifactId>shopfast-backend</artifactId>
    <version>2.3.1</version>
    <packaging>jar</packaging>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
    </parent>
    
    <!-- [CLE] NEXUS: Point d'entrée unique Maven -->
    <repositories>
        <repository>
            <id>maven-public</id>
            <name>Nexus Maven Public</name>
            <url>https://nexus.shopfast.com/repository/maven-public/</url>
            <releases><enabled>true</enabled></releases>
            <snapshots><enabled>true</enabled></snapshots>
        </repository>
    </repositories>
    
    <pluginRepositories>
        <pluginRepository>
            <id>maven-public</id>
            <url>https://nexus.shopfast.com/repository/maven-public/</url>
        </pluginRepository>
    </pluginRepositories>
    
    <!-- [RAPIDE] NEXUS: Où publier nos artefacts -->
    <distributionManagement>
        <repository>
            <id>nexus-releases</id>
            <name>Nexus Releases</name>
            <url>https://nexus.shopfast.com/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>nexus-snapshots</id>
            <name>Nexus Snapshots</name>
            <url>https://nexus.shopfast.com/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>
    
    <dependencies>
        <!-- Spring Boot Web & Data -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        
        <!-- PostgreSQL -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.6.0</version>
        </dependency>
        
        <!-- Redis Cache -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
        <!-- [OBJECTIF] LIBRAIRIE INTERNE (hébergée dans Nexus maven-releases!) -->
        <dependency>
            <groupId>com.shopfast</groupId>
            <artifactId>shopfast-commons</artifactId>
            <version>1.5.2</version>
        </dependency>
        
        <!-- Tests -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
```

### Dockerfile

```dockerfile
# [DOCKER] Image de base depuis Nexus (cache Docker Hub)
FROM nexus.shopfast.com:5002/openjdk:11-jre-slim

WORKDIR /app

# Copier le JAR compilé
COPY target/shopfast-backend-2.3.1.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]
```

### Pipeline CI/CD (.gitlab-ci.yml)

```yaml
# Image Maven depuis Nexus (pas de téléchargement Docker Hub!)
image: nexus.shopfast.com:5002/maven:3.8-openjdk-11

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  NEXUS_USER: $CI_DEPLOY_USER
  NEXUS_PASSWORD: $CI_DEPLOY_PASSWORD

cache:
  paths:
    - .m2/repository/

stages:
  - build
  - test
  - package
  - docker
  - deploy

# [OK] Stage BUILD: Compile via Nexus
build:
  stage: build
  script:
    - mvn clean compile
    # Maven télécharge TOUTES les dépendances depuis Nexus maven-public
    # Temps: 30s (avant: 8 min!)
  artifacts:
    paths:
      - target/classes/
    expire_in: 1 hour

# [OK] Stage TEST: Tests unitaires & intégration
test:
  stage: test
  script:
    - mvn test
    # 1500+ tests unitaires
  artifacts:
    reports:
      junit: target/surefire-reports/TEST-*.xml
  coverage: '/\d+\.\d+%\s*$/'

# [OK] Stage PACKAGE: Build JAR
package:
  stage: package
  script:
    - mvn package -DskipTests
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 week

# [OK] Stage DOCKER: Build & Push image vers Nexus
docker-build:
  stage: docker
  image: docker:latest
  services:
    - docker:dind
  script:
    # Login à Nexus docker-hosted
    - docker login nexus.shopfast.com:5000 -u $NEXUS_USER -p $NEXUS_PASSWORD
    
    # Build image (utilise base image depuis Nexus)
    - docker build -t nexus.shopfast.com:5000/shopfast-backend:2.3.1 .
    - docker tag nexus.shopfast.com:5000/shopfast-backend:2.3.1 nexus.shopfast.com:5000/shopfast-backend:latest
    
    # Push vers Nexus (pas Docker Hub!)
    - docker push nexus.shopfast.com:5000/shopfast-backend:2.3.1
    - docker push nexus.shopfast.com:5000/shopfast-backend:latest

# [OK] Stage DEPLOY: Kubernetes
deploy-staging:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    # Kubernetes pull image depuis Nexus (5s au lieu de 2min depuis Docker Hub)
    - kubectl set image deployment/shopfast-backend 
        shopfast-backend=nexus.shopfast.com:5000/shopfast-backend:2.3.1 
        -n staging
    - kubectl rollout status deployment/shopfast-backend -n staging
  only:
    - develop

deploy-prod:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/shopfast-backend 
        shopfast-backend=nexus.shopfast.com:5000/shopfast-backend:2.3.1 
        -n production
    - kubectl rollout status deployment/shopfast-backend -n production
  only:
    - main
  when: manual
```

**Améliorations apportées:**
- Maven compile en 30s (au lieu de 8 min)
- Pipeline complet: 5 min (au lieu de 25 min)
- 100% fiable (pas de dépendance Internet)
- Versions reproductibles

---

## [PACKAGE] PROJET 2 : SHOPFAST-COMMONS (Librairie partagée)

### Structure

```
shopfast-commons/
├── pom.xml
├── src/main/java/com/shopfast/commons/
│   ├── utils/
│   │   ├── DateUtils.java
│   │   ├── StringUtils.java
│   │   └── ValidationUtils.java
│   ├── models/
│   │   ├── User.java
│   │   ├── Order.java
│   │   └── Product.java
│   └── exceptions/
│       └── ShopfastException.java
└── README.md
```

### pom.xml

```xml
<project>
    <groupId>com.shopfast</groupId>
    <artifactId>shopfast-commons</artifactId>
    <version>1.5.2</version>
    
    <repositories>
        <repository>
            <id>maven-public</id>
            <url>https://nexus.shopfast.com/repository/maven-public/</url>
        </repository>
    </repositories>
    
    <distributionManagement>
        <repository>
            <id>nexus-releases</id>
            <url>https://nexus.shopfast.com/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>nexus-snapshots</id>
            <url>https://nexus.shopfast.com/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.13.0</version>
        </dependency>
    </dependencies>
</project>
```

### Workflow de développement

```bash
# Phase 1: Développement (version SNAPSHOT)
mvn versions:set -DnewVersion=1.5.3-SNAPSHOT
mvn clean test
mvn deploy
# -> Uploadé dans nexus-snapshots
# -> Autres devs: <version>1.5.3-SNAPSHOT</version>

# Phase 2: Release (version stable)
mvn versions:set -DnewVersion=1.5.3
mvn clean test
mvn deploy
# -> Uploadé dans nexus-releases
# -> Utilisable partout en confiance

# Phase 3: Utilisation dans shopfast-backend
# Dans pom.xml:
# <version>1.5.3</version> (au lieu de SNAPSHOT)
```

**Avantages:**
- [OK] Source unique de vérité
- [OK] Pas de copier/coller
- [OK] Versioning propre
- [OK] Réutilisable partout
- [OK] Testable indépendamment

---

## [DESIGN] PROJET 3 : SHOPFAST-FRONTEND (React + npm)

### Structure & package.json

```json
{
  "name": "shopfast-frontend",
  "version": "3.1.0",
  "private": true,
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.16.0",
    "axios": "^1.5.1",
    "redux": "^4.2.1",
    "react-redux": "^8.1.3",
    "@reduxjs/toolkit": "^1.9.7",
    "@shopfast/ui-components": "^2.4.0"
  },
  "devDependencies": {
    "typescript": "^5.2.2",
    "vite": "^4.5.0",
    "eslint": "^8.52.0",
    "prettier": "^3.0.3"
  },
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "vitest",
    "lint": "eslint . --ext ts,tsx"
  }
}
```

### .npmrc (Configuration pour Nexus)

```
# [CLE] Registry par défaut: npm-group (tous les packages)
registry=https://nexus.shopfast.com/repository/npm-group/

# Scoped packages: npm-private pour @shopfast/*
@shopfast:registry=https://nexus.shopfast.com/repository/npm-private/

# Auth token (depuis CI/CD variables)
//nexus.shopfast.com/repository/npm-group/:_authToken=${NPM_AUTH}
//nexus.shopfast.com/repository/npm-private/:_authToken=${NPM_AUTH}

always-auth=true
```

### Dockerfile (Multi-stage)

```dockerfile
# Stage 1: Build
FROM nexus.shopfast.com:5002/node:18-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci
# [HOT] npm télécharge 1200+ packages depuis Nexus en 20s!

COPY . .
RUN npm run build
# Sortie: dist/

# Stage 2: Serve
FROM nexus.shopfast.com:5002/nginx:alpine

COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
```

### Pipeline CI/CD

```yaml
image: nexus.shopfast.com:5002/node:18

cache:
  paths:
    - node_modules/

stages:
  - install
  - lint
  - test
  - build
  - docker
  - deploy

# [ENTREE] Install: télécharge 1200+ packages depuis Nexus
install:
  stage: install
  script:
    - npm ci
    # Temps: 20s (avant: 5 min!)
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

# [RECHERCHE] Lint: analyse code
lint:
  stage: lint
  script:
    - npm run lint

# [OK] Test: tests unitaires
test:
  stage: test
  script:
    - npm run test -- --run
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'

# [CONSTRUCTION] Build: compile TypeScript -> JavaScript
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

# [DOCKER] Docker: Build & push image
docker-build:
  stage: docker
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login nexus.shopfast.com:5000 -u $NEXUS_USER -p $NEXUS_PASSWORD
    - docker build -t nexus.shopfast.com:5000/shopfast-frontend:3.1.0 .
    - docker push nexus.shopfast.com:5000/shopfast-frontend:3.1.0

# [RAPIDE] Deploy
deploy-staging:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/shopfast-frontend 
        shopfast-frontend=nexus.shopfast.com:5000/shopfast-frontend:3.1.0 
        -n staging
  only:
    - develop
```

**Gains:**
- npm install: 20s (au lieu de 5 min)
- Pipeline complet: 3 min (au lieu de 15 min)
- Zéro dépendance à npmjs.org
- @shopfast/* disponibles en private

---

## [MODULE] PROJET 4 : @SHOPFAST/UI-COMPONENTS (Composants React partagés)

### Structure & package.json

```
shopfast-ui-components/
├── package.json
├── .npmrc
├── src/
│   ├── index.ts
│   ├── Button/
│   │   ├── Button.tsx
│   │   └── Button.test.tsx
│   ├── Card/
│   ├── Modal/
│   ├── Input/
│   └── ProductCard/
└── dist/ (généré)
```

```json
{
  "name": "@shopfast/ui-components",
  "version": "2.4.0",
  "description": "Shared React components for ShopFast",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "test": "vitest",
    "storybook": "storybook dev -p 6006"
  },
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  },
  "publishConfig": {
    "registry": "https://nexus.shopfast.com/repository/npm-private/"
  }
}
```

### Workflow de publication

```bash
# 1. Développer un composant ProductCard
# src/ProductCard/ProductCard.tsx

# 2. Tester localement
npm test

# 3. Build TypeScript -> JavaScript
npm run build
# dist/ProductCard.js + dist/ProductCard.d.ts

# 4. Login à Nexus npm-private
npm login --registry=https://nexus.shopfast.com/repository/npm-private/
# Username: dev@shopfast.com
# Password: (token depuis .npmrc)

# 5. Publier
npm publish
# -> Uploadé dans nexus-shopfast.com:5000/npm-private/

# 6. Utilisation dans shopfast-frontend
npm install @shopfast/ui-components@^2.4.0

# 7. Dans le code
import { ProductCard, Button } from '@shopfast/ui-components';
```

---

## [MOBILE] PROJET 5 : SHOPFAST-MOBILE (React Native)

### Structure & package.json

```json
{
  "name": "shopfast-mobile",
  "version": "1.2.0",
  "dependencies": {
    "react": "^18.2.0",
    "react-native": "^0.72.0",
    "expo": "^49.0.0",
    "axios": "^1.5.1",
    "@shopfast/ui-components": "^2.4.0"
  }
}
```

### eas.json (Expo build config)

```json
{
  "build": {
    "preview": {
      "android": {
        "buildType": "apk"
      },
      "ios": {
        "buildType": "simulator"
      }
    },
    "production": {
      "extends": "base"
    }
  },
  "submit": {
    "production": {
      "android": {
        "serviceAccount": "google-play.json"
      },
      "ios": {
        "appleId": "build@shopfast.com"
      }
    }
  }
}
```

**Bénéfice Nexus:** Expo build pull dépendances npm depuis Nexus (ultra rapide!)

---

## [GRAPHIQUE] STATISTIQUES AVANT/APRÈS NEXUS

### [TEMPS] Temps de build (moyenne)

| Projet | Avant | Après | Amélioration |
|--------|-------|-------|--------------|
| shopfast-backend | 8m 30s | 35s | **95%** [RAPIDE] |
| shopfast-frontend | 5m 20s | 25s | **92%** [RAPIDE] |
| shopfast-mobile | 6m 10s | 28s | **92%** [RAPIDE] |
| shopfast-commons | 2m 40s | 20s | **87%** [RAPIDE] |

### [SYNC] Impact CI/CD (par jour)

```
Pipelines/jour:        50
Temps avant:           50 × 8 min = 400 min = 6h 40min
Temps après:           50 × 35s = 29 min
Gain quotidien:        6h 11min
Gain mensuel:          185 heures ≈ 23 jours de travail! [RAPIDE]

Coût évité par mois: 23 jours × 5 devs × 250€/jour = 28 750€
```

### [RESEAU] Bande passante Internet

```
Téléchargements/jour avant:  50 builds × 1 Go = 50 Go
Téléchargements/jour après:  ~2 Go (premier cache)
Économie:                    96% [BAISSE]

Coût bande passante: ~500€/mois épargné
```

### [OBJECTIF] Fiabilité

```
Incidents/mois (npmjs.org down):
AVANT: 100% builds frontend cassent
APRÈS: 0% (Nexus en cache local)

Uptime réel: 99.99% [OK]
```

### [RUNNER] Onboarding nouveau développeur

```
Avant:
  Clone repo:       2 min
  Build backend:    8 min
  Build frontend:   5 min
  Total:            15 min

Après:
  Clone repo:       2 min
  Build backend:    35s
  Build frontend:   25s
  Total:            3 min

Amélioration: 80% [RAPIDE]
Impact: nouveau dev productif immédiatement
```

---

## [DEMARRAGE] SCÉNARIOS RÉELS D'UTILISATION

### Scénario 1 : Bug critique en production (vendredi 16h)

```bash
# 16:00 - Bug découvert!
git checkout -b hotfix/payment-bug main

# 16:05 - Code fixé
# Modifie PaymentController.java

# 16:10 - Tests locaux
mvn clean test
# Dépendances depuis Nexus: 30s (au lieu de 8 min!)

# 16:11 - Pousse
git push origin hotfix/payment-bug

# 16:12 - Pipeline CI démarre (depuis GitLab)
# [build]    35s  (Maven cache Nexus)
# [test]     2min (1500 tests)
# [docker]   1min (image depuis Nexus)
# Total:     3m 35s

# 16:16 - Tests staging [OK]

# 16:20 - Deploy production
# Kubernetes pull image depuis Nexus (5s au lieu de 2min)

# 16:21 - Bug fixed! [BRAVO]
# Production revenue restored!
```

### Scénario 2 : npmjs.org indisponible (mardi 9h)

**AVANT Nexus:**
```
npmjs.org crash -> Frontend build échoue -> Tous les devs bloqués
-> 50 devs × 2 heures d'attente = 100 heures perdues
```

**APRÈS Nexus:**
```
npmjs.org crash -> npm-registry (cache) servit localement
-> Tous les builds frontend continuent normalement
-> Zéro impact productivité [OK]
```

### Scénario 3 : Déploiement multi-région simultané

```bash
# Production EU + Production US (simultané)
# 2 Kubernetes clusters pulling images

# AVANT Nexus:
# - EU: docker pull shopfast-backend:2.3.1 de Docker Hub (2 min)
# - US: docker pull shopfast-backend:2.3.1 de Docker Hub (2 min)
# - Total: 4 min (images en concurrence)

# APRÈS Nexus:
# - EU: docker pull shopfast-backend:2.3.1 de Nexus local (5s)
# - US: docker pull shopfast-backend:2.3.1 de Nexus via replique (5s)
# - Total: 10s (parallèle, cache local) [RAPIDE]
```

### Scénario 4 : Sécurité - Vulnérabilité découverte

```bash
# Lundi: CVE-2024-XXXX découvert dans commons-lang3:3.12.0

# AVANT Nexus:
# - Modifier pom.xml (3.13.0)
# - 50 projets à updater
# - Build échoue chez certains devs (téléchargement lent)
# - Déploiement chaotique

# APRÈS Nexus:
# 1. Update dans shopfast-commons:
mvn versions:set -DnewVersion=1.5.3
# (commons-lang3:3.13.0)
mvn deploy
# -> nexus-releases

# 2. Tous les projets dépendants reçoivent l'update:
mvn dependency:update-project
mvn clean test
# Dépendances depuis Nexus (30s au lieu de 8 min)

# 3. Deploy centralisé & rapide [RAPIDE]
# Toute l'organisation patchée en 30 min
```

---

## [VERROUILLE] SÉCURITÉ & CONFORMITÉ (Features Nexus)

### 1. Authentification centralisée (LDAP)

```bash
# Configuration Nexus (Admin UI)
Security -> Realms -> Activer "LDAP"

# LDAP config:
Hostname: ldap.shopfast.com
Port: 389
Search Base: ou=developers,dc=shopfast,dc=com
User Object Class: inetOrgPerson

# Résultat:
[OK] Tous les devs = credentials d'entreprise
[OK] Permissions sync automatiques
[OK] Revoke user = immédiat partout
[OK] Audit trail complet
```

### 2. Cleanup policies (retention & sécurité)

```
Policy: "snapshots-old-30d"
├── Condition: Age > 30 jours
├── Asset type: Maven Snapshots
└── Action: Delete

Policy: "npm-unused-90d"
├── Condition: Last downloaded > 90 jours
├── Asset type: npm packages
└── Action: Delete (après validation)

Policy: "docker-dangling"
├── Condition: Untagged images
├── Action: Delete after 7 days

[OK] Réduit surface d'attaque
[OK] Libère 30% stockage
[OK] Exécution: nightly
```

### 3. Scanning & audit des vulnérabilités

```bash
# Integration avec Nexus IQ (Pro) ou Snyk/Trivy (OSS)

# Exemple: Pipeline CI scan
stages:
  - build
  - scan
  - test

scan-dependencies:
  stage: scan
  image: snyk/snyk:latest
  script:
    # Scan dépendances Maven
    - snyk test --all-projects --severity-threshold=high
    # Scan image Docker
    - snyk container test nexus.shopfast.com:5000/shopfast-backend:2.3.1
  allow_failure: true
  # Flag vulnérabilités, continue build

# Résultat:
[OK] CVEs détectées -> alertes
[OK] Policies enforced (ex: no critical vulns)
[OK] Audit trail Nexus
```

### 4. Contrôle d'accès granulaire (RBAC)

```
Role: "developers"
├── Repository: maven-public (READ)
├── Repository: npm-group (READ)
├── Repository: docker-group (READ)
└── Actions: [read, browse]

Role: "devops"
├── Repository: maven-releases (READ, WRITE)
├── Repository: npm-private (READ, WRITE)
├── Repository: docker-hosted (READ, WRITE)
├── Repository: scripts-shared (READ, WRITE)
└── Actions: [read, write, browse, create, manage]

Role: "admin"
└── All repositories: ADMIN

[OK] Developers: ne peuvent que lire
[OK] DevOps: peuvent publier librairies
[OK] Admins: contrôle total
```

### 5. Token rotation & audit

```bash
# Configuration:
Security -> API Tokens
├── User tokens expiry: 90 days
├── Service tokens expiry: 1 year
└── Audit events: enabled

# Workflow:
1. Dev reçoit token CI
2. Token utilisé dans .npmrc/.m2/settings.xml
3. Après 90j: token expire
4. Dev gen nouveau token automatiquement
5. Logs Nexus: traçable qui a fait quoi

# Exemple audit:
2024-01-15 14:23:42 | USER: dev@shopfast.com | ACTION: publish 
  | ARTIFACT: @shopfast/ui-components:2.4.0 | STATUS: SUCCESS
```

---

## [OUTIL] OPÉRATIONS & MAINTENANCE

### Installation & Configuration (Jour 1)

```bash
# 1. Infrastructure
apt-get update && apt-get install -y docker.io docker-compose

# 2. Disque séparé pour blobstore
lsblk
# Identify /dev/sdb
fdisk /dev/sdb
mkfs.ext4 /dev/sdb1
mkdir -p /data/nexus-blobstore
mount /dev/sdb1 /data/nexus-blobstore
chmod 777 /data/nexus-blobstore

# 3. docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
  nexus:
    image: sonatype/nexus3:latest
    restart: unless-stopped
    ports:
      - "8081:8081"
    volumes:
      - nexus-data:/nexus-data
      - /data/nexus-blobstore:/nexus-data/blobs
    environment:
      - INSTALL4J_ADD_VM_PARAMS=-Xms2g -Xmx4g
      - NEXUS_CONTEXT_PATH=/nexus
    networks:
      - nexus-net

  # Reverse proxy (HTTPS)
  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - nexus
    networks:
      - nexus-net

volumes:
  nexus-data:
    driver: local

networks:
  nexus-net:
    driver: bridge
EOF

# 4. Start Nexus
docker-compose up -d

# 5. Wait for startup (check logs)
docker-compose logs -f nexus
# Wait for "Started Sonatype Nexus"

# 6. Initial password
NEXUS_PASSWORD=$(docker-compose exec -T nexus cat /nexus-data/admin.password)
echo "Admin password: $NEXUS_PASSWORD"
```

### Backup & Disaster Recovery

```bash
# Backup script (backup.sh)
#!/bin/bash
set -e

BACKUP_DIR="/backups/nexus-$(date +%Y%m%d-%H%M%S)"
mkdir -p $BACKUP_DIR

# 1. Stop Nexus
docker-compose stop nexus

# 2. Backup DB + metadata
tar -czf $BACKUP_DIR/nexus-data.tar.gz /data/nexus-blobstore

# 3. Backup PostgreSQL (si external)
# pg_dump -h localhost -U nexus_user nexus_db > $BACKUP_DIR/nexus_db.sql

# 4. Start Nexus
docker-compose start nexus

# 5. Replicate to S3 (ou NFS)
aws s3 sync $BACKUP_DIR s3://shopfast-backups/nexus/

# 6. Cleanup old backups (30 days retention)
find /backups -name "nexus-*" -mtime +30 -exec rm -rf {} \;

echo "[OK] Backup completed: $BACKUP_DIR"
```

```bash
# Schedule daily (crontab)
0 2 * * * /scripts/nexus-backup.sh >> /var/log/nexus-backup.log 2>&1
```

### Restoration (DR playbook)

```bash
# Step 1: Stop Nexus
docker-compose stop nexus

# Step 2: Clear existing data
rm -rf /data/nexus-blobstore/* /nexus-data/*

# Step 3: Restore backup
BACKUP_FILE="s3://shopfast-backups/nexus/nexus-20240115-020000/nexus-data.tar.gz"
aws s3 cp $BACKUP_FILE /tmp/nexus-data.tar.gz
tar -xzf /tmp/nexus-data.tar.gz -C /

# Step 4: Verify permissions
chown -R 200:200 /nexus-data
chmod -R 755 /nexus-data

# Step 5: Start Nexus
docker-compose start nexus

# Step 6: Validate
docker-compose logs -f nexus
# Verify repositories accessible
curl -u admin:$PASSWORD https://nexus.shopfast.com/repository/maven-public/
```

### Monitoring & Alerting

```yaml
# prometheus.yml (scrape Nexus metrics)
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'nexus'
    static_configs:
      - targets: ['nexus.shopfast.com:8081']
    metrics_path: '/nexus/service/metrics/prometheus'
    basic_auth:
      username: 'prometheus'
      password: '${NEXUS_PASSWORD}'

# Grafana Dashboard (alertes)
Alerts:
  - name: DiskUsage > 70%
    query: node_filesystem_avail_bytes{mountpoint="/data"} < 30G
    action: Slack notification

  - name: HeapMemory > 80%
    query: jvm_memory_used_bytes{area="heap"} > 3.2G
    action: Page on-call DevOps

  - name: Backup Failed
    query: nexus_backup_last_success_timestamp_seconds < now - 86400
    action: Slack + PagerDuty
```

---

## [HAUSSE] Checklist d'implémentation (Jour-1 -> Production)

### Jour 1 : Infrastructure & Déploiement
- [ ] Provision serveur (8 vCPU, 16 GB, 500 GB SSD)
- [ ] Mount disque séparé pour blobstore
- [ ] Deploy Nexus (docker-compose)
- [ ] Configurer HTTPS (Let's Encrypt + nginx)
- [ ] Vérifier accès https://nexus.shopfast.com

### Jour 2 : Repositories & Configuration
- [ ] Créer repos Maven (central, releases, snapshots, public)
- [ ] Créer repos npm (registry, private, group)
- [ ] Créer repos Docker (hosted, proxy, group)
- [ ] Créer repo raw (scripts)
- [ ] Test: mvn clean compile (maven-public)
- [ ] Test: npm ci (npm-group)
- [ ] Test: docker pull nexus:5002/busybox (docker-group)

### Jour 3 : Sécurité & LDAP
- [ ] Intégrer LDAP d'entreprise
- [ ] Créer rôles (developers, devops, admin)
- [ ] Activer npm Bearer Token Realm
- [ ] Configurer cleanup policies
- [ ] Générer service accounts (CI/CD)

### Jour 4 : Backup & Monitoring
- [ ] Configurer backup quotidien (s3/NFS)
- [ ] Test complet restoration
- [ ] Setup Prometheus + Grafana
- [ ] Configurer alertes (Slack, PagerDuty)
- [ ] Documenter playbooks DR

### Jour 5 : CI/CD Integration
- [ ] Update pom.xml (tous projets Maven)
- [ ] Update .npmrc (tous projets npm)
- [ ] Update .gitlab-ci.yml (maven-public, npm-group)
- [ ] Configurer docker daemon
- [ ] Test premier build complet

### Jour 6-7 : Validation & Training
- [ ] Tous les builds passent par Nexus [OK]
- [ ] Metrics & monitoring actifs
- [ ] DR plan documenté & testé
- [ ] Formation équipe (docs + workshop)
- [ ] Go-live!

---

## [DOCS] Librairie de Scripts Utiles

### Script 1 : Cleanup Maven snapshots

```bash
#!/bin/bash
# cleanup-snapshots.sh

NEXUS_URL="https://nexus.shopfast.com"
NEXUS_USER="admin"
NEXUS_PASSWORD="${NEXUS_PASSWORD}"
REPO="maven-snapshots"
DAYS_OLD=30

# Récupère tous les snapshots
curl -s -u "$NEXUS_USER:$NEXUS_PASSWORD" \
  "$NEXUS_URL/service/rest/v1/search?repository=$REPO&format=maven2" | \
  jq -r '.items[] | select(.last_modified | fromdateiso8601 < now - ('$DAYS_OLD' * 86400)) | .id' | \
  while read -r ITEM_ID; do
    echo "Deleting $ITEM_ID"
    curl -X DELETE -u "$NEXUS_USER:$NEXUS_PASSWORD" \
      "$NEXUS_URL/service/rest/v1/components/$ITEM_ID"
  done

echo "[OK] Cleanup completed"
```

### Script 2 : Publish Maven artifact

```bash
#!/bin/bash
# publish-maven.sh

GROUP_ID="com.shopfast"
ARTIFACT_ID="shopfast-commons"
VERSION="${1:-1.5.2}"

cd /path/to/shopfast-commons
mvn versions:set -DnewVersion=$VERSION
mvn clean deploy -DskipTests

echo "[OK] Published $ARTIFACT_ID:$VERSION"
```

### Script 3 : Sync Docker image

```bash
#!/bin/bash
# sync-docker-image.sh

IMAGE="${1:-openjdk:11-jre-slim}"
NEXUS_REGISTRY="nexus.shopfast.com:5001"

docker pull $IMAGE
docker tag $IMAGE $NEXUS_REGISTRY/$IMAGE
docker push $NEXUS_REGISTRY/$IMAGE

echo "[OK] Synced $IMAGE to Nexus"
```

### Script 4 : Health check Nexus

```bash
#!/bin/bash
# health-check.sh

NEXUS_URL="https://nexus.shopfast.com"

# Check API
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $NEXUS_URL/service/rest/v1/status)

if [ "$STATUS" == "200" ]; then
  echo "[OK] Nexus is healthy"
  exit 0
else
  echo "[X] Nexus returned status $STATUS"
  # Send alert
  curl -X POST https://hooks.slack.com/... \
    -d '{"text": "[ATTENTION] Nexus health check failed: HTTP '$STATUS'"}'
  exit 1
fi
```

---

## [GUIDE] Guide Référence Rapide

### Commandes Maven courantes

```bash
# Compile (télécharge dépendances depuis maven-public)
mvn clean compile

# Tests (idem)
mvn test

# Build JAR
mvn package

# Publish SNAPSHOT
mvn deploy
# -> nexus-snapshots/

# Publish RELEASE
mvn deploy
# -> nexus-releases/ (si version sans -SNAPSHOT)

# Update dépendances
mvn dependency:tree
mvn dependency:update-project
```

### Commandes npm courantes

```bash
# Install (télécharge depuis npm-group)
npm ci

# Install avec scope (@shopfast)
npm install @shopfast/ui-components

# Publish (vers npm-private pour scoped packages)
npm publish

# Check registry
npm config get registry

# Login
npm login --registry=https://nexus.shopfast.com/repository/npm-private/
```

### Commandes Docker courantes

```bash
# Login à Nexus
docker login nexus.shopfast.com:5000

# Build & tag
docker build -t nexus.shopfast.com:5000/shopfast-backend:2.3.1 .

# Push
docker push nexus.shopfast.com:5000/shopfast-backend:2.3.1

# Pull (depuis docker-group)
docker pull nexus.shopfast.com:5002/node:18-alpine
```

---

## [GRAPHIQUE] ROI & Conclusion

### Bénéfices Quantifiés

| Métrique | AVANT | APRÈS | Impact |
|----------|-------|-------|--------|
| Build time | 8 min | 35s | -95% [RAPIDE] |
| CI/CD/jour | 400 min | 29 min | Gain 6h+ |
| Bande passante | 50 Go/jour | 2 Go/jour | -96% [BAISSE] |
| Fiabilité | 90% | 99.99% | +10% [OK] |
| Onboarding dev | 15 min | 3 min | -80% [RAPIDE] |
| Coût bande/mois | €500 | €20 | Gain €480 [ARGENT] |
| Coût temps/mois | 185h | - | Gain 23j [PERSONNE][PRO] |

### Coût Total d'Ownership (Year 1)

```
Hardware:           €2,000  (serveur 8vCPU + SSD)
Bandwidth saved:    €6,000  (€500 × 12 mois)
Dev time saved:     €45,000 (23 jours/mois × 5 devs × €250/jour)
License (OSS):      €0

Total savings:      €51,000
ROI:                2,550% [OBJECTIF]
Payback period:     <1 week
```

### Prochaines étapes

1. **Court terme (Semaine 1-2):**
   - Deploy Nexus en production
   - Intégrer CI/CD pipelines
   - Former l'équipe

2. **Moyen terme (Mois 1-3):**
   - Monitoring & alertes
   - Backup & DR validation
   - Optimisation policies

3. **Long terme (Mois 3+):**
   - Multi-région (EU/US)
   - Évaluer Nexus Pro (HA/clustering)
   - Intégrer scanning vulnérabilités
   - DevOps automation avancée



[OK] FIN DU GUIDE

Ce guide couvre l'essentiel de Nexus Repository Manager.
Pour aller plus loin:
- Consultez la documentation officielle
- Rejoignez la communauté Sonatype
- Testez les fonctionnalités avancées (Nexus Pro)
- Automatisez vos workflows
- Partagez vos configurations

Bon courage avec Nexus! [RAPIDE]