diff --git a/src/main/java/fil/sr2/flopbox/FTPResource.java b/src/main/java/fil/sr2/flopbox/FTPResource.java
index 97578c7b38807efe2955eabfa269076a4b3941d5..6d5989a3a22338428220a14b3eb6e6a4ce0aa7c9 100644
--- a/src/main/java/fil/sr2/flopbox/FTPResource.java
+++ b/src/main/java/fil/sr2/flopbox/FTPResource.java
@@ -3,10 +3,14 @@ package fil.sr2.flopbox;
 import jakarta.ws.rs.*;
 import jakarta.ws.rs.core.*;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 
 import org.apache.commons.net.ftp.FTP;
 import org.apache.commons.net.ftp.FTPClient;
@@ -15,6 +19,7 @@ import org.apache.commons.net.ftp.FTPFile;
 @Path("/ftps")
 public class FTPResource {
 
+    // ======== FTP Servers ========
     // GET /ftps - liste des serveurs FTP enregistrés
     @GET
     @Produces(MediaType.APPLICATION_JSON)
@@ -24,18 +29,48 @@ public class FTPResource {
         return Response.ok(servers).build();
     }
 
-    // returns the content of the directory as an array it is a directory OR the
-    // content of the file
+    // POST /ftps - enregistre un nouveau serveur FTP
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response addFTPServer(FTPServerConfig config, @Context UriInfo uriInfo) {
+        System.out.println("addFTPServer()");
+        boolean created = FTPServerRepository.getInstance().addServer(config);
+        if (!created) {
+            return Response.status(Response.Status.CONFLICT).entity("Alias déjà utilisé").build();
+        }
+        UriBuilder builder = uriInfo.getAbsolutePathBuilder();
+        builder.path(config.getAlias());
+        return Response.created(builder.build()).build();
+    }
+
+    @DELETE
+    @Path("/{alias}")
+    public Response removeFTPServer(@PathParam("alias") String alias) {
+        System.out.println("removeFTPServer()");
+        boolean removed = FTPServerRepository.getInstance().removeServer(alias);
+        return removed ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build();
+    }
+
+    @PUT
+    @Path("/{alias}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateFTPServer(@PathParam("alias") String alias, FTPServerConfig newConfig) {
+        System.out.println("updateFTPServer()");
+        boolean updated = FTPServerRepository.getInstance().updateServer(alias, newConfig);
+        return updated ? Response.ok(newConfig).build() : Response.status(Response.Status.NOT_FOUND).build();
+    }
+    // =============================
+
+    // ========= Resources =========
     @GET
     @Path("/{alias}/{path: .+}")
-    @Produces(MediaType.APPLICATION_JSON)
+    @Produces({ MediaType.APPLICATION_OCTET_STREAM, "application/zip" })
     public Response getFTPResource(
             @PathParam("alias") String alias,
             @PathParam("path") String path,
             @HeaderParam("X-FTP-User") String user,
             @HeaderParam("X-FTP-Pass") String pass) {
 
-        System.out.println("GetFTPResource()");
         FTPServerConfig config = FTPServerRepository.getInstance().getServer(alias);
         if (config == null) {
             return Response.status(Response.Status.NOT_FOUND)
@@ -50,42 +85,161 @@ public class FTPResource {
             }
             ftpClient.enterLocalPassiveMode();
             ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
-            // Normaliser le chemin en retirant le slash final
+
+            // Normaliser le chemin
             if (path.endsWith("/")) {
                 path = path.substring(0, path.length() - 1);
             }
-            // Vérifier si le chemin est un répertoire
+
+            // Vérifier si c'est un dossier
+            boolean isDirectory = ftpClient.changeWorkingDirectory(path);
+            if (isDirectory) {
+                String currentDirectory = ftpClient.printWorkingDirectory();
+                System.out.println("Répertoire courant : " + currentDirectory);
+
+                // Créer un ZIP du dossier
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                ZipOutputStream zos = new ZipOutputStream(baos);
+                addDirectoryToZip(ftpClient, currentDirectory, "", zos);
+                zos.close();
+                return Response.ok(baos.toByteArray())
+                        .type("application/zip")
+                        .header("Content-Disposition", "attachment; filename=\"" + getFileName(path) + ".zip\"")
+                        .build();
+            } else {
+                // Télécharger le fichier
+                InputStream is = ftpClient.retrieveFileStream(path);
+                if (is != null) {
+                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+                    byte[] buffer = new byte[4096];
+                    int bytesRead;
+                    while ((bytesRead = is.read(buffer)) != -1) {
+                        outputStream.write(buffer, 0, bytesRead);
+                    }
+                    is.close();
+                    ftpClient.completePendingCommand();
+                    return Response.ok(outputStream.toByteArray())
+                            .type(determineContentType(path))
+                            .header("Content-Disposition", "attachment; filename=\"" + getFileName(path) + "\"")
+                            .build();
+                } else {
+                    return Response.status(Response.Status.NOT_FOUND)
+                            .entity("Ressource non trouvée").build();
+                }
+            }
+        } catch (IOException e) {
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+                    .entity("Erreur FTP: " + e.getMessage()).build();
+        } finally {
+            try {
+                if (ftpClient.isConnected()) {
+                    ftpClient.logout();
+                    ftpClient.disconnect();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private String determineContentType(String path) {
+        if (path.endsWith(".txt"))
+            return MediaType.TEXT_PLAIN;
+        if (path.endsWith(".html"))
+            return MediaType.TEXT_HTML;
+        if (path.endsWith(".json"))
+            return MediaType.APPLICATION_JSON;
+        return MediaType.APPLICATION_OCTET_STREAM;
+    }
+
+    private void addDirectoryToZip(FTPClient ftpClient, String remotePath, String basePath, ZipOutputStream zos)
+            throws IOException {
+        FTPFile[] files = ftpClient.listFiles(remotePath);
+        if (files == null || files.length == 0) {
+            System.out.println("Aucun fichier trouvé dans le dossier : " + remotePath);
+            return;
+        }
+
+        for (FTPFile file : files) {
+            String filePath = remotePath.isEmpty() ? file.getName() : remotePath + "/" + file.getName();
+            String zipEntryPath = basePath.isEmpty() ? file.getName() : basePath + "/" + file.getName();
+
+            if (file.isDirectory()) {
+                // Ajouter une entrée de dossier au ZIP
+                zos.putNextEntry(new ZipEntry(zipEntryPath + "/"));
+                zos.closeEntry();
+                // Explorer le sous-dossier récursivement
+                addDirectoryToZip(ftpClient, filePath, zipEntryPath, zos);
+            } else {
+                // Ajouter un fichier au ZIP
+                ZipEntry entry = new ZipEntry(zipEntryPath);
+                zos.putNextEntry(entry);
+                InputStream is = ftpClient.retrieveFileStream(filePath);
+                if (is == null) {
+                    System.out.println("Impossible de lire le fichier : " + filePath);
+                    continue;
+                }
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = is.read(buffer)) != -1) {
+                    zos.write(buffer, 0, bytesRead);
+                }
+                is.close();
+                ftpClient.completePendingCommand(); // Important pour finaliser la lecture
+                zos.closeEntry();
+            }
+        }
+    }
+
+    @GET
+    @Path("/list/{alias}/{path: .+}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response listDirectory(
+            @PathParam("alias") String alias,
+            @PathParam("path") String path,
+            @HeaderParam("X-FTP-User") String user,
+            @HeaderParam("X-FTP-Pass") String pass) {
+
+        FTPServerConfig config = FTPServerRepository.getInstance().getServer(alias);
+        if (config == null) {
+            return Response.status(Response.Status.NOT_FOUND)
+                    .entity("Serveur FTP non trouvé").build();
+        }
+        FTPClient ftpClient = new FTPClient();
+        try {
+            ftpClient.connect(config.getHost(), config.getPort());
+            if (!ftpClient.login(user, pass)) {
+                return Response.status(Response.Status.UNAUTHORIZED)
+                        .entity("Authentification FTP échouée").build();
+            }
+            ftpClient.enterLocalPassiveMode();
+            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
+
+            if (path.endsWith("/")) {
+                path = path.substring(0, path.length() - 1);
+            }
+
             FTPFile[] files = ftpClient.listFiles(path);
             if (files == null || files.length == 0) {
                 return Response.status(Response.Status.NOT_FOUND)
-                        .entity("Ressource non trouvée : " + path).build();
+                        .entity("Ressource non trouvée: " + path).build();
             }
-            // Construire la structure JSON
+
             FtpNode root = buildFtpTree(ftpClient, path);
-            ftpClient.logout();
-            ftpClient.disconnect();
             return Response.ok(root).build();
         } catch (IOException e) {
             return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
-                    .entity("Erreur FTP : " + e.getMessage()).build();
-        }
-    }
-
-    // Fonction récursive pour construire l'arborescence FTP
-    private FtpNode buildFtpTree(FTPClient ftpClient, String path) throws IOException {
-        FTPFile[] files = ftpClient.listFiles(path);
-        FtpNode node = new FtpNode(getFileName(path), true); // Root est un dossier
-        if (files != null) {
-            for (FTPFile file : files) {
-                String fullPath = path + "/" + file.getName();
-                if (file.isDirectory()) {
-                    node.children.add(buildFtpTree(ftpClient, fullPath)); // Récursif pour les dossiers
-                } else {
-                    node.children.add(new FtpNode(file.getName(), false)); // Ajouter fichier
+                    .entity("Erreur FTP: " + e.getMessage()).build();
+        } finally {
+            try {
+                if (ftpClient.isConnected()) {
+                    ftpClient.logout();
+                    ftpClient.disconnect();
                 }
+            } catch (IOException e) {
+                e.printStackTrace();
             }
         }
-        return node;
     }
 
     // Classe représentant un nœud JSON (fichier ou dossier)
@@ -103,35 +257,21 @@ public class FTPResource {
         }
     }
 
-    // POST /ftps - enregistre un nouveau serveur FTP
-    @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response addFTPServer(FTPServerConfig config, @Context UriInfo uriInfo) {
-        System.out.println("addFTPServer()");
-        boolean created = FTPServerRepository.getInstance().addServer(config);
-        if (!created) {
-            return Response.status(Response.Status.CONFLICT).entity("Alias déjà utilisé").build();
+    // Fonction récursive pour construire l'arborescence FTP
+    private FtpNode buildFtpTree(FTPClient ftpClient, String path) throws IOException {
+        FTPFile[] files = ftpClient.listFiles(path);
+        FtpNode node = new FtpNode(getFileName(path), true); // Root est un dossier
+        if (files != null) {
+            for (FTPFile file : files) {
+                String fullPath = path + "/" + file.getName();
+                if (file.isDirectory()) {
+                    node.children.add(buildFtpTree(ftpClient, fullPath)); // Récursif pour les dossiers
+                } else {
+                    node.children.add(new FtpNode(file.getName(), false)); // Ajouter fichier
+                }
+            }
         }
-        UriBuilder builder = uriInfo.getAbsolutePathBuilder();
-        builder.path(config.getAlias());
-        return Response.created(builder.build()).build();
-    }
-
-    @DELETE
-    @Path("/{alias}")
-    public Response removeFTPServer(@PathParam("alias") String alias) {
-        System.out.println("removeFTPServer()");
-        boolean removed = FTPServerRepository.getInstance().removeServer(alias);
-        return removed ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build();
-    }
-
-    @PUT
-    @Path("/{alias}")
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response updateFTPServer(@PathParam("alias") String alias, FTPServerConfig newConfig) {
-        System.out.println("updateFTPServer()");
-        boolean updated = FTPServerRepository.getInstance().updateServer(alias, newConfig);
-        return updated ? Response.ok(newConfig).build() : Response.status(Response.Status.NOT_FOUND).build();
+        return node;
     }
 
     @PUT
@@ -142,18 +282,45 @@ public class FTPResource {
             @PathParam("path") String path,
             @HeaderParam("X-FTP-User") String user,
             @HeaderParam("X-FTP-Pass") String pass,
+            @HeaderParam("X-Zip-Extract") Boolean extractZip,
             InputStream fileStream) {
 
-        System.out.println("uploadFile()");
         FTPServerConfig config = FTPServerRepository.getInstance().getServer(alias);
+        if (config == null) {
+            return Response.status(Response.Status.NOT_FOUND).entity("Serveur non trouvé").build();
+        }
         FTPClient ftp = new FTPClient();
         try {
             ftp.connect(config.getHost(), config.getPort());
             ftp.login(user, pass);
-            boolean success = ftp.storeFile(path, fileStream);
-            return success ? Response.ok().build() : Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+            ftp.enterLocalPassiveMode();
+            ftp.setFileType(FTP.BINARY_FILE_TYPE);
+
+            if (extractZip != null && extractZip) {
+                if (!ftp.changeWorkingDirectory(path)) {
+                    return Response.status(400).entity("Le chemin n'est pas un dossier").build();
+                }
+                ZipInputStream zis = new ZipInputStream(fileStream);
+                ZipEntry entry;
+                while ((entry = zis.getNextEntry()) != null) {
+                    String fullPath = path + "/" + entry.getName();
+                    if (entry.isDirectory()) {
+                        createDirectories(ftp, fullPath);
+                    } else {
+                        String parentDir = fullPath.substring(0, fullPath.lastIndexOf('/'));
+                        createDirectories(ftp, parentDir);
+                        ftp.storeFile(fullPath, zis);
+                    }
+                    zis.closeEntry();
+                }
+                zis.close();
+                return Response.ok().build();
+            } else {
+                boolean success = ftp.storeFile(path, fileStream);
+                return success ? Response.ok().build() : Response.status(500).entity("Erreur d'upload").build();
+            }
         } catch (IOException e) {
-            return Response.serverError().entity(e.getMessage()).build();
+            return Response.serverError().entity("Erreur FTP: " + e.getMessage()).build();
         } finally {
             try {
                 if (ftp.isConnected()) {
@@ -166,6 +333,21 @@ public class FTPResource {
         }
     }
 
+    private void createDirectories(FTPClient ftp, String path) throws IOException {
+        String[] dirs = path.split("/");
+        StringBuilder sb = new StringBuilder();
+        for (String dir : dirs) {
+            if (dir.isEmpty())
+                continue;
+            sb.append("/").append(dir);
+            String currentDir = sb.toString();
+            if (!ftp.changeWorkingDirectory(currentDir)) {
+                ftp.makeDirectory(currentDir);
+                ftp.changeWorkingDirectory(currentDir);
+            }
+        }
+    }
+
     @POST
     @Path("/{alias}/{path: .+}")
     @Consumes({ MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN })
@@ -310,4 +492,5 @@ public class FTPResource {
     private String getFileName(String path) {
         return path.substring(path.lastIndexOf('/') + 1);
     }
+    // =============================
 }