diff --git a/TD4/.gitignore b/TD4/.gitignore
deleted file mode 100644
index 5ff6309b7199129c1afe4f4ec1906e640bec48c6..0000000000000000000000000000000000000000
--- a/TD4/.gitignore
+++ /dev/null
@@ -1,38 +0,0 @@
-target/
-!.mvn/wrapper/maven-wrapper.jar
-!**/src/main/**/target/
-!**/src/test/**/target/
-
-### IntelliJ IDEA ###
-.idea/modules.xml
-.idea/jarRepositories.xml
-.idea/compiler.xml
-.idea/libraries/
-*.iws
-*.iml
-*.ipr
-
-### Eclipse ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-.sts4-cache
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-build/
-!**/src/main/**/build/
-!**/src/test/**/build/
-
-### VS Code ###
-.vscode/
-
-### Mac OS ###
-.DS_Store
\ No newline at end of file
diff --git a/TD4/pom.xml b/TD4/pom.xml
index 1831701f7aca46b6037ee03a2eeb8f82c6078148..cd8d951a5ad5a121755110d9a968759e3248c8ed 100644
--- a/TD4/pom.xml
+++ b/TD4/pom.xml
@@ -4,14 +4,64 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>fr.miage23</groupId>
+    <groupId>fr.miage23.filestore</groupId>
     <artifactId>TD4</artifactId>
     <version>1.0-SNAPSHOT</version>
+    <packaging>war</packaging>
 
     <properties>
