diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8888326ac0b172ff17439e17817b43165b576a2b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/training-session.iml" filepath="$PROJECT_DIR$/.idea/training-session.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/training-session.iml b/.idea/training-session.iml
new file mode 100644
index 0000000000000000000000000000000000000000..cf84ae4a69877a117dad3f555c9d8ebf05a4fc20
--- /dev/null
+++ b/.idea/training-session.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="EMPTY_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 1428f80d1a3d6adba08daebf7d69aa03b51ba2ee..55a9725011bbef1cc34848cbd49d0d3540068ffb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,3 +6,4 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+cursive = "0.19.0"
\ No newline at end of file
diff --git a/src/app.rs b/src/app.rs
new file mode 100644
index 0000000000000000000000000000000000000000..71b86e9b72f12b8409e6aa812fcb12e7a8eb5b6d
--- /dev/null
+++ b/src/app.rs
@@ -0,0 +1,153 @@
+/// Importer le module `Training` depuis le fichier externe
+use crate::training::Training;
+
+/// Importations des bibliothèques standard et de cursive
+use std::rc::Rc;
+use cursive::Cursive;
+use cursive::{
+    views::{Button, Dialog, DummyView, EditView, LinearLayout, SelectView, TextView, NamedView, ResizedView},
+    traits::*,
+};
+
+/// Fonction publique pour générer le TUI
+pub fn run() {
+    // Initialisation de Cursive
+    let mut siv = cursive::default();
+
+    // Vue des entraînements
+    let select = SelectView::<Training>::new()
+        .on_submit(on_submit) // Appelé lors de la soumission de la sélection
+        .with_name("select") // Nom de la vue
+        .fixed_size((10, 5)); // Taille fixe de la vue
+
+    // Buttons pour ajouter et supprimer un entraînement
+    let buttons = LinearLayout::vertical()
+        .child(Button::new("Add new", add_training)) // Bouton pour ajouter un nouvel entraînement
+        .child(Button::new("Delete", delete_training)) // Bouton pour supprimer un entraînement
+        .child(DummyView) // Vue fictive pour ajouter de l'espace
+        .child(Button::new("Quit", Cursive::quit)); // Bouton pour quitter l'application
+
+    // Ajout de la couche de dialogue principale à Cursive
+    siv.add_layer(Dialog::around(LinearLayout::horizontal()
+        .child(select) // Ajout de la vue de sélection
+        .child(DummyView) // Ajout d'espace vide
+        .child(buttons)) // Ajout des boutons
+        .title("Select a training")); // Titre de la couche de dialogue
+
+    // Exécution de la boucle principale de Cursive
+    siv.run();
+}
+
+/// Fonction interne pour gérer l'ajout d'un nouvel entraînement
+///
+/// # Arguments
+///
+/// * `s` - Une référence mutable à Cursive
+fn add_training(s: &mut Cursive) {
+    fn ok(s: &mut Cursive, training: Training) {
+        // Ajout de l'entraînement à la vue de sélection
+        s.call_on_name("select", |view: &mut SelectView<Training>| {
+            view.add_item(training.name.clone(), training.clone()); // Using the cloned_training
+        });
+
+        s.pop_layer(); // Fermer la couche de dialogue
+    }
+
+    // Ajout d'une couche de dialogue pour l'ajout d'un nouvel entraînement
+    s.add_layer(Dialog::around(
+        LinearLayout::vertical()
+            .with(
+                |list| for item in Training::TRAINING_ITEMS.iter() {
+                    list.add_child(create_label(item)); // Ajout d'un label pour chaque élément de l'entraînement
+                    list.add_child(create_edit_view(item)); // Ajout d'un champ de saisie pour chaque élément
+                    list.add_child(DummyView); // Ajout d'espace vide
+                })
+            .child(DummyView) // Ajout d'espace vide
+            .child(LinearLayout::horizontal()
+                .child(Button::new(
+                    "Ok", |s| { // Bouton "Ok" pour valider l'ajout
+                        // Récupération des données saisies par l'utilisateur
+                        let name = get_view_content(s, "name");
+                        let description = get_view_content(s, "description");
+                        let date = get_view_content(s, "date");
+                        let location = get_view_content(s, "location");
+                        let duration = get_view_content(s, "duration").parse::<i32>().unwrap_or(0);
+                        let participants_str = get_view_content(s, "participants").to_string();
+                        let participants = participants_str.split(",").map(str::trim).collect();
+
+                        // Vérification si le nom est vide
+                        if name.is_empty() {
+                            s.add_layer(Dialog::info("Name cannot be empty")); // Affichage d'un message d'erreur
+                        } else {
+                            ok(s, Training::new(&name, &description, &date, &location, duration, participants)); // Appel de la fonction `ok` pour gérer l'ajout
+                        }
+                    }))
+                .child(Button::new("Cancel", |s| {
+                    s.pop_layer(); // Annuler l'ajout et fermer la couche de dialogue
+                }))))
+                    .title("Enter a new training") // Titre de la couche de dialogue
+                    .scrollable() // Permettre le défilement si le contenu dépasse
+    );
+}
+
+/// Récupérer le contenu de la vue
+///
+/// # Arguments
+///
+/// * `s` - Une référence mutable à Cursive
+/// * `name` - Le nom du champ de saisie
+fn get_view_content(s: &mut Cursive, name: &str) -> Rc<String> {
+    s.call_on_name(name, |view: &mut EditView| view.get_content()).unwrap()
+}
+
+/// Créer un label pour un champ de l'entraînement
+///
+/// # Arguments
+///
+/// * `name` - Le nom du champ
+fn create_label(name: &str) -> NamedView<TextView> {
+    TextView::new(format!("{}:", name)).with_name(format!("{}_label", &name))
+}
+
+/// Créer un champ de saisie pour un champ de l'entraînement
+///
+/// # Arguments
+///
+/// * `name` - Le nom du champ
+fn create_edit_view(name: &str) -> ResizedView<NamedView<EditView>> {
+    EditView::new()
+        .with_name(name)
+        .fixed_width(18)
+}
+
+/// Supprimer un entraînement
+///
+/// # Arguments
+///
+/// * `s` - Une référence mutable à Cursive
+fn delete_training(s: &mut Cursive) {
+    let mut select = s.find_name::<SelectView<Training>>("select").unwrap(); // Trouver la vue de sélection
+    match select.selected_id() {
+        None => s.add_layer(Dialog::info("No train to remove")), // Afficher un message s'il n'y a pas de formation sélectionnée
+        Some(focus) => {
+            select.remove_item(focus); // Supprimer l'entraînement sélectionnée
+        }
+    }
+}
+
+/// Appelé lorsque l'utilisateur soumet un entraînement
+///
+/// # Arguments
+///
+/// * `s` - Une référence mutable à Cursive
+/// * `training` - Une référence à la structure Training soumise
+fn on_submit(s: &mut Cursive, training: &Training) {
+    // Afficher les informations de l'entraînement dans une couche de dialogue
+    s.add_layer(Dialog::text(training.to_string())
+                    .title(format!("{}'s info", training.name)) // Titre de la couche de dialogue
+                    .button("Quit", |s| {
+                        s.pop_layer(); // Ajouter un bouton pour fermer la couche de dialogue
+                    })
+                    .scrollable() // Permettre le défilement si le contenu dépasse
+    );
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index e7a11a969c037e00a796aafeff6258501ec15e9a..cca283573d2705aa3076280c49831b450131a88b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,7 @@
+/// Module de l'application
+mod app;
+/// Module pour la gestion de l'entraînement
+mod training;
 fn main() {
-    println!("Hello, world!");
-}
+    app::run();
+}
\ No newline at end of file
diff --git a/src/training.rs b/src/training.rs
new file mode 100644
index 0000000000000000000000000000000000000000..90631e0271587766e47b6dc11e4cef4fb392756f
--- /dev/null
+++ b/src/training.rs
@@ -0,0 +1,55 @@
+/// Structure représentant un entraînement
+#[derive(Clone)]
+pub struct Training {
+    /// Nom de l'entraînement
+    pub name: String,
+    /// Description de l'entraînement
+    pub description: String,
+    /// Date de l'entraînement
+    pub date: String,
+    /// Lieu de l'entraînement
+    pub location: String,
+    /// Durée de l'entraînement en heures
+    pub duration: i32,
+    /// Liste des participants à l'entraînement
+    pub participants: Vec<String>,
+}
+
+impl Training {
+    /// Tableau des éléments de l'entraînement
+    pub const TRAINING_ITEMS: [&'static str; 6] = ["name", "description", "date", "location", "duration", "participants"];
+
+    /// Crée une nouvelle instance de la structure Training
+    ///
+    /// # Arguments
+    ///
+    /// * `name` - Le nom de l'entraînement
+    /// * `description` - La description de l'entraînement
+    /// * `date` - La date de l'entraînement
+    /// * `location` - Le lieu de l'entraînement
+    /// * `duration` - La durée de l'entraînement en heures
+    /// * `participants` - Les participants à l'entraînement sous forme de vecteur de chaînes de caractères
+    pub fn new(
+        name: &str,
+        description: &str,
+        date: &str,
+        location: &str,
+        duration: i32,
+        participants: Vec<&str>
+    ) -> Training {
+        Training {
+            name: name.to_string(),
+            description: description.to_string(),
+            date: date.to_string(),
+            location: location.to_string(),
+            duration,
+            participants: participants.iter().map(ToString::to_string).collect(),
+        }
+    }
+
+    /// Convertit la structure Training en une chaîne de caractères formatée
+    pub fn to_string(&self) -> String {
+        format!("Name: {}\nDescription: {}\nDate: {}\nLocation: {}\nDuration: {}\nParticipants: {}",
+                self.name, self.description, self.date, self.location, self.duration.to_string(), self.participants.join(","))
+    }
+}
\ No newline at end of file