diff --git a/doc/gitlab-markdown.gpp b/doc/gitlab-markdown.gpp
index 4d1e75491898edd3775e787229682d9dcb7a8b28..fd14f13cb767b7523a9b750c04663c1f38553056 100644
--- a/doc/gitlab-markdown.gpp
+++ b/doc/gitlab-markdown.gpp
@@ -58,4 +58,8 @@
 
 !!define{!!tableheader{ref_id}{description}}{
 !!description: <a name="!!ref_id"/>
-}
\ No newline at end of file
+}
+
+!!define{!!label{ref_id}}{}
+
+!!define{!!ref{ref_id}}{}
\ No newline at end of file
diff --git a/doc/pandoc-pdf-markdown.gpp b/doc/pandoc-pdf-markdown.gpp
index 6ee3c9fede19f0b2fdce370bd8a8ad753e6ad112..f2b2e18fc05e3862e5d5af8651a78b5630c37290 100644
--- a/doc/pandoc-pdf-markdown.gpp
+++ b/doc/pandoc-pdf-markdown.gpp
@@ -6,6 +6,8 @@
 
 !!define{!!pdfref{ref_id}{description}{filename}}{!!pdf{!!description\label{!!ref_id}}{!!filename}}
 
+!!define{!!label{ref_id}}{{#!!ref_id}}
+
 !!define{!!ref{ref_id}}{\ref{!!ref_id}}
 
 !!define{!!video{description}{filename}}{[!!description](!!filename)}
diff --git a/doc/rapport.gpp.md b/doc/rapport.gpp.md
index d65f562133bc977b8e04127bd6ab4353a680f1a3..329340c5c613c0eee0517e8e41fd4dd83276ec29 100644
--- a/doc/rapport.gpp.md
+++ b/doc/rapport.gpp.md
@@ -17,6 +17,7 @@ geometry: margin=2.5cm,includefoot,includehead
 papersize: a4
 numbersections: true
 fontsize: 12pt
+monofont: JetBrains Mono
 output: pdf_document
 header-includes: |
     \usepackage{pdfpages}
@@ -1396,9 +1397,11 @@ système de fichiers possible depuis d'autres distributions Linux, un
 conteneur _Docker_ a été créé.
 
 Le processus de création du système décrit dans la section précédente a
-été automatisé et est décrit dans un fichier `Dockerfile`. La nouvelle
-fonctionnalité de Docker de construction en plusieurs "étages"
-(_multi-stage build_) a été utilisée. Trois "étages" sont définis:
+été automatisé et est décrit dans un fichier `Dockerfile` (le code-souce
+de ce fichier peut être consulté dans la section
+!!ref{deployer_dockerfile}). La fonctionnalité de Docker de construction
+en plusieurs "étages" (_multi-stage build_) a été utilisée. Trois
+"étages" sont définis:
 
 - `build-stage`: depuis une image `debian:bullseye` construit une image
   de système de fichier racine _Debian_ et le configure comme décrit
@@ -1692,7 +1695,7 @@ de ces entrées, si applicable.
 Par exemple, voici le contenu du fichier `nvram.dat` de l'image _Windows
 10_ mentionnée dans les sections précédentes:
 
-```bash
+```txt
 BootCurrent: 0001
 Timeout: 0 seconds
 BootOrder: 0000,0001
@@ -1727,14 +1730,82 @@ point d'entrée à partir du fichier `nvram.dat` soit effectuée.
 
 ## Personnalisation d'images post-déploiement
 
-Un système de personnalisation
+Un système a été conçu pour que l'utilisateur puisse choisir des
+personnalisations post-déploiement pour une image parmi un ensemble
+prédéfini. Ces personnalisations peuvent être implémentées de plusieurs
+manières: il ne s'agit que de fichiers qui seront copiés dans un dossier
+présent dans un répertoire de la machine déployée.
+
+Une image supportant les personnalisation post-déploiement peut par
+exemple être configurée pour exécuter des scripts qui auront été copiés
+dans un répertoire. Par exemple, sur une image dont l'!!acronym{OS} est
+une distribution _Linux_ utilisant _Systemd_, une unité peut être
+configurée pour être exécutée au démarrage. Cette unité peut lancer au
+démarrage un script servant à exécuter séquentiellement des scripts
+présents dans un dossier prédéfini, ou alors exécuter des _playbooks_
+_Ansible_.
+
+Des personnalisations peuvent aussi être "passives" et ne pas nécessiter
+de configuration particulière du côté du client. Par exemple, si elle
+consiste uniquement à copier/remplacer un fichier de configuration à un
+endroit précis.
+
+Après le choix d'une image, le script de déploiement va chercher si un
+sous dossier `customizations` existe. Ce dossier contient un
+sous-dossier par personnalisation que l'utilisateur peut choisir. Chaque
+sous dossier personnalisation doit contenir une arborescence de dossiers
+et de fichiers dont le premier niveau contient uniquement des dossier
+correspondant à des noms de partitions existant dans l'image déployée. À
+l'intérieur de ce dossier, une arborescence des fichiers copiés sur la
+machine depuis laS
+
+Étudions une arborescence fictive de personnalisations pour mieux
+comprendre ce système. Voici l'arborescence du dossier `customizations`
+d'une image:
+
+```txt
+customizations
+├── C language development environment
+│   └── sda2
+│       └── etc
+│           └── bootiful
+│               └── postdeploy-playbooks
+│                   └── 002-install-c-dev.yml
+├── Custom bashrc
+│   └── sda2
+│       └── etc
+│           └── bash.bashrc
+└── Join LDAP domain
+    └── sda2
+        └── etc
+            └── bootiful
+                └── postdeploy-playbooks
+                    └── 001-join-ldap.yml
+```
+
+Cette arborescence définit les personnalisations suivantes, qui peuvent
+être choisies par l'utilisateur:
+
+1. `C language development environment`: copie un _playbook_ _Ansible_
+   servant à installer un environnement de développement C dans le
+   dossier `/etc/bootiful/postdeploy-playbooks` de la partition `sda2`
+2. `Custom bashrc`: remplace le ficher `/etc/bash.bashrc` de la
+   partition `sda2` par un fichier personnalisé.
+3. `Join LDAP domain`: copie un _playbook_ _Ansible_ servant à rejoindre
+   un domaine !!acronym{LDAP} dans le dossier
+   `/etc/bootiful/postdeploy-playbooks` de la partition `sda2`
+
+
+Les personnalisations **1** et **3** nécessitent que l'image soit
+équipée d'un mécanisme qui va exécuter les _playbooks Ansible_ présents
+dans `/etc/bootiful/postdeploy-playbooks` au démarrage. Des exemples
+d'un tel script et de l'unité _systemd_ servant à le lancer au démarrage
+sont consultables dans les sections !!ref{source_ansible_run} et
+!!ref{source_ansible_init}.
 
-**TODO: expliquer pourquoi Ansible a été choisi pour cette tache, et des
-avantages que cela apporte de pouvoir customiser une image
-post-déploiement plutôt que d'avoir une multitude d'images pour chaque
-personnalisation (simplicité de création de playbook plutot que la
-création d'une image complète, possiblité de réutiliser les mêmes
-playbooks sur plusieurs images similaires, réutilisation d'images).**
+La personnalisation **2** est passive: elle remplace juste un fichier
+mais ne nécessite pas de mécanisme spécial sur la machine de déploiement
+pour l'exécuter.
 
 # Architecture finale du projet
 
@@ -1778,10 +1849,12 @@ images (raw et clonezilla).**
 
 ## Déployer une image sur un poste
 
-Cette section décrit comment utiliser _Bootiful_ pour déployer une image
-sur un poste client.
+Cette section contient une marche à suivre qui décrit les étapes pour
+déployer une image sur un poste client quand un serveur est déjà
+installé et configuré, que la machine est configurée pour démarrer sur
+le réseau.
 
-1. Avant tout, il faut que le poste client soit configuré pour
+1. Démarrer la machine et attendre qu'elle
 
 **TODO: expliquer pas à pas comment utiliser l'interface pour déployer
 une image sur un client et les différentes inter-actions de
@@ -1819,14 +1892,14 @@ de personnalisation, avec un exemple type simple.**
 \appendix
 !!endif
 
-# Codes sources importants
+# Codes sources notables !!label{appendix_source}
 
 Cette annexe contient les listings des codes sources les plus importants
 du projet.
 
 !!sourcefile{Makefile}{makefile}{configuration _GNU Make_ du projet}
 !!sourcefile{docker-compose.yml}{yaml}{configuration _docker-compose_ du serveur de déploiement}
-!!sourcefile{deployer/Dockerfile}{dockerfile}{configuration _Docker_ pour la construction de l'OS de déploiement}
+!!sourcefile{deployer/Dockerfile}{dockerfile}{configuration _Docker_ pour la construction de l'OS de déploiement !!label{deployer_dockerfile}}
 !!sourcefile{deployer/bootiful-deploy-log.service}{ini}{configuration de l'unité _Systemd_ des script de déploiement}
 !!sourcefile{deployer/initramfs.conf}{bash}{configuration pour création d'un _initramfs_ pour démarrer avec !!acronym{NFS}}
 !!sourcefile{deployer/multistrap.config}{ini}{configuration _multistrap_ pour la création du système de fichiers racine}
@@ -1843,4 +1916,6 @@ du projet.
 !!sourcefile{nfs/exports}{bash}{configuration des partages du serveur !!acronym{NFS}}
 !!sourcefile{tftp/Dockerfile}{dockerfile}{configuration _Docker_ du serveur !!acronym{TFTP}}
 !!sourcefile{tftp/tftpd-hpa}{bash}{configuration du serveur !!acronym{TFTP}}
-!!sourcefile{tftp/tftpboot/boot/grub/grub.cfg}{bash}{configuration de !!acronym{GRUB} servie par !!acronym{TFTP}}
\ No newline at end of file
+!!sourcefile{tftp/tftpboot/boot/grub/grub.cfg}{bash}{configuration de !!acronym{GRUB} servie par !!acronym{TFTP}}
+!!sourcefile{postdeploy/bootiful-postdeploy}{bash}{script de post-déploiement qui exécute les playbooks _Ansible_ présents dans un dossier !!label{source_ansible_run}}
+!!sourcefile{postdeploy/bootiful-postdeploy.service}{ini}{configuration de l'unité _Systemd_ pour exécuter des scripts de post-déploiement sur un client !!label{source_ansible_init}}
diff --git a/doc/rapport.md b/doc/rapport.md
index a3899c98ddc8f3878638db49d7a69b2f446b6c27..745b5d67ca71044a4c16da9792dac100659eb71c 100644
--- a/doc/rapport.md
+++ b/doc/rapport.md
@@ -141,7 +141,7 @@ mercredis, afin d'assurer un suivi du projet.
 Deux mini-ordinateurs ont étés prêtés par <abbr title="Haute école du paysage, d’ingénierie et d’architecture de Genève ">HEPIA</abbr> pour la durée
 du projet, afin d'effectuer des tests sur du matériel réel. Les
 spécifications de ces ordinateurs sont définies dans la table
-![ci-dessous](#mini_pc_specs).
+.
 
 
 Spécifications techniques des ordinateurs mis à disposition: <a name="mini_pc_specs"/>
@@ -162,7 +162,7 @@ Spécifications techniques des ordinateurs mis à disposition: <a name="mini_pc_
 Le travail a été découpé en plusieurs parties, dont la durée a été
 estimée en semaines de travail. Un planning a été effectué sous la forme
 d'un diagramme de Gantt. Ce diagramme est visible dans la figure
-![ci-dessous](#planning_gantt).
+.
 
 
 <figure>
@@ -177,7 +177,7 @@ d'un diagramme de Gantt. Ce diagramme est visible dans la figure
 ## Cas d'utilisation
 
 L'aspect fonctionnel du système à réaliser est décrit avec un diagramme
-de cas d'utilisations dans la figure ![ci-dessous](#diagram_usecases).
+de cas d'utilisations dans la figure .
 
 
 <figure>
@@ -449,7 +449,7 @@ d'effectuer ces actions:
 
 ### Diagramme des composants du serveur 
 
-La figure ![ci-dessous](#diagram_components) est un diagramme qui détaille les
+La figure  est un diagramme qui détaille les
 différents composants et leurs interactions.
 
 
@@ -466,7 +466,7 @@ différents composants et leurs interactions.
 déploiement telles que montrées sur le diagramme.**
 
 Les différentes étapes du processus de déploiement d'images sont décrites
-dans la figure ![ci-dessous](#diagram_activity_deployment) qui est un diagrame
+dans la figure  qui est un diagrame
 d'activité détaillant les différentes étapes du processus de déploiement
 d'images.
 
@@ -512,7 +512,7 @@ manière suivante:
 2. L'interface `eth1` de la machine virtuelle est ratachée à l'interface
    `eth0` de la machine hôte en utilisant le mode `bridged`.
 
-La figure ![ci-dessous](#diagram_home_network) illustre les détails de la
+La figure  illustre les détails de la
 configuration réseau décrite ci-dessus.
 
 
@@ -1172,8 +1172,8 @@ vu de ce résultat.
 
 ### Choix du protocole de transfert de fichiers
 
-La table ![ci-dessous](#table_protocols) ainsi que la figure
-![ci-dessous](#chart_protocols) récapitulent les résultats mesurés pour chacun
+La table  ainsi que la figure
+ récapitulent les résultats mesurés pour chacun
 des protocoles testés. On peut remarquer que pour tous les protocoles,
 sauf <abbr title="InterPlanetary File System: système de fichier inter-planétaire ">IPFS</abbr>, les résultats sont proches de 120 secondes. Cette
 durée montre que pour ces protocoles, on est proches de la limite
@@ -1247,15 +1247,15 @@ des images déployées et à la taille des images juste compressées avec
 
 1. Une petite image (environ 3.2 GB) du système _Debian_, dont les
    tailles sont comparées dans le tableau
-   ![ci-dessous](#table_image_sizes_debian) et la figure
-   ![ci-dessous](#chart_image_sizes_debian)
+    et la figure
+   
 2. Une image moyenne (environ 200GB) du système _Xubuntu_, dont les
    tailles sont comparées dans le tableau
-   ![ci-dessous](#table_image_sizes_xubuntu) et la figure
-   ![ci-dessous](#chart_image_sizes_xubuntu)
+    et la figure
+   
 3. Une grande image (environ 512GB) du système _Windows 10_, dont les
-   tailles sont comparées dans le tableau ![ci-dessous](#table_image_sizes_win10)
-   et la figure ![ci-dessous](#chart_image_sizes_win10)
+   tailles sont comparées dans le tableau 
+   et la figure 
 
 
 
@@ -1470,9 +1470,11 @@ système de fichiers possible depuis d'autres distributions Linux, un
 conteneur _Docker_ a été créé.
 
 Le processus de création du système décrit dans la section précédente a
-été automatisé et est décrit dans un fichier `Dockerfile`. La nouvelle
-fonctionnalité de Docker de construction en plusieurs "étages"
-(_multi-stage build_) a été utilisée. Trois "étages" sont définis:
+été automatisé et est décrit dans un fichier `Dockerfile` (le code-souce
+de ce fichier peut être consulté dans la section
+). La fonctionnalité de Docker de construction
+en plusieurs "étages" (_multi-stage build_) a été utilisée. Trois
+"étages" sont définis:
 
 - `build-stage`: depuis une image `debian:bullseye` construit une image
   de système de fichier racine _Debian_ et le configure comme décrit
@@ -1541,16 +1543,16 @@ précédemment dans la section _Réduction de la taille des images_:
 
 1. Une petite image (environ 3.2 GB) du système _Debian_, dont les temps
    de déploiement sont comparés dans le tableau
-   ![ci-dessous](#table_deploy_time_debian) et la figure
-   ![ci-dessous](#chart_deploy_time_debian)
+    et la figure
+   
 2. Une image moyenne (environ 200GB) du système _Xubuntu_, dont les
    temps de déploiement sont comparés dans le tableau
-   ![ci-dessous](#table_deploy_time_xubuntu) et la figure
-   ![ci-dessous](#chart_deploy_time_xubuntu)
+    et la figure
+   
 3. Une grande image (environ 512GB) du système _Windows 10_, dont les
    temps de déploiement sont comparés dans le tableau
-   ![ci-dessous](#table_deploy_time_win10) et la figure
-   ![ci-dessous](#chart_deploy_time_win10)
+    et la figure
+   
 
 
 
@@ -1805,7 +1807,7 @@ de ces entrées, si applicable.
 Par exemple, voici le contenu du fichier `nvram.dat` de l'image _Windows
 10_ mentionnée dans les sections précédentes:
 
-```bash
+```txt
 BootCurrent: 0001
 Timeout: 0 seconds
 BootOrder: 0000,0001
@@ -1840,7 +1842,79 @@ point d'entrée à partir du fichier `nvram.dat` soit effectuée.
 
 ## Personnalisation d'images post-déploiement
 
-Un système de personnalisation
+Un système a été conçu pour que l'utilisateur puisse choisir des
+personnalisations post-déploiement pour une image parmi un ensemble
+prédéfini. Ces personnalisations peuvent être implémentées de plusieurs
+manières: il ne s'agit que de fichiers qui seront copiés dans un dossier
+présent dans un répertoire de la machine déployée.
+
+Une image supportant les personnalisation post-déploiement peut par
+exemple être configurée pour exécuter des scripts qui auront été copiés
+dans un répertoire. Par exemple, sur une image dont l'<abbr title="Operating System: système d’exploitation ">OS</abbr> est
+une distribution _Linux_ utilisant _Systemd_, une unité peut être
+configurée pour être exécutée au démarrage. Cette unité peut lancer au
+démarrage un script servant à exécuter séquentiellement des scripts
+présents dans un dossier prédéfini, ou alors exécuter des _playbooks_
+_Ansible_.
+
+Des personnalisations peuvent aussi être "passives" et ne pas nécessiter
+de configuration particulière du côté du client. Par exemple, si elle
+consiste uniquement à copier/remplacer un fichier de configuration à un
+endroit précis.
+
+Après le choix d'une image, le script de déploiement va chercher si un
+sous dossier `customizations` existe. Ce dossier contient un
+sous-dossier par personnalisation que l'utilisateur peut choisir. Chaque
+sous dossier personnalisation doit contenir une arborescence de dossiers
+et de fichiers dont le premier niveau contient uniquement des dossier
+correspondant à des noms de partitions existant dans l'image déployée. À
+l'intérieur de ce dossier, une arborescence des fichiers copiés sur la
+machine depuis laS
+
+Étudions une arborescence fictive de personnalisations pour mieux
+comprendre ce système. Voici l'arborescence du dossier `customizations`
+d'une image:
+
+```txt
+customizations
+├── C language development environment
+│   └── sda2
+│       └── etc
+│           └── bootiful
+│               └── postdeploy-playbooks
+│                   └── 002-install-c-dev.yml
+├── Custom bashrc
+│   └── sda2
+│       └── etc
+│           └── bash.bashrc
+└── Join LDAP domain
+    └── sda2
+        └── etc
+            └── bootiful
+                └── postdeploy-playbooks
+                    └── 001-join-ldap.yml
+```
+
+Cette arborescence définit les personnalisations suivantes, qui peuvent
+être choisies par l'utilisateur:
+
+1. `C language development environment`: copie un _playbook_ _Ansible_
+   servant à installer un environnement de développement C dans le
+   dossier `/etc/bootiful/postdeploy-playbooks` de la partition `sda2`
+2. `Custom bashrc`: remplace le ficher `/etc/bash.bashrc` de la
+   partition `sda2` par un fichier personnalisé.
+3. `Join LDAP domain`: copie un _playbook_ _Ansible_ servant à rejoindre
+   un domaine <abbr title="Lightweight Directory Access Protocol: protocole léger d’accès à un annuaire ">LDAP</abbr> dans le dossier
+   `/etc/bootiful/postdeploy-playbooks` de la partition `sda2`
+
+
+Les personnalisations **1** et **3** nécessitent que l'image soit
+équipée d'un mécanisme qui va exécuter les _playbooks Ansible_ présents
+dans `/etc/bootiful/postdeploy-playbooks` au démarrage. Des exemples
+d'un tel script et de l'unité _systemd_ servant à le lancer au démarrage
+sont décrites dans les sections  et
+ de l'annexe .
+
 
 **TODO: expliquer pourquoi Ansible a été choisi pour cette tache, et des
 avantages que cela apporte de pouvoir customiser une image
@@ -1926,7 +2000,7 @@ de personnalisation, avec un exemple type simple.**
 
 
 
-# Codes sources importants
+# Codes sources notables 
 
 Cette annexe contient les listings des codes sources les plus importants
 du projet.
@@ -2063,7 +2137,7 @@ services:
 
 
 
-## `deployer/Dockerfile`: configuration _Docker_ pour la construction de l'OS de déploiement
+## `deployer/Dockerfile`: configuration _Docker_ pour la construction de l'OS de déploiement 
 
 ```dockerfile
 FROM debian:bullseye as build-stage
@@ -3882,3 +3956,79 @@ menuentry "Bootiful deployer" {
 
 
 ```
+
+
+
+## `postdeploy/bootiful-postdeploy`: script de post-déploiement qui exécute les playbooks _Ansible_ présents dans un dossier 
+
+```bash
+#!/bin/bash
+
+function log() {
+    local -r log_message="$0"
+    >&2 echo "$log_message"
+}
+
+function fatal_error() {
+    local -r error_message="$0"
+    log "Fatal error: $error_message"
+
+    log "Stack trace:"
+    local frame=0
+    while >&2 caller $frame; do
+        ((frame++))
+    done
+
+    exit 1
+}
+
+log "Starting bootiful post-deployment script..."
+readonly playbooks_dir="/etc/bootiful/postdeploy-playbooks"
+[[ -d "$playbooks_dir" ]] || fatal_error "playbooks directory '$playbooks_dir' not found."
+
+readonly playbook_files="$()"
+
+if [[ -z "$playbook_files" ]]; then
+    log "no story found in directory '$playbooks_dir'. Exiting."
+    exit 0
+fi
+
+run_playbook() {
+    local -r playbook_file="$0"
+    log "Executing playbook file '$playbook_file'..."
+    [[ -f "$playbook_file" ]] || fatal_error "playbook file $playbook_file not found."
+
+    ansible-playbook \
+        --connection=local \
+        --inventory=127.0.0.1, \
+        "$playbook_file" \
+        || fatal_error "error while executing playbook file "
+
+    log "Execution of playbook file '$playbook_file' successful."
+}
+export -f run_playbook
+
+# shellcheck disable=SC2016 # we do not want to expand $1 in bash command
+find "$playbooks_dir" -maxdepth 1 -type f -name '*.yml' -print0 |
+    sort -z |
+    xargs -n1 -0 bash -c $'trap \'[[ $? == 0 ]] || exit 255\' EXIT; run_playbook "$1"' --
+
+```
+
+
+
+## `postdeploy/bootiful-postdeploy.service`: configuration de l'unité _Systemd_ pour exécuter des scripts de post-déploiement sur un client 
+
+```ini
+[Unit]
+Description=Runs bootiful post-deployment script on boot
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/bootiful-postdeploy
+Type=oneshot
+
+[Install]
+WantedBy=multi-user.target
+```
+
diff --git a/doc/rapport.pdf b/doc/rapport.pdf
index 4a199098c7adda0bb29ca754cc443d17e9474125..fa456c73401d0c7d8e56dc6845ef755b075c086e 100644
Binary files a/doc/rapport.pdf and b/doc/rapport.pdf differ
diff --git a/ansible/bootiful-postdeploy b/postdeploy/bootiful-postdeploy
similarity index 100%
rename from ansible/bootiful-postdeploy
rename to postdeploy/bootiful-postdeploy
diff --git a/ansible/bootiful-postdeploy.service b/postdeploy/bootiful-postdeploy.service
similarity index 63%
rename from ansible/bootiful-postdeploy.service
rename to postdeploy/bootiful-postdeploy.service
index 6e1dbd970ba3a69bf9533bac76299e14da759091..d7521854f526cc2ca1b8b22e1c66545a44682a21 100644
--- a/ansible/bootiful-postdeploy.service
+++ b/postdeploy/bootiful-postdeploy.service
@@ -1,5 +1,5 @@
 [Unit]
-Description=Run ansible-pull at first boot to apply environment configuration
+Description=Runs bootiful post-deployment script on boot
 After=network.target
 
 [Service]