diff --git a/.eslintrc.js b/.eslintrc.js
index af6684f5fa25103b99509cad538e95995403cf41..bee267378c3cc4b67bf8cd3dc6bfd97578fa52ca 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -25,6 +25,7 @@ module.exports = {
         { "allowWholeFile": true }
       ],
     "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], // will only ignore variables that start with an underscore _
+    "@typescript-eslint/no-inferrable-types": "off", // this enforces the removal of the type declarations for variables that are initialized with a value (e.g. let foo: string = "foo")
     "vue/multi-word-component-names": "off"
   },
 }
diff --git a/package.json b/package.json
index ddcaf4e0098a630619d85b05900143449f6ed996..ed5252c419779c681b4c794139f8709b04c48646 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
     "coverage": "vitest run --coverage"
   },
   "dependencies": {
-    "@coscine/api-client": "^3.0.0",
+    "@coscine/api-client": "^3.1.0",
     "@coscine/form-generator": "^3.2.2",
     "@dynamic-mapper/mapper": "^1.10.2",
     "@pinia/testing": "^0.1.2",
@@ -92,6 +92,7 @@
     "vite": "^4.3.9",
     "vite-aliases": "^0.11.2",
     "vite-plugin-node-polyfills": "^0.9.0",
+    "vite-plugin-rewrite-all": "^1.0.1",
     "vite-plugin-windicss": "^1.9.0",
     "vitest": "^0.32.2",
     "vue-template-compiler": "^2.7.14"
diff --git a/src/components/coscine/CoscineFormGroup.vue b/src/components/coscine/CoscineFormGroup.vue
index 5e636e6fe129ae7b387c8e39cef5feadaf5ad8ad..43feda82f887ce82304fd2d9bf6b8a59722a1b8f 100644
--- a/src/components/coscine/CoscineFormGroup.vue
+++ b/src/components/coscine/CoscineFormGroup.vue
@@ -1,45 +1,55 @@
 <template>
-  <b-form-group
-    :class="mandatory === true ? 'mandatory' : ''"
-    :label-for="labelFor"
-    :label-cols-sm="labelColsSm"
-    :label-align-sm="labelAlignSm"
-  >
-    <!-- Loading Skeleton -->
-    <b-skeleton-wrapper :loading="isLoading">
-      <template #loading>
-        <b-skeleton :type="type" animation="fade"></b-skeleton>
-      </template>
-      <slot />
-    </b-skeleton-wrapper>
+  <b-container class="mb-3 p-0 w-100">
+    <b-row no-gutters>
+      <b-form-group
+        class="w-100 m-0"
+        :class="mandatory === true ? 'mandatory' : ''"
+        :label-for="labelFor"
+        :label-cols-sm="labelColsSm"
+        :label-align-sm="labelAlignSm"
+      >
+        <!-- Loading Skeleton -->
+        <b-skeleton-wrapper :loading="isLoading">
+          <template #loading>
+            <b-skeleton :type="type" animation="fade"></b-skeleton>
+          </template>
 
-    <!-- Label Template -->
-    <template #label>
-      <!-- Label -->
-      <span id="label" class="text-break">{{ label }}</span>
+          <div class="flex-center">
+            <slot />
+          </div>
+        </b-skeleton-wrapper>
 
-      <div v-if="info" class="d-inline ml-1">
-        <!-- Information Circle Icon -->
-        <b-icon :id="`${labelFor}Info`" icon="info-circle" />
+        <!-- Label Template -->
+        <template #label>
+          <!-- Label -->
+          <span id="label" class="text-break">{{ label }}</span>
 
-        <!-- Popover -->
-        <b-popover
-          over
-          :target="`${labelFor}Info`"
-          triggers="hover focus"
-          placement="bottom"
-        >
-          <!-- Popover Contents -->
-          <slot name="popover" />
-        </b-popover>
-      </div>
-    </template>
+          <div v-if="info" class="d-inline ml-1">
+            <!-- Information Circle Icon -->
+            <b-icon :id="`${labelFor}Info`" icon="info-circle" />
 
-    <!-- Hint Text -->
-    <div id="hint" class="small text-muted">
-      <slot name="hint" />
-    </div>
-  </b-form-group>
+            <!-- Popover -->
+            <b-popover
+              over
+              :target="`${labelFor}Info`"
+              triggers="hover focus"
+              placement="bottom"
+            >
+              <!-- Popover Contents -->
+              <slot name="popover" />
+            </b-popover>
+          </div>
+        </template>
+      </b-form-group>
+    </b-row>
+    <b-row no-gutters>
+      <b-col :sm="labelColsSm" />
+      <!-- Hint Text -->
+      <b-col id="hint" class="small text-muted pl-1" align-self="end">
+        <slot name="hint" />
+      </b-col>
+    </b-row>
+  </b-container>
 </template>
 
 <script lang="ts">
@@ -90,4 +100,18 @@ export default defineComponent({
   content: " *";
   color: #a70619;
 }
+.flex-center {
+  /* Needed to center the content vertically */
+  display: flex;
+  align-items: center;
+  height: 100%;
+  width: 100%;
+}
+#hint {
+  position: relative;
+}
+.form-row :deep(.col) {
+  /* Removes the right padding from the inner col, making it go until the end */
+  padding: 0 0 0 5px;
+}
 </style>
diff --git a/src/components/elements/BreadCrumbs.vue b/src/components/elements/BreadCrumbs.vue
index de4f63aadb9bac5afaa16d8a8a9412f06dea5f6e..b99f12c01a0dd3d13dff34382a3dd1c460989073 100644
--- a/src/components/elements/BreadCrumbs.vue
+++ b/src/components/elements/BreadCrumbs.vue
@@ -1,10 +1,13 @@
 <template>
   <b-breadcrumb class="breadcrumbs">
+    <!-- Home -->
     <b-breadcrumb-item :to="{ name: 'home' }" :active="crumbs.length === 0">
       <b-icon v-if="crumbs.length === 0" icon="house-fill" aria-hidden="true" />
       <b-icon v-else icon="house" aria-hidden="true" />
       {{ $t(`breadcrumbs.home`) }}
     </b-breadcrumb-item>
+
+    <!-- Rest -->
     <b-breadcrumb-item
       v-for="(crumb, id) in crumbs"
       :key="id"
@@ -29,6 +32,7 @@ import type {
   ProjectDto,
   ResourceDto,
 } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type { RouteRecord } from "vue-router";
 
 interface RouteLink {
   to: RawLocation;
@@ -46,72 +50,14 @@ export default defineComponent({
 
   computed: {
     crumbs(): RouteLink[] {
-      let pathArray = this.$route.path.split("/");
-      pathArray = pathArray.filter(
-        (path) =>
-          path.trim() !== "" && path.trim() !== "p" && path.trim() !== "r"
-      );
-      // Deal with Root Path inclusion
-      if (pathArray.length === 1) {
-        pathArray.unshift("");
-      }
-      const breadcrumbs = pathArray.reduce(
-        (breadcrumbArray: RouteLink[], path, idx) => {
-          // Deal with Root Path inclusion
-          if (path === "") {
-            return breadcrumbArray;
-          }
-          breadcrumbArray.push({
-            to: {
-              name: this.$route.matched[idx].name
-                ? this.$route.matched[idx].name
-                : this.$route.matched[idx].meta.default,
-            },
-            text:
-              this.$route.matched[idx] &&
-              this.$route.matched[idx].meta &&
-              this.$route.matched[idx].meta.breadCrumb
-                ? this.$t(
-                    `breadcrumbs.${this.$route.matched[idx].meta.breadCrumb}`,
-                    {
-                      path: path,
-                      projectName: this.project
-                        ? this.project.displayName
-                        : path,
-                      resourceName:
-                        this.resource && this.resource.type
-                          ? `${this.$t(
-                              "resourceTypes." +
-                                this.resource.type.specificType +
-                                ".displayName"
-                            )}: ${this.resource.displayName}`
-                          : path,
-                    }
-                  ).toString()
-                : path,
-          });
-          return breadcrumbArray;
-        },
-        []
-      );
-      if (this.project && this.parentProjects) {
-        const parentBreadCrumbs = this.parentProjects.map((parentProject) => {
-          return {
-            to: {
-              name: "project-page",
-              params: { slug: parentProject.slug },
-            },
-            text: this.$t(`breadcrumbs.project.page`, {
-              projectName: parentProject.displayName,
-            }).toString(),
-          } as RouteLink;
-        });
-        breadcrumbs.unshift(...parentBreadCrumbs);
-      }
-      if (breadcrumbs.length > 0) {
-        breadcrumbs[breadcrumbs.length - 1].active = true;
-      }
-      return breadcrumbs;
+      // Get the relevant path from the route (ignores everything after "/-")
+      const relevantPath = this.$route.path.split("/-")[0];
+      // Filter out empty paths and the project and resource path
+      let pathArray = this.filterPaths(relevantPath.split("/"));
+      pathArray = this.includeRootPath(pathArray);
+      let breadcrumbs = this.generateRouteLinks(pathArray);
+      breadcrumbs = this.addParentProjects(breadcrumbs);
+      return this.markLastActive(breadcrumbs);
     },
 
     parentProjects(): ProjectDto[] | null {
@@ -155,7 +101,11 @@ export default defineComponent({
   },
 
   methods: {
-    setDocumentTitle(title = "") {
+    /**
+     * Set the document title.
+     * @param {string} [title=""] - The title to set. If empty, the default title will be used.
+     */
+    setDocumentTitle(title: string = "") {
       if (title.trim() !== "") {
         document.title = this.$t("title.modified", {
           title: title,
@@ -164,6 +114,126 @@ export default defineComponent({
         document.title = this.$t("title.default").toString();
       }
     },
+
+    /**
+     * Filters out unwanted paths from the given array.
+     * @param {string[]} paths - The array of paths.
+     * @returns {string[]} - The filtered array of paths.
+     */
+    filterPaths(paths: string[]): string[] {
+      return paths.filter(
+        (path) =>
+          path.trim() !== "" &&
+          path.trim() !== "p" &&
+          path.trim() !== "r" &&
+          path.trim() !== "-"
+      );
+    },
+
+    /**
+     * Adds a root path if the path array contains only one element.
+     * @param {string[]} pathArray - The array of paths.
+     * @returns {string[]} - The array of paths possibly including the root.
+     */
+    includeRootPath(pathArray: string[]): string[] {
+      if (pathArray.length === 1) {
+        pathArray.unshift("");
+      }
+      return pathArray;
+    },
+
+    /**
+     * Generates RouteLink objects based on the path array.
+     * @param {string[]} pathArray - The array of paths.
+     * @returns {RouteLink[]} - The array of RouteLink objects.
+     */
+    generateRouteLinks(pathArray: string[]): RouteLink[] {
+      return pathArray.reduce((breadcrumbArray: RouteLink[], path, idx) => {
+        if (path === "") return breadcrumbArray;
+        const routeMatched = this.$route.matched[idx];
+        if (routeMatched) {
+          breadcrumbArray.push(this.generateRouteLink(routeMatched, path));
+        }
+        return breadcrumbArray;
+      }, []);
+    },
+
+    /**
+     * Generates a single RouteLink object.
+     * @param {RouteRecord} routeMatched - The matched route record.
+     * @param {string} path - The path segment for this breadcrumb.
+     * @returns {RouteLink} - The RouteLink object.
+     */
+    generateRouteLink(routeMatched: RouteRecord, path: string): RouteLink {
+      return {
+        to: {
+          name: routeMatched.name
+            ? routeMatched.name
+            : routeMatched.meta.default,
+        },
+        text: routeMatched?.meta?.breadCrumb
+          ? this.$t(`breadcrumbs.${routeMatched.meta.breadCrumb}`, {
+              path: path,
+              projectName: this.project ? this.project.displayName : path,
+              resourceName: this.resource ? this.resourceDisplayName() : path,
+            }).toString()
+          : path,
+      } as RouteLink;
+    },
+
+    /**
+     * Retrieves the display name of the resource if available.
+     * @returns {string} - The display name of the resource or an empty string.
+     */
+    resourceDisplayName(): string {
+      if (this.resource?.displayName) {
+        if (this.resource.type?.specificType) {
+          // e.g. "RWTH-RDS-S3: My Resource Name"
+          return `${this.$t(
+            "resourceTypes." + this.resource.type.specificType + ".displayName"
+          )}: ${this.resource.displayName}`;
+        }
+        return this.resource.displayName;
+      }
+      return "";
+    },
+
+    /**
+     * Adds parent projects to the breadcrumb array.
+     * @param {RouteLink[]} breadcrumbs - The existing array of RouteLink objects.
+     * @returns {RouteLink[]} - The updated array of RouteLink objects.
+     */
+    addParentProjects(breadcrumbs: RouteLink[]): RouteLink[] {
+      if (this.project && this.parentProjects) {
+        const parentBreadCrumbs: RouteLink[] = this.parentProjects.map(
+          (parentProject) => {
+            return {
+              to: {
+                name: "project-page",
+                params: { slug: parentProject.slug },
+              },
+              text: this.$t(`breadcrumbs.project.page`, {
+                projectName: parentProject.displayName,
+              }).toString(),
+            } as RouteLink;
+          }
+        );
+        breadcrumbs.unshift(...parentBreadCrumbs);
+      }
+      return breadcrumbs;
+    },
+
+    /**
+     * Marks the last breadcrumb as active.
+     * @param {RouteLink[]} breadcrumbs - The existing array of RouteLink objects.
+     * @returns {RouteLink[]} - The updated array of RouteLink objects.
+     */
+    markLastActive(breadcrumbs: RouteLink[]): RouteLink[] {
+      if (breadcrumbs.length > 0) {
+        breadcrumbs[breadcrumbs.length - 1].active = true;
+      }
+      return breadcrumbs;
+    },
   },
 });
 </script>
diff --git a/src/components/elements/SidebarMenu.vue b/src/components/elements/SidebarMenu.vue
index b84af98d74df1b0421903347b1ac437135292da7..4986a4773503d1a9e12ad83b623ee5369816346f 100644
--- a/src/components/elements/SidebarMenu.vue
+++ b/src/components/elements/SidebarMenu.vue
@@ -166,6 +166,7 @@ export default defineComponent({
                   params: {
                     slug: this.project ? this.project.slug : undefined,
                     guid: resource.id,
+                    dirTrail: "",
                   },
                 },
                 icon: "bi bi-archive",
diff --git a/src/data/mockup/metadata/applicationProfile.ts b/src/data/mockup/metadata/applicationProfile.ts
index 9d58c11d07010a592d9f6eb3a0b67a7994305cf7..7a12b125de9b1c1b5c2ec9704c4731c857f0d8f9 100644
--- a/src/data/mockup/metadata/applicationProfile.ts
+++ b/src/data/mockup/metadata/applicationProfile.ts
@@ -1 +1,2 @@
-export const radarApplicationProfile = `[{"@id":"https://purl.org/coscine/ap/radar/","@graph":[{"@id":"https://purl.org/coscine/ap/radar#subject","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/subject"}],"http://www.w3.org/ns/shacl#order":[{"@value":"3","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#class":[{"@id":"http://www.dfg.de/dfg_profil/gremien/fachkollegien/faecher/"}],"http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Fachrichtung"},{"@language":"en","@value":"Subject Area"}]},{"@id":"https://purl.org/coscine/ap/radar#created","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/created"}],"http://www.w3.org/ns/shacl#order":[{"@value":"2","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Production Date"},{"@language":"de","@value":"Erstelldatum"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#date"}],"http://www.w3.org/ns/shacl#defaultValue":[{"@value":"{TODAY}"}]},{"@id":"https://purl.org/coscine/ap/radar#creator","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/creator"}],"http://www.w3.org/ns/shacl#order":[{"@value":"0","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Ersteller"},{"@language":"en","@value":"Creator"}],"http://www.w3.org/ns/shacl#minLength":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}],"http://www.w3.org/ns/shacl#defaultValue":[{"@value":"{ME}"}]},{"@id":"https://purl.org/coscine/ap/radar#rights","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/rights"}],"http://www.w3.org/ns/shacl#order":[{"@value":"5","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Rights"},{"@language":"de","@value":"Berechtigung"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}]},{"@id":"https://purl.org/coscine/ap/radar#rightsHolder","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/rightsHolder"}],"http://www.w3.org/ns/shacl#order":[{"@value":"6","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Rightsholder"},{"@language":"de","@value":"Rechteinhaber"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}]},{"@id":"https://purl.org/coscine/ap/radar#title","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/title"}],"http://www.w3.org/ns/shacl#order":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Titel"},{"@language":"en","@value":"Title"}],"http://www.w3.org/ns/shacl#minLength":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}]},{"@id":"https://purl.org/coscine/ap/radar#type","http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/type"}],"http://www.w3.org/ns/shacl#order":[{"@value":"4","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#class":[{"@id":"http://purl.org/dc/dcmitype/"}],"http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Resource"},{"@language":"de","@value":"Ressource"}]},{"@id":"https://purl.org/coscine/ap/radar/","@type":["http://www.w3.org/ns/shacl#NodeShape"],"http://purl.org/dc/terms/license":[{"@id":"http://spdx.org/licenses/MIT"}],"http://purl.org/dc/terms/rights":[{"@value":"Copyright © 2020 IT Center, RWTH Aachen University"}],"http://www.w3.org/ns/shacl#targetClass":[{"@id":"https://purl.org/coscine/ap/radar/"}],"http://www.w3.org/ns/shacl#closed":[{"@value":"true","@type":"http://www.w3.org/2001/XMLSchema#boolean"}],"http://www.w3.org/ns/shacl#property":[{"@id":"https://purl.org/coscine/ap/radar#creator"},{"@id":"https://purl.org/coscine/ap/radar#rights"},{"@id":"https://purl.org/coscine/ap/radar#subject"},{"@id":"https://purl.org/coscine/ap/radar#created"},{"@id":"https://purl.org/coscine/ap/radar#type"},{"@id":"_:b8922734"},{"@id":"https://purl.org/coscine/ap/radar#rightsHolder"},{"@id":"https://purl.org/coscine/ap/radar#title"}],"http://purl.org/dc/terms/title":[{"@language":"en","@value":"radar application profile"}],"http://purl.org/dc/terms/publisher":[{"@id":"https://itc.rwth-aachen.de/"}],"http://purl.org/dc/terms/description":[{"@value":"The RADAR metadata schema v09 was created by the 2018 FIZ Karlsruhe - Leibniz-Institut fuer Informationsinfrastruktur GmbH and has been published under CC BY 4.0."}]},{"@id":"_:b8922734","http://www.w3.org/ns/shacl#path":[{"@id":"http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}]}]}]`;
+export const baseApplicationProfile = `[{"@id":"_:b6482494","http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#order":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Creator"},{"@language":"de","@value":"Ersteller"}],"http://www.w3.org/ns/shacl#description":[{"@language":"de","@value":"Wer ist der Ersteller der Daten?"},{"@language":"en","@value":"Who is the creator of the data?"}],"http://www.w3.org/ns/shacl#defaultValue":[{"@value":"{ME}"}],"http://www.w3.org/ns/shacl#minLength":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/creator"}]},{"@id":"_:b6482495","http://www.w3.org/ns/shacl#description":[{"@language":"de","@value":"Von welchem Datentyp sind Ihre Daten?"},{"@language":"en","@value":"What type of data is your data?"}],"http://www.w3.org/ns/shacl#order":[{"@value":"4","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#class":[{"@id":"http://purl.org/dc/dcmitype/"}],"http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/type"}],"http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Typ"},{"@language":"en","@value":"Type"}]},{"@id":"https://purl.org/coscine/ap/base/","http://purl.org/dc/terms/title":[{"@language":"en","@value":"Base Profile"},{"@language":"de","@value":"Basisprofil"}],"http://purl.org/dc/terms/creator":[{"@value":"Hanna Führ"}],"http://www.w3.org/ns/shacl#closed":[{"@value":"false","@type":"http://www.w3.org/2001/XMLSchema#boolean"}],"@type":["http://www.w3.org/ns/shacl#NodeShape"],"http://www.w3.org/ns/shacl#targetClass":[{"@id":"https://purl.org/coscine/ap/base/"}],"http://www.w3.org/ns/shacl#property":[{"@id":"_:b6482493"},{"@id":"_:b6482496"},{"@id":"_:b6482494"},{"@id":"_:b6482497"},{"@id":"_:b6482495"}],"http://purl.org/dc/terms/description":[{"@language":"de","@value":"Basisprofil, das Grundbausteine enthält"},{"@language":"en","@value":"Base application profile, which contains the basic building blocks"}],"http://purl.org/dc/terms/created":[{"@value":"2023-02-06","@type":"http://www.w3.org/2001/XMLSchema#date"}],"http://purl.org/dc/terms/license":[{"@value":"https://spdx.org/licenses/CC-BY-4.0.html"}]},{"@id":"_:b6482497","http://www.w3.org/ns/shacl#name":[{"@language":"en","@value":"Creation Date"},{"@language":"de","@value":"Erstellungsdatum"}],"http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/created"}],"http://www.w3.org/ns/shacl#defaultValue":[{"@value":"{TODAY}"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#date"}],"http://www.w3.org/ns/shacl#description":[{"@language":"en","@value":"When was the data created?"},{"@language":"de","@value":"Wann wurden die Daten erstellt?"}],"http://www.w3.org/ns/shacl#order":[{"@value":"2","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#maxCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}]},{"@id":"_:b6482493","http://www.w3.org/ns/shacl#description":[{"@language":"en","@value":"Which subject does your data belong to?"},{"@language":"de","@value":"Welcher Fachrichtung gehören Ihre Daten an?"}],"http://www.w3.org/ns/shacl#class":[{"@id":"http://www.dfg.de/dfg_profil/gremien/fachkollegien/faecher/"}],"http://www.w3.org/ns/shacl#order":[{"@value":"3","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Fachrichtung"},{"@language":"en","@value":"Subject Area"}],"http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/subject"}]},{"@id":"_:b6482496","http://www.w3.org/ns/shacl#name":[{"@language":"de","@value":"Titel"},{"@language":"en","@value":"Title"}],"http://www.w3.org/ns/shacl#datatype":[{"@id":"http://www.w3.org/2001/XMLSchema#string"}],"http://www.w3.org/ns/shacl#minLength":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#order":[{"@value":"0","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#minCount":[{"@value":"1","@type":"http://www.w3.org/2001/XMLSchema#integer"}],"http://www.w3.org/ns/shacl#description":[{"@language":"en","@value":"Enter a title to describe your data."},{"@language":"de","@value":"Geben Sie einen Titel an, um Ihre Daten zu beschreiben."}],"http://www.w3.org/ns/shacl#path":[{"@id":"http://purl.org/dc/terms/title"}]}]`;
+export const baseApplicationProfileFormat = "application/ld+json";
diff --git a/src/data/mockup/responses/getMetadata.ts b/src/data/mockup/responses/getMetadata.ts
index f0ef8041e2f60f1c027d3244166278b50b1c29d2..e9d45b925640bf05a92e87cd738328926207ec5c 100644
--- a/src/data/mockup/responses/getMetadata.ts
+++ b/src/data/mockup/responses/getMetadata.ts
@@ -1,104 +1,80 @@
-export const getMetadataResponse = {
-  data: {
-    metadataStorage: [
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTesta":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTesta> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTesta> <http://purl.org/dc/terms/created> "2022-02-25"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTesta> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTesta> <http://purl.org/dc/terms/title> "Test"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTest":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTest> <http://purl.org/dc/terms/created> "2021-12-09"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTest> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FTest> <http://purl.org/dc/terms/title> "Test"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FcoolerEintrag":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FcoolerEintrag> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FcoolerEintrag> <http://purl.org/dc/terms/created> "2022-03-07"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FcoolerEintrag> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2FcoolerEintrag> <http://purl.org/dc/terms/title> "test"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Freview":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Freview> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Freview> <http://purl.org/dc/terms/created> "2022-03-10"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Freview> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Freview> <http://purl.org/dc/terms/title> "MyTest2"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf> <http://purl.org/dc/terms/created> "2022-03-10"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf> <http://purl.org/dc/terms/rights> "awer"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Feawfaewf> <http://purl.org/dc/terms/title> "awerawe"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-      {
-        "https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Fw":
-          '<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Fw> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://purl.org/coscine/ap/radar/> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Fw> <http://purl.org/dc/terms/created> "2022-04-04"^^<http://www.w3.org/2001/XMLSchema#date> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Fw> <http://purl.org/dc/terms/creator> "Benedikt Heinrichs"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n<https://hdl.handle.net/21.11102/eeb8d803-46a1-49ba-a47c-81cd4f49cd65@path=%2Fw> <http://purl.org/dc/terms/title> "a"^^<http://www.w3.org/2001/XMLSchema#string> .\r\n',
-      },
-    ],
-    fileStorage: [
-      {
-        Name: "Testa",
-        Path: "/Testa",
-        Size: 7,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
-      {
-        Name: "Test",
-        Path: "/Test",
-        Size: 18,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
-      {
-        Name: "coolerEintrag",
-        Path: "/coolerEintrag",
-        Size: 14,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
-      {
-        Name: "review",
-        Path: "/review",
-        Size: 14,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
-      {
-        Name: "eawfaewf",
-        Path: "/eawfaewf",
-        Size: 14,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
-      {
-        Name: "w",
-        Path: "/w",
-        Size: 9,
-        Kind: "file",
-        Modified: null,
-        Created: null,
-        Provider: "linked",
-        IsFolder: false,
-        IsFile: true,
-        Action: {},
-      },
+import type {
+  FileDto,
+  MetadataDto,
+  TreeDataType,
+} from "@coscine/api-client/dist/types/Coscine.Api";
+
+export const getMetadataTreeResponse: MetadataDto[] = [
+  {
+    version: "1693212042",
+    availableVersions: ["1693212042"],
+    definition:
+      '@base <https://purl.org/coscine/resources/4103cbea-ffa3-40a5-9e5c-b99cc16f0007/folder_1/folder_2/A.txt/@type=metadata&version=1693212042>.\r\n\r\n@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.\r\n@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.\r\n@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\r\n@prefix ns2: <http://purl.org/dc/terms/>.\r\n\r\n_:b8477997 ns2:created "2023-08-15"^^xsd:date;\r\n ns2:creator "Petar Hristov";\r\n ns2:title "Title inside Form Generator";\r\n a <https://purl.org/coscine/ap/base/>.\r\n',
+    format: "text/turtle",
+    path: "folder_1/folder_2/A.txt",
+    type: "Leaf" as TreeDataType.Leaf,
+  },
+  {
+    version: "1692777419",
+    availableVersions: ["1692777419"],
+    definition:
+      '@base <https://purl.org/coscine/resources/4103cbea-ffa3-40a5-9e5c-b99cc16f0007/file_1.txt/@type=metadata&version=1692777419>.\r\n\r\n@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.\r\n@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.\r\n@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\r\n@prefix ns2: <http://purl.org/dc/terms/>.\r\n\r\n_:b8425359 ns2:created "2023-08-18"^^xsd:date;\r\n ns2:creator "Petar Hristov";\r\n ns2:title "file_1";\r\n a <https://purl.org/coscine/ap/base/>.\r\n',
+    format: "text/turtle",
+    path: "file_1.txt",
+    type: "Leaf" as TreeDataType.Leaf,
+  },
+  {
+    version: "1692779210",
+    availableVersions: [
+      "1692340745",
+      "1692340906",
+      "1692340959",
+      "1692341031",
+      "1692779210",
     ],
+    definition:
+      '@base <https://purl.org/coscine/resources/4103cbea-ffa3-40a5-9e5c-b99cc16f0007/file_0.txt/@type=metadata&version=1692779210>.\r\n\r\n@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.\r\n@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.\r\n@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\r\n@prefix ns2: <http://purl.org/dc/terms/>.\r\n\r\n_:b8425361 ns2:created "2023-08-18"^^xsd:date;\r\n ns2:creator "Petar Hristov";\r\n ns2:title "Revised";\r\n a <https://purl.org/coscine/ap/base/>.\r\n',
+    format: "text/turtle",
+    path: "file_0.txt",
+    type: "Leaf" as TreeDataType.Leaf,
+  },
+  {
+    version: "1693209938",
+    availableVersions: ["1693209938"],
+    definition:
+      '@base <https://purl.org/coscine/resources/4103cbea-ffa3-40a5-9e5c-b99cc16f0007/my_folder/file_of_folder.txt/@type=metadata&version=1693209938>.\r\n\r\n@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.\r\n@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.\r\n@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\r\n@prefix ns2: <http://purl.org/dc/terms/>.\r\n\r\n_:b8477996 ns2:created "2023-08-15"^^xsd:date;\r\n ns2:creator "Petar Hristov";\r\n ns2:title "From Insomnia";\r\n a <https://purl.org/coscine/ap/base/>.\r\n',
+    format: "text/turtle",
+    path: "my_folder/file_of_folder.txt",
+    type: "Leaf" as TreeDataType.Leaf,
+  },
+];
+export const getFileTreeResponse: FileDto[] = [
+  {
+    parentDirectory: "",
+    name: "folder_1",
+    size: 0,
+    creationDate: "2023-09-01T16:57:48.2525218+02:00",
+    changeDate: "2023-09-01T16:57:48.2525225+02:00",
+    path: "folder_1/",
+    type: "Tree" as TreeDataType.Tree,
+  },
+  {
+    parentDirectory: "",
+    name: "my_folder",
+    size: 0,
+    creationDate: "2023-09-01T16:57:48.2525245+02:00",
+    changeDate: "2023-09-01T16:57:48.2525249+02:00",
+    path: "my_folder/",
+    type: "Tree" as TreeDataType.Tree,
+  },
+  {
+    parentDirectory: "",
+    name: "file_0.txt",
+    extension: "txt",
+    size: 2513352,
+    creationDate: "2023-08-23T10:27:20.062+02:00",
+    changeDate: "2023-08-23T10:27:20.062+02:00",
+    path: "file_0.txt",
+    type: "Leaf" as TreeDataType.Leaf,
   },
-};
+];
diff --git a/src/data/mockup/testResource.ts b/src/data/mockup/testResource.ts
index 6fb94c13387499313e48b1fc0f8cbca4d02b1f75..9cc50478575fb27873203d20e06e60f8575068c6 100644
--- a/src/data/mockup/testResource.ts
+++ b/src/data/mockup/testResource.ts
@@ -3,7 +3,10 @@ import type {
   ResourceState,
 } from "@/modules/resource/types";
 import { parseRDFDefinition } from "@/modules/resource/utils/linkedData";
-import { radarApplicationProfile } from "./metadata/applicationProfile";
+import {
+  baseApplicationProfile,
+  baseApplicationProfileFormat,
+} from "./metadata/applicationProfile";
 import { radarFixedValues } from "./metadata/fixedValues";
 import { testDiscipline, getTestUser } from "./testUser";
 import type {
@@ -40,10 +43,10 @@ export const testResourceType: ResourceTypeInformationDto = {
 
 export const getTestResource: () => Promise<VisitedResourceObject> =
   async () => {
-    const apUrl = "https://purl.org/coscine/ap/radar/";
+    const apUrl = "https://purl.org/coscine/ap/base/";
     const ap = await parseRDFDefinition(
-      radarApplicationProfile,
-      "application/ld+json",
+      baseApplicationProfile,
+      baseApplicationProfileFormat,
       apUrl
     );
     const resourceObject: VisitedResourceObject = {
diff --git a/src/mapping/tree.ts b/src/mapping/tree.ts
new file mode 100644
index 0000000000000000000000000000000000000000..15084f64009a31a773e370b456f3be6c3f89aa30
--- /dev/null
+++ b/src/mapping/tree.ts
@@ -0,0 +1,51 @@
+import { MapperConfiguration, MappingPair } from "@dynamic-mapper/mapper";
+import { v4 as uuidv4 } from "uuid";
+
+import type {
+  TreeDataType,
+  FileDto,
+} from "@coscine/api-client/dist/types/Coscine.Api";
+import type {
+  FileInformation,
+  FolderInformation,
+} from "@/modules/resource/types";
+
+export const TreeDto2FileInformation = new MappingPair<
+  FileDto,
+  FileInformation
+>();
+
+export const TreeDto2FolderInformation = new MappingPair<
+  FileDto,
+  FolderInformation
+>();
+
+const configuration = new MapperConfiguration((cfg) => {
+  cfg.createMap(TreeDto2FileInformation, {
+    id: (opt) => opt.mapFrom((_) => uuidv4()),
+    name: (opt) => opt.mapFrom((dto) => dto.name ?? ""),
+    parentDirectory: (opt) => opt.mapFrom((dto) => dto.parentDirectory ?? ""),
+    path: (opt) => opt.mapFrom((dto) => dto.path ?? ""),
+    type: (opt) => opt.mapFrom((_) => "Leaf" as TreeDataType.Leaf),
+    isFolder: (opt) => opt.mapFrom((_) => false),
+    createdAt: (opt) => opt.mapFrom((dto) => dto.creationDate ?? undefined),
+    lastModified: (opt) => opt.mapFrom((dto) => dto.changeDate),
+    size: (opt) => opt.mapFrom((dto) => dto.size ?? 0),
+    version: (opt) => opt.mapFrom((_) => `${+new Date()}`),
+    metadata: (opt) => opt.mapFrom((_) => null), // Set outside of the mapper
+  });
+
+  cfg.createMap(TreeDto2FolderInformation, {
+    id: (opt) => opt.mapFrom((_) => uuidv4()),
+    name: (opt) => opt.mapFrom((dto) => dto.name ?? ""),
+    parentDirectory: (opt) => opt.mapFrom((dto) => dto.parentDirectory ?? ""),
+    path: (opt) => opt.mapFrom((dto) => dto.path ?? ""),
+    type: (opt) => opt.mapFrom((_) => "Tree" as TreeDataType.Tree),
+    isFolder: (opt) => opt.mapFrom((_) => true),
+    createdAt: (opt) => opt.mapFrom((dto) => dto.creationDate ?? undefined),
+    lastModified: (opt) => opt.mapFrom((dto) => dto.changeDate),
+    metadata: (opt) => opt.mapFrom((_) => null), // Set outside of the mapper
+  });
+});
+
+export const treeMapper = configuration.createMapper();
diff --git a/src/modules/project/pages/ProjectPage.vue b/src/modules/project/pages/ProjectPage.vue
index 0314a132d84eb0d3c4c250dab8a5560f725074a4..9a024eafc5606f50026535391edfe92a344b7e41 100644
--- a/src/modules/project/pages/ProjectPage.vue
+++ b/src/modules/project/pages/ProjectPage.vue
@@ -173,7 +173,7 @@ export default defineComponent({
     toResource(resource: ResourceDto): RawLocation {
       const route = {
         name: "resource-page",
-        params: { guid: resource.id },
+        params: { guid: resource.id, dirTrail: "" },
       } as RawLocation;
       return route;
     },
diff --git a/src/modules/resource/ResourceModule.vue b/src/modules/resource/ResourceModule.vue
index 4aa1641a87670ce05d5d0c527f241c2f4daaa797..268736e2aaa7f070076dc096870e5ec969b03c20 100644
--- a/src/modules/resource/ResourceModule.vue
+++ b/src/modules/resource/ResourceModule.vue
@@ -70,6 +70,11 @@ export default defineComponent({
     this.initialize();
   },
 
+  beforeDestroy() {
+    // Set current resource ID to null
+    this.resourceStore.currentId = null;
+  },
+
   methods: {
     async initialize() {
       await this.apiFetch(this.$router.currentRoute);
diff --git a/src/modules/resource/components/create-resource/ApplicationProfile.vue b/src/modules/resource/components/create-resource/ApplicationProfile.vue
index 7c6a5d44a84f94e51b897def5fb3bf788f19091e..afe80d1af34215a440d0a94291b27ae70cf39f53 100644
--- a/src/modules/resource/components/create-resource/ApplicationProfile.vue
+++ b/src/modules/resource/components/create-resource/ApplicationProfile.vue
@@ -28,7 +28,7 @@
       </template>
 
       <!-- Dropdown -->
-      <div class="d-flex align-items-center gap-2">
+      <div class="d-inline-flex align-items-center gap-2 w-100">
         <multiselect
           id="applicationProfiles"
           v-model="selectedApplicationProfile"
@@ -69,7 +69,7 @@
           <b-button
             variant="outline-primary"
             name="createAP"
-            class="d-flex justify-content-between align-items-center"
+            class="d-flex gap-2 justify-content-between align-items-center w-fit"
             @click="$bvModal.show('createAPModal')"
           >
             <b-icon icon="file-earmark-plus" aria-hidden="true" />
diff --git a/src/modules/resource/components/create-resource/ConfigurationSizeSlider.vue b/src/modules/resource/components/create-resource/ConfigurationSizeSlider.vue
index 3232083c3110a81b315b5f9c6d0e9e34e1b9a128..2828efead43ee7580fdf3e26332ac02e162f76b2 100644
--- a/src/modules/resource/components/create-resource/ConfigurationSizeSlider.vue
+++ b/src/modules/resource/components/create-resource/ConfigurationSizeSlider.vue
@@ -4,23 +4,25 @@
       :mandatory="true"
       :label="$t('page.createResource.configuration.labels.size')"
     >
-      <!-- Slider -->
-      <b-form-input
-        id="slider"
-        :disabled="!sliderValue || max < min"
-        type="range"
-        :min="min"
-        :max="max"
-        :value="sliderValue"
-        @change="update"
-      />
-      <div>
-        {{ sliderText }}
+      <div class="w-100">
+        <!-- Slider -->
+        <b-form-input
+          id="slider"
+          :disabled="!sliderValue || max < min"
+          type="range"
+          :min="min"
+          :max="max"
+          :value="sliderValue"
+          @change="update"
+        />
+        <div>
+          {{ sliderText }}
 
-        <!-- Router Link -->
-        <router-link v-if="isOwner" :to="{ name: 'project-quota' }">
-          {{ $t("page.createResource.configuration.needMore") }}
-        </router-link>
+          <!-- Router Link -->
+          <router-link v-if="isOwner" :to="{ name: 'project-quota' }">
+            {{ $t("page.createResource.configuration.needMore") }}
+          </router-link>
+        </div>
       </div>
     </CoscineFormGroup>
   </div>
diff --git a/src/modules/resource/components/resource-page/FilesView.spec.ts b/src/modules/resource/components/resource-page/FilesView.spec.ts
index 7da372077001ea1f89b7e7c7ade42860600ccf84..66a621a117744d64d173583c11c5b0520973c7f2 100644
--- a/src/modules/resource/components/resource-page/FilesView.spec.ts
+++ b/src/modules/resource/components/resource-page/FilesView.spec.ts
@@ -1,5 +1,5 @@
 /* Testing imports */
-import { createLocalVue, mount } from "@vue/test-utils";
+import { type Wrapper, createLocalVue, mount } from "@vue/test-utils";
 import { createTestingPinia } from "@pinia/testing";
 
 /* Vue i18n */
@@ -15,6 +15,8 @@ import { PiniaVuePlugin } from "pinia";
 
 /* Tested Component */
 import FilesView from "./FilesView.vue";
+import VueRouter from "vue-router";
+import { routes } from "@/router";
 
 import type Vue from "vue";
 
@@ -22,7 +24,10 @@ import { getTestUserState } from "@/data/mockup/testUser";
 import { getTestResourceState } from "@/data/mockup/testResource";
 import { testProjectState } from "@/data/mockup/testProject";
 import useResourceStore from "../../store";
-import { getMetadataResponse } from "@/data/mockup/responses/getMetadata";
+import {
+  getFileTreeResponse,
+  getMetadataTreeResponse,
+} from "@/data/mockup/responses/getMetadata";
 
 function sleep(ms: number) {
   return new Promise((resolve) => setTimeout(resolve, ms));
@@ -31,58 +36,82 @@ function sleep(ms: number) {
 /* Create a local Vue instance */
 const localVue = createLocalVue();
 localVue.use(PiniaVuePlugin);
+localVue.use(VueRouter);
+const router = new VueRouter({ routes: routes });
 
-describe("FilesView.vue", () => {
-  /* Checks for local storage setting of columns */
-  test("testLocalStorageSetting", async () => {
-    const testingPinia = createTestingPinia({
-      createSpy: vitest.fn,
-      initialState: {
-        project: testProjectState,
-        resource: await getTestResourceState(),
-        user: getTestUserState(),
-      },
-    });
-
-    const resourceStore = useResourceStore(testingPinia);
-    vi.mocked(resourceStore.getMetadata).mockReturnValue(
-      Promise.resolve(getMetadataResponse)
-    );
-    vi.mocked(resourceStore.getVocabularyInstances).mockReturnValue(
-      Promise.resolve({ en: [], de: [] })
-    );
-
-    const wrapper = mount(FilesView as unknown as typeof Vue, {
+// Define the Vue instance type (computed properties)
+interface ResourcePageComponent extends Vue {
+  dirTrail: string;
+}
+
+describe("FilesView.vue", async () => {
+  let wrapper: Wrapper<ResourcePageComponent>;
+
+  // Create a mocked pinia instance with initial state
+  const testingPinia = createTestingPinia({
+    createSpy: vitest.fn,
+    initialState: {
+      project: testProjectState,
+      resource: await getTestResourceState(),
+      user: getTestUserState(),
+    },
+  });
+
+  // Mock the API calls
+  const resourceStore = useResourceStore(testingPinia);
+  vi.mocked(resourceStore.getMetadataTree).mockReturnValue(
+    Promise.resolve(getMetadataTreeResponse)
+  );
+  vi.mocked(resourceStore.getFileTree).mockReturnValue(
+    Promise.resolve(getFileTreeResponse)
+  );
+  vi.mocked(resourceStore.getVocabularyInstances).mockReturnValue(
+    Promise.resolve({ en: [], de: [] })
+  );
+
+  beforeEach(() => {
+    // shallowMount does not work here!
+    wrapper = mount(FilesView as unknown as typeof Vue, {
       pinia: testingPinia,
+      router,
       i18n,
       localVue,
-    });
+    }) as Wrapper<ResourcePageComponent>;
+  });
 
-    await wrapper.vm.$nextTick();
+  test(
+    "Should toggle column visibility and persist to local storage",
+    async () => {
+      await wrapper.vm.$nextTick();
 
-    // Wait for 1 second until everything is set up
-    await sleep(1000);
+      // Wait for 1 second until everything is set up
+      await sleep(1000); // Don't remove!
 
-    expect(resourceStore.setStoredColumns).toBeCalledTimes(1);
+      expect(resourceStore.setStoredColumns).toBeCalledTimes(1);
 
-    const selectButton = wrapper.find("#addColumnDropDown__BV_toggle_");
-    await selectButton.trigger("click");
+      const selectButton = wrapper.find("#addColumnDropDown__BV_toggle_");
+      await selectButton.trigger("click");
 
-    const checkBox = wrapper.find("#addColumnDropDown .custom-control-input");
-    await checkBox.trigger("click");
+      const checkBox = wrapper.find("#addColumnDropDown .custom-control-input");
+      await checkBox.trigger("click");
 
-    // The previous clicks should have done that, workaround for now
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    (wrapper.vm as any).columns[0].active = true;
+      // The previous clicks should have done that, workaround for now
+      // eslint-disable-next-line @typescript-eslint/no-explicit-any
+      (wrapper.vm as any).columns[0].active = true;
 
-    await wrapper.vm.$nextTick();
+      await wrapper.vm.$nextTick();
 
-    // Wait for 1 second until everything is set up
-    await sleep(1000);
+      // Wait for 1 second until everything is set up
+      await sleep(1000); // Don't remove!
 
-    const additionalColumnHeader = wrapper.find(".additionalColumnHeader");
-    expect(additionalColumnHeader.exists()).toBeTruthy();
+      const additionalColumnHeader = wrapper.find(".additionalColumnHeader");
+      expect(additionalColumnHeader.exists()).toBeTruthy();
 
-    expect(resourceStore.setStoredColumns).toBeCalledTimes(2);
-  });
+      expect(resourceStore.setStoredColumns).toBeCalledTimes(2);
+    },
+    {
+      // Override the maximum run time for this test (10 sec), due to the sleep() calls
+      timeout: 10000,
+    }
+  );
 });
diff --git a/src/modules/resource/components/resource-page/FilesView.vue b/src/modules/resource/components/resource-page/FilesView.vue
index 2da6291fe6acfe1acf86bb348d686b77b1a5be33..ace291b8ef67e76d3df33bfcf28397071d7041ae 100644
--- a/src/modules/resource/components/resource-page/FilesView.vue
+++ b/src/modules/resource/components/resource-page/FilesView.vue
@@ -1,11 +1,14 @@
 <template>
   <div class="DataSource">
+    <!-- Files View Header -->
     <FilesViewHeader
       v-model="filter"
       :is-uploading="isUploading"
       @clickFileSelect="clickFileSelect"
     />
+
     <b-row>
+      <!-- Files View Table -->
       <b-table
         id="resourceViewTable"
         ref="adaptTable"
@@ -31,25 +34,31 @@
         :empty-filtered-text="$t('page.resource.emptyFilterText')"
         @row-selected="onRowSelected"
       >
+        <!-- Loading Spinner for Busy State -->
         <div slot="table-busy" class="text-center text-danger my-2">
-          <b-spinner class="align-middle"></b-spinner>
-          <strong style="margin-left: 1%">{{
-            $t("page.resource.loading")
-          }}</strong>
+          <b-spinner class="align-middle" />
+          <strong style="margin-left: 1%">
+            {{ $t("page.resource.loading") }}
+          </strong>
         </div>
+
+        <!-- Column "Name" -->
         <template #head(name)="row">
-          <b-form-checkbox
-            v-model="selectAll"
-            @change="allSelect(row)"
-          ></b-form-checkbox>
+          <b-form-checkbox v-model="selectAll" @change="allSelect(row)" />
           <span>{{ $t("page.resource.fileName") }}</span>
         </template>
+
+        <!-- Column "Last Modified" -->
         <template #head(lastModified)="row">
           <span>{{ row.label }}</span>
         </template>
+
+        <!-- Column "Size" -->
         <template #head(size)="row">
           <span>{{ row.label }}</span>
         </template>
+
+        <!--  -->
         <template #head()="row">
           <template v-if="visibleColumns.includes(row.field.key)">
             <span>{{ row.label }}</span>
@@ -61,11 +70,16 @@
             </span>
           </template>
         </template>
+
+        <!-- Column "Add Column"/Filter -->
         <template #head(addColumn)>
           <b-dropdown id="addColumnDropDown" size="sm" right :no-caret="true">
+            <!-- Button Template + Icon -->
             <template #button-content>
-              <b-icon icon="arrow-down" />
+              <b-icon icon="funnel" />
             </template>
+
+            <!-- Checkbox Options -->
             <b-form-checkbox
               v-for="column in columns"
               :key="column.key"
@@ -76,56 +90,72 @@
             </b-form-checkbox>
           </b-dropdown>
         </template>
+
+        <!-- Row "Name" -->
         <template #cell(name)="row">
-          <span class="checkFile">
-            <b-form-checkbox
-              v-model="row.rowSelected"
-              class="tableCheck"
-              @change="select(row)"
-            />
-            <b-icon
-              :icon="row.item.isFolder ? 'folder' : 'file-earmark'"
-            ></b-icon>
-          </span>
-          <a
-            v-if="!editableDataUrl"
-            class="dataSourceItem"
-            :href="'#' + row.item.absolutePath"
-            @click="
-              row.item.isFolder ? openFolder(row.item) : openFile(row.item)
-            "
-            >{{ row.item.name }}</a
-          >
-          <a v-else>{{ row.item.name }}</a>
-          <b-dropdown
-            class="dotMenu"
-            left
-            variant="link"
-            toggle-class="text-decoration-none"
-            size="sm"
-            :no-caret="true"
-            :disabled="editableDataUrl && resource && resource.archived"
-          >
-            <template #button-content> ... </template>
-            <b-dropdown-item
-              v-if="!editableDataUrl"
-              @click="
-                row.item.isFolder ? openFolder(row.item) : openFile(row.item)
-              "
-            >
-              {{ $t("page.resource.metadataManagerBtnDownload") }}
-            </b-dropdown-item>
-            <b-dropdown-item
-              v-if="!isGuest"
-              :disabled="
-                (resource && resource.archived) ||
-                (resourceTypeInformation && !resourceTypeInformation.canDelete)
-              "
-              @click="showModalDeleteFile(row.item)"
+          <span class="d-flex justify-between fileViewEntryWrapper">
+            <span class="d-inline-flex gap-2">
+              <!-- File Icon and Checkbox -->
+              <span class="checkFile">
+                <!-- Show a checkbox for elements that are not read-only -->
+                <b-form-checkbox
+                  v-if="!row.item.readOnly"
+                  v-model="row.rowSelected"
+                  class="tableCheck"
+                  @change="select(row)"
+                />
+                <!-- Icon -->
+                <b-icon
+                  :icon="row.item.isFolder ? 'folder' : 'file-earmark'"
+                  class="ml-1"
+                />
+              </span>
+              <a
+                v-if="!editableDataUrl"
+                class="fileViewEntry"
+                @click="triggerNavigation(row.item)"
+              >
+                {{ row.item.name }}
+              </a>
+              <span v-else class="fileViewEntry"> {{ row.item.name }} </span>
+            </span>
+            <!-- Row File "..." Menu -->
+            <b-dropdown
+              class="dotMenu"
+              left
+              variant="link"
+              toggle-class="text-decoration-none"
+              size="sm"
+              :no-caret="true"
+              :disabled="editableDataUrl && resource && resource.archived"
             >
-              {{ $t("buttons.delete") }}
-            </b-dropdown-item>
-          </b-dropdown>
+              <!-- Row File "..." Button Template + Icon -->
+              <template #button-content>
+                <b-icon icon="three-dots-vertical" />
+              </template>
+
+              <!-- Option "Download" -->
+              <b-dropdown-item
+                v-if="!editableDataUrl && !row.item.isFolder"
+                @click="openFile(row.item)"
+              >
+                {{ $t("page.resource.metadataManagerBtnDownload") }}
+              </b-dropdown-item>
+
+              <!-- Option "Delete" -->
+              <b-dropdown-item
+                v-if="!isGuest"
+                :disabled="
+                  (resource && resource.archived) ||
+                  (resourceTypeInformation &&
+                    !resourceTypeInformation.canDelete)
+                "
+                @click="showModalDeleteFile(row.item)"
+              >
+                {{ $t("buttons.delete") }}
+              </b-dropdown-item>
+            </b-dropdown>
+          </span>
         </template>
       </b-table>
     </b-row>
@@ -134,42 +164,45 @@
 
 <script lang="ts">
 import { defineComponent, type PropType, reactive } from "vue";
-
 // import the store for current module
 import useResourceStore from "../../store";
 import useProjectStore from "@/modules/project/store";
-
 import FilesViewHeader from "./FilesViewHeader.vue";
-
-import type {
-  FileInformation,
-  FolderContent,
-  FolderInformation,
-  ReadOnlyFolderInformation,
-} from "../../utils/EntryDefinition";
-
 import MetadataManagerUtil from "../../utils/MetadataManagerUtil";
-
 import fileSaver from "file-saver";
-
+import { FileUtil } from "../../utils/FileUtil";
+import { v4 as uuidv4 } from "uuid";
+import { parseRDFDefinition } from "../../utils/linkedData";
+import factory from "rdf-ext";
+import {
+  TreeDto2FileInformation,
+  TreeDto2FolderInformation,
+  treeMapper,
+} from "@/mapping/tree";
+import type { BFormRow, BTable } from "bootstrap-vue";
+import type { Dataset, Literal, Quad } from "@rdfjs/types";
+import type {
+  TreeDataType,
+  ProjectDto,
+  ResourceTypeInformationDto,
+  FileDto,
+  MetadataDto,
+} from "@coscine/api-client/dist/types/Coscine.Api";
 import type {
   BilingualLabels,
   CustomTableField,
+  FileInformation,
+  FolderContent,
+  FolderInformation,
+  ReadOnlyFolderInformation,
   VisitedResourceObject,
 } from "../../types";
-import type { BFormRow, BTable } from "bootstrap-vue";
-import { FileUtil } from "../../utils/FileUtil";
-
-import { v4 as uuidv4 } from "uuid";
-import { parseRDFDefinition } from "../../utils/linkedData";
-import factory from "rdf-ext";
-import type { Dataset, Literal } from "@rdfjs/types";
-import type { ResourceTypeInformationDto } from "@coscine/api-client/dist/types/Coscine.Api";
 
 export default defineComponent({
   components: {
     FilesViewHeader,
   },
+
   props: {
     folderContents: {
       default: () => {
@@ -177,10 +210,6 @@ export default defineComponent({
       },
       type: Array as PropType<FolderContent[]>,
     },
-    currentFolder: {
-      default: "/",
-      type: String,
-    },
     fileListEdit: {
       default: () => {
         return [];
@@ -191,21 +220,37 @@ export default defineComponent({
       default: false,
       type: Boolean,
     },
+    dirTrail: {
+      required: true,
+      type: String,
+    },
+    dirCrumbs: {
+      required: true,
+      type: Array as PropType<string[]>,
+    },
+  },
+
+  emits: {
+    clickFileSelect: () => true,
+    fileListEdit: (_: FolderContent[]) => true,
+    folderContents: (_: FolderContent[]) => true,
+    showDetail: (_: boolean) => true,
+    showModalDelete: (_: FolderContent[]) => true,
   },
+
   setup() {
     const resourceStore = useResourceStore();
     const projectStore = useProjectStore();
 
     return { resourceStore, projectStore };
   },
+
   data() {
     return {
       columns: [] as CustomTableField[],
       isBusy: true,
       selectAll: false,
       filter: "",
-      folderPath: [] as string[],
-      selectableFiles: [] as FolderContent[],
       sortBy: "",
       sortDesc: false,
     };
@@ -218,10 +263,12 @@ export default defineComponent({
     applicationProfile(): Dataset | null {
       return this.resourceStore.currentFullApplicationProfile;
     },
+    project(): null | ProjectDto {
+      return this.projectStore.currentProject;
+    },
     resource(): null | VisitedResourceObject {
       return this.resourceStore.currentResource;
     },
-
     classes(): { [className: string]: BilingualLabels } {
       return this.resourceStore.classes;
     },
@@ -237,7 +284,7 @@ export default defineComponent({
       );
     },
     locale(): string {
-      //Define as computed property to translate RCV Table
+      // Define as computed property to translate RCV Table
       return this.$root.$i18n.locale;
     },
     defaultHeaders(): Array<CustomTableField> {
@@ -332,8 +379,8 @@ export default defineComponent({
     locale() {
       this.getColumns();
     },
-    resource() {
-      this.getData();
+    async resource() {
+      await this.navigateTree();
     },
     sortBy() {
       this.saveInLocalStorage();
@@ -341,153 +388,256 @@ export default defineComponent({
     sortDesc() {
       this.saveInLocalStorage();
     },
+    async dirTrail() {
+      // Reacts to route changes from 'triggerNavigation()'
+      await this.navigateTree();
+    },
   },
-  created() {
+
+  async created() {
     this.isBusy = true;
     this.getColumns();
     if (this.resource) {
-      this.getData();
+      await this.navigateTree();
     }
+    this.isBusy = false;
   },
+
   methods: {
+    /**
+     * Generates the table columns based on the application profile.
+     * This method reads paths from the application profile and checks the local storage to see if
+     * certain columns should be active or not. The resulting columns are reactive objects.
+     */
     getColumns() {
       this.columns.length = 0;
+
+      if (!this.applicationProfile) return;
+
       // keys a, b, name, active
-      if (this.applicationProfile) {
-        const oldColumns = this.loadFromLocalStorage();
-        const paths = this.applicationProfile.match(
-          undefined,
-          factory.namedNode("http://www.w3.org/ns/shacl#path")
-        );
-        for (const path of paths) {
-          // read the active value from the localStorage
-          const identifier = path.object.value;
-          const names = this.applicationProfile.match(
-            path.subject,
-            factory.namedNode("http://www.w3.org/ns/shacl#name")
+      const oldColumns = this.loadFromLocalStorage();
+      const shaclPath = factory.namedNode("http://www.w3.org/ns/shacl#path");
+      const shaclName = factory.namedNode("http://www.w3.org/ns/shacl#name");
+
+      const paths = this.applicationProfile.match(undefined, shaclPath);
+      for (const path of paths) {
+        // Read the active value from the localStorage
+        const identifier = path.object.value;
+
+        // Find the name of the column in the preferred language or a default if not available.
+        const names = this.applicationProfile.match(path.subject, shaclName);
+        const name = this.getColumnName(names);
+
+        // Determine if the column should be active based on stored settings.
+        const activeColumn = this.isColumnActive(identifier, oldColumns);
+
+        if (name) {
+          this.columns.push(
+            this.createColumn(name, identifier, path, activeColumn)
           );
-          let name: string | null = null;
-          for (const nameEntry of names) {
-            name = nameEntry.object.value;
-            if (
-              (nameEntry.object as Literal).language === this.$root.$i18n.locale
-            ) {
-              break;
-            }
+        }
+      }
+    },
+
+    /**
+     * Retrieves the column name from the provided names list.
+     * It prioritizes names in the current locale.
+     *
+     * @param {Dataset<Quad, Quad>} names - The list of potential names.
+     * @returns {string | null} - The retrieved name or null.
+     */
+    getColumnName(names: Dataset<Quad, Quad>): string | null {
+      let name: string | null = null;
+      for (const nameEntry of names) {
+        name = nameEntry.object.value;
+        if (
+          (nameEntry.object as Literal).language === this.$root.$i18n.locale
+        ) {
+          break;
+        }
+      }
+      return name;
+    },
+
+    /**
+     * Determines if a column should be active based on the provided identifier and the stored columns.
+     * @param {string} identifier - The identifier of the column to check.
+     * @param {CustomTableField[]} oldColumns - The collection of stored old columns.
+     * @returns {boolean} - True if the column should be active, false otherwise.
+     */
+    isColumnActive(
+      identifier: string,
+      oldColumns: CustomTableField[]
+    ): boolean {
+      for (const oldColumn of oldColumns) {
+        if (oldColumn.key === identifier) {
+          return oldColumn.active;
+        }
+      }
+      return false;
+    },
+
+    /**
+     * Creates a column based on the provided name, identifier and path.
+     * @param {string} name - The name of the column.
+     * @param {string} identifier - The identifier of the column.
+     * @param {Quad} path - The path of the column.
+     * @param {boolean} activeColumn - True if the column should be active, false otherwise.
+     * @returns {CustomTableField} - The created column.
+     */
+    createColumn(
+      name: string,
+      identifier: string,
+      path: Quad,
+      activeColumn: boolean
+    ): CustomTableField {
+      return reactive({
+        label: name,
+        key: identifier,
+        sortable: true,
+        active: activeColumn,
+        formatter: (value, key, item: FolderContent) => {
+          return this.formatColumnValue(item.metadata, path);
+        },
+        sortByFormatted: true,
+        filterByFormatted: true,
+      });
+    },
+
+    /**
+     * Formats the column value based on the provided metadata and path.
+     * @param {Dataset<Quad, Quad>} metadata - The metadata containing information to format.
+     * @param {Quad} path - The RDF quad defining the property path for the column.
+     * @returns {string} - The formatted column value, where multiple values are separated by a line break ("<br>").
+     */
+    formatColumnValue(
+      metadata: Dataset<Quad, Quad> | null,
+      path: Quad
+    ): string {
+      // Extract all matching entries from the metadata using the specified path.
+      const entries = metadata?.match(undefined, path.object);
+
+      // If there are no matching entries, return an empty string.
+      if (!entries?.size) return "";
+
+      const returnList: string[] = [];
+      for (const entry of entries) {
+        const entryObject = entry.object;
+        let entryValue = entryObject.value;
+
+        // If the entry object is a literal, further formatting might be needed.
+        if (entryObject.termType === "Literal") {
+          // If the datatype of the literal indicates a date, format it accordingly.
+          if (entryObject.datatype.value.endsWith("date")) {
+            const date = entryObject.value;
+            const dateObject = new Date(date);
+            entryValue = dateObject.toLocaleDateString(this.$i18n.locale);
           }
+        }
+        // If the entry object is a named node, it might need to be translated into a more readable form.
+        else if (entryObject.termType === "NamedNode") {
+          // Loop through all available classes to find a match for the named node's value.
+          for (const classValue of Object.values(this.classes)) {
+            // Depending on the user's locale, choose the appropriate language list.
+            const langClassList =
+              this.$i18n.locale === "de" ? classValue.de : classValue.en;
+
+            // If a language-specific list is available, search for the named node's value in it.
+            if (langClassList) {
+              const foundEntry = langClassList.find(
+                (langClassEntry) => langClassEntry.value === entryValue
+              );
 
-          let activeColumn = false;
-          for (const oldColumn of oldColumns) {
-            if (oldColumn.key === identifier) {
-              activeColumn = oldColumn.active;
+              // If a match is found, replace the entryValue with the more readable name.
+              if (foundEntry && foundEntry.name) {
+                entryValue = foundEntry.name;
+                break; // Exit the loop once a match is found.
+              }
             }
           }
-          if (name) {
-            this.columns.push(
-              reactive({
-                label: name,
-                key: identifier,
-                sortable: true,
-                active: activeColumn,
-                formatter: (value, key, item: FolderContent) => {
-                  const metadata = item.metadata;
-                  const entries = metadata.match(undefined, path.object);
-                  if (entries.size) {
-                    const returnList: string[] = [];
-                    for (const entry of entries) {
-                      const entryObject = entry.object;
-                      let entryValue = entryObject.value;
-                      if (entryObject.termType === "Literal") {
-                        if (entryObject.datatype.value.endsWith("date")) {
-                          const date = entryObject.value;
-                          const dateObject = new Date(date);
-                          entryValue = dateObject.toLocaleDateString(
-                            this.$i18n.locale
-                          );
-                        }
-                      } else if (entryObject.termType === "NamedNode") {
-                        for (const classValue of Object.values(this.classes)) {
-                          const langClassList =
-                            this.$i18n.locale === "de"
-                              ? classValue.de
-                              : classValue.en;
-                          if (langClassList) {
-                            const foundEntry = langClassList.find(
-                              (langClassEntry) =>
-                                langClassEntry.value === entryValue
-                            );
-                            if (foundEntry && foundEntry.name) {
-                              entryValue = foundEntry.name;
-                              break;
-                            }
-                          }
-                        }
-                      }
-                      returnList.push(entryValue);
-                    }
-                    return returnList.join("<br>");
-                  }
-                  return "";
-                },
-                sortByFormatted: true,
-                filterByFormatted: true,
-              })
-            );
-          }
         }
+
+        // Add the processed entry value to the list of results.
+        returnList.push(entryValue);
       }
+
+      // Join the list of results with line breaks and return the final formatted value.
+      return returnList.join("<br>");
     },
-    getData() {
-      // Doesn't end with '/' => Probably a file
-      let currentFolder = this.currentFolder;
-      if (!currentFolder.endsWith("/") && currentFolder !== "") {
+
+    /**
+     * Navigate the folder structure based on the current folder's path.
+     * This method serves to identify whether the current folder is actually a file,
+     * opens it accordingly, and then navigates the directory structure.
+     */
+    async navigateTree() {
+      // Start with the current folder as the reference
+      let currentFolder = this.dirTrail;
+
+      // Check if the current folder might actually be a file and handle it
+      if (this.isProbablyFile(currentFolder)) {
         // TODO: Change to open modal
-        this.openFile({
-          id: uuidv4(),
-          isFolder: false,
+        await this.openFile({
           name: currentFolder.substring(currentFolder.lastIndexOf("/") + 1),
           path: currentFolder,
-          absolutePath: currentFolder,
-          version: `${+new Date()}`,
-          size: 0,
-          metadata: factory.dataset() as unknown as Dataset,
-        });
-        currentFolder = currentFolder.substring(
-          0,
-          currentFolder.lastIndexOf("/") + 1
-        );
-      }
-      if (currentFolder !== "/") {
-        let combine = "";
-        const folderSplit = currentFolder.split("/");
-        for (const folderKey in folderSplit) {
-          if (Object.prototype.hasOwnProperty.call(folderSplit, folderKey)) {
-            const folder = folderSplit[folderKey];
-            if (combine !== "" && folder === "") {
-              continue;
-            }
-            combine += folder + "/";
-            this.folderPath.push(combine);
-          }
-        }
-        this.folderPath.pop();
-        if (this.folderPath.length > 0) {
-          this.$emit("currentFolder", this.folderPath.pop());
-        } else {
-          this.$emit("currentFolder", "");
-        }
-      } else {
-        this.$emit("currentFolder", "");
+        } as FileInformation);
+        // Remove the file name from the path to get the folder path, then navigate to it
+        currentFolder = this.dirCrumbs.join("");
+        this.triggerNavigation({ path: currentFolder } as FolderInformation);
       }
-      this.openFolder({
-        id: uuidv4(),
-        isFolder: true,
-        name: currentFolder.substring(currentFolder.lastIndexOf("/") + 1),
-        path: currentFolder,
-        absolutePath: currentFolder,
-        metadata: factory.dataset() as unknown as Dataset,
+
+      // Finally, open the current folder to display its contents
+      await this.openFolder({ path: currentFolder } as FolderInformation);
+    },
+
+    /**
+     * Navigates to the specified folder or resource based on the given `entry`.
+     * If the provided `entry.path` is different from the current `dirTrail`,
+     * a new route will be pushed to the Vue router.
+     *
+     * @param {FolderContent} entry - The folder or file information object to navigate to.
+     */
+    triggerNavigation(entry: FolderContent) {
+      this.$router.push({
+        name: "resource-page",
+        params: {
+          dirTrail: entry.path,
+        },
       });
     },
+
+    /**
+     * Determines if a given path represents a file based on its structure.
+     * Files typically do not end with a slash `/`.
+     *
+     * @param {string} path - The path to evaluate.
+     * @returns {boolean} - True if the path might represent a file, false otherwise.
+     */
+    isProbablyFile(path: string | undefined): boolean | undefined {
+      return path !== "" && !path?.endsWith("/");
+    },
+
+    /**
+     * Splits a path into its constituent directories.
+     *
+     * @param {string} path - The path to split.
+     * @returns {string[]} - An array representing the folder's hierarchical structure.
+     */
+    splitPathIntoDirectories(path: string): string[] {
+      const directories = [];
+      let combinedPath = "";
+      const splitFolders = path.split("/");
+      for (const folder of splitFolders) {
+        if (combinedPath && !folder) continue;
+        combinedPath += folder + "/";
+        directories.push(combinedPath);
+      }
+      return directories;
+    },
+
+    /**
+     * Saves table preferences in local storage.
+     */
     async saveInLocalStorage() {
       await this.resourceStore.setStoredColumns({
         columns: this.columns,
@@ -496,20 +646,34 @@ export default defineComponent({
         sortDesc: this.sortDesc,
       });
     },
+
+    /**
+     * Loads table preferences from local storage.
+     * @returns {Array<CustomTableField>} - Array of table fields.
+     */
     loadFromLocalStorage(): Array<CustomTableField> {
-      let element: Array<CustomTableField> = [];
-      if (this.resourceStore.currentStoredColumns) {
-        // Deal with old values
-        if (Array.isArray(this.resourceStore.currentStoredColumns)) {
-          return this.resourceStore.currentStoredColumns;
+      let storedColumns: Array<CustomTableField> = [];
+      const currentStoredColumns = this.resourceStore.currentStoredColumns;
+
+      if (currentStoredColumns) {
+        // If the stored columns are just an array (legacy format)
+        if (Array.isArray(currentStoredColumns)) {
+          return currentStoredColumns;
         }
-        element = this.resourceStore.currentStoredColumns.columns;
-        this.filter = this.resourceStore.currentStoredColumns.filter;
-        this.sortBy = this.resourceStore.currentStoredColumns.sortBy;
-        this.sortDesc = this.resourceStore.currentStoredColumns.sortDesc;
+
+        // Retrieve and set stored preferences
+        storedColumns = currentStoredColumns.columns;
+        this.filter = currentStoredColumns.filter;
+        this.sortBy = currentStoredColumns.sortBy;
+        this.sortDesc = currentStoredColumns.sortDesc;
       }
-      return element;
+      return storedColumns;
     },
+
+    /**
+     * Deactivates a column based on the provided row.
+     * @param {BFormRow} row - Row which represents a column.
+     */
     removeColumn(row: BFormRow) {
       for (const column of this.columns) {
         if (column.key === row.column) {
@@ -517,109 +681,192 @@ export default defineComponent({
         }
       }
     },
+
+    /**
+     * Emits an event to show the delete modal for a specific file.
+     * @param {FolderContent} file - File to delete.
+     */
     showModalDeleteFile(file: FolderContent) {
       this.$emit("showModalDelete", [file]);
     },
 
-    async openFolder(folder: FolderInformation) {
-      if (this.resource?.id) {
-        this.isBusy = true;
+    /**
+     * Asynchronously opens the specified file, fetching its blob content and triggering a download.
+     * @async
+     * @param {FileInformation} file - Information about the file to be opened.
+     */
+    async openFile(file: FileInformation) {
+      if (this.project?.id && this.resource?.id) {
+        // Download the file as a blob (binary data)
+        const asBlob = true;
+
+        // Fetch the blob content of the file
+        const response = await this.resourceStore.getBlob(
+          this.project.id,
+          this.resource.id,
+          file.path,
+          asBlob
+        );
 
-        // Empty file list, since the context changes
-        // (Other workaround would be to keep the editing files open)
-        this.$emit("fileListEdit", []);
+        if (response) {
+          // Trigger file download
+          fileSaver.saveAs(
+            new Blob([response.data], {
+              type: response.headers["content-type"],
+            }),
+            file.name
+          );
 
-        const absolutePath =
-          folder.absolutePath !== "" ? folder.absolutePath : "/";
+          // TODO: Consider adding a visual indicator that the file is being downloaded
+        }
+      }
+    },
+
+    /**
+     * Asynchronously opens the given folder, fetching its file tree and metadata tree.
+     * @async
+     * @param {FolderInformation} folder - Information about the folder to be opened.
+     */
+    async openFolder(folder: FolderInformation) {
+      if (!this.project?.id || !this.resource?.id) return;
 
-        // Show location change
-        window.location.hash = absolutePath;
+      this.isBusy = true;
 
-        const response = await this.resourceStore.getMetadata(
+      // Empty file list, since the context changes
+      // (Other workaround would be to keep the editing files open)
+      this.emitEmptyFileList();
+
+      // Determine the path of the folder and fetch its file and metadata trees
+      const path = this.determinePath(folder);
+      const [fileTree, metadataTree] = await Promise.all([
+        this.resourceStore.getFileTree(this.project.id, this.resource.id, path),
+        this.resourceStore.getMetadataTree(
+          this.project.id,
           this.resource.id,
-          absolutePath
-        );
+          path
+        ),
+      ]);
 
-        const tmpFolder: FolderContent[] = [];
-        if (folder.name === "..") {
-          this.$emit("currentFolder", this.folderPath.pop());
-        } else if (this.currentFolder !== "") {
-          this.folderPath.push(this.currentFolder);
-          this.$emit("currentFolder", absolutePath);
-        } else {
-          this.$emit("currentFolder", absolutePath);
-        }
+      // Create a temporary folder to store the entries
+      const folderContents = await this.constructFolderContents(
+        fileTree,
+        metadataTree
+      );
 
-        if (this.folderPath.length > 0) {
-          const path = this.folderPath[this.folderPath.length - 1];
-          const navigateUpFolder: ReadOnlyFolderInformation = {
-            id: uuidv4(),
-            isFolder: true,
-            name: "..",
-            absolutePath: path,
-            path: path,
-            readOnly: true,
-            metadata: factory.dataset() as unknown as Dataset,
-          };
-          tmpFolder.push(navigateUpFolder);
-        }
+      this.isBusy = false;
+      this.$emit("folderContents", folderContents);
+    },
 
-        for (const obj of response.data.fileStorage) {
-          const newEntry: FileInformation = {
-            id: uuidv4(),
-            isFolder: obj.IsFolder,
-            name: obj.Name,
-            path: obj.Path,
-            absolutePath: obj.Path,
-            lastModified: obj.Modified,
-            created: obj.Created,
-            size: obj.Size,
-            version: `${+new Date()}`,
-            metadata: factory.dataset() as unknown as Dataset,
-          };
-
-          const resultArray = MetadataManagerUtil.filterMetadataStorage(
-            response.data.metadataStorage,
-            newEntry.absolutePath
-          );
+    /**
+     * Emits an event to notify of an empty file list.
+     */
+    emitEmptyFileList() {
+      this.$emit("fileListEdit", []);
+    },
 
-          if (resultArray.length > 0) {
-            const result = resultArray[0][Object.keys(resultArray[0])[0]];
-            if (typeof result === "string") {
-              newEntry.metadata = await parseRDFDefinition(
-                result,
-                "application/n-triples"
-              );
-            }
-          }
+    /**
+     * Determines the correct path for the folder.
+     * @param {FolderInformation} folder - Information about the folder for which path needs to be determined.
+     * @returns {string} The determined path.
+     */
+    determinePath(folder: FolderInformation): string {
+      return folder.path; // !== "" ? folder.path : "/";
+    },
 
-          tmpFolder.push(newEntry);
+    /**
+     * Constructs the folder content based on the provided file and metadata trees.
+     * @async
+     * @param {FileDto[] | null | undefined} fileTree - File tree of the folder.
+     * @param {MetadataDto[] | null | undefined} metadataTree - Metadata tree of the folder.
+     * @returns {FolderContent[]} An array containing folder content.
+     */
+    async constructFolderContents(
+      fileTree: FileDto[] | null | undefined,
+      metadataTree: MetadataDto[] | null | undefined
+    ): Promise<FolderContent[]> {
+      const folderContents = [];
+
+      if (this.dirCrumbs.length > 0) {
+        // Add navigate up folder entry (..)
+        folderContents.push(this.createNavigateUpFolder());
+      }
+
+      // Iterate over the file tree and map the entries for the files view table
+      for (const fileEntry of fileTree || []) {
+        const content = this.mapFileEntryToContent(fileEntry);
+        if (content) {
+          const metadataEntry = metadataTree?.find(
+            (md) => md.path === fileEntry.path
+          );
+          if (metadataEntry?.definition && metadataEntry?.format) {
+            content.metadata = await parseRDFDefinition(
+              metadataEntry.definition,
+              metadataEntry.format
+            );
+          }
+          folderContents.push(content);
         }
-        this.isBusy = false;
-        this.$emit("folderContents", tmpFolder);
       }
+      return folderContents;
     },
 
-    async openFile(file: FileInformation) {
-      if (this.resource?.id) {
-        const response = await this.resourceStore.getFile(
-          this.resource.id,
-          file.absolutePath,
-          true
-        );
-        if (response !== null) {
-          fileSaver.saveAs(response, file.name);
-        }
-        window.location.hash = this.currentFolder;
+    /**
+     * Creates a representation for the "navigate up" folder.
+     * @returns {FolderContent} A representation of the "navigate up" folder.
+     */
+    createNavigateUpFolder(): FolderContent {
+      // Make a shallow copy of the array and copy all but the last element as it is the current folder itself
+      const currentDirCrumbs = this.dirCrumbs.slice(0, -1);
+      const path = currentDirCrumbs.join("");
+      return {
+        id: uuidv4(),
+        isFolder: true,
+        name: "..",
+        path: path,
+        readOnly: true,
+        type: "Tree" as TreeDataType.Tree,
+        parentDirectory: "",
+        metadata: factory.dataset() as unknown as Dataset,
+      } as ReadOnlyFolderInformation;
+    },
+
+    /**
+     * Maps a file entry to its corresponding folder content.
+     * @param {FileDto} fileEntry - The file data transfer object to map.
+     * @returns {FolderContent | undefined} The corresponding folder content or undefined if the type is unknown.
+     */
+    mapFileEntryToContent(fileEntry: FileDto): FolderContent | undefined {
+      let content: FolderContent | undefined = undefined;
+      switch (fileEntry.type) {
+        case "Tree" as TreeDataType.Tree:
+          content = treeMapper.map(TreeDto2FolderInformation, fileEntry);
+          break;
+        case "Leaf" as TreeDataType.Leaf:
+          content = treeMapper.map(TreeDto2FileInformation, fileEntry);
+          break;
+        default:
+          console.error("Unknown content type: ", fileEntry.type);
+          break;
       }
+      return content;
     },
+
+    /**
+     * Handles when a row is selected, updating the UI and emitting necessary events.
+     * @param {FolderContent[]} items - Selected items.
+     */
     onRowSelected(items: FolderContent[]) {
       this.$emit("showDetail", items.length > 0);
       this.selectAll = items.length === this.folderContents.length;
-      // Filter out folders like ".."
-      this.selectableFiles = items.filter((item) => !item.readOnly);
-      this.updateFileListEdit();
+      // Filter out read-only entires like the navigation up folder ".."
+      const selectedFiles = items.filter((item) => !item.readOnly);
+      this.updateFileListEdit(selectedFiles);
     },
+
+    /**
+     * Selects or deselects all rows.
+     * @param {BTable} row - Reference to the table.
+     */
     allSelect(row: BTable) {
       if (this.selectAll) {
         row.selectAllRows();
@@ -627,77 +874,84 @@ export default defineComponent({
         row.clearSelected();
       }
     },
+
+    /**
+     * Toggles the selection of a specific row.
+     * @param {{ rowSelected: boolean; index: number }} row - Info about the row's status and its index.
+     */
     select(row: { rowSelected: boolean; index: number }) {
-      if (row.rowSelected) {
-        (this.$refs.adaptTable as BTable).selectRow(row.index);
-      } else {
-        (this.$refs.adaptTable as BTable).unselectRow(row.index);
-      }
+      const tableRef = this.$refs.adaptTable as BTable;
+      row.rowSelected
+        ? tableRef.selectRow(row.index)
+        : tableRef.unselectRow(row.index);
     },
+
+    /**
+     * Emits an event for file selection.
+     */
     clickFileSelect() {
       this.$emit("clickFileSelect");
     },
-    async updateFileListEdit() {
-      const newFileListEdit = [] as FolderContent[];
-      for (const currentFileEdit of this.fileListEdit) {
-        const selectedFile = this.selectableFiles.find(
-          (f) =>
-            this.currentFolder === currentFileEdit.path &&
-            f.name === currentFileEdit.name
-        );
-        if (selectedFile) {
-          newFileListEdit.push(currentFileEdit);
-        }
-      }
-      for (const currentSelectableFile of this.selectableFiles) {
-        const selectableFile = currentSelectableFile;
-        const fileEdit = newFileListEdit.find(
-          (f) => f.path === this.currentFolder && f.name === selectableFile.name
-        );
-        if (!fileEdit) {
-          const loadedMetadata = await MetadataManagerUtil.loadMetadata(
-            selectableFile,
-            this.resource
+
+    /**
+     * Updates the file list for editing based on current selections.
+     */
+    async updateFileListEdit(selectedFiles: FolderContent[]) {
+      const existingFilesSet = new Set(this.fileListEdit.map((f) => f.name));
+      const newFileListEdit: FileInformation[] = [];
+
+      for (const file of selectedFiles) {
+        // Check if file already exists in the list
+        if (existingFilesSet.has(file.name) && this.dirTrail === file.path) {
+          const existingFile = this.fileListEdit.find(
+            (f) => f.name === file.name
           );
-          newFileListEdit.push({
-            id: uuidv4(),
-            lastModified: selectableFile.lastModified,
-            created: selectableFile.created,
-            path: this.currentFolder,
-            version: `${+new Date()}`,
-            uploading: false,
-            name: selectableFile.name,
-            metadata: loadedMetadata,
-            isFolder: selectableFile.isFolder,
-            absolutePath: selectableFile.absolutePath,
-            info:
-              selectableFile.isFolder === false
-                ? selectableFile.info
-                : undefined,
-            size: selectableFile.isFolder === false ? selectableFile.size : 0,
-          });
+          if (existingFile) {
+            newFileListEdit.push(existingFile as FileInformation);
+          }
+          continue;
         }
+
+        // If file doesn't exist, fetch metadata and add
+        const loadedMetadata = await MetadataManagerUtil.loadMetadataForFile(
+          file,
+          this.project,
+          this.resource
+        );
+
+        newFileListEdit.push({
+          ...file,
+          id: uuidv4(),
+          version: `${+new Date()}`,
+          uploading: false,
+          metadata: loadedMetadata,
+          info: file.isFolder ? undefined : file.info,
+          size: file.isFolder ? 0 : file.size,
+        } as FileInformation);
       }
+
       this.$emit("fileListEdit", newFileListEdit);
-      if (this.selectableFiles.length > 0) {
-        this.$emit("showDetail", true);
-      } else {
-        this.$emit("showDetail", false);
-      }
+      this.$emit("showDetail", selectedFiles.length > 0);
     },
+
+    /**
+     * Converts last modified date into a locale string format.
+     * @param {FolderContent} item - Item to retrieve the date from.
+     * @returns {string} - Formatted date string.
+     */
     renderDate(item: FolderContent): string {
-      if (!item.lastModified) {
-        return "";
-      }
-      const date = item.lastModified;
-      const dateObject = new Date(date);
-      return dateObject.toLocaleDateString(this.$i18n.locale);
+      return item.lastModified
+        ? new Date(item.lastModified).toLocaleDateString(this.$i18n.locale)
+        : "";
     },
+
+    /**
+     * Converts size into a readable string format.
+     * @param {FolderContent} item - Item to retrieve the size from.
+     * @returns {string} - Formatted size string.
+     */
     renderSize(item: FolderContent): string {
-      if (!item.isFolder) {
-        return FileUtil.formatBytes(item.size);
-      }
-      return "";
+      return !item.isFolder ? FileUtil.formatBytes(item.size) : "";
     },
   },
 });
@@ -763,22 +1017,6 @@ export default defineComponent({
 #resourceViewTable div.tableCheck.custom-checkbox label,
 .checkFile {
   vertical-align: top;
-  cursor: pointer;
-}
-
-#resourceViewTable tr:hover .dotMenu button {
-  font-weight: bold;
-  margin: 0;
-}
-
-#resourceViewTable .dotMenu {
-  position: absolute;
-  right: 0px;
-  margin-top: -5px;
-}
-
-#resourceViewTable .dotMenu .dropdown-item {
-  margin: 1px;
 }
 </style>
 
@@ -810,10 +1048,6 @@ export default defineComponent({
   margin-right: 20px;
 }
 
-#resourceViewTable th .additionalColumnHeader svg {
-  cursor: pointer;
-}
-
 .adaptTable {
   overflow: auto;
   position: absolute;
@@ -824,12 +1058,16 @@ export default defineComponent({
   width: auto;
 }
 
-.rightFloating {
-  float: right;
+.fileViewEntryWrapper {
+  align-items: center;
 }
 
-.dataSourceItem {
-  vertical-align: sub;
+.fileViewEntry {
+  padding: 0.05rem 0.5rem;
+}
+
+a.fileViewEntry {
+  cursor: pointer;
 }
 
 .DataSource {
diff --git a/src/modules/resource/components/resource-page/FilesViewHeader.vue b/src/modules/resource/components/resource-page/FilesViewHeader.vue
index e2d36dbb4400d20774623397d965ac41e0d07200..6c2e4079924d7701fc041ea4d691efaabd3604c7 100644
--- a/src/modules/resource/components/resource-page/FilesViewHeader.vue
+++ b/src/modules/resource/components/resource-page/FilesViewHeader.vue
@@ -34,6 +34,7 @@
           :disabled="isUploading || readOnly || (resource && resource.archived)"
           @click="upload"
         >
+          <!-- TODO: Add GitLab branch disabled logic as in MetadataManagerHeader -->
           <b-icon icon="plus" :title="$t('page.resource.upload')" />
         </b-button>
 
diff --git a/src/modules/resource/components/resource-page/MetadataManager.vue b/src/modules/resource/components/resource-page/MetadataManager.vue
index 1570c7c88ff78f376aebf9dc2064d9deef19d67f..7e8a614c9b389df6890a7f4ce23ee21066cd566c 100644
--- a/src/modules/resource/components/resource-page/MetadataManager.vue
+++ b/src/modules/resource/components/resource-page/MetadataManager.vue
@@ -1,5 +1,6 @@
 <template>
   <b-container id="detail-view">
+    <!-- Header Buttons -->
     <MetadataManagerHeader
       v-if="resource"
       :editable-data-url="editableDataUrl"
@@ -12,6 +13,8 @@
       @selectFiles="selectFiles"
       @showModalDeleteFolderContents="showModalDeleteFolderContents"
     />
+
+    <!-- Selected Files Table -->
     <MetadataManagerTable
       :current-file-id="currentFileId"
       :current-folder-content="currentFolderContent"
@@ -23,8 +26,11 @@
       @loadAllFilesTab="changeMetadata(-1)"
       @removeElement="removeElement"
     />
+
+    <!-- Metadata Section -->
     <b-row id="metadataManagerMetadataSection">
       <b-col>
+        <!-- File Information -->
         <MetadataManagerFileInformation
           v-if="
             showDetail &&
@@ -35,6 +41,7 @@
           :current-file-id="currentFileId"
           :file-list-edit="fileListEdit"
         />
+        <!-- Special Properties (see Linked Data) -->
         <MetadataManagerSpecialProperties
           v-if="
             shownFiles.length > 0 &&
@@ -51,6 +58,7 @@
           @updateAbsolutePath="updateAbsolutePath"
           @updateDataUrl="updateDataUrl"
         />
+        <!-- Form Generator -->
         <span
           v-if="
             resource && resource.applicationProfile !== '' && applicationProfile
@@ -77,6 +85,7 @@
       </b-col>
     </b-row>
 
+    <!-- Footer -->
     <MetadataManagerFooter
       :is-uploading="isUploading"
       :number-of-currently-processed-files="numberOfCurrentlyProcessedFiles"
@@ -89,11 +98,15 @@
       @update="update"
       @uploadPreparation="uploadPreparation"
     />
+
+    <!-- Validation Popover -->
     <ValidationPopover
       v-if="validationResults[currentFileId + 1]"
       :valid="valid"
       :validation-results="validationResults[currentFileId + 1].results"
     />
+
+    <!-- Duplicate Files Modal -->
     <SaveDuplicateFilesModal
       :visible="saveDuplicateFilesModalVisible"
       :upload-file-list-replace-files="uploadFileListReplaceFiles"
@@ -111,40 +124,36 @@ import { defineComponent, reactive, type PropType } from "vue";
 import useResourceStore from "../../store";
 import useProjectStore from "@/modules/project/store";
 import useUserStore from "@/modules/user/store";
-
+import useNotificationStore from "@/store/notification";
 import fileSaver from "file-saver";
-
 import MetadataManagerUtil from "../../utils/MetadataManagerUtil";
-
 import MetadataManagerHeader from "./metadata/MetadataManagerHeader.vue";
 import MetadataManagerTable from "./metadata/MetadataManagerTable.vue";
 import MetadataManagerFileInformation from "./metadata/MetadataManagerFileInformation.vue";
 import MetadataManagerSpecialProperties from "./metadata/MetadataManagerSpecialProperties.vue";
 import MetadataManagerFooter from "./metadata/MetadataManagerFooter.vue";
-
 import SaveDuplicateFilesModal from "./modals/SaveDuplicateFilesModal.vue";
 import ValidationPopover from "./popovers/ValidationPopover.vue";
-
-import type {
-  FileInformation,
-  FolderContent,
-} from "../../utils/EntryDefinition";
-
 import "@/plugins/form-generator";
-
-import type { Dataset } from "@rdfjs/types";
 import factory from "rdf-ext";
-
-import type ValidationReport from "rdf-validate-shacl/src/validation-report";
-
 import { v4 as uuidv4 } from "uuid";
-import useNotificationStore from "@/store/notification";
+import { serializeRDFDefinition } from "../../utils/linkedData";
+import type ValidationReport from "rdf-validate-shacl/src/validation-report";
+import type { Dataset } from "@rdfjs/types";
 import type {
+  MetadataTreeForCreationDto,
+  MetadataTreeForUpdateDto,
+  ProjectDto,
+  RdfFormat,
   ResourceDto,
   ResourceTypeInformationDto,
   UserDto,
 } from "@coscine/api-client/dist/types/Coscine.Api";
-import type { BilingualLabels } from "../../types";
+import type {
+  BilingualLabels,
+  FileInformation,
+  FolderContent,
+} from "../../types";
 
 export default defineComponent({
   components: {
@@ -157,6 +166,7 @@ export default defineComponent({
     SaveDuplicateFilesModal,
     ValidationPopover,
   },
+
   props: {
     showDetail: {
       default: false,
@@ -184,11 +194,26 @@ export default defineComponent({
       },
       type: Array as PropType<FolderContent[]>,
     },
-    currentFolder: {
-      default: "/",
+    dirTrail: {
+      required: true,
       type: String,
     },
+    dirCrumbs: {
+      required: true,
+      type: Array as PropType<string[]>,
+    },
+  },
+
+  emits: {
+    clickFileSelect: () => true,
+    emptyFileLists: (_: boolean) => true,
+    isUploading: (_: boolean) => true,
+    navigateTree: () => true,
+    removeElement: (_index: number, _count: number) => true,
+    removeSelection: (_index: number, _count: number) => true,
+    showModalDelete: (_: FolderContent[]) => true,
   },
+
   setup() {
     const resourceStore = useResourceStore();
     const projectStore = useProjectStore();
@@ -202,9 +227,10 @@ export default defineComponent({
       notificationStore,
     };
   },
+
   data() {
     return {
-      currentUsedMetadata: factory.dataset() as unknown as Dataset,
+      currentUsedMetadata: factory.dataset() as unknown as Dataset | null,
       numberOfCurrentlyProcessedFiles: 0,
       totalNumberOfCurrentlyProcessedFiles: 0,
       uploadDuplicates: true,
@@ -227,6 +253,7 @@ export default defineComponent({
       saveDuplicateFilesModalVisible: false,
     };
   },
+
   computed: {
     isGuest(): boolean | undefined {
       return this.projectStore.currentUserRoleIsGuest;
@@ -234,6 +261,9 @@ export default defineComponent({
     applicationProfile(): Dataset | null {
       return this.resourceStore.currentFullApplicationProfile;
     },
+    project(): null | ProjectDto {
+      return this.projectStore.currentProject;
+    },
     resource(): null | ResourceDto {
       return this.resourceStore.currentResource;
     },
@@ -264,7 +294,8 @@ export default defineComponent({
     currentFolderContent(): FolderContent | undefined {
       return this.shownFiles[this.currentFileId];
     },
-    currentMetadata(): Dataset {
+
+    currentMetadata(): Dataset | null {
       if (
         this.currentFileId >= 0 &&
         this.currentFileId < this.shownFiles.length
@@ -350,8 +381,11 @@ export default defineComponent({
     fileListUpload() {
       this.getOptions();
     },
-    fileListEdit() {
-      this.getOptions();
+    fileListEdit(newVal, oldVal) {
+      // Trigger only the value really changed. Otherwise double API calls are triggered.
+      if (newVal !== oldVal) {
+        this.getOptions();
+      }
     },
     isValidating() {
       if (!this.isValidating && this.storedSwitch !== null) {
@@ -370,15 +404,28 @@ export default defineComponent({
       );
     },
   },
+
   created() {
     this.getOptions();
   },
+
   methods: {
+    /**
+     * Fetches vocabulary instances for a given class name from the store.
+     *
+     * @async
+     * @param {string} className - The class name for which vocabulary instances need to be fetched.
+     * @returns {Promise<BilingualLabels>} Returns a promise resolving to bilingual labels.
+     */
     async getVocabularyInstances(className: string): Promise<BilingualLabels> {
       return await this.resourceStore.getVocabularyInstances(className);
     },
+
+    /**
+     * Applies metadata templates to the shown files.
+     */
     applyMetadataTemplate() {
-      if (this.currentUsedMetadata.size > 0) {
+      if (this.currentUsedMetadata && this.currentUsedMetadata.size > 0) {
         for (const currentFile of this.shownFiles) {
           currentFile.metadata = factory.dataset(
             Array.from(this.currentUsedMetadata)
@@ -386,6 +433,13 @@ export default defineComponent({
         }
       }
     },
+
+    /**
+     * Validates a file based on provided validation results.
+     *
+     * @param {ValidationReport} valid - The validation report.
+     * @param {string} fileString - The file string which will be converted to a number to identify the file.
+     */
     isValid(valid: ValidationReport, fileString: string) {
       let fileId = Number(fileString);
       if (isNaN(fileId)) {
@@ -404,9 +458,22 @@ export default defineComponent({
         );
       }
     },
+
+    /**
+     * Updates the validation status.
+     *
+     * @param {boolean} isValidating - The current validation status.
+     * @param {string} _ - Placeholder for an unused parameter.
+     */
     isValidatingChange(isValidating: boolean, _: string) {
       this.isValidating = isValidating;
     },
+
+    /**
+     * Changes the currently viewed metadata based on the provided index.
+     *
+     * @param {number} index - The index of the file whose metadata is to be viewed.
+     */
     changeMetadata(index: number) {
       if (this.isValidating) {
         this.storedSwitch = index;
@@ -414,6 +481,13 @@ export default defineComponent({
         this.currentFileId = index;
       }
     },
+
+    /**
+     * Removes elements from the list based on the provided index and count.
+     *
+     * @param {number} index - The starting index for the removal.
+     * @param {number} count - The number of elements to be removed.
+     */
     removeElement(index: number, count = 1) {
       if (this.showDetail) {
         this.$emit("removeSelection", index, count);
@@ -421,6 +495,14 @@ export default defineComponent({
         this.$emit("removeElement", index, count);
       }
     },
+
+    /**
+     * Adjusts the status of processed files. Sends notifications if necessary.
+     *
+     * @param {FolderContent} file - The file whose status needs adjustment.
+     * @param {boolean} error - A flag indicating if there was an error processing the file.
+     * @param {boolean} reload - A flag indicating if the page should reload.
+     */
     adjustRemainingFiles(file: FolderContent, error = false, reload = false) {
       this.numberOfCurrentlyProcessedFiles -= 1;
       this.progressStatus = 0;
@@ -480,6 +562,12 @@ export default defineComponent({
         }
       }
     },
+
+    /**
+     * Initializes the count of remaining files to be processed.
+     *
+     * @param {number} numberOfFiles - The initial number of files to be processed.
+     */
     initRemainingFiles(numberOfFiles: number) {
       this.fileListError = [];
       this.numberOfCurrentlyProcessedFiles = numberOfFiles;
@@ -498,12 +586,24 @@ export default defineComponent({
         this.$emit("isUploading", true);
       }
     },
+
+    /**
+     * Updates the metadata for the current folder content and sets the current metadata.
+     *
+     * @param {Dataset} metadata - The metadata to be set.
+     */
     inputMetadata(metadata: Dataset) {
       if (this.currentFolderContent) {
         this.currentFolderContent.metadata = metadata;
       }
       this.currentUsedMetadata = metadata;
     },
+
+    /**
+     * Prepares for file uploads by segregating new files and replacement files.
+     *
+     * @async
+     */
     async uploadPreparation() {
       this.uploadFileListNewFiles = [];
       this.uploadFileListReplaceFiles = [];
@@ -523,6 +623,12 @@ export default defineComponent({
         await this.upload();
       }
     },
+
+    /**
+     * Starts the file upload process.
+     *
+     * @async
+     */
     async upload() {
       if (this.currentFileId === -1) {
         this.applyMetadataTemplate();
@@ -539,26 +645,66 @@ export default defineComponent({
         }
       }
     },
+
+    /**
+     * Asynchronously uploads a file and its metadata.
+     * It first constructs and serializes a metadata tree DTO for the file, and then
+     * attempts to create this metadata tree. If successful, the function uploads the file's content.
+     *
+     * @param {FileInformation} file - The file information object to be uploaded.
+     * @async
+     */
     async uploadFile(file: FileInformation) {
-      if (this.resource?.id) {
-        const result = await this.resourceStore.storeMetadata(
-          this.resource.id,
-          file.absolutePath,
-          file.metadata
-        );
-        if (result) {
-          if (!this.editableDataUrl && file.info) {
-            await this.handleUploadContent(file.info, file);
-          } else if (file.dataUrl !== undefined) {
-            this.fillData(file);
-            const blob = new Blob([file.dataUrl], { type: "plain/text" });
-            await this.handleUploadContent(blob, file);
-          }
-        } else {
-          this.adjustRemainingFiles(file, true);
+      if (!this.project?.id || !this.resource?.id) {
+        return;
+      }
+
+      // Specify the target content type
+      const contentType = "text/turtle";
+
+      // Create the metadata tree DTO and serialize the definition
+      const metadataTreeForCreationDto: MetadataTreeForCreationDto = {
+        path: file.path,
+        definition: await serializeRDFDefinition(file.metadata, contentType),
+        format: contentType as RdfFormat,
+      };
+
+      // Trigger metadata tree creation. Metadata might be already present, so we try updating it if true.
+      const success = await this.resourceStore.addOrUpdateMetadataTree(
+        this.project.id,
+        this.resource.id,
+        metadataTreeForCreationDto
+      );
+
+      if (success) {
+        // Check if the file is not editable via data URL and has info, and if so, handle its content upload
+        if (!this.editableDataUrl && file.info) {
+          await this.handleUploadContent(file.info, file);
         }
+        // Else, if the file has a data URL, convert it to a blob and handle its content upload
+        else if (file.dataUrl !== undefined) {
+          this.fillData(file);
+          const blob = new Blob([file.dataUrl], { type: "plain/text" });
+          await this.handleUploadContent(blob, file);
+        }
+      } else {
+        // On Failure, post a generic warning notification
+        this.notificationStore.postNotification({
+          title: this.$t("toast.apiError.failure.title").toString(),
+          body: this.$t("toast.apiError.failure.message").toString(),
+          variant: "warning",
+        });
+        // If metadata tree creation was not successful, adjust the count of files remaining
+        this.adjustRemainingFiles(file, true);
       }
     },
+
+    /**
+     * Converts a FileInformation's dataUrl into a File object.
+     * If no dataUrl exists, initializes it as an empty string.
+     *
+     * @param {FileInformation} file - The file information to process.
+     */
     fillData(file: FileInformation) {
       if (!file.dataUrl) {
         file.dataUrl = "";
@@ -567,109 +713,188 @@ export default defineComponent({
         type: "text/plain",
       });
     },
+
+    /**
+     * Handles the uploading of file contents.
+     * Depending on whether the file already exists, either updates or creates a new blob.
+     * Emits updated folder contents if necessary.
+     *
+     * @param {Blob} contents - The file contents to upload.
+     * @param {FileInformation} file - The file information.
+     * @async
+     */
     async handleUploadContent(contents: Blob, file: FileInformation) {
-      if (this.resource?.id) {
-        this.progressStatus = 0;
-        const result = await this.resourceStore.storeFile(
-          this.resource.id,
-          file.absolutePath,
-          [contents],
-          {
-            onUploadProgress: (progressEvent: ProgressEvent) => {
-              this.progressStatus = Math.round(
-                (progressEvent.loaded * 100) / progressEvent.total
-              );
-            },
-          }
+      if (this.project?.id && this.resource?.id) {
+        const fileExists = this.folderContents.some(
+          (x) => x.name === file.name
         );
-        if (!result) {
+        this.progressStatus = 0;
+
+        // Update progress as the file is uploaded
+        const onUploadProgress = (progressEvent: ProgressEvent) => {
+          this.progressStatus = Math.round(
+            (progressEvent.loaded * 100) / progressEvent.total
+          );
+        };
+
+        // Depending on the file's existence, either update or create the blob
+        const uploadResult = fileExists
+          ? await this.resourceStore.updateBlob(
+              this.project.id,
+              this.resource.id,
+              file.path,
+              contents,
+              { onUploadProgress }
+            )
+          : await this.resourceStore.createBlob(
+              this.project.id,
+              this.resource.id,
+              file.path,
+              contents,
+              { onUploadProgress }
+            );
+
+        if (!uploadResult) {
           this.adjustRemainingFiles(file, true);
         }
+      }
 
-        const entry = this.folderContents.find((x) => x.name === file.name);
-        if (entry === undefined) {
-          const newRow: FileInformation = {
-            id: uuidv4(),
-            isFolder: false,
-            name: file.name,
-            absolutePath: file.absolutePath,
-            lastModified: new Date().toString(),
-            created: new Date().toString(),
-            size: file.size,
-            path: file.path,
-            info: file.info,
-            metadata: factory.dataset() as unknown as Dataset,
-            version: `${+new Date()}`,
-          };
-          MetadataManagerUtil.copyMetadata(file.metadata, newRow);
-          this.$emit("folderContents", [...this.folderContents, newRow]);
-        } else {
-          entry.lastModified = new Date().toString();
-          entry.created = new Date().toString();
-          if (!entry.isFolder) {
-            entry.size = file.size;
-          }
-          MetadataManagerUtil.copyMetadata(file.metadata, entry);
+      // Update or emit the updated folder contents
+      const entry = this.folderContents.find((x) => x.name === file.name);
+      if (entry === undefined) {
+        const newRow: FileInformation = {
+          id: uuidv4(),
+          isFolder: false,
+          name: file.name,
+          type: file.type,
+          parentDirectory: file.parentDirectory,
+          lastModified: new Date().toString(),
+          createdAt: new Date().toString(),
+          size: file.size,
+          path: file.path,
+          info: file.info,
+          metadata: factory.dataset() as unknown as Dataset,
+          version: `${+new Date()}`,
+        };
+        MetadataManagerUtil.copyMetadata(file.metadata, newRow);
+        this.$emit("navigateTree");
+      } else {
+        entry.lastModified = new Date().toString();
+        entry.createdAt = new Date().toString();
+        if (!entry.isFolder) {
+          entry.size = file.size;
         }
-        this.adjustRemainingFiles(file);
+        MetadataManagerUtil.copyMetadata(file.metadata, entry);
       }
+      this.adjustRemainingFiles(file);
     },
+
+    /**
+     * Downloads selected files.
+     * If the detail view is active, attempts to download each shown file.
+     *
+     * @async
+     */
     async download() {
-      if (this.showDetail && this.resource?.id) {
+      if (this.showDetail && this.project?.id && this.resource?.id) {
         for (const editableFile of this.shownFiles) {
-          const response = await this.resourceStore.getFile(
+          const response = await this.resourceStore.getBlob(
+            this.project.id,
             this.resource.id,
-            editableFile.absolutePath,
-            true
+            editableFile.path
           );
-          if (response) {
-            fileSaver.saveAs(response, editableFile.name);
+          if (response !== null) {
+            fileSaver.saveAs(
+              new Blob([response.data], {
+                type: response.headers["content-type"],
+              }),
+              editableFile.name
+            );
           }
         }
       }
     },
+
+    /**
+     * Emits an event signaling the selection of files.
+     */
     selectFiles() {
       this.$emit("clickFileSelect");
     },
+
+    /**
+     * Asynchronously updates the resource's metadata based on the files in the edit list.
+     * It applies metadata templates, initializes remaining files, and then iterates over
+     * the edit list to update each file's metadata. It also handles file uploads when
+     * necessary.
+     *
+     * @async
+     */
     async update() {
-      if (this.resource?.id) {
-        if (this.currentFileId === -1) {
-          this.applyMetadataTemplate();
-        }
-        this.initRemainingFiles(this.fileListEdit.length);
+      if (!this.project?.id || !this.resource?.id) {
+        return;
+      }
 
-        for (const editableFile of this.fileListEdit) {
-          const result = await this.resourceStore.storeMetadata(
-            this.resource.id,
-            editableFile.absolutePath,
-            editableFile.metadata
-          );
-          if (result) {
-            const tmp = this.folderContents.find(
-              (x) => x.name === editableFile.name
-            );
-            if (
-              this.editableDataUrl &&
-              !editableFile.isFolder &&
-              editableFile.dataUrl !== undefined
-            ) {
-              this.fillData(editableFile);
-              const blob = new Blob([editableFile.dataUrl], {
-                type: "plain/text",
-              });
-              await this.handleUploadContent(blob, editableFile);
-            } else {
-              MetadataManagerUtil.copyMetadata(editableFile.metadata, tmp);
-              this.adjustRemainingFiles(editableFile);
-            }
+      // Specify the target content type
+      const contentType = "text/turtle";
+
+      // If this is the initial file, apply the metadata template
+      if (this.currentFileId === -1) {
+        this.applyMetadataTemplate();
+      }
+
+      // Initialize files yet to be processed
+      this.initRemainingFiles(this.fileListEdit.length);
+
+      for (const file of this.fileListEdit) {
+        // Create the metadata tree DTO and serialize the definition
+        const metadataTreeForUpdateDto: MetadataTreeForUpdateDto = {
+          path: file.path,
+          definition: await serializeRDFDefinition(file.metadata, contentType),
+          format: contentType as RdfFormat,
+        };
+
+        const success = await this.resourceStore.updateOrAddMetadataTree(
+          this.project.id,
+          this.resource.id,
+          metadataTreeForUpdateDto
+        );
+
+        if (success) {
+          // Find the corresponding file entry from folder contents
+          const tmp = this.folderContents.find((x) => x.name === file.name);
+
+          // If the file has a data URL and is editable, handle its content upload
+          if (
+            this.editableDataUrl &&
+            !file.isFolder &&
+            file.dataUrl !== undefined
+          ) {
+            this.fillData(file);
+            const blob = new Blob([file.dataUrl], {
+              type: "plain/text",
+            });
+            await this.handleUploadContent(blob, file);
           } else {
-            this.adjustRemainingFiles(editableFile, true);
+            // If not a file for upload, just copy the metadata
+            MetadataManagerUtil.copyMetadata(file.metadata, tmp);
+            this.adjustRemainingFiles(file);
           }
+        } else {
+          // If the update was not successful, adjust the remaining files count
+          this.adjustRemainingFiles(file, true);
         }
       }
     },
+
+    /**
+     * Retrieves blob options for each shown file, if applicable.
+     * Updates the data URL for each file from the store.
+     *
+     * @async
+     */
     async getOptions() {
-      if (this.resource?.id) {
+      if (this.project?.id && this.resource?.id) {
         if (this.shownFiles.length === 1) {
           this.currentFileId = 0;
         }
@@ -681,51 +906,89 @@ export default defineComponent({
                 return;
               }
               element.requesting = true;
-              const response = await this.resourceStore.getFile(
+              const response = await this.resourceStore.getBlob(
+                this.project.id,
                 this.resource.id,
-                element.absolutePath
+                element.path
               );
-              this.$set(element, "dataUrl", response);
+              if (response !== null) {
+                this.$set(element, "dataUrl", response.data);
+              }
               element.requesting = false;
             }
           }
         }
       }
     },
+
+    /**
+     * Updates the absolute path of the current folder content based on a new value.
+     *
+     * @param {string} value - The new value for the folder content's name.
+     */
     updateAbsolutePath(value: string) {
       if (this.currentFolderContent) {
         this.currentFolderContent.name = value;
+        const currentFolder = this.dirCrumbs.join("");
         this.currentFolderContent.path =
-          this.currentFolderContent.path !== ""
-            ? this.currentFolderContent.path
-            : "/";
-        this.currentFolderContent.absolutePath =
-          this.currentFolderContent.path + this.currentFolderContent.name;
+          currentFolder + this.currentFolderContent.name;
       }
     },
+
+    /**
+     * Updates the data URL and size of the current folder content based on a new value.
+     *
+     * @param {string} value - The new value for the data URL.
+     */
     updateDataUrl(value: string) {
       if (this.currentFolderContent && !this.currentFolderContent.isFolder) {
         this.currentFolderContent.dataUrl = value;
         this.currentFolderContent.size = value.length;
       }
     },
+
+    /**
+     * Emits an event to clean up file lists.
+     */
     cleanup() {
-      this.$emit("emptyFileLists");
+      this.$emit("emptyFileLists", true);
     },
+
+    /**
+     * Emits an event to display the modal for deleting folder contents.
+     */
     showModalDeleteFolderContents() {
       this.$emit("showModalDelete", this.fileListEdit);
     },
+
+    /**
+     * Displays the modal for saving duplicate files.
+     */
     showModalSaveDuplicateFiles() {
       this.saveDuplicateFilesModalVisible = true;
     },
+
+    /**
+     * Hides the modal for saving duplicate files.
+     */
     hideModalSaveDuplicateFiles() {
       this.saveDuplicateFilesModalVisible = false;
     },
+
+    /**
+     * Handles the overwrite action in the modal for saving duplicate files.
+     * Initiates the upload process afterward.
+     */
     overwriteModalSaveDuplicateFiles() {
       this.uploadDuplicates = true;
       this.saveDuplicateFilesModalVisible = false;
       this.upload();
     },
+
+    /**
+     * Handles the skip action in the modal for saving duplicate files.
+     * Initiates the upload process afterward.
+     */
     skipModalSaveDuplicateFiles() {
       this.uploadDuplicates = false;
       this.saveDuplicateFilesModalVisible = false;
diff --git a/src/modules/resource/components/resource-page/metadata/MetadataManagerFileInformation.vue b/src/modules/resource/components/resource-page/metadata/MetadataManagerFileInformation.vue
index 020d30858ebe1a47ba9d8bee67e30b2ddd9c8c37..0dedfe575534029fcd1a909948eec1b3063dc6e5 100644
--- a/src/modules/resource/components/resource-page/metadata/MetadataManagerFileInformation.vue
+++ b/src/modules/resource/components/resource-page/metadata/MetadataManagerFileInformation.vue
@@ -1,9 +1,9 @@
 <template>
   <span>
+    <!-- File Name -->
     <CoscineFormGroup :label="$t('page.resource.infoFileName')">
       <div
-        id="fileInfoFieldID"
-        class="fileInfoField"
+        id="fileInfofileName"
         data-toggle="tooltip"
         :title="currentFile.name"
       >
@@ -14,42 +14,39 @@
         }}
       </div>
     </CoscineFormGroup>
+
+    <!-- Last Modified -->
     <CoscineFormGroup :label="$t('page.resource.infoFileLastModified')">
-      <div class="fileInfoField">
-        {{
-          !currentFile.lastModified
-            ? $t("page.resource.infoFileNoInformation")
-            : new Date(currentFile.lastModified).toLocaleDateString(
-                $i18n.locale
-              )
-        }}
-      </div>
+      {{
+        !currentFile.lastModified
+          ? $t("page.resource.infoFileNoInformation")
+          : new Date(currentFile.lastModified).toLocaleDateString($i18n.locale)
+      }}
     </CoscineFormGroup>
+
+    <!-- Uploaded -->
     <CoscineFormGroup :label="$t('page.resource.infoFileCreated')">
-      <div class="fileInfoField">
-        {{
-          !currentFile.created
-            ? $t("page.resource.infoFileNoInformation")
-            : new Date(currentFile.created).toLocaleDateString($i18n.locale)
-        }}
-      </div>
+      {{
+        !currentFile.createdAt
+          ? $t("page.resource.infoFileNoInformation")
+          : new Date(currentFile.createdAt).toLocaleDateString($i18n.locale)
+      }}
     </CoscineFormGroup>
+
+    <!-- File Size -->
     <CoscineFormGroup :label="$t('page.resource.infoFileSize')">
-      <div class="fileInfoField">
-        {{
-          currentFile.isFolder === false
-            ? currentFile.size + " Bytes"
-            : $t("page.resource.infoFileNoInformation")
-        }}
-      </div>
+      {{
+        currentFile.isFolder === false
+          ? currentFile.size + " Bytes"
+          : $t("page.resource.infoFileNoInformation")
+      }}
     </CoscineFormGroup>
   </span>
 </template>
 
 <script lang="ts">
 import { defineComponent, type PropType } from "vue";
-
-import type { FolderContent } from "../../../utils/EntryDefinition";
+import type { FolderContent } from "@/modules/resource/types";
 
 export default defineComponent({
   props: {
@@ -71,12 +68,7 @@ export default defineComponent({
 </script>
 
 <style scoped>
-.fileInfoField {
-  padding-top: calc(0.375rem + 1px);
-  padding-bottom: calc(0.375rem + 1px);
-}
-#fileInfoFieldID {
-  margin-left: auto;
+#fileInfofileName {
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
diff --git a/src/modules/resource/components/resource-page/metadata/MetadataManagerHeader.vue b/src/modules/resource/components/resource-page/metadata/MetadataManagerHeader.vue
index 5af166d194c077d716201ec5d54a5bc115bc343c..f3923c7d8ef1885bace2c50b6fc70110b124818d 100644
--- a/src/modules/resource/components/resource-page/metadata/MetadataManagerHeader.vue
+++ b/src/modules/resource/components/resource-page/metadata/MetadataManagerHeader.vue
@@ -65,20 +65,20 @@
 
 <script lang="ts">
 import { defineComponent, type PropType } from "vue";
-
 import useProjectStore from "@/modules/project/store";
 // import the store for current module
 import useResourceStore from "../../../store";
-
-import type { FolderContent } from "../../../utils/EntryDefinition";
-
 import type { TranslateResult } from "vue-i18n";
 import type {
   GitlabBranchDto,
   ResourceDto,
   ResourceTypeInformationDto,
 } from "@coscine/api-client/dist/types/Coscine.Api";
-import { CoscineResourceTypes } from "@/modules/resource/types";
+import {
+  CoscineResourceTypes,
+  type FolderContent,
+} from "@/modules/resource/types";
+
 export default defineComponent({
   props: {
     editableDataUrl: {
@@ -168,7 +168,6 @@ export default defineComponent({
       const accessToken =
         this.resource.type?.options?.gitLabOptions?.accessToken;
       const currentBranch = this.resource.type?.options?.gitLabOptions?.branch;
-
       if (projectId && domain && accessToken && currentBranch) {
         const gitlabBranches =
           await this.resourceStore.getGitlabBranchesForProject(
diff --git a/src/modules/resource/components/resource-page/metadata/MetadataManagerSpecialProperties.vue b/src/modules/resource/components/resource-page/metadata/MetadataManagerSpecialProperties.vue
index 4120042ad9e9f0da9e11abce47116bcbefad57d6..d0aaa67efe3f64a9ce11dcb3d469967b86230b66 100644
--- a/src/modules/resource/components/resource-page/metadata/MetadataManagerSpecialProperties.vue
+++ b/src/modules/resource/components/resource-page/metadata/MetadataManagerSpecialProperties.vue
@@ -1,5 +1,6 @@
 <template>
   <div>
+    <!-- Data URL -->
     <span v-if="editableDataUrl && !currentFolderContent.isFolder">
       <CoscineFormGroup
         :mandatory="true"
@@ -21,6 +22,8 @@
         </b-input-group>
       </CoscineFormGroup>
     </span>
+
+    <!-- Entry Name - Editable Key -->
     <span v-if="editableKey">
       <CoscineFormGroup
         :mandatory="true"
@@ -43,7 +46,7 @@
 import { defineComponent, type PropType } from "vue";
 import useProjectStore from "@/modules/project/store";
 
-import type { FolderContent } from "../../../utils/EntryDefinition";
+import type { FolderContent } from "@/modules/resource/types";
 import type { ResourceDto } from "@coscine/api-client/dist/types/Coscine.Api";
 
 export default defineComponent({
diff --git a/src/modules/resource/components/resource-page/metadata/MetadataManagerTable.vue b/src/modules/resource/components/resource-page/metadata/MetadataManagerTable.vue
index e6ddadc099f1937f75bcbaaafd379c2070354081..ea85cea51ed93a0d8c33722703fec796bb00f30f 100644
--- a/src/modules/resource/components/resource-page/metadata/MetadataManagerTable.vue
+++ b/src/modules/resource/components/resource-page/metadata/MetadataManagerTable.vue
@@ -72,9 +72,9 @@
             {{ currentFolderContent.name }}
           </span>
         </span>
-        <span v-else-if="shownFiles.length > 0">{{
-          $t("page.resource.allFiles")
-        }}</span>
+        <span v-else-if="shownFiles.length > 0">
+          {{ $t("page.resource.allFiles") }}
+        </span>
       </b-col>
     </b-row>
   </div>
@@ -83,7 +83,7 @@
 <script lang="ts">
 import { defineComponent, type PropType } from "vue";
 
-import type { FolderContent } from "../../../utils/EntryDefinition";
+import type { FolderContent } from "@/modules/resource/types";
 
 export default defineComponent({
   props: {
diff --git a/src/modules/resource/components/resource-page/modals/DeleteFolderContentsModal.vue b/src/modules/resource/components/resource-page/modals/DeleteFolderContentsModal.vue
index c79ea2e4094d4f36beef6a9d1e32151c07caeeff..5b5ba6513cd68a93428a63966027e08fd49ada87 100644
--- a/src/modules/resource/components/resource-page/modals/DeleteFolderContentsModal.vue
+++ b/src/modules/resource/components/resource-page/modals/DeleteFolderContentsModal.vue
@@ -39,7 +39,7 @@
 
 <script lang="ts">
 import { defineComponent, type PropType } from "vue";
-import type { FolderContent } from "../../../utils/EntryDefinition";
+import type { FolderContent } from "@/modules/resource/types";
 
 export default defineComponent({
   props: {
diff --git a/src/modules/resource/components/resource-page/modals/SaveDuplicateFilesModal.vue b/src/modules/resource/components/resource-page/modals/SaveDuplicateFilesModal.vue
index 33527fd30354940dc50114f3c1ea388d7fa6caca..cca04be3826359119450ceefa7c080ed51dba42a 100644
--- a/src/modules/resource/components/resource-page/modals/SaveDuplicateFilesModal.vue
+++ b/src/modules/resource/components/resource-page/modals/SaveDuplicateFilesModal.vue
@@ -56,8 +56,8 @@ import { defineComponent, type PropType } from "vue";
 import useResourceStore from "../../../store";
 import useProjectStore from "@/modules/project/store";
 
-import type { VisitedResourceObject } from "../../../types";
-import type { FileInformation } from "@/modules/resource/utils/EntryDefinition";
+import type { FileInformation, VisitedResourceObject } from "../../../types";
+
 import type { ResourceTypeInformationDto } from "@coscine/api-client/dist/types/Coscine.Api";
 
 export default defineComponent({
diff --git a/src/modules/resource/pages/ResourcePage.spec.ts b/src/modules/resource/pages/ResourcePage.spec.ts
index 846ba7429e01d24ffd580a4bcca2934160d25930..8b4ceb1a4693bf23f6e8b7cddd938c2a95a075c1 100644
--- a/src/modules/resource/pages/ResourcePage.spec.ts
+++ b/src/modules/resource/pages/ResourcePage.spec.ts
@@ -1,5 +1,5 @@
 /* Testing imports */
-import { createLocalVue, mount } from "@vue/test-utils";
+import { type Wrapper, createLocalVue, mount } from "@vue/test-utils";
 import { createTestingPinia } from "@pinia/testing";
 
 /* Vue i18n */
@@ -15,14 +15,19 @@ import { PiniaVuePlugin } from "pinia";
 
 /* Tested Component */
 import ResourcePage from "./ResourcePage.vue";
+import VueRouter from "vue-router";
+import { routes } from "@/router";
 
-import type Vue from "vue";
+import Vue from "vue";
 
 import { getTestUserState } from "@/data/mockup/testUser";
 import { getTestResourceState } from "@/data/mockup/testResource";
 import { testProjectState } from "@/data/mockup/testProject";
 import useResourceStore from "../store";
-import { getMetadataResponse } from "@/data/mockup/responses/getMetadata";
+import {
+  getFileTreeResponse,
+  getMetadataTreeResponse,
+} from "@/data/mockup/responses/getMetadata";
 
 function sleep(ms: number) {
   return new Promise((resolve) => setTimeout(resolve, ms));
@@ -31,61 +36,87 @@ function sleep(ms: number) {
 /* Create a local Vue instance */
 const localVue = createLocalVue();
 localVue.use(PiniaVuePlugin);
+localVue.use(VueRouter);
+const router = new VueRouter({ routes: routes });
 
-describe("ResourcePage.vue", () => {
-  /* Checks for correct default handling of RCV page */
-  test(
-    "defaultHandling",
-    async () => {
-      const testingPinia = createTestingPinia({
-        createSpy: vitest.fn,
-        initialState: {
-          project: testProjectState,
-          resource: await getTestResourceState(),
-          user: getTestUserState(),
-        },
-      });
+// Define the Vue instance type (computed properties)
+interface ResourcePageComponent extends Vue {
+  dirTrail: string;
+}
 
-      const resourceStore = useResourceStore(testingPinia);
-      vi.mocked(resourceStore.getMetadata).mockReturnValue(
-        Promise.resolve(getMetadataResponse)
-      );
-      vi.mocked(resourceStore.getVocabularyInstances).mockReturnValue(
-        Promise.resolve({ en: [], de: [] })
-      );
+describe("ResourcePage.vue", async () => {
+  let wrapper: Wrapper<ResourcePageComponent>;
 
-      const wrapper = mount(ResourcePage as unknown as typeof Vue, {
-        pinia: testingPinia,
-        i18n,
-        localVue,
-      });
+  // Create a mocked pinia instance with initial state
+  const testingPinia = createTestingPinia({
+    createSpy: vitest.fn,
+    initialState: {
+      project: testProjectState,
+      resource: await getTestResourceState(),
+      user: getTestUserState(),
+    },
+  });
+
+  // Mock the API calls
+  const resourceStore = useResourceStore(testingPinia);
+  vi.mocked(resourceStore.getMetadataTree).mockReturnValue(
+    Promise.resolve(getMetadataTreeResponse)
+  );
+  vi.mocked(resourceStore.getFileTree).mockReturnValue(
+    Promise.resolve(getFileTreeResponse)
+  );
+  vi.mocked(resourceStore.getVocabularyInstances).mockReturnValue(
+    Promise.resolve({ en: [], de: [] })
+  );
 
+  beforeEach(() => {
+    // shallowMount does not work here!
+    wrapper = mount(ResourcePage as unknown as typeof Vue, {
+      pinia: testingPinia,
+      router,
+      i18n,
+      localVue,
+    }) as Wrapper<ResourcePageComponent>;
+  });
+
+  test(
+    "Should render form fields and file entries and reflect metadata upon selection",
+    async () => {
       await wrapper.vm.$nextTick();
 
       // Wait for 1 second until everything is set up
-      await sleep(1000);
+      await sleep(1000); // Don't remove!
 
       // Form-Generator rendered
-      let textFields = wrapper.findAllComponents({ name: "InputTextField" });
-      expect(textFields.length).toBeGreaterThanOrEqual(4);
+      // The test resource uses the Base Application profile,
+      // which has has 5 fields (2x text, 1x date, 2x combo box)
+      let wrapperInputFields = wrapper.findAllComponents({
+        name: "WrapperInput",
+      });
+      expect(wrapperInputFields.length).toBe(5);
 
-      // Entries in table rendered
-      const tableFields = wrapper.findAll(".dataSourceItem");
-      expect(tableFields.length).toBeGreaterThanOrEqual(6);
+      // File-View rendered with as many entries as the test resource has files/folders
+      const tableFields = wrapper.findAll(".fileViewEntry");
+      expect(tableFields.length).toBeGreaterThanOrEqual(3);
 
-      // Find first entry checkbox
+      // Find the first entry in the table and select it
       const firstFound = wrapper.find(".tableCheck .custom-control-input");
       await firstFound.setChecked(true);
 
       // Wait for 1 second until everything is updated
-      await sleep(1000);
+      await sleep(1000); // Don't remove!
 
       // After selecting an entry in the table, its metadata should be rendered in the metadata manager
-      textFields = wrapper.findAllComponents({ name: "InputTextField" });
-      const textInput = textFields.wrappers[1];
-      expect((textInput.element as HTMLInputElement).value).toBe("Test");
+      wrapperInputFields = wrapper.findAllComponents({
+        name: "InputTextField",
+      });
+      const textInput = wrapperInputFields.wrappers[0]; // For the used AP, the first InputTextField is "Title"
+      expect((textInput.element as HTMLInputElement).value).toBe(
+        "Title inside Form Generator"
+      );
     },
     {
+      // Override the maximum run time for this test (10 sec), due to the sleep() calls
       timeout: 10000,
     }
   );
diff --git a/src/modules/resource/pages/ResourcePage.vue b/src/modules/resource/pages/ResourcePage.vue
index c894c2999ffcddfa54715042bac1460c77f7ac36..327c5ae62de21e7ee723ba5422cb9c1ca6a98b0d 100644
--- a/src/modules/resource/pages/ResourcePage.vue
+++ b/src/modules/resource/pages/ResourcePage.vue
@@ -7,33 +7,46 @@
     @dragover.prevent=""
     @drop.prevent="uploadDrop"
   >
+    <!-- Drop File to Upload -->
     <div v-if="showDroppable && fileAddable" class="droppable">
-      <p class="droppableText">{{ $t("page.resource.canDropFile") }}</p>
+      <p class="droppableText">
+        {{ $t("page.resource.canDropFile") }}
+      </p>
     </div>
+
+    <!-- Headline -->
     <coscine-headline
-      v-show="!isFullscreen"
+      v-show="!isFullscreenActive"
       :headline="$t('page.resource.resources')"
     />
+
+    <!-- Form File Window -->
     <b-form-file
       ref="fileTrigger"
       multiple
       class="mt-3"
       plain
       @input="fileListUploadSelected"
-    ></b-form-file>
+    />
+
+    <!-- Files View Column -->
     <span id="filesViewSpan">
-      <div id="filesViewCard" :class="isFullscreen == false ? 'card' : ''">
-        <div :class="isFullscreen == false ? 'card-body' : ''">
+      <div
+        id="filesViewCard"
+        :class="isFullscreenActive == false ? 'card' : ''"
+      >
+        <!-- Files View -->
+        <div :class="isFullscreenActive == false ? 'card-body' : ''">
           <FilesView
             ref="filesView"
             :folder-contents="folderContents"
-            :current-folder="currentFolder"
             :is-uploading="isUploading"
             :file-list-edit="fileListEdit"
+            :dir-trail="dirTrail"
+            :dir-crumbs="dirCrumbs"
             @showDetail="setShowDetail"
-            @currentFolder="setCurrentFolder"
-            @folderContents="setFolder"
-            @fileListEdit="setFileListEdit"
+            @folderContents="updateFolderContent"
+            @fileListEdit="updateEditFileList"
             @clickFileSelect="clickFileSelect"
             @showModalDelete="showModalDelete"
             @waitingForResponse="setWaitingForResponse"
@@ -41,17 +54,25 @@
         </div>
       </div>
     </span>
+
+    <!-- Metadata Manager Column -->
     <div
       id="metadataManagerDiv"
-      :class="isMetadataManagerHidden == true ? 'hiddenMetadataManager' : ''"
+      :class="{ hiddenMetadataManager: isMetadataManagerHidden }"
     >
+      <!-- Vertical Button Bar for Fullscreen -->
       <b-button
-        v-show="isFullscreen"
+        v-show="isFullscreenActive"
         id="metadataManagerToggleFullscreen"
         squared
-        @click="toggleMenu()"
-        ><span>{{ $t("page.resource.metadataManager") }}</span></b-button
+        @click="toggleMetadataPanel()"
       >
+        <span>
+          {{ $t("page.resource.metadataManager") }}
+        </span>
+      </b-button>
+
+      <!-- Metadata Manager -->
       <div class="card">
         <div class="card-body">
           <MetadataManager
@@ -59,44 +80,37 @@
             :file-list-edit="fileListEdit"
             :file-list-upload="fileListUpload"
             :folder-contents="folderContents"
-            :current-folder="currentFolder"
+            :dir-trail="dirTrail"
+            :dir-crumbs="dirCrumbs"
             :is-uploading="isUploading"
             @emptyFileLists="emptyFileLists"
-            @folderContents="setFolder"
-            @removeElement="removeElement"
+            @navigateTree="navigateTreeInFilesView"
+            @removeElement="deleteFromUploadList"
             @removeSelection="removeSelection"
             @isUploading="setIsUploading"
             @showModalDelete="showModalDelete"
             @clickFileSelect="clickFileSelect"
           />
+
+          <!-- Toggle Fullscreen Button -->
           <div
             id="toggleFullscreenButton"
-            :class="
-              isMetadataManagerHidden == true ? '' : 'hiddenMetadataManager'
-            "
+            :class="{ hiddenMetadataManager: !isMetadataManagerHidden }"
           >
-            <button
-              v-if="isFullscreen"
-              class="btn btn-secondary"
-              type="button"
-              @click="toggleFullscreen"
-            >
-              <b-icon icon="fullscreen-exit" />
-            </button>
-            <button
-              v-else
-              type="button"
-              class="btn btn-secondary"
-              @click="toggleFullscreen"
-            >
-              <b-icon icon="fullscreen" />
+            <button class="btn btn-secondary" @click="toggleViewMode">
+              <b-icon
+                :icon="isFullscreenActive ? 'fullscreen-exit' : 'fullscreen'"
+              />
             </button>
           </div>
         </div>
       </div>
     </div>
+
+    <!-- Page Loading Spinner -->
     <LoadingSpinner :is-waiting-for-response="isWaitingForResponse" />
-    <!-- Delete RCV File Modal -->
+
+    <!-- Delete File Modal -->
     <DeleteFolderContentsModal
       :visible="deleteModalVisible"
       :shown-files="filesToBeDeleted"
@@ -109,33 +123,25 @@
 <script lang="ts">
 import { defineComponent } from "vue";
 import type Vue from "vue";
-
 // import the store for current module
 import useResourceStore from "../store";
 // import the main store
 import useMainStore from "@/store/index";
 import useProjectStore from "@/modules/project/store";
-
 import FilesView from "../components/resource-page/FilesView.vue";
 import MetadataManager from "../components/resource-page/MetadataManager.vue";
-
 import DeleteFolderContentsModal from "../components/resource-page/modals/DeleteFolderContentsModal.vue";
-
-import type {
-  FileInformation,
-  FolderContent,
-  FolderInformation,
-} from "../utils/EntryDefinition";
-
 import { v4 as uuidv4 } from "uuid";
 import factory from "rdf-ext";
-
 import type { BFormFile, BTable } from "bootstrap-vue";
 import type { Dataset } from "@rdfjs/types";
 import type {
+  ProjectDto,
   ResourceDto,
   ResourceTypeInformationDto,
+  TreeDataType,
 } from "@coscine/api-client/dist/types/Coscine.Api";
+import type { FolderContent, FileInformation } from "../types";
 
 export default defineComponent({
   components: {
@@ -143,10 +149,12 @@ export default defineComponent({
     MetadataManager,
     DeleteFolderContentsModal,
   },
+
   beforeRouteLeave(to, from, next) {
-    this.setFullscreen(false);
+    this.updateViewMode(false);
     next();
   },
+
   setup() {
     const mainStore = useMainStore();
     const projectStore = useProjectStore();
@@ -158,18 +166,14 @@ export default defineComponent({
   data() {
     return {
       isWaitingForResponse: false,
-      fileListEdit: [] as FolderContent[],
       showDetail: false,
+      fileListEdit: [] as FolderContent[],
       fileListUpload: [] as FileInformation[],
-      folderContents: [] as FolderContent[],
       filesToBeDeleted: [] as FolderContent[],
-      currentFolder:
-        window.location.hash.indexOf("#") !== -1
-          ? window.location.hash.substring(1)
-          : "/",
+      folderContents: [] as FolderContent[],
       dragCounter: 0,
 
-      isFullscreen: false,
+      isFullscreenActive: false,
       isMetadataManagerHidden: false,
       isUploading: false,
 
@@ -181,6 +185,9 @@ export default defineComponent({
     resource(): null | ResourceDto {
       return this.resourceStore.currentResource;
     },
+    project(): null | ProjectDto {
+      return this.projectStore.currentProject;
+    },
     resourceTypeInformation(): ResourceTypeInformationDto | undefined {
       return this.resourceStore.enabledResourceTypes?.find(
         (resourceType) => resourceType.id === this.resource?.type?.id
@@ -200,7 +207,22 @@ export default defineComponent({
     isGuest(): boolean | undefined {
       return this.projectStore.currentUserRoleIsGuest;
     },
+    dirTrail(): string {
+      return this.$route.params.dirTrail ?? "";
+    },
+    dirCrumbs(): string[] {
+      const trail = this.dirTrail;
+      const pathArray = trail
+        .substring(0, trail.lastIndexOf("/") + 1)
+        .split("/")
+        .filter((n) => n);
+
+      return pathArray.map((f) => {
+        return f ? `${f}/` : "";
+      });
+    },
   },
+
   watch: {
     fileListEdit() {
       if (this.fileListEdit.length > 0) {
@@ -211,23 +233,30 @@ export default defineComponent({
       this.emptyFileLists();
     },
   },
+
   mounted() {
     this.$nextTick(() => {
-      window.addEventListener("resize", this.getWindowWidth);
+      window.addEventListener("resize", this.adjustViewForScreenWidth);
 
-      this.getWindowWidth();
+      this.adjustViewForScreenWidth();
     });
     this.emptyFileLists();
   },
+
   methods: {
+    /**
+     * Trigger file selection, if not editable data URL is provided.
+     */
     clickFileSelect() {
       this.showDetail = false;
+      // Check if editableDataUrl is present
       if (
         this.resourceTypeInformation?.resourceContent?.metadataView
           ?.editableDataUrl
       ) {
         this.emptyFileLists();
       } else {
+        // Trigger a click event on fileTrigger element
         (this.$refs.fileTrigger as BFormFile).$el.dispatchEvent(
           new MouseEvent("click", {
             view: window,
@@ -237,37 +266,75 @@ export default defineComponent({
         );
       }
     },
+
+    /**
+     * Display the modal for file deletion and set the files to be deleted.
+     * @param {FolderContent[]} files - Files to be deleted.
+     */
     showModalDelete(files: FolderContent[]) {
-      //open modal
+      // Open modal
       this.deleteModalVisible = true;
-      //pass files from emit
+      // Pass files from emit
       this.filesToBeDeleted = files;
     },
+
+    /**
+     * Close the delete modal and reset the filesToBeDeleted list.
+     */
+    closeModalDeleteFile() {
+      this.deleteModalVisible = false;
+      this.filesToBeDeleted = [];
+    },
+
+    /**
+     * Trigger a navigation in the child component to update the view.
+     */
+    async navigateTreeInFilesView() {
+      await (
+        this.$refs.filesView as unknown as typeof FilesView
+      ).navigateTree();
+    },
+
+    /**
+     * Delete selected files.
+     */
     async deleteFiles() {
-      if (this.resource?.id) {
+      if (this.resource?.id && this.project?.id) {
         for (const fileToDelete of this.filesToBeDeleted) {
           this.$emit("waitingForResponse", true);
-          await this.resourceStore.deleteFile(
+
+          await this.resourceStore.deleteBlob(
+            this.project.id,
             this.resource.id,
-            fileToDelete.absolutePath
+            fileToDelete.path
           );
-          this.$emit("waitingForResponse", false);
         }
-        location.reload();
+        this.closeModalDeleteFile();
+        // Trigger a navigation in the child component to update the view after deletion
+        await this.navigateTreeInFilesView();
+        this.$emit("waitingForResponse", false);
       }
     },
 
-    closeModalDeleteFile() {
-      this.deleteModalVisible = false;
-      this.filesToBeDeleted = [];
-    },
+    /**
+     * Handle drag enter event. Increase drag counter on dragEnter.
+     */
     dragEnter() {
       this.dragCounter++;
     },
+
+    /**
+     * Handle drag leave event. Decrease drag counter on dragLeave.
+     */
     dragLeave() {
       this.dragCounter--;
     },
-    emptyFileLists(emptyUpload = true) {
+
+    /**
+     * Clear the file lists.
+     * @param {boolean} emptyUpload - Indicates whether to clear upload list as well.
+     */
+    emptyFileLists(emptyUpload: boolean = true) {
       this.removeSelection(0, this.fileListEdit.length);
       this.fileListEdit.length = 0;
       if (emptyUpload) {
@@ -276,31 +343,43 @@ export default defineComponent({
       this.showDetail = false;
       this.initializeForResourceType();
     },
+
+    /**
+     * Add selected files to the fileListUpload list.
+     * @param {File[] | File} selectedFiles - Selected files.
+     */
     fileListUploadSelected(selectedFiles: File[] | File) {
       if (!Array.isArray(selectedFiles)) {
         selectedFiles = [selectedFiles];
       }
       this.emptyFileLists(false);
+
+      // Pushing selected files into the upload list
       for (const file of selectedFiles) {
         this.fileListUpload.push({
           id: uuidv4(),
-          path: this.currentFolder,
+          path: this.dirTrail + file.name,
+          parentDirectory: this.dirTrail,
+          type: file.type,
           version: `${+new Date()}`,
           uploading: false,
           info: file,
           name: file.name,
           size: file.size,
-          lastModified: "" + file.lastModified,
+          lastModified: `${file.lastModified}`,
           metadata: factory.dataset() as unknown as Dataset,
-          isFolder: false,
-          absolutePath: this.currentFolder + file.name,
-        });
+        } as FileInformation);
       }
+      // Clear selection in files view table
       (
         (this.$refs.filesView as Vue).$refs.adaptTable as BTable
       ).clearSelected();
       this.showDetail = false;
     },
+
+    /**
+     * Initialize the file based on resource type.
+     */
     initializeForResourceType() {
       if (
         this.resourceTypeInformation?.resourceContent?.metadataView
@@ -313,16 +392,24 @@ export default defineComponent({
           uploading: false,
           name: "",
           isFolder: false,
-          absolutePath: this.currentFolder,
+          parentDirectory: this.dirTrail,
+          type: "Leaf" as TreeDataType.Leaf,
           size: 0,
           metadata: factory.dataset() as unknown as Dataset,
           dataUrl: "",
-        });
+        } as FileInformation);
       }
     },
+
+    /**
+     * Handle file drop action for upload.
+     * @param {DragEvent} ev - Drag event.
+     */
     uploadDrop(ev: DragEvent) {
       if (this.fileAddable) {
         this.dragCounter = 0;
+
+        // Handling file drops
         if (ev?.dataTransfer?.items) {
           for (const item of ev.dataTransfer.items) {
             if (item.kind === "file") {
@@ -335,33 +422,75 @@ export default defineComponent({
         }
       }
     },
-    setShowDetail(newShowDetail: boolean) {
-      this.showDetail = newShowDetail;
-    },
-    setWaitingForResponse(newIsWaitingForResponse: boolean) {
-      this.isWaitingForResponse = newIsWaitingForResponse;
+
+    /**
+     * Update the detail visibility.
+     *
+     * @param {boolean} visibility - New visibility state.
+     */
+    setShowDetail(visibility: boolean) {
+      this.showDetail = visibility;
     },
-    setIsUploading(newIsUploading: boolean) {
-      this.isUploading = newIsUploading;
+
+    /**
+     * Update the state indicating if the system is waiting for a response.
+     *
+     * @param {boolean} waiting - Whether the system is waiting for a response or not.
+     */
+    setWaitingForResponse(waiting: boolean) {
+      this.isWaitingForResponse = waiting;
     },
-    setCurrentFolder(newCurrentFolder: string) {
-      this.currentFolder = newCurrentFolder;
+
+    /**
+     * Update the uploading state.
+     *
+     * @param {boolean} uploading - Indicates if a file is currently uploading.
+     */
+    setIsUploading(uploading: boolean) {
+      this.isUploading = uploading;
     },
-    setFolder(newFolder: FolderInformation[]) {
-      this.folderContents = newFolder;
+
+    /**
+     * Updates the current folder's content.
+     *
+     * @param {FolderContent[]} folderContent - Information about the items in the folder.
+     */
+    updateFolderContent(folderContent: FolderContent[]) {
+      this.folderContents = folderContent;
     },
-    setFileListEdit(newFileListEdit: FileInformation[]) {
-      this.fileListEdit = newFileListEdit;
+
+    /**
+     * Updates the list of files being edited.
+     *
+     * @param {FolderContent[]} fileList - New list of files for editing.
+     */
+    updateEditFileList(fileList: FolderContent[]) {
+      this.fileListEdit = fileList;
     },
-    removeElement(index: number, count: number) {
-      this.fileListUpload.splice(index, count);
+
+    /**
+     * Deletes files from the upload list.
+     *
+     * @param {number} startIndex - Where to start the deletion in the list.
+     * @param {number} numberOfFiles - How many files to delete from the list.
+     */
+    deleteFromUploadList(startIndex: number, numberOfFiles: number) {
+      this.fileListUpload.splice(startIndex, numberOfFiles);
     },
+
+    /**
+     * Remove selected items from the list.
+     * @param {number} index - Start index.
+     * @param {number} count - Number of items to remove.
+     */
     removeSelection(index: number, count: number) {
       const selectionRemovable: FolderContent[] = this.fileListEdit.splice(
         index,
         count
       );
       const table = (this.$refs.filesView as Vue).$refs.adaptTable as BTable;
+
+      // Unselecting rows in table
       for (let i = 0; i < table.items.length; i++) {
         const item = (table.items as FolderContent[])[i];
         if (
@@ -372,28 +501,43 @@ export default defineComponent({
         }
       }
     },
-    setFullscreen(newIsFullscreen: boolean) {
-      this.isFullscreen = newIsFullscreen;
-      if (newIsFullscreen) {
-        document.body.classList.add("fullscreen");
+
+    /**
+     * Update the view mode based on the given fullscreen state.
+     *
+     * @param {boolean} activateFullscreen - Whether to activate the fullscreen mode.
+     */
+    updateViewMode(activateFullscreen: boolean) {
+      this.isFullscreenActive = activateFullscreen;
+
+      if (activateFullscreen) {
+        document.body.classList.add("fullscreen-mode");
         this.mainStore.sidebarActive = false;
       } else {
-        document.body.classList.remove("fullscreen");
-        this.isMetadataManagerHidden = false;
+        document.body.classList.remove("fullscreen-mode");
+        this.isMetadataManagerHidden = true;
       }
     },
-    toggleFullscreen() {
-      this.setFullscreen(!this.isFullscreen);
+
+    /**
+     * Toggle between fullscreen and regular mode.
+     */
+    toggleViewMode() {
+      this.updateViewMode(!this.isFullscreenActive);
     },
-    toggleMenu() {
+
+    /**
+     * Toggle the visibility of the metadata panel.
+     */
+    toggleMetadataPanel() {
       this.isMetadataManagerHidden = !this.isMetadataManagerHidden;
     },
-    getWindowWidth() {
-      if (document.documentElement.clientWidth < 1250) {
-        this.setFullscreen(true);
-      } else {
-        this.setFullscreen(false);
-      }
+
+    /**
+     * Adjust view mode based on window width.
+     */
+    adjustViewForScreenWidth() {
+      this.updateViewMode(document.documentElement.clientWidth < 1250);
     },
   },
 });
diff --git a/src/modules/resource/routes.ts b/src/modules/resource/routes.ts
index 6d776872c7635efa64e33e9ad67ad4bff113a3ef..55772fb005b81cc25a22556a838a9a9e43dc5d16 100644
--- a/src/modules/resource/routes.ts
+++ b/src/modules/resource/routes.ts
@@ -41,10 +41,27 @@ export const ResourceRoutes: RouteConfig[] = [
     children: [
       {
         path: "/",
+        redirect: (to) => {
+          return {
+            name: "resource-page",
+            params: {
+              slug: to.params.slug,
+              guid: to.params.guid,
+              dirTrail: "",
+            },
+            meta: {
+              breadCrumb: "resource.page",
+              requiresAuth: true,
+            },
+          };
+        },
+      },
+      {
+        path: "-/:dirTrail(.*)*",
         name: "resource-page",
+        pathToRegexpOptions: { strict: true, sensitive: true },
         component: ResourcePage,
         meta: {
-          breadCrumb: "resource.page",
           requiresAuth: true,
         },
       },
diff --git a/src/modules/resource/store.ts b/src/modules/resource/store.ts
index 4f1ef88aca75f05e65761f38a7b4cdbc3b42c1e6..2e8398d8ad83708d7b557186f5ec20187df13542 100644
--- a/src/modules/resource/store.ts
+++ b/src/modules/resource/store.ts
@@ -19,13 +19,9 @@ import {
   VocabularyApi,
 } from "@coscine/api-client";
 import type { Route } from "vue-router/types/router";
-import type { AxiosError } from "axios";
+import axios, { AxiosError } from "axios";
 import useNotificationStore from "@/store/notification";
-import {
-  parseRDFDefinition,
-  resolveImports,
-  serializeRDFDefinition,
-} from "./utils/linkedData";
+import { parseRDFDefinition, resolveImports } from "./utils/linkedData";
 import factory from "rdf-ext";
 import { useLocalStorage } from "@vueuse/core";
 import type {
@@ -33,12 +29,16 @@ import type {
   ApplicationProfileDto,
   GitlabBranchDto,
   GitlabProjectDto,
+  MetadataTreeForCreationDto,
+  MetadataTreeForUpdateDto,
   ProjectDto,
   ResourceDto,
   ResourceForCreationDto,
   ResourceForUpdateDto,
   ResourceQuotaDto,
   AcceptedLanguage,
+  FileDto,
+  MetadataDto,
 } from "@coscine/api-client/dist/types/Coscine.Api/api";
 import { wrapListRequest } from "@/util/wrapListRequest";
 /*  
@@ -159,10 +159,14 @@ export const useResourceStore = defineStore({
             "JsonLd" as RdfFormat
           );
           const returnedData = apiResponse.data.data;
-          if (returnedData?.definition && returnedData?.baseUri) {
+          if (
+            returnedData?.definition &&
+            returnedData?.format &&
+            returnedData?.baseUri
+          ) {
             resource.rawApplicationProfile = await parseRDFDefinition(
               returnedData.definition,
-              "application/ld+json",
+              returnedData.format,
               returnedData.baseUri
             );
             resource.fullApplicationProfile = await resolveImports(
@@ -192,10 +196,14 @@ export const useResourceStore = defineStore({
           "JsonLd" as RdfFormat
         );
         const returnedData = apiResponse.data.data;
-        if (returnedData?.definition && returnedData?.baseUri) {
+        if (
+          returnedData?.definition &&
+          returnedData?.format &&
+          returnedData?.baseUri
+        ) {
           let returnApplicationProfile = await parseRDFDefinition(
             returnedData.definition,
-            "application/ld+json",
+            returnedData.format,
             returnedData.baseUri
           );
           if (doResolveImports) {
@@ -409,18 +417,6 @@ export const useResourceStore = defineStore({
       }
     },
 
-    async deleteFile(resourceId: string, absoluteFilePath: string) {
-      const notificationStore = useNotificationStore();
-      try {
-        await BlobApi.blobDeleteFileWithParameter(resourceId, absoluteFilePath);
-        return true;
-      } catch (error) {
-        // Handle other Status Codes
-        notificationStore.postApiErrorNotification(error as AxiosError);
-        return false;
-      }
-    },
-
     async getVocabularyInstances(className: string): Promise<BilingualLabels> {
       const notificationStore = useNotificationStore();
       try {
@@ -431,7 +427,7 @@ export const useResourceStore = defineStore({
               undefined,
               "en" as AcceptedLanguage.En,
               pageNumber,
-              50
+              150
             )
           );
           const deInstances = await wrapListRequest((pageNumber: number) =>
@@ -440,7 +436,7 @@ export const useResourceStore = defineStore({
               undefined,
               "de" as AcceptedLanguage.De,
               pageNumber,
-              50
+              150
             )
           );
 
@@ -448,13 +444,13 @@ export const useResourceStore = defineStore({
             de: deInstances.map((instance) => {
               return {
                 name: instance.displayName,
-                value: instance.graphUri,
+                value: instance.instanceUri,
               };
             }),
             en: enInstances.map((instance) => {
               return {
                 name: instance.displayName,
-                value: instance.graphUri,
+                value: instance.instanceUri,
               };
             }),
           };
@@ -469,23 +465,206 @@ export const useResourceStore = defineStore({
       }
     },
 
-    async getFile(
+    async createMetadataTree(
+      projectId: string,
+      resourceId: string,
+      metadataTreeForCreationDto: MetadataTreeForCreationDto
+    ): Promise<boolean> {
+      const notificationStore = useNotificationStore();
+      try {
+        await TreeApi.createMetadataTree(
+          projectId,
+          resourceId,
+          metadataTreeForCreationDto
+        );
+        return true;
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+        return false;
+      }
+    },
+
+    async updateMetadataTree(
+      projectId: string,
+      resourceId: string,
+      metadataTreeForUpdateDto: MetadataTreeForUpdateDto
+    ): Promise<boolean> {
+      const notificationStore = useNotificationStore();
+      try {
+        await TreeApi.updateMetadataTree(
+          projectId,
+          resourceId,
+          metadataTreeForUpdateDto
+        );
+        return true;
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+        return false;
+      }
+    },
+
+    /**
+     * Attempts to add a new metadata tree. If a conflict (409) error occurs, it tries to update the existing metadata tree.
+     *
+     * @param {string} projectId - The ID of the project.
+     * @param {string} resourceId - The ID of the resource.
+     * @param {MetadataTreeForCreationDto | MetadataTreeForUpdateDto} metadataTreeDto - The data transfer object containing metadata tree details. Can be for creation or update.
+     * @returns {Promise<boolean>} Returns true if the operation is successful, false otherwise.
+     * @throws {AxiosError} Throws an AxiosError if the API call fails.
+     */
+    async addOrUpdateMetadataTree(
+      projectId: string,
+      resourceId: string,
+      metadataTreeDto: MetadataTreeForCreationDto | MetadataTreeForUpdateDto
+    ): Promise<boolean> {
+      const notificationStore = useNotificationStore();
+
+      try {
+        // Attempt to create metadata tree
+        await TreeApi.createMetadataTree(
+          projectId,
+          resourceId,
+          metadataTreeDto
+        );
+        return true;
+      } catch (error: unknown) {
+        if (axios.isAxiosError(error)) {
+          if (error.response?.status === 409) {
+            // Metadata tree already exists, attempt to update
+            try {
+              await TreeApi.updateMetadataTree(
+                projectId,
+                resourceId,
+                metadataTreeDto // NOTE: Potential issue here, as the DTO might not be the same for creation and update if signature changes
+              );
+              return true;
+            } catch (updateError) {
+              // Handle other Status Codes
+              notificationStore.postApiErrorNotification(
+                updateError as AxiosError
+              );
+              return false;
+            }
+          }
+        }
+      }
+      // Handle notification externally
+      return false;
+    },
+
+    /**
+     * Attempts to update a new metadata tree. If a not found (404) error occurs, it tries to create a new metadata tree.
+     *
+     * @param {string} projectId - The ID of the project.
+     * @param {string} resourceId - The ID of the resource.
+     * @param {MetadataTreeForCreationDto | MetadataTreeForUpdateDto} metadataTreeDto - The data transfer object containing metadata tree details. Can be for creation or update.
+     * @returns {Promise<boolean>} Returns true if the operation is successful, false otherwise.
+     * @throws {AxiosError} Throws an AxiosError if the API call fails.
+     */
+    async updateOrAddMetadataTree(
+      projectId: string,
+      resourceId: string,
+      metadataTreeDto: MetadataTreeForCreationDto | MetadataTreeForUpdateDto
+    ): Promise<boolean> {
+      const notificationStore = useNotificationStore();
+
+      try {
+        // Attempt to update metadata tree
+        await TreeApi.updateMetadataTree(
+          projectId,
+          resourceId,
+          metadataTreeDto // NOTE: Potential issue here, as the DTO might not be the same for creation and update if signature changes
+        );
+        return true;
+      } catch (error: unknown) {
+        if (axios.isAxiosError(error)) {
+          if (error.response?.status === 404) {
+            // Metadata tree already exists, attempt to update
+            try {
+              await TreeApi.createMetadataTree(
+                projectId,
+                resourceId,
+                metadataTreeDto // NOTE: Potential issue here, as the DTO might not be the same for creation and update if signature changes
+              );
+              return true;
+            } catch (updateError) {
+              // Handle other Status Codes
+              notificationStore.postApiErrorNotification(
+                updateError as AxiosError
+              );
+              return false;
+            }
+          }
+        }
+      }
+      // Handle notification externally
+      return false;
+    },
+
+    async getMetadataTree(
+      projectId: string,
+      resourceId: string,
+      filePath: string,
+      format?: RdfFormat
+    ): Promise<MetadataDto[] | null | undefined> {
+      const notificationStore = useNotificationStore();
+      try {
+        const response = await TreeApi.getMetadataTree(
+          projectId,
+          resourceId,
+          filePath,
+          format
+        );
+        return response.data.data;
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+        return null;
+      }
+    },
+
+    async getFileTree(
+      projectId: string,
+      resourceId: string,
+      filePath: string
+    ): Promise<FileDto[] | null | undefined> {
+      const notificationStore = useNotificationStore();
+      try {
+        const response = await TreeApi.getFileTree(
+          projectId,
+          resourceId,
+          filePath
+        );
+        return response.data.data;
+      } catch (error) {
+        // Handle other Status Codes
+        notificationStore.postApiErrorNotification(error as AxiosError);
+        return null;
+      }
+    },
+
+    async getBlob(
+      projectId: string,
       resourceId: string,
       absoluteFilePath: string,
       asBlob = false
     ) {
       const notificationStore = useNotificationStore();
       try {
-        const response = await BlobApi.blobGetFileWithParameter(
+        const response = await BlobApi.getBlob(
+          projectId,
           resourceId,
           absoluteFilePath,
+          /* the following is an axios option */
           asBlob
             ? {
                 responseType: "blob",
               }
             : undefined
         );
-        return response.data;
+        return response;
       } catch (error) {
         // Handle other Status Codes
         notificationStore.postApiErrorNotification(error as AxiosError);
@@ -493,37 +672,47 @@ export const useResourceStore = defineStore({
       }
     },
 
-    async getMetadata(resourceId: string, absoluteFilePath: string) {
+    async createBlob(
+      projectId: string,
+      resourceId: string,
+      absoluteFilePath: string,
+      file: Blob,
+      options?: unknown
+    ) {
       const notificationStore = useNotificationStore();
       try {
-        const response = await TreeApi.treeGetMetadataWithParameter(
+        const response = await BlobApi.createBlob(
+          projectId,
           resourceId,
           absoluteFilePath,
-          "application/n-triples"
+          file,
+          options
         );
-        return response.data;
+        return response.status >= 200 && response.status < 300;
       } catch (error) {
         // Handle other Status Codes
         notificationStore.postApiErrorNotification(error as AxiosError);
-        return null;
+        return false;
       }
     },
 
-    async storeFile(
+    async updateBlob(
+      projectId: string,
       resourceId: string,
       absoluteFilePath: string,
-      files: Blob[],
+      file: Blob,
       options?: unknown
     ) {
       const notificationStore = useNotificationStore();
       try {
-        await BlobApi.blobUploadFileWithParameter(
+        const response = await BlobApi.updateBlob(
+          projectId,
           resourceId,
           absoluteFilePath,
-          files,
+          file,
           options
         );
-        return true;
+        return response.status >= 200 && response.status < 300;
       } catch (error) {
         // Handle other Status Codes
         notificationStore.postApiErrorNotification(error as AxiosError);
@@ -531,19 +720,14 @@ export const useResourceStore = defineStore({
       }
     },
 
-    async storeMetadata(
+    async deleteBlob(
+      projectId: string,
       resourceId: string,
-      absoluteFilePath: string,
-      body: Dataset
+      absoluteFilePath: string
     ) {
       const notificationStore = useNotificationStore();
       try {
-        await TreeApi.treeStoreMetadataForFileWithParameter(
-          resourceId,
-          absoluteFilePath,
-          "text/turtle",
-          { data: { metadata: await serializeRDFDefinition(body) } }
-        );
+        await BlobApi.deleteBlob(projectId, resourceId, absoluteFilePath);
         return true;
       } catch (error) {
         // Handle other Status Codes
diff --git a/src/modules/resource/types.ts b/src/modules/resource/types.ts
index d783bcb1b3695d6b5a3aede4f5ed2d1c021d5b3c..2d640c054fd518beec87f858edde52e304bac50b 100644
--- a/src/modules/resource/types.ts
+++ b/src/modules/resource/types.ts
@@ -8,6 +8,7 @@ import type {
   GitlabProjectDto,
   ResourceDto,
   ResourceTypeInformationDto,
+  TreeDataType,
 } from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 import type { Dataset } from "@rdfjs/types";
@@ -185,3 +186,38 @@ export interface Label {
   name?: string | null;
   value?: string | null;
 }
+
+export interface GeneralInformation {
+  id: string;
+  name: string;
+  path: string;
+  parentDirectory: string;
+  type: TreeDataType;
+  isFolder: boolean;
+  lastModified?: string | null;
+  readOnly?: boolean;
+  createdAt?: string;
+  metadata: Dataset | null;
+}
+
+export interface FileInformation extends GeneralInformation {
+  type: TreeDataType.Leaf;
+  isFolder: false;
+  version: string;
+  size: number;
+  dataUrl?: string;
+  info?: File;
+  uploading?: boolean;
+  requesting?: boolean;
+}
+
+export interface FolderInformation extends GeneralInformation {
+  type: TreeDataType.Tree;
+  isFolder: true;
+}
+
+export interface ReadOnlyFolderInformation extends FolderInformation {
+  readOnly: true;
+}
+
+export type FolderContent = FileInformation | FolderInformation;
diff --git a/src/modules/resource/utils/EntryDefinition.ts b/src/modules/resource/utils/EntryDefinition.ts
deleted file mode 100644
index 34309e24e83c113d219687c1ea6dcd5ef712461e..0000000000000000000000000000000000000000
--- a/src/modules/resource/utils/EntryDefinition.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import type { Dataset } from "@rdfjs/types";
-
-export interface GeneralInformation {
-  id: string;
-  path: string;
-  absolutePath: string;
-  name: string;
-  isFolder: boolean;
-  lastModified?: string;
-  readOnly?: boolean;
-  created?: string;
-  metadata: Dataset;
-}
-
-export interface FileInformation extends GeneralInformation {
-  isFolder: false;
-  version: string;
-  size: number;
-  dataUrl?: string;
-  info?: File;
-  uploading?: boolean;
-  requesting?: boolean;
-}
-
-export interface FolderInformation extends GeneralInformation {
-  isFolder: true;
-}
-
-export interface ReadOnlyFolderInformation extends FolderInformation {
-  readOnly: true;
-}
-
-export type FolderContent = FileInformation | FolderInformation;
diff --git a/src/modules/resource/utils/MetadataManagerUtil.ts b/src/modules/resource/utils/MetadataManagerUtil.ts
index d935173a6ca547ae33317628400fe9cdba5b006b..c49ef45e1c2a5c8eb2f4cc6345a1e6b067c94176 100644
--- a/src/modules/resource/utils/MetadataManagerUtil.ts
+++ b/src/modules/resource/utils/MetadataManagerUtil.ts
@@ -1,110 +1,66 @@
 import useResourceStore from "../store";
-import type { FolderContent } from "./EntryDefinition";
 import type { Dataset } from "@rdfjs/types";
 import factory from "rdf-ext";
 import { parseRDFDefinition } from "./linkedData";
-import type { Metadata } from "../types";
-import type { ResourceDto } from "@coscine/api-client/dist/types/Coscine.Api";
+import type { FolderContent } from "../types";
+import type {
+  ProjectDto,
+  ResourceDto,
+} from "@coscine/api-client/dist/types/Coscine.Api";
 
 export default {
-  filterMetadataStorage(
-    metadataStorage: Metadata[],
-    filterPath: string
-  ): Metadata[] {
-    return metadataStorage.filter((x) => {
-      if (Object.keys(x).length > 0) {
-        const graphName = Object.keys(x)[0];
-        const pathQueryString = "path=";
-        if (graphName.indexOf(pathQueryString) !== -1) {
-          let path = graphName.substring(
-            graphName.indexOf(pathQueryString) + pathQueryString.length
-          );
-          if (path.indexOf("&") !== -1) {
-            path = path.substring(0, path.indexOf("&"));
-          }
-          if (
-            decodeURIComponent(path) === filterPath ||
-            decodeURIComponent(path) === "/" + filterPath
-          ) {
-            return true;
-          }
-        }
-        const typeQueryString = "/@type=metadata";
-        if (graphName.indexOf(typeQueryString) !== -1) {
-          const urlEnd = graphName.substring(
-            0,
-            graphName.indexOf(typeQueryString)
-          );
-          if (
-            urlEnd.endsWith(filterPath) ||
-            decodeURIComponent(urlEnd).endsWith(filterPath)
-          ) {
-            return true;
-          }
-        }
-      }
-      return false;
-    });
-  },
-  async loadMetadata(
+  /**
+   * Loads metadata for a specified file. If no metadata is found, it returns an empty dataset.
+   *
+   * @param {FolderContent} fileInfo - Information about the file for which metadata is to be loaded.
+   * @param {ProjectDto | null} project - Parent project of the file.
+   * @param {ResourceDto | null} resource - Parent resource of the file.
+   * @returns {Promise<Dataset>} A promise that resolves to the metadata for the file or an empty dataset if none is found.
+   */
+  async loadMetadataForFile(
     fileInfo: FolderContent,
+    project: ProjectDto | null,
     resource: ResourceDto | null
-  ): Promise<Dataset> {
-    if (
-      fileInfo !== undefined &&
-      fileInfo.absolutePath !== undefined &&
-      resource?.id
-    ) {
-      if (fileInfo.metadata) {
-        if (fileInfo.metadata.size > 0) {
-          return fileInfo.metadata;
-        }
-      }
-
-      const response = await useResourceStore().getMetadata(
-        resource.id,
-        fileInfo.absolutePath
-      );
+  ): Promise<Dataset | null> {
+    // Return an empty dataset if no file info is available
+    if (!fileInfo?.path || !project?.id || !resource?.id) {
+      return factory.dataset() as unknown as Dataset;
+    }
 
-      const metadataStorage = response.data.metadataStorage;
+    // Return existing metadata if available
+    if (fileInfo.metadata && fileInfo.metadata.size > 0) {
+      return fileInfo.metadata;
+    }
 
-      if (metadataStorage.length === 0) {
-        return factory.dataset() as unknown as Dataset;
-      }
+    // Fetch metadata from the API
+    const metadataTree = await useResourceStore().getMetadataTree(
+      project.id,
+      resource.id,
+      fileInfo.path
+    );
 
-      const resultArray = this.filterMetadataStorage(
-        metadataStorage,
-        fileInfo.absolutePath
+    // If the metadata exists and has a definition, parse it
+    if (metadataTree?.[0]?.definition && metadataTree[0].format) {
+      return await parseRDFDefinition(
+        metadataTree[0].definition,
+        metadataTree[0].format
       );
-
-      if (resultArray.length === 0) {
-        return factory.dataset() as unknown as Dataset;
-      }
-
-      const result = resultArray[0];
-
-      const objectKeys = Object.keys(result);
-      if (
-        response.data.metadataStorage !== undefined &&
-        objectKeys.length === 1
-      ) {
-        const entry = result[objectKeys[0]];
-        if (typeof entry === "string") {
-          return await parseRDFDefinition(entry, "application/n-triples");
-        }
-      } else if (
-        response.data.metadataStorage !== undefined &&
-        objectKeys.length > 1
-      ) {
-        const entry = result;
-        if (typeof entry === "string") {
-          return await parseRDFDefinition(entry, "application/n-triples");
-        }
-      }
     }
+
+    // Return an empty dataset if no metadata was found
     return factory.dataset() as unknown as Dataset;
   },
-  copyMetadata(source: Dataset | undefined, target: FolderContent | undefined) {
+
+  /**
+   * Copies metadata from the source to the target.
+   *
+   * @param {Dataset | null | undefined} source - The source dataset from which to copy metadata.
+   * @param {FolderContent | undefined} target - The target where the metadata should be copied to.
+   */
+  copyMetadata(
+    source: Dataset | null | undefined,
+    target: FolderContent | undefined
+  ) {
     if (source && target) {
       target.metadata = factory.dataset(
         Array.from(source)
diff --git a/src/modules/resource/utils/linkedData.ts b/src/modules/resource/utils/linkedData.ts
index 8da4b03e6809814dad6c398b16dd6814ea981f45..c0632b8abfb61ecb0871340f3e31aa496472d81b 100644
--- a/src/modules/resource/utils/linkedData.ts
+++ b/src/modules/resource/utils/linkedData.ts
@@ -30,18 +30,25 @@ export async function parseRDFDefinition(
   return dataset as unknown as Dataset;
 }
 
+/**
+ * Serializes an RDF dataset into a specified format.
+ *
+ * @param {Dataset | null} dataset - The RDF dataset to be serialized.
+ * @param {string} [contentType="text/turtle"] - The MIME type for the serialization format.
+ * @returns {Promise<string>} A promise that resolves with the serialized dataset as a string.
+ *
+ * @example
+ * const turtleStr = await serializeRDFDefinition(myDataset, "text/turtle");
+ */
 export async function serializeRDFDefinition(
-  dataset: Dataset,
-  contentType = "text/turtle"
+  dataset: Dataset | null,
+  contentType: string = "text/turtle"
 ): Promise<string> {
-  const canonical = dataset.toCanonical();
-  if (!canonical) {
-    return "";
-  }
+  if (!dataset || !dataset.toCanonical()) return "";
+
   const output = formats.serializers.import(contentType, dataset.toStream());
-  if (output === null) {
-    return "";
-  }
+  if (!output) return "";
+
   return await stringifyStream(output as NodeJS.ReadableStream);
 }
 
@@ -80,10 +87,10 @@ export async function resolveImports(
                 "JsonLd" as RdfFormat
               );
             const apResponse = importedApiResponse.data.data;
-            if (apResponse?.definition) {
+            if (apResponse?.definition && apResponse?.format) {
               const importedApplicationProfile = await parseRDFDefinition(
                 apResponse.definition,
-                "application/ld+json",
+                apResponse.format,
                 importedAP.value
               );
               fullApplicationProfile = (
diff --git a/src/modules/search/pages/components/MetadataResult.vue b/src/modules/search/pages/components/MetadataResult.vue
index 318a75e2cb0d8e32d812705a1d7ed5d4bc069969..8b442b9a31a8fd310c1be65fe11737b0fe394e05 100644
--- a/src/modules/search/pages/components/MetadataResult.vue
+++ b/src/modules/search/pages/components/MetadataResult.vue
@@ -73,8 +73,8 @@
             v-html="
               $options.filters
                 ? $options.filters.highlight(
-                    resourceType.displayName
-                      ? resourceTypeName(resourceType.displayName)
+                    resourceType.specificType
+                      ? resourceTypeName(resourceType.specificType)
                       : null,
                     query
                   )
@@ -113,8 +113,10 @@ import { defineComponent, type PropType } from "vue";
 import useResourceStore from "@/modules/resource/store";
 
 import type { ItemSearchResult } from "@coscine/api-client/dist/types/Coscine.Api.Search";
-import type { ResourceTypeObject } from "@coscine/api-client/dist/types/Coscine.Api.Resources";
-import type { ProjectDto } from "@coscine/api-client/dist/types/Coscine.Api/api";
+import type {
+  ProjectDto,
+  ResourceTypeInformationDto,
+} from "@coscine/api-client/dist/types/Coscine.Api/api";
 
 export default defineComponent({
   name: "MetadataResult",
@@ -208,7 +210,7 @@ export default defineComponent({
       }
       return null;
     },
-    resourceType(): ResourceTypeObject | undefined | null {
+    resourceType(): ResourceTypeInformationDto | undefined | null {
       if (
         this.resourceTypes &&
         this.result.type === "Resource" &&
@@ -223,7 +225,7 @@ export default defineComponent({
       }
       return null;
     },
-    resourceTypes(): ResourceTypeObject[] | null {
+    resourceTypes(): ResourceTypeInformationDto[] | undefined | null {
       return this.resourceStore.enabledResourceTypes;
     },
     fields(): Record<string, string> {
@@ -285,6 +287,7 @@ export default defineComponent({
           params: {
             guid: this.resourceId,
             slug: this.project.slug,
+            dirTrail: "",
           },
         }).href;
       } else if (
@@ -298,6 +301,7 @@ export default defineComponent({
           params: {
             guid: this.resourceId,
             slug: this.project.slug,
+            dirTrail: "",
           },
         }).href;
       } else {
diff --git a/src/router/index.ts b/src/router/index.ts
index 78d6cd9396904e41e607a49a1a530cda2786b235..0802fb472e2f82d4bf0f5d976be82bda72789992 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -42,7 +42,12 @@ VueRouter.prototype.push = async function (location: RawLocation) {
     );
   } catch (err) {
     if (err instanceof Error) {
-      if (err.name !== "NavigationDuplicated") {
+      if (
+        // Ignore errors from navigating to the same route
+        err.name !== "NavigationDuplicated" &&
+        // Ignore errors from redirecting enforced by a navigation guard
+        !err.message.includes("via a navigation guard")
+      ) {
         throw err;
       }
     }
@@ -115,6 +120,11 @@ router.beforeEach((to, _, next) => {
   else if (to.name === "login" && loginStore.isLoggedIn) {
     next({ name: "home" });
   }
+  // Navigation Guard - Set directory trail for resource page when no dirTrail is provided
+  else if (to.name === "resource-page" && to.params.dirTrail === undefined) {
+    to.params.dirTrail = "";
+    next({ name: "resource-page", params: { ...to.params } });
+  }
   // Continue navigation
   else {
     next();
diff --git a/vite.config.js b/vite.config.js
index e637d1fe22f67ac0ddbcc414a2ad032352d05ed9..e45ad2fbb79162c1f6a5b8429ea0b15a3656abdc 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,6 +1,7 @@
 import path from "node:path";
 import { defineConfig } from "vite";
 import vue from "@vitejs/plugin-vue2";
+import pluginRewriteAll from 'vite-plugin-rewrite-all';
 
 import { nodePolyfills } from 'vite-plugin-node-polyfills';
 
@@ -39,6 +40,9 @@ const config = defineConfig({
   plugins: [
     nodePolyfills(),
     vue(),
+    // This plugin fixes a vite bug, that breaks SPA-fallback with a dot (.) in the URL (e.g. /file_0.txt). 
+    // TODO: Check if the issue is resolved after upgrading to vite 5.0.0
+    pluginRewriteAll(), 
     WindiCSS(),
     Components({
       dts: 'src/components.d.ts',
@@ -46,6 +50,8 @@ const config = defineConfig({
       exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
     }),
   ],
+  
+  appType: "spa",
 
   server: {
     host: true,
diff --git a/yarn.lock b/yarn.lock
index cb6a1e3c4fb57d507ded47ef4a242ea057196ef1..f5c5881e591fe78d8dd258d833e461a49fe18c6d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -428,12 +428,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@coscine/api-client@npm:^3.0.0":
-  version: 3.0.0
-  resolution: "@coscine/api-client@npm:3.0.0"
+"@coscine/api-client@npm:^3.1.0":
+  version: 3.1.0
+  resolution: "@coscine/api-client@npm:3.1.0"
   dependencies:
     axios: ^0.21.1
-  checksum: b4722c0428ca3851f47f21bd606617d8386efc1c547ab68d55cbd8038496182684465b2fa6f27e37e9bc780160206eb3d5a9ecc26790bc4bf9df2d8c1e5304e6
+  checksum: 71892411a48930421486b299915a0bd7b3b3e6209953f2304cc22ab2cc3705b56d4c702b8ea4d6e7dd438cd67fa348bb86219df5e7b128ab0ae4e356501e6e82
   languageName: node
   linkType: hard
 
@@ -4243,6 +4243,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"connect-history-api-fallback@npm:^1.6.0":
+  version: 1.6.0
+  resolution: "connect-history-api-fallback@npm:1.6.0"
+  checksum: 804ca2be28c999032ecd37a9f71405e5d7b7a4b3defcebbe41077bb8c5a0a150d7b59f51dcc33b2de30bc7e217a31d10f8cfad27e8e74c2fc7655eeba82d6e7e
+  languageName: node
+  linkType: hard
+
 "consola@npm:^2.15.0":
   version: 2.15.3
   resolution: "consola@npm:2.15.3"
@@ -11895,7 +11902,7 @@ __metadata:
   version: 0.0.0-use.local
   resolution: "ui@workspace:."
   dependencies:
-    "@coscine/api-client": ^3.0.0
+    "@coscine/api-client": ^3.1.0
     "@coscine/form-generator": ^3.2.2
     "@dynamic-mapper/mapper": ^1.10.2
     "@pinia/testing": ^0.1.2
@@ -11965,6 +11972,7 @@ __metadata:
     vite: ^4.3.9
     vite-aliases: ^0.11.2
     vite-plugin-node-polyfills: ^0.9.0
+    vite-plugin-rewrite-all: ^1.0.1
     vite-plugin-windicss: ^1.9.0
     vitest: ^0.32.2
     vue: ^2.7.14
@@ -12263,6 +12271,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"vite-plugin-rewrite-all@npm:^1.0.1":
+  version: 1.0.1
+  resolution: "vite-plugin-rewrite-all@npm:1.0.1"
+  dependencies:
+    connect-history-api-fallback: ^1.6.0
+  peerDependencies:
+    vite: ^2.0.0 || ^3.0.0 || ^4.0.0
+  checksum: 9a22e51e80fc14d58d32556208c26740baf3f02eae2d0a5f356ddc1ea478bd2f56803cc17e77261ffad33d27301017ba03736143446685c03bb0f076eef2fdd0
+  languageName: node
+  linkType: hard
+
 "vite-plugin-windicss@npm:^1.9.0":
   version: 1.9.0
   resolution: "vite-plugin-windicss@npm:1.9.0"