-        <maven.compiler.source>21</maven.compiler.source>
-        <maven.compiler.target>21</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
+        <maven.compiler.release>17</maven.compiler.release>
+        <jakartaee-api.version>10.0.0</jakartaee-api.version>
+        <wildfly.version>29.0.1.Final</wildfly.version>
+        <compiler-plugin.version>3.11.0</compiler-plugin.version>
+        <war-plugin.version>3.4.0</war-plugin.version>
+        <wildfly-plugin.version>4.2.0.Final</wildfly-plugin.version>
     </properties>
 
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.platform</groupId>
+            <artifactId>jakarta.jakartaee-api</artifactId>
+            <version>${jakartaee-api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-multipart-provider</artifactId>
+            <version>6.2.6.Final</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>filestore</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${compiler-plugin.version}</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>${war-plugin.version}</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                </configuration>
+            </plugin>
+
+            <!-- Execute 'mvn clean package wildfly:dev' to run the application. -->
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <version>${wildfly-plugin.version}</version>
+                <configuration>
+                    <version>${wildfly.version}</version>
+                    <server-config>standalone-full.xml</server-config>
+                    <jbossHome>C:\Users\LB-C\Bureau\Logiciels\wildfly-29.0.1.Final</jbossHome>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>
\ No newline at end of file
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java b/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2c2b00b6f69a3779c8d7b4b2065b6ce795d4670
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/FilestoreApplication.java
@@ -0,0 +1,8 @@
+package fr.miage23.filestore.api;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+
+@ApplicationPath("api")
+public class FilestoreApplication extends Application {
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/CreateNodeDto.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/CreateNodeDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..906bc78bf267582a3a971abacfcca47633cf6dc2
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/CreateNodeDto.java
@@ -0,0 +1,38 @@
+package fr.miage23.filestore.api.dto;
+
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.core.MediaType;
+import org.jboss.resteasy.annotations.providers.multipart.PartType;
+
+import java.io.InputStream;
+
+public class CreateNodeDto {
+
+    @FormParam("name")
+    @PartType(MediaType.TEXT_PLAIN)
+    private String name;
+    @FormParam("data")
+    @PartType(MediaType.APPLICATION_OCTET_STREAM)
+    private InputStream data = null;
+
+    public CreateNodeDto() {
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public InputStream getData() {
+        return data;
+    }
+
+    public void setData(InputStream data) {
+        this.data = data;
+    }
+
+}
+
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/dto/Hello.java b/TD4/src/main/java/fr/miage23/filestore/api/dto/Hello.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ed5044a9702c030033b5e75c7b6d36f0529b38f
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/dto/Hello.java
@@ -0,0 +1,14 @@
+package fr.miage23.filestore.api.dto;
+
+public class Hello {
+
+	private String name;
+	
+	public Hello(String name) {
+        this.name = name;
+	}
+
+	public String getHello(){
+		return name;
+	}
+}
\ No newline at end of file
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/exceptions/NodeNotFoundExceptionMapper.java b/TD4/src/main/java/fr/miage23/filestore/api/exceptions/NodeNotFoundExceptionMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..09ca011fed0791d0d9d0473bb89da25193cb0540
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/exceptions/NodeNotFoundExceptionMapper.java
@@ -0,0 +1,16 @@
+package fr.miage23.filestore.api.exceptions;
+
+import fr.miage23.filestore.files.exceptions.NodeNotFoundException;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class NodeNotFoundExceptionMapper implements ExceptionMapper<NodeNotFoundException> {
+
+    @Override
+    public Response toResponse(NodeNotFoundException e) {
+        return Response.status(Response.Status.NOT_FOUND).entity(e.getMessage()).build();
+    }
+}
+
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java b/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd5cc3c5484e2f6a28391a1d6504e0fec22d5db9
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/mapper/NodeHtmlMapper.java
@@ -0,0 +1,45 @@
+package fr.miage23.filestore.api.mapper;
+
+import fr.miage23.filestore.files.entity.Node;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.Provider;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+
+@Provider
+@Produces(MediaType.TEXT_HTML)
+public class NodeHtmlMapper implements MessageBodyWriter<Node> {
+
+
+    @Override
+    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    @Override
+    public void writeTo(Node node, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
+        Writer writer = new PrintWriter(outputStream);
+        writer.write("<html><head><title>Filestore</title></head>");
+        writer.write("<body><h2>" + node.getName() + "</h2>");
+        writer.write("<ul><li>id: " + node.getId() + "</li>");
+        writer.write("<li>type: " + node.getType() + "</li>");
+        writer.write("<li>size: " + node.getSize() + "</li>");
+        writer.write("<li>creation: " + node.getCreation() + "</li>");
+        writer.write("<li>modification: " + node.getModification() + "</li>");
+        writer.write("</ul></body>");
+        writer.flush();
+        writer.close();
+    }
+}
+
+
diff --git a/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d16a38c77e8ccc574164db9e841bd6a2df553ef
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/api/resources/NodesResource.java
@@ -0,0 +1,79 @@
+package fr.miage23.filestore.api.resources;
+
+import fr.miage23.filestore.api.dto.CreateNodeDto;
+import fr.miage23.filestore.files.FileService;
+import fr.miage23.filestore.files.InMemoryFileServiceBean;
+import fr.miage23.filestore.files.entity.Node;
+import fr.miage23.filestore.files.exceptions.ContentException;
+import fr.miage23.filestore.files.exceptions.NodeAlreadyExistsException;
+import fr.miage23.filestore.files.exceptions.NodeNotFoundException;
+import fr.miage23.filestore.files.exceptions.NodeTypeException;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriInfo;
+import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@Path("nodes")
+public class NodesResource {
+
+    private FileService service = InMemoryFileServiceBean.getInstance();
+    private static final Logger LOGGER = Logger.getLogger(NodesResource.class.getName());
+    @Context
+    UriInfo uriInfo; // Injectez l'objet UriInfo pour accéder aux informations d'URI.
+
+    @GET
+    public Response redirectToDefaultNode() {
+        String defaultNodeUrl = uriInfo.getBaseUriBuilder().path("nodes/root").build().toString();
+        return Response.seeOther(URI.create(defaultNodeUrl)).build();
+    }
+
+    @GET
+    @Path("{id}")
+    @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
+    public Node getNode(@PathParam("id") String id) throws NodeNotFoundException {
+        LOGGER.log(Level.INFO, "GET /api/nodes/" + id);
+        return service.get(id);
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response createNode(@FormParam("id") String id, @FormParam("name") String name, @Context UriInfo uriInfo) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException {
+        LOGGER.log(Level.INFO, "POST /api/nodes/" + id);
+        String newid = service.add(id, name);
+        return Response.created(uriInfo.getBaseUriBuilder().path(NodesResource.class).path(newid).build()).entity(newid).build();
+    }
+
+    @POST
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response createNodeWithPath(@PathParam("id") String id, @FormParam("name") String name, @Context UriInfo uriInfo) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException {
+        LOGGER.log(Level.INFO, "POST /api/nodes/" + id);
+        String newid = service.add(id, name);
+        return Response.created(uriInfo.getBaseUriBuilder().path(NodesResource.class).path(newid).build()).entity(newid).build();
+    }
+
+    @POST
+    @Path("{id}")
+    @Produces(MediaType.TEXT_HTML)
+    @Consumes(MediaType.MULTIPART_FORM_DATA)
+    public Response createView(@PathParam("id") final String id, @MultipartForm CreateNodeDto dto, @Context UriInfo info) throws NodeNotFoundException, NodeTypeException, NodeAlreadyExistsException, ContentException, IOException {
+        LOGGER.log(Level.INFO, "POST /api/nodes/" + id + " (html)");
+        if (dto.getData() != null) {
+            service.add(id, dto.getName(), dto.getData());
+        } else {
+            service.add(id, dto.getName());
+        }
+        URI createdUri = info.getBaseUriBuilder().path(NodesResource.class).path(id).path("content").build();
+        return Response.seeOther(createdUri).build();
+    }
+
+
+}
+
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/FileService.java b/TD4/src/main/java/fr/miage23/filestore/files/FileService.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd636788f98bc3c3ad43c182626f146496c78f6d
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/FileService.java
@@ -0,0 +1,27 @@
+package fr.miage23.filestore.files;
+
+import fr.miage23.filestore.files.entity.Node;
+import fr.miage23.filestore.files.exceptions.*;
+
+import java.io.InputStream;
+import java.util.List;
+
+public interface FileService {
+
+    String ROOT_NODE_ID = "root";
+    String TREE_NODE_MIMETYPE = "application/fs-folder";
+
+    List<Node> list(String id) throws NodeNotFoundException;
+
+    Node get(String id) throws NodeNotFoundException;
+
+    InputStream getContent(String id) throws NodeNotFoundException, NodeTypeException, ContentException;
+
+    String add(String parent, String name) throws NodeNotFoundException, NodeAlreadyExistsException, NodeTypeException;
+
+    String add(String parent, String name, InputStream content) throws NodeNotFoundException, NodeAlreadyExistsException, NodeTypeException, ContentException;
+
+    void remove(String parent, String name) throws NodeNotFoundException, NodeNotEmptyException, NodeTypeException;
+
+
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java b/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..1882b32ae9904352785028992a2d0f93faa3ee07
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/InMemoryFileServiceBean.java
@@ -0,0 +1,147 @@
+package fr.miage23.filestore.files;
+
+import fr.miage23.filestore.files.entity.Node;
+import fr.miage23.filestore.files.exceptions.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+public class InMemoryFileServiceBean implements FileService {
+
+    private static final Logger LOGGER = Logger.getLogger(InMemoryFileServiceBean.class.getName());
+
+    private static Map<String, Node> nodes;
+    private static Map<String, byte[]> contents;
+
+    private static final class InstanceHolder {
+        private static final FileService instance = new InMemoryFileServiceBean();
+    }
+
+    public static FileService getInstance(){
+        return InstanceHolder.instance;
+    }
+
+    private InMemoryFileServiceBean() {
+        LOGGER.log(Level.INFO, "Instantiating file service bean");
+        contents = new HashMap<>();
+        nodes = new ConcurrentHashMap<>();
+        Node root = new Node(Node.Type.TREE, "", ROOT_NODE_ID, "root");
+        nodes.put(root.getId(), root);
+    }
+
+    @Override
+    public List<Node> list(String parent) throws NodeNotFoundException {
+        String pid = (parent == null || parent.isEmpty())? ROOT_NODE_ID:parent;
+        LOGGER.log(Level.INFO, "Listing nodes for parent: " + pid);
+        if (!nodes.containsKey(pid)) {
+            throw new NodeNotFoundException("unable to find a node with id " + pid + " in the storage");
+        }
+        return nodes.values().stream().filter(n -> n.getParent().equals(pid)).collect(Collectors.toList());
+    }
+
+    @Override
+    public Node get(String id) throws NodeNotFoundException {
+        LOGGER.log(Level.INFO, "Getting node with id: " + id);
+        if (!nodes.containsKey(id)) {
+            throw new NodeNotFoundException("unable to find a node with id " + id + " in the storage");
+        }
+        return nodes.get(id);
+    }
+
+    @Override
+    public InputStream getContent(String id) throws NodeNotFoundException, NodeTypeException, ContentException {
+        LOGGER.log(Level.INFO, "Getting content for node with id: " + id);
+        if (!nodes.containsKey(id)) {
+            throw new NodeNotFoundException("unable to find a node with id " + id + " in the storage");
+        }
+        Node node = nodes.get(id);
+        if (!node.getType().equals(Node.Type.BLOB)) {
+            throw new NodeTypeException("only node of type BLOB have content");
+        }
+        if (!contents.containsKey(node.getContent())) {
+            throw new ContentException("unable to find node content with id: " + node.getContent() + " in storage");
+        }
+        return new ByteArrayInputStream(contents.get(node.getContent()));
+    }
+
+    @Override
+    public String add(String parent, String name) throws NodeNotFoundException, NodeAlreadyExistsException, NodeTypeException {
+        String pid = (parent == null || parent.isEmpty())? ROOT_NODE_ID:parent;
+        LOGGER.log(Level.INFO, "Adding TREE node with name: " + name + " for parent with id: " + pid);
+        if (!nodes.containsKey(pid)) {
+            throw new NodeNotFoundException("Unable to find a node with id: " + pid);
+        }
+        Node pnode = nodes.get(pid);
+        if (!pnode.getType().equals(Node.Type.TREE)) {
+            throw new NodeTypeException("Parent must be a node of type TREE");
+        }
+        if (nodes.values().stream().filter(n -> n.getParent().equals(pid)).anyMatch(n -> n.getName().equals(name))) {
+            throw new NodeAlreadyExistsException("A node with name: " + name + " already exists in tree with id: " + pid);
+        }
+        Node node = new Node(Node.Type.TREE, pid, UUID.randomUUID().toString(), name);
+        nodes.put(node.getId(), node);
+        pnode.setSize(pnode.getSize()+1);
+        return node.getId();
+    }
+
+    @Override
+    public String add(String parent, String name, InputStream content) throws NodeNotFoundException, NodeAlreadyExistsException, NodeTypeException, ContentException {
+        String pid = (parent == null || parent.isEmpty())? ROOT_NODE_ID:parent;
+        LOGGER.log(Level.INFO, "Adding BLOB node with name: " + name + " for parent with id: " + pid);
+        if (!nodes.containsKey(pid)) {
+            throw new NodeNotFoundException("Unable to find a parent node with id: " + pid);
+        }
+        Node pnode = nodes.get(pid);
+        if (!pnode.getType().equals(Node.Type.TREE)) {
+            throw new NodeTypeException("Parent must be a node of type TREE");
+        }
+        if (nodes.values().stream().filter(n -> n.getParent().equals(pid)).anyMatch(n -> n.getName().equals(name))) {
+            throw new NodeAlreadyExistsException("A node with name: " + name + " already exists in tree with id: " + pid);
+        }
+        String cid = UUID.randomUUID().toString();
+        try {
+            contents.put(cid, content.readAllBytes());
+            Node node = new Node(Node.Type.BLOB, pid, UUID.randomUUID().toString(), name);
+            node.setContent(cid);
+            node.setSize(contents.get(cid).length);
+            node.setMimetype("application/octet-stream");
+            nodes.put(node.getId(), node);
+            pnode.setSize(pnode.getSize()+1);
+            return node.getId();
+        } catch (IOException e) {
+            throw new ContentException("unable to read file content", e);
+        }
+    }
+
+    @Override
+    public void remove(String parent, String name) throws NodeNotFoundException, NodeNotEmptyException, NodeTypeException {
+        String pid = (parent == null || parent.isEmpty())? ROOT_NODE_ID:parent;
+        LOGGER.log(Level.FINE, "Remove node with name: " + name + " and parent: " + pid);
+        if (!nodes.containsKey(pid)) {
+            throw new NodeNotFoundException("Unable to find a parent node with id: " + pid);
+        }
+        Node pnode = nodes.get(pid);
+        if (!pnode.getType().equals(Node.Type.TREE)) {
+            throw new NodeTypeException("Parent must be a node of type TREE");
+        }
+        Optional<Node> node = nodes.values().stream().filter(n -> n.getParent().equals(pid)).filter(n -> n.getName().equals(name)).findAny();
+        if (node.isEmpty()) {
+            throw new NodeNotFoundException("A node with name: " + name + " does not exists in tree with id: " + pid);
+        }
+        if (node.get().getType().equals(Node.Type.TREE) && nodes.values().stream().anyMatch(n -> n.getParent().equals(node.get().getId()))) {
+            throw new NodeNotEmptyException("The node with name: " + name + " is not empty");
+        }
+        if (node.get().getType().equals(Node.Type.BLOB)) {
+            contents.remove(node.get().getContent());
+        }
+        nodes.remove(node.get().getId());
+        pnode.setSize(pnode.getSize()-1);
+    }
+
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java b/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9929a80a6db15e965d7a88947d86fc24a6b5be5
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/entity/Node.java
@@ -0,0 +1,193 @@
+package fr.miage23.filestore.files.entity;
+
+import fr.miage23.filestore.files.FileService;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Objects;
+
+public class Node implements Comparable<Node>, Serializable {
+
+    private Type type;
+    private String id;
+    private long version;
+    private String parent;
+    private String name;
+    private String mimetype;
+    private long size;
+    private long creation;
+    private long modification;
+    private String content;
+
+    public Node() {
+        this.creation = this.modification = System.currentTimeMillis();
+        this.size = 0;
+    }
+
+    public Node(Type type, String parent, String id, String name) {
+        this();
+        this.parent = parent;
+        this.type = type;
+        this.id = id;
+        this.name = name;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    public void setType(Type type) {
+        this.type = type;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+
+    public void setVersion(long version) {
+        this.version = version;
+    }
+
+    public String getParent() {
+        return parent;
+    }
+
+    public void setParent(String parent) {
+        this.parent = parent;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getMimetype() {
+        return mimetype;
+    }
+
+    public void setMimetype(String mimetype) {
+        this.mimetype = mimetype;
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public void setSize(long size) {
+        this.size = size;
+    }
+
+    public long getCreation() {
+        return creation;
+    }
+
+    public void setCreation(long creation) {
+        this.creation = creation;
+    }
+
+    public long getModification() {
+        return modification;
+    }
+
+    public void setModification(long modification) {
+        this.modification = modification;
+    }
+
+    public boolean isRoot() {
+        return this.id.equals(FileService.ROOT_NODE_ID);
+    }
+
+    public boolean isFolder() {
+        return this.type.equals(Type.TREE);
+    }
+
+    public enum Type {
+        TREE,
+        BLOB
+    }
+
+    @Override
+    public int compareTo(Node o) {
+        if (this.getType().equals(o.getType())) {
+            return this.getName().compareTo(o.getName());
+        } else if (this.getType().equals(Type.TREE)){
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Node node = (Node) o;
+        return creation == node.creation && modification == node.modification && type == node.type && Objects.equals(id, node.id) && Objects.equals(name, node.name) && Objects.equals(content, node.content) && Objects.equals(mimetype, node.mimetype);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, id, name, content, mimetype, creation, modification);
+    }
+
+    @Override
+    public String toString() {
+        return "Node{" +
+                "type=" + type +
+                ", id='" + id + '\'' +
+                ", version=" + version +
+                ", parent='" + parent + '\'' +
+                ", name='" + name + '\'' +
+                ", mimetype='" + mimetype + '\'' +
+                ", size=" + size +
+                ", creation=" + creation +
+                ", modification=" + modification +
+                ", content='" + content + '\'' +
+                '}';
+    }
+
+    public static class NameComparatorAsc implements Comparator<Node> {
+        @Override
+        public int compare(Node o1, Node o2) {
+            if ( o1.isFolder() && !o2.isFolder() ) {
+                return -1;
+            }
+            if ( !o1.isFolder() && o2.isFolder() ) {
+                return 1;
+            }
+            return o1.getName().compareTo(o2.getName());
+        }
+    }
+
+    public static class NameComparatorDesc implements Comparator<Node> {
+        @Override
+        public int compare(Node o1, Node o2) {
+            if ( o1.isFolder() && !o2.isFolder() ) {
+                return -1;
+            }
+            if ( !o1.isFolder() && o2.isFolder() ) {
+                return 1;
+            }
+            return o2.getName().compareTo(o1.getName());
+        }
+    }
+}
\ No newline at end of file
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/exceptions/ContentException.java b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/ContentException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a4e0fa71cab5842c4f4b6067ea2ac75932d6d0d
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/ContentException.java
@@ -0,0 +1,11 @@
+package fr.miage23.filestore.files.exceptions;
+
+public class ContentException extends Exception {
+
+    public ContentException(String message) {
+        super(message);
+    }
+    public ContentException(String message, Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeAlreadyExistsException.java b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeAlreadyExistsException.java
new file mode 100644
index 0000000000000000000000000000000000000000..529f709719743737912904faf877613344109ae3
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeAlreadyExistsException.java
@@ -0,0 +1,7 @@
+package fr.miage23.filestore.files.exceptions;
+
+public class NodeAlreadyExistsException extends Exception {
+    public NodeAlreadyExistsException(String message) {
+        super(message);
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotEmptyException.java b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotEmptyException.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e97d12176e04ce4fcca342fae01e6aedaf2faab
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotEmptyException.java
@@ -0,0 +1,7 @@
+package fr.miage23.filestore.files.exceptions;
+
+public class NodeNotEmptyException extends Exception {
+    public NodeNotEmptyException(String message) {
+        super(message);
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotFoundException.java b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..0995a3a5fa74983711f6a3ceb38019fcee2d4043
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeNotFoundException.java
@@ -0,0 +1,11 @@
+package fr.miage23.filestore.files.exceptions;
+
+public class NodeNotFoundException extends Exception {
+    public NodeNotFoundException(String message) {
+        super(message);
+    }
+
+    public NodeNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeTypeException.java b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeTypeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a845ded18dc5ea6aa3922b54f55cef6bd2dcec2
--- /dev/null
+++ b/TD4/src/main/java/fr/miage23/filestore/files/exceptions/NodeTypeException.java
@@ -0,0 +1,7 @@
+package fr.miage23.filestore.files.exceptions;
+
+public class NodeTypeException extends Exception {
+    public NodeTypeException(String message) {
+        super(message);
+    }
+}
diff --git a/TD4/src/main/webapp/WEB-INF/web.xml b/TD4/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d15a96f24b32bfe21ee5303c86aaf6dada59cb2c
--- /dev/null
+++ b/TD4/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
+         version="6.0">
+
+
+</web-app>
\ No newline at end of file
diff --git a/TD4/src/main/webapp/index.html b/TD4/src/main/webapp/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..3d75f9217c227599bd4cc31560f7e7a462709ca7
--- /dev/null
+++ b/TD4/src/main/webapp/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>Welcome to Filestore!</title>
+</head>
+<body>
+	<h2>Welcome!</h2>
+</body>
+</html>
\ No newline at end of file
diff --git a/TD4/src/site/site.xml b/TD4/src/site/site.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1285a50a8a0c67f251e0ff7059cc9b6b4d4f9c05
--- /dev/null
+++ b/TD4/src/site/site.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Maven" xmlns="http://maven.apache.org/DECORATION/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+    <bannerLeft>
+        <name>Miage FileStore project</name>
+        <src>http://maven.apache.org/images/apache-maven-project.png</src>
+        <href>http://maven.apache.org/</href>
+    </bannerLeft>
+    <bannerRight>
+        <src>http://maven.apache.org/images/maven-small.gif</src>
+    </bannerRight>
+    <body>
+        <links>
+            <item name="Apache" href="http://www.apache.org/" />
+            <item name="Maven 1.0" href="http://maven.apache.org/"/>
+            <item name="Maven 2" href="http://maven.apache.org/maven2/"/>
+        </links>
+        <menu name="Maven 2.0">
+            <item name="Introduction" href="intro.html"/>
+        </menu>
+    </body>
+</project>