diff --git a/components/AccountPlaceholder.vue b/components/AccountPlaceholder.vue
index 6b61f929ff9729c0150b69d70f3393d79d892071..a155f1427b905fff3437a515ea8c3c08bf53554f 100644
--- a/components/AccountPlaceholder.vue
+++ b/components/AccountPlaceholder.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import userData from '~/data/mock/user.json';
-import {UserMapper} from "~/utils/mapper/UserMapper";
+import {UserMapper} from "~/server/utils/mapper/UserMapper";
 
 const user = ref<User>(UserMapper.from(userData));
 
diff --git a/components/ExerciceItem.vue b/components/Parcours/ExerciceItem.vue
similarity index 100%
rename from components/ExerciceItem.vue
rename to components/Parcours/ExerciceItem.vue
diff --git a/components/Parcours/Exercices.vue b/components/Parcours/Exercices.vue
index e53d45d2fe0292f78781b2df6926ac1b201907b8..1734ac10cddc4e8e03ad8872d6764e23f3f9ca25 100644
--- a/components/Parcours/Exercices.vue
+++ b/components/Parcours/Exercices.vue
@@ -1,15 +1,8 @@
 <script setup lang="ts">
-import L, {type LeafletMouseEvent, Marker, type PointTuple} from 'leaflet';
+import L, {type LeafletMouseEvent, Marker, type MarkerOptions, type PointTuple} from 'leaflet';
 import 'leaflet.markercluster';
-import myData from '~/data/mock/exercices.json';
 import type {Exercise} from "~/types/Exercise";
-
-const {$api} = useNuxtApp();
-const map = ref(null) as any;
-const inCreation = ref(false);
-const exercises = await $api.exercises.getExercises();
-const exerciseSearch = ref('');
-const selectedExercises: Exercise[] = [];
+import type {Step} from "~/types/Step";
 
 // TODO : Move to a separate file
 interface MarkerCluster {
@@ -17,48 +10,69 @@ interface MarkerCluster {
     markers: Marker[];
 }
 
+interface MarkerProps {
+    name?: string,
+    lat: number,
+    lng: number,
+    options: MarkerOptions,
+    popup?: string
+}
+
+const {$api} = useNuxtApp();
+
+// Map utilities
+const exerciseSearch = ref('');
+const inCreation = ref(false);
+const locations = ref<MarkerProps[]>([]);
+const map = ref(null) as any;
 let markerCluster: MarkerCluster;
+let createCluster: MarkerCluster;
 
-// DATA
-const zoom = ref(17)
-const chantrerie: PointTuple = [47.287, -1.524]
+const exercises = ref<Exercise[]>([]);
+const selectedExercises: Exercise[] = [];
+const steps = ref<Step[]>([]);
 
-const locations: any = myData.map((exo) => {
-    return {
-        name: exo.id,
-        lat: exo.lat,
-        lng: exo.lng,
-        options: {
-            icon: L.icon({
+// TODO : Make it dynamic
+const zoom = ref(17)
+const center: PointTuple = [47.287, -1.524]
+
+async function updateLocations() {
+    locations.value = steps.value.map((step) => {
+        return {
+            name: step.id.toString(),
+            lat: step.latitude,
+            lng: step.longitude,
+            options: {
+                icon: L.icon({
+                    iconUrl: '/svg/pin.svg',
+                    iconSize: [30, 30],
+                })
+            }
+        }
+    })
+    markerCluster?.markerCluster?.clearLayers();
+    markerCluster = await useLMarkerCluster({
+        leafletObject: map?.value?.leafletObject,
+        markers: locations.value as MarkerProps[]
+    })
+    markerCluster.markers.forEach((marker: Marker) => {
+        marker.on('click', onMarkerSelect);
+        marker.on('mouseover', () => {
+            marker.setIcon(L.icon({
+                iconUrl: '/svg/pin.svg',
+                iconSize: [45, 45],
+            }));
+        });
+        marker.on('mouseout', () => {
+            marker.setIcon(L.icon({
                 iconUrl: '/svg/pin.svg',
                 iconSize: [30, 30],
-            })
-        },
-        popup: exo.name
-    }
-})
+            }));
+        });
+    })
+}
 
-// TODO & FIXME : menu contextuel à revoir
 const items = ref([
-    [
-        {
-            label: 'Appearance',
-            children: [
-                {
-                    label: 'System',
-                    icon: 'i-lucide-monitor'
-                },
-                {
-                    label: 'Light',
-                    icon: 'i-lucide-sun'
-                },
-                {
-                    label: 'Dark',
-                    icon: 'i-lucide-moon'
-                }
-            ]
-        }
-    ],
     [
         {
             label: 'Delete the point',
@@ -69,22 +83,23 @@ const items = ref([
     ],
 ])
 
-// Functions
 async function onMapReady() {
-    markerCluster = await useLMarkerCluster({
+    createCluster = await useLMarkerCluster({
         leafletObject: map?.value?.leafletObject,
-        markers: locations
+        markers: [],
     });
+    steps.value = (await $api.step.postArea(map.value.leafletObject.getBounds())).message as Step[];
+    await updateLocations();
 
-    map.value.leafletObject.on('moveend', () => {
-        // ask api for new markers in bounds
-        // map.value.leafletObject.getBounds()
+    map.value.leafletObject.on('moveend', async () => {
+        steps.value = (await $api.step.postArea(map.value.leafletObject.getBounds())).message as Step[];
+        await updateLocations();
     });
 }
 
 function deleteMarker(): void {
     if (!inCreation.value) return;
-    markerCluster.markerCluster.clearLayers();
+    createCluster.markerCluster.clearLayers();
     inCreation.value = false;
 }
 
@@ -99,66 +114,19 @@ function MapEvents(e: LeafletMouseEvent): void {
         iconUrl: '/svg/pinadd.svg',
         iconSize: [30, 30],
     }));
-    markerCluster.markerCluster.addLayer(newMarker);
+    createCluster.markerCluster.addLayer(newMarker);
 }
 
-// TODO : changement d'affichage des clusters
-const _cluster_visible = (cluster: any) => L.divIcon({
-    html: `<div style="background-color: red;">${cluster.getChildCount()}</div>`,
-    className: 'marker-cluster',
-    iconSize: L.point(40, 40)
-});
-
-// FIXME : still a lot of works around this
-function hooverMarker(exo: Exercise): void {
-    markerCluster.markers.find((marker: Marker) => {
-        if (marker.getLatLng().lat === exo.lat && marker.getLatLng().lng === exo.lng) {
-            if (map.value.leafletObject.hasLayer(marker)) {
-                // Not in a cluster (ie marker is visible on map)
-                marker.setIcon(L.icon({
-                    iconUrl: '/svg/pin.svg',
-                    iconSize: [45, 45],
-                }));
-                // } else {
-                //     In a cluster (ie marker is not visible on map)
-                //     map.value.leafletObject.eachLayer((layer: any) => {
-                //         if (layer instanceof L.FeatureGroup && layer.hasLayer(marker)) {
-                //             (layer as any).options = {
-                //                 iconCreateFunction: (cluster: any) => {
-                //                     return L.divIcon({
-                //                         html: `<div style="background-color: red;">${cluster.getChildCount()}</div>`,
-                //                         className: 'marker-cluster',
-                //                         iconSize: L.point(40, 40)
-                //                     });
-                //                 }
-                //             }
-                //             console.log((layer as any));
-                //             console.log((layer as any)._markerCluster);
-                //             (newMarkerCluster as any).refreshClusters();
-                //             (layer as any).setIcon(cluster_visible);
-                //             map.value.leafletObject.removeLayer(layer);
-                //             map.value.leafletObject.addLayer(layer);
-                //             (map.value.leafletObject as L.LayerGroup)
-                //         }
-                //     });
-            }
-        }
-    });
+// TODO : reimplement these ? => see git history
+function mouseoverExercise(_: Exercise): void {
+    return
 }
-
-function leaveMarker(exo: Exercise): void {
-    markerCluster.markers.find((marker: any) => {
-        if (marker.getLatLng().lat === exo.lat && marker.getLatLng().lng === exo.lng) {
-            marker.setIcon(L.icon({
-                iconUrl: '/svg/pin.svg',
-                iconSize: [30, 30],
-            }));
-        }
-    });
+function mouseoutExercise(_: Exercise): void {
+    return
 }
 
 function filterExercise(): Exercise[] {
-    return exercises.filter((exo: Exercise) => {
+    return exercises.value.filter((exo: Exercise) => {
         return exo.name.toLowerCase().includes(exerciseSearch.value.toLowerCase());
     });
 }
@@ -167,7 +135,7 @@ function onExerciceClick(exo: Exercise): void {
     if (exo.selected) {
         selectedExercises.splice(selectedExercises.indexOf(exo), 1);
         document.getElementById(`exercise-item-${exo.id}`)?.classList.remove('exercise-selected');
-        exercises.find((exercise: Exercise) => {
+        exercises.value.find((exercise: Exercise) => {
             if (exercise.id === exo.id) {
                 exercise.selected = false;
             }
@@ -175,35 +143,49 @@ function onExerciceClick(exo: Exercise): void {
     } else {
         selectedExercises.push(exo);
         document.getElementById(`exercise-item-${exo.id}`)?.classList.add('exercise-selected');
-        exercises.find((exercise: Exercise) => {
+        exercises.value.find((exercise: Exercise) => {
             if (exercise.id === exo.id) {
                 exercise.selected = true;
             }
         })
     }
 }
+
+function onMarkerSelect(e: PointerEvent): void {
+    if (e.target instanceof Marker) {
+        const stepId = (e.target as Marker).options.title;
+        exercises.value = steps.value
+            .filter((step: Step) => step.id.toString() === stepId)
+            .map((step: Step) => {
+                return step.specificExercises
+                    .concat(step.terrainType.genericExercises);
+            }).flat();
+    }
+}
 </script>
 
 <template>
     <div id="exercices">
         <UContextMenu :items="items" :ui="{ content: 'w-48' }">
-            <LMap
-                ref="map"
-                :zoom="zoom"
-                :min-zoom="15"
-                :center="chantrerie"
-                :use-global-leaflet="true"
-                :options="{ zoomSnap: 0.75 }"
-                @ready="onMapReady"
-                @click="MapEvents"
-            >
-                <LTileLayer
-                    url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
-                    attribution="&amp;copy; <a href=&quot;https://www.openstreetmap.org/&quot;>OpenStreetMap</a>"
-                    layer-type="base"
-                    name="OpenStreetMap"
-                />
-            </LMap>
+            <div>
+                <LMap
+                    ref="map"
+                    :zoom="zoom"
+                    :min-zoom="15"
+                    :center="center"
+                    :use-global-leaflet="true"
+                    :options="{ zoomSnap: 0.75 }"
+                    @ready="onMapReady"
+                    @click="MapEvents"
+                >
+                    <LTileLayer
+                        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
+                        attribution="&amp;copy; <a href=&quot;https://www.openstreetmap.org/&quot;>OpenStreetMap</a>"
+                        layer-type="base"
+                        name="OpenStreetMap"
+                    />
+                </LMap>
+            </div>
         </UContextMenu>
         <div id="side" class="flex flex-col w-full h-full p-2 overflow-hidden">
             <UInput
@@ -222,13 +204,13 @@ function onExerciceClick(exo: Exercise): void {
             </UInput>
             <USeparator class="m-1 w-full"/>
             <div id="exercices-list" class="flex flex-col w-full h-full overflow-auto gap-1">
-                <ExerciceItem
+                <ParcoursExerciceItem
                     v-for="exercise in filterExercise()" :id="'exercise-item-'+exercise.id"
                     :key="exercise.id" ref="list"
                     :exercise="exercise as Exercise"
                     class="skeletton gap-4"
                     @click="onExerciceClick(exercise)"
-                    @mouseover="hooverMarker(exercise as Exercise)" @mouseleave="leaveMarker(exercise as Exercise)"/>
+                    @mouseover="mouseoverExercise(exercise as Exercise)" @mouseleave="mouseoutExercise(exercise as Exercise)"/>
                 <div class="skeletton gap-4">
                     <USkeleton class="h-12 w-12 rounded-full"/>
                     <div class="grid gap-2 w-full">
diff --git a/package-lock.json b/package-lock.json
index d65a610b6943a840ea2fe5f078c1beb5e5361d3f..8fb3542ba8186ae28566fd332f222108bf0e409d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,7 @@
       "name": "nuxt-app",
       "hasInstallScript": true,
       "dependencies": {
-        "@nuxt/eslint": "^1.0.1",
+        "@nuxt/eslint": "^1.1.0",
         "@nuxt/ui": "^3.0.0-alpha.13",
         "@nuxtjs/leaflet": "^1.2.6",
         "eslint": "^9.20.1",
@@ -22,9 +22,9 @@
         "@iconify-json/material-symbols": "^1.2.14",
         "@nuxt/test-utils": "^3.15.4",
         "@vue/test-utils": "^2.4.6",
-        "happy-dom": "^17.1.0",
+        "happy-dom": "^17.1.1",
         "typescript": "^5.7.3",
-        "vitest": "^3.0.5"
+        "vitest": "^3.0.6"
       }
     },
     "node_modules/@alloc/quick-lru": {
@@ -584,9 +584,9 @@
       }
     },
     "node_modules/@clack/prompts": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.9.1.tgz",
-      "integrity": "sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==",
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.10.0.tgz",
+      "integrity": "sha512-H3rCl6CwW1NdQt9rE3n373t7o5cthPv7yUoxF2ytZvyvlJv89C5RYMJu83Hed8ODgys5vpBU0GKxIRG83jd8NQ==",
       "license": "MIT",
       "dependencies": {
         "@clack/core": "0.4.1",
@@ -1966,15 +1966,15 @@
       }
     },
     "node_modules/@nuxt/eslint": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@nuxt/eslint/-/eslint-1.0.1.tgz",
-      "integrity": "sha512-Bh6M9Tjf4jyIyfobu/ekW6YHMCsWpvZHuZN/6tRVKwXgAL6fiJG6tHm3uYJ5ILcVTdp6tz/j/sW8dgP+ijHLDQ==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/eslint/-/eslint-1.1.0.tgz",
+      "integrity": "sha512-T5CmWwMhJIjpPk2yTSj2aOifBug5bRA3sv8ec6FpWZV+cMBV9wnXsAxrIHjX+PZMt691It89ORunPjkoPSCDVQ==",
       "license": "MIT",
       "dependencies": {
         "@eslint/config-inspector": "^1.0.0",
-        "@nuxt/devtools-kit": "^1.7.0",
-        "@nuxt/eslint-config": "1.0.1",
-        "@nuxt/eslint-plugin": "1.0.1",
+        "@nuxt/devtools-kit": "^2.1.0",
+        "@nuxt/eslint-config": "1.1.0",
+        "@nuxt/eslint-plugin": "1.1.0",
         "@nuxt/kit": "^3.15.4",
         "chokidar": "^4.0.3",
         "eslint-flat-config-utils": "^2.0.1",
@@ -1982,8 +1982,8 @@
         "find-up": "^7.0.0",
         "get-port-please": "^3.1.2",
         "mlly": "^1.7.4",
-        "pathe": "^2.0.2",
-        "unimport": "^4.1.0"
+        "pathe": "^2.0.3",
+        "unimport": "^4.1.2"
       },
       "peerDependencies": {
         "eslint": "^9.0.0",
@@ -2000,30 +2000,30 @@
       }
     },
     "node_modules/@nuxt/eslint-config": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.0.1.tgz",
-      "integrity": "sha512-N1sSvtrCWehBHOhB4VBVDxZyDxkXv5b4QN+NQC0suCGR4VekZj8mciaepWFTb66gNrpA/IHYfBId308Na++FwA==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.1.0.tgz",
+      "integrity": "sha512-xPKoACePUL5ItyLRqsExTnuQOeOr0JiQ7ESY7XKeJZAxAUUiWRuxpxDbPoHX9REKlz2oVBSzFQZFnJzpOPNyrA==",
       "license": "MIT",
       "dependencies": {
         "@antfu/install-pkg": "^1.0.0",
-        "@clack/prompts": "^0.9.1",
-        "@eslint/js": "^9.19.0",
-        "@nuxt/eslint-plugin": "1.0.1",
-        "@stylistic/eslint-plugin": "^3.0.1",
-        "@typescript-eslint/eslint-plugin": "^8.23.0",
-        "@typescript-eslint/parser": "^8.23.0",
-        "eslint-config-flat-gitignore": "^2.0.0",
+        "@clack/prompts": "^0.10.0",
+        "@eslint/js": "^9.20.0",
+        "@nuxt/eslint-plugin": "1.1.0",
+        "@stylistic/eslint-plugin": "^4.0.0",
+        "@typescript-eslint/eslint-plugin": "^8.24.1",
+        "@typescript-eslint/parser": "^8.24.1",
+        "eslint-config-flat-gitignore": "^2.1.0",
         "eslint-flat-config-utils": "^2.0.1",
-        "eslint-merge-processors": "^1.0.0",
+        "eslint-merge-processors": "^2.0.0",
         "eslint-plugin-import-x": "^4.6.1",
         "eslint-plugin-jsdoc": "^50.6.3",
         "eslint-plugin-regexp": "^2.7.0",
-        "eslint-plugin-unicorn": "^56.0.1",
+        "eslint-plugin-unicorn": "^57.0.0",
         "eslint-plugin-vue": "^9.32.0",
-        "eslint-processor-vue-blocks": "^1.0.0",
-        "globals": "^15.14.0",
+        "eslint-processor-vue-blocks": "^2.0.0",
+        "globals": "^15.15.0",
         "local-pkg": "^1.0.0",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "vue-eslint-parser": "^9.4.3"
       },
       "peerDependencies": {
@@ -2036,6 +2036,18 @@
         }
       }
     },
+    "node_modules/@nuxt/eslint-config/node_modules/globals": {
+      "version": "15.15.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+      "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@nuxt/eslint-config/node_modules/local-pkg": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz",
@@ -2053,18 +2065,44 @@
       }
     },
     "node_modules/@nuxt/eslint-plugin": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.0.1.tgz",
-      "integrity": "sha512-pqad64otqRmYTnaUSD1Jc57iWHACdWebD6UUb1hLVl/ML1B4yFxn5xq8kXRjzQsSKX3yMs7dFTYS0ygw04n+SA==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.1.0.tgz",
+      "integrity": "sha512-WRN2xvEdNfqLgjllDG8jtK/31daGitVpr2yb7N9XNNYIh29mWD0GP1lN8znBbJvnG3AXwN9qOb8NAXXvekw/IQ==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "^8.23.0",
-        "@typescript-eslint/utils": "^8.23.0"
+        "@typescript-eslint/types": "^8.24.1",
+        "@typescript-eslint/utils": "^8.24.1"
       },
       "peerDependencies": {
         "eslint": "^9.0.0"
       }
     },
+    "node_modules/@nuxt/eslint/node_modules/@nuxt/devtools-kit": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.1.0.tgz",
+      "integrity": "sha512-1fhwU7dDq/vIpjpNRwjEmTllRT1O0nzyBEhY187bQ8xBpoCC93t3zG3iTKcl8XkpT1aK9SqcgmXOnj5fNIAaYA==",
+      "license": "MIT",
+      "dependencies": {
+        "@nuxt/kit": "^3.15.4",
+        "@nuxt/schema": "^3.15.4",
+        "execa": "^9.5.2"
+      },
+      "peerDependencies": {
+        "vite": ">=6.0"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/@sindresorhus/merge-streams": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+      "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@nuxt/eslint/node_modules/escape-string-regexp": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
@@ -2077,6 +2115,69 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@nuxt/eslint/node_modules/execa": {
+      "version": "9.5.2",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz",
+      "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@sindresorhus/merge-streams": "^4.0.0",
+        "cross-spawn": "^7.0.3",
+        "figures": "^6.1.0",
+        "get-stream": "^9.0.0",
+        "human-signals": "^8.0.0",
+        "is-plain-obj": "^4.1.0",
+        "is-stream": "^4.0.1",
+        "npm-run-path": "^6.0.0",
+        "pretty-ms": "^9.0.0",
+        "signal-exit": "^4.1.0",
+        "strip-final-newline": "^4.0.0",
+        "yoctocolors": "^2.0.0"
+      },
+      "engines": {
+        "node": "^18.19.0 || >=20.5.0"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/get-stream": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+      "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+      "license": "MIT",
+      "dependencies": {
+        "@sec-ant/readable-stream": "^0.4.1",
+        "is-stream": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/human-signals": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
+      "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/is-stream": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+      "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@nuxt/eslint/node_modules/local-pkg": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz",
@@ -2093,29 +2194,122 @@
         "url": "https://github.com/sponsors/antfu"
       }
     },
-    "node_modules/@nuxt/eslint/node_modules/unimport": {
+    "node_modules/@nuxt/eslint/node_modules/npm-run-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+      "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^4.0.0",
+        "unicorn-magic": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/path-key": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/signal-exit": {
       "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/unimport/-/unimport-4.1.0.tgz",
-      "integrity": "sha512-y5ZYDG+j7IB45+Y6CIkWIKou4E1JFigCUw6vI+h15HdYAKmT0oQWcawnxXuwJG8srJyXhIZuWz5uXB1MQ/ARZw==",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/strip-final-newline": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+      "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/tinyglobby": {
+      "version": "0.2.11",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.11.tgz",
+      "integrity": "sha512-32TmKeeKUahv0Go8WmQgiEp9Y21NuxjwjqiRC1nrUB51YacfSwuB44xgXD+HdIppmMRgjQNPdrHyA6vIybYZ+g==",
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.4.3",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/unicorn-magic": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+      "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/unimport": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/unimport/-/unimport-4.1.2.tgz",
+      "integrity": "sha512-oVUL7PSlyVV3QRhsdcyYEMaDX8HJyS/CnUonEJTYA3//bWO+o/4gG8F7auGWWWkrrxBQBYOO8DKe+C53ktpRXw==",
       "license": "MIT",
       "dependencies": {
         "acorn": "^8.14.0",
         "escape-string-regexp": "^5.0.0",
         "estree-walker": "^3.0.3",
-        "fast-glob": "^3.3.3",
         "local-pkg": "^1.0.0",
         "magic-string": "^0.30.17",
         "mlly": "^1.7.4",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "picomatch": "^4.0.2",
         "pkg-types": "^1.3.1",
         "scule": "^1.3.0",
         "strip-literal": "^3.0.0",
-        "unplugin": "^2.1.2",
-        "unplugin-utils": "^0.2.3"
+        "tinyglobby": "^0.2.11",
+        "unplugin": "^2.2.0",
+        "unplugin-utils": "^0.2.4"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/@nuxt/eslint/node_modules/unplugin": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.2.0.tgz",
+      "integrity": "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw==",
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "webpack-virtual-modules": "^0.6.2"
       },
       "engines": {
-        "node": ">=18.20.6"
+        "node": ">=18.12.0"
       }
     },
     "node_modules/@nuxt/fonts": {
@@ -3578,12 +3772,12 @@
       }
     },
     "node_modules/@stylistic/eslint-plugin": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-3.0.1.tgz",
-      "integrity": "sha512-rQ3tcT5N2cynofJfbjUsnL4seoewTaOVBLyUEwtNldo7iNMPo3h/GUQk+Cl3iHEWwRxjq2wuH6q0FufQrbVL1A==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.0.1.tgz",
+      "integrity": "sha512-RwKkRKiDrF4ptiur54ckDhOByQYKYZ1dEmI5K8BJCmuGpauFJXzVL1UQYTA2zq702CqMFdYiJcVFJWfokIgFxw==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/utils": "^8.13.0",
+        "@typescript-eslint/utils": "^8.23.0",
         "eslint-visitor-keys": "^4.2.0",
         "espree": "^10.3.0",
         "estraverse": "^5.3.0",
@@ -3593,7 +3787,7 @@
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
       "peerDependencies": {
-        "eslint": ">=8.40.0"
+        "eslint": ">=9.0.0"
       }
     },
     "node_modules/@swc/helpers": {
@@ -3986,16 +4180,16 @@
       "license": "MIT"
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz",
-      "integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
+      "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==",
       "license": "MIT",
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "8.23.0",
-        "@typescript-eslint/type-utils": "8.23.0",
-        "@typescript-eslint/utils": "8.23.0",
-        "@typescript-eslint/visitor-keys": "8.23.0",
+        "@typescript-eslint/scope-manager": "8.24.1",
+        "@typescript-eslint/type-utils": "8.24.1",
+        "@typescript-eslint/utils": "8.24.1",
+        "@typescript-eslint/visitor-keys": "8.24.1",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
         "natural-compare": "^1.4.0",
@@ -4024,15 +4218,15 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz",
-      "integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz",
+      "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/scope-manager": "8.23.0",
-        "@typescript-eslint/types": "8.23.0",
-        "@typescript-eslint/typescript-estree": "8.23.0",
-        "@typescript-eslint/visitor-keys": "8.23.0",
+        "@typescript-eslint/scope-manager": "8.24.1",
+        "@typescript-eslint/types": "8.24.1",
+        "@typescript-eslint/typescript-estree": "8.24.1",
+        "@typescript-eslint/visitor-keys": "8.24.1",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -4048,13 +4242,13 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz",
-      "integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz",
+      "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.23.0",
-        "@typescript-eslint/visitor-keys": "8.23.0"
+        "@typescript-eslint/types": "8.24.1",
+        "@typescript-eslint/visitor-keys": "8.24.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4065,13 +4259,13 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz",
-      "integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz",
+      "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "8.23.0",
-        "@typescript-eslint/utils": "8.23.0",
+        "@typescript-eslint/typescript-estree": "8.24.1",
+        "@typescript-eslint/utils": "8.24.1",
         "debug": "^4.3.4",
         "ts-api-utils": "^2.0.1"
       },
@@ -4088,9 +4282,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz",
-      "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz",
+      "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==",
       "license": "MIT",
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4101,13 +4295,13 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz",
-      "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz",
+      "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.23.0",
-        "@typescript-eslint/visitor-keys": "8.23.0",
+        "@typescript-eslint/types": "8.24.1",
+        "@typescript-eslint/visitor-keys": "8.24.1",
         "debug": "^4.3.4",
         "fast-glob": "^3.3.2",
         "is-glob": "^4.0.3",
@@ -4127,15 +4321,15 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz",
-      "integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz",
+      "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==",
       "license": "MIT",
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@typescript-eslint/scope-manager": "8.23.0",
-        "@typescript-eslint/types": "8.23.0",
-        "@typescript-eslint/typescript-estree": "8.23.0"
+        "@typescript-eslint/scope-manager": "8.24.1",
+        "@typescript-eslint/types": "8.24.1",
+        "@typescript-eslint/typescript-estree": "8.24.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4150,12 +4344,12 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "8.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz",
-      "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==",
+      "version": "8.24.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz",
+      "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==",
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.23.0",
+        "@typescript-eslint/types": "8.24.1",
         "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
@@ -4361,15 +4555,15 @@
       }
     },
     "node_modules/@vitest/expect": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.5.tgz",
-      "integrity": "sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz",
+      "integrity": "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/spy": "3.0.5",
-        "@vitest/utils": "3.0.5",
-        "chai": "^5.1.2",
+        "@vitest/spy": "3.0.6",
+        "@vitest/utils": "3.0.6",
+        "chai": "^5.2.0",
         "tinyrainbow": "^2.0.0"
       },
       "funding": {
@@ -4377,13 +4571,13 @@
       }
     },
     "node_modules/@vitest/mocker": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.5.tgz",
-      "integrity": "sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.6.tgz",
+      "integrity": "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/spy": "3.0.5",
+        "@vitest/spy": "3.0.6",
         "estree-walker": "^3.0.3",
         "magic-string": "^0.30.17"
       },
@@ -4404,9 +4598,9 @@
       }
     },
     "node_modules/@vitest/pretty-format": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.5.tgz",
-      "integrity": "sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.6.tgz",
+      "integrity": "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -4417,38 +4611,38 @@
       }
     },
     "node_modules/@vitest/runner": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.5.tgz",
-      "integrity": "sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.6.tgz",
+      "integrity": "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/utils": "3.0.5",
-        "pathe": "^2.0.2"
+        "@vitest/utils": "3.0.6",
+        "pathe": "^2.0.3"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
       }
     },
     "node_modules/@vitest/snapshot": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.5.tgz",
-      "integrity": "sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.6.tgz",
+      "integrity": "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/pretty-format": "3.0.5",
+        "@vitest/pretty-format": "3.0.6",
         "magic-string": "^0.30.17",
-        "pathe": "^2.0.2"
+        "pathe": "^2.0.3"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
       }
     },
     "node_modules/@vitest/spy": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.5.tgz",
-      "integrity": "sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.6.tgz",
+      "integrity": "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -4459,14 +4653,14 @@
       }
     },
     "node_modules/@vitest/utils": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.5.tgz",
-      "integrity": "sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.6.tgz",
+      "integrity": "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/pretty-format": "3.0.5",
-        "loupe": "^3.1.2",
+        "@vitest/pretty-format": "3.0.6",
+        "loupe": "^3.1.3",
         "tinyrainbow": "^2.0.0"
       },
       "funding": {
@@ -5377,12 +5571,12 @@
       "license": "MIT"
     },
     "node_modules/builtin-modules": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
-      "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-4.0.0.tgz",
+      "integrity": "sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA==",
       "license": "MIT",
       "engines": {
-        "node": ">=6"
+        "node": ">=18.20"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -5503,9 +5697,9 @@
       "license": "CC-BY-4.0"
     },
     "node_modules/chai": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
-      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+      "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -6688,21 +6882,6 @@
         "url": "https://github.com/fb55/entities?sponsor=1"
       }
     },
-    "node_modules/error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "license": "MIT",
-      "dependencies": {
-        "is-arrayish": "^0.2.1"
-      }
-    },
-    "node_modules/error-ex/node_modules/is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
-      "license": "MIT"
-    },
     "node_modules/error-stack-parser-es": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz",
@@ -6851,9 +7030,9 @@
       }
     },
     "node_modules/eslint-config-flat-gitignore": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.0.0.tgz",
-      "integrity": "sha512-9iH+DZO94uxsw5iFjzqa9GfahA5oK3nA1GoJK/6u8evAtooYJMwuSWiLcGDfrdLoqdQ5/kqFJKKuMY/+SAasvg==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.1.0.tgz",
+      "integrity": "sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==",
       "license": "MIT",
       "dependencies": {
         "@eslint/compat": "^1.2.5"
@@ -6898,9 +7077,9 @@
       }
     },
     "node_modules/eslint-merge-processors": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-merge-processors/-/eslint-merge-processors-1.0.0.tgz",
-      "integrity": "sha512-4GybyHmhXtT7/W8RAouQzNM0791sYasJCTYHIAYjuiJvbNFY0jMKkoESREhX+mjX37dxiN6v4EqhZ1nc0tJF7A==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-merge-processors/-/eslint-merge-processors-2.0.0.tgz",
+      "integrity": "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA==",
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/antfu"
@@ -6983,27 +7162,27 @@
       }
     },
     "node_modules/eslint-plugin-unicorn": {
-      "version": "56.0.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz",
-      "integrity": "sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==",
+      "version": "57.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-57.0.0.tgz",
+      "integrity": "sha512-zUYYa6zfNdTeG9BISWDlcLmz16c+2Ck2o5ZDHh0UzXJz3DEP7xjmlVDTzbyV0W+XksgZ0q37WEWzN2D2Ze+g9Q==",
       "license": "MIT",
       "dependencies": {
-        "@babel/helper-validator-identifier": "^7.24.7",
-        "@eslint-community/eslint-utils": "^4.4.0",
-        "ci-info": "^4.0.0",
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "@eslint-community/eslint-utils": "^4.4.1",
+        "ci-info": "^4.1.0",
         "clean-regexp": "^1.0.0",
-        "core-js-compat": "^3.38.1",
+        "core-js-compat": "^3.40.0",
         "esquery": "^1.6.0",
-        "globals": "^15.9.0",
-        "indent-string": "^4.0.0",
-        "is-builtin-module": "^3.2.1",
-        "jsesc": "^3.0.2",
+        "globals": "^15.15.0",
+        "indent-string": "^5.0.0",
+        "is-builtin-module": "^4.0.0",
+        "jsesc": "^3.1.0",
         "pluralize": "^8.0.0",
-        "read-pkg-up": "^7.0.1",
+        "read-package-up": "^11.0.0",
         "regexp-tree": "^0.1.27",
-        "regjsparser": "^0.10.0",
-        "semver": "^7.6.3",
-        "strip-indent": "^3.0.0"
+        "regjsparser": "^0.12.0",
+        "semver": "^7.7.1",
+        "strip-indent": "^4.0.0"
       },
       "engines": {
         "node": ">=18.18"
@@ -7012,7 +7191,19 @@
         "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
       },
       "peerDependencies": {
-        "eslint": ">=8.56.0"
+        "eslint": ">=9.20.0"
+      }
+    },
+    "node_modules/eslint-plugin-unicorn/node_modules/globals": {
+      "version": "15.15.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+      "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/eslint-plugin-vue": {
@@ -7065,16 +7256,16 @@
       }
     },
     "node_modules/eslint-processor-vue-blocks": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-1.0.0.tgz",
-      "integrity": "sha512-q+Wn9bCml65NwYtuINVCE5dUqZa/uVoY4jfc8qEDwWbcGqdRyfJJmAONNZsreA4Q9EJqjYGjk8Hk1QuwAktgkw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-2.0.0.tgz",
+      "integrity": "sha512-u4W0CJwGoWY3bjXAuFpc/b6eK3NQEI8MoeW7ritKj3G3z/WtHrKjkqf+wk8mPEy5rlMGS+k6AZYOw2XBoN/02Q==",
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/antfu"
       },
       "peerDependencies": {
         "@vue/compiler-sfc": "^3.3.0",
-        "eslint": "^8.50.0 || ^9.0.0"
+        "eslint": ">=9.0.0"
       }
     },
     "node_modules/eslint-scope": {
@@ -7626,6 +7817,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/find-up-simple": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz",
+      "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/flat-cache": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
@@ -8078,9 +8281,9 @@
       }
     },
     "node_modules/happy-dom": {
-      "version": "17.1.0",
-      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.0.tgz",
-      "integrity": "sha512-9tUhXyePCjzUMycaHS/IzrIpF69xiq/laAT7golk4MtZ6t8ft5+Rv7U3lfrs2b4NMH0JTL3EhZzjfahrPmOnaQ==",
+      "version": "17.1.1",
+      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.1.tgz",
+      "integrity": "sha512-OSTkBlmD/6Do7gCd7nZB5iFq1bF9VQg/iFmjHmxvVX2S1UiOpo6sT+aFNnu3XUsB8hCZb9+GZ0G1g1TaMiAggw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -8119,9 +8322,21 @@
       "license": "MIT"
     },
     "node_modules/hosted-git-info": {
-      "version": "2.8.9",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+      "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^10.0.1"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/hosted-git-info/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
       "license": "ISC"
     },
     "node_modules/html-tags": {
@@ -8283,12 +8498,15 @@
       }
     },
     "node_modules/indent-string": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
-      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
+      "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
       "license": "MIT",
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/index-to-position": {
@@ -8361,15 +8579,15 @@
       }
     },
     "node_modules/is-builtin-module": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
-      "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-4.0.0.tgz",
+      "integrity": "sha512-rWP3AMAalQSesXO8gleROyL2iKU73SX5Er66losQn9rWOWL4Gef0a/xOEOVqjWGMuR2vHG3FJ8UUmT700O8oFg==",
       "license": "MIT",
       "dependencies": {
-        "builtin-modules": "^3.3.0"
+        "builtin-modules": "^4.0.0"
       },
       "engines": {
-        "node": ">=6"
+        "node": ">=18.20"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
@@ -8714,12 +8932,6 @@
       "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
       "license": "MIT"
     },
-    "node_modules/json-parse-even-better-errors": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
-      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
-      "license": "MIT"
-    },
     "node_modules/json-schema-to-typescript-lite": {
       "version": "14.1.0",
       "resolved": "https://registry.npmjs.org/json-schema-to-typescript-lite/-/json-schema-to-typescript-lite-14.1.0.tgz",
@@ -9125,12 +9337,6 @@
         "url": "https://github.com/sponsors/antonk52"
       }
     },
-    "node_modules/lines-and-columns": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
-      "license": "MIT"
-    },
     "node_modules/listhen": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.0.tgz",
@@ -9775,24 +9981,17 @@
       }
     },
     "node_modules/normalize-package-data": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
+      "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
       "license": "BSD-2-Clause",
       "dependencies": {
-        "hosted-git-info": "^2.1.4",
-        "resolve": "^1.10.0",
-        "semver": "2 || 3 || 4 || 5",
-        "validate-npm-package-license": "^3.0.1"
-      }
-    },
-    "node_modules/normalize-package-data/node_modules/semver": {
-      "version": "5.7.2",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
-      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
-      "license": "ISC",
-      "bin": {
-        "semver": "bin/semver"
+        "hosted-git-info": "^7.0.0",
+        "semver": "^7.3.5",
+        "validate-npm-package-license": "^3.0.4"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
       }
     },
     "node_modules/normalize-path": {
@@ -10145,15 +10344,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/package-json-from-dist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -11145,135 +11335,42 @@
         "destr": "^2.0.3"
       }
     },
-    "node_modules/read-pkg": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
-      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/normalize-package-data": "^2.4.0",
-        "normalize-package-data": "^2.5.0",
-        "parse-json": "^5.0.0",
-        "type-fest": "^0.6.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg-up": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
-      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
-      "license": "MIT",
-      "dependencies": {
-        "find-up": "^4.1.0",
-        "read-pkg": "^5.2.0",
-        "type-fest": "^0.8.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/read-pkg-up/node_modules/find-up": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-      "license": "MIT",
-      "dependencies": {
-        "locate-path": "^5.0.0",
-        "path-exists": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg-up/node_modules/locate-path": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-      "license": "MIT",
-      "dependencies": {
-        "p-locate": "^4.1.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg-up/node_modules/p-limit": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+    "node_modules/read-package-up": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
+      "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==",
       "license": "MIT",
       "dependencies": {
-        "p-try": "^2.0.0"
+        "find-up-simple": "^1.0.0",
+        "read-pkg": "^9.0.0",
+        "type-fest": "^4.6.0"
       },
       "engines": {
-        "node": ">=6"
+        "node": ">=18"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/read-pkg-up/node_modules/p-locate": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-      "license": "MIT",
-      "dependencies": {
-        "p-limit": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg-up/node_modules/path-exists": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg-up/node_modules/type-fest": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
-      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
-      "license": "(MIT OR CC0-1.0)",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/read-pkg/node_modules/parse-json": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
-      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+    "node_modules/read-pkg": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
+      "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
       "license": "MIT",
       "dependencies": {
-        "@babel/code-frame": "^7.0.0",
-        "error-ex": "^1.3.1",
-        "json-parse-even-better-errors": "^2.3.0",
-        "lines-and-columns": "^1.1.6"
+        "@types/normalize-package-data": "^2.4.3",
+        "normalize-package-data": "^6.0.0",
+        "parse-json": "^8.0.0",
+        "type-fest": "^4.6.0",
+        "unicorn-magic": "^0.1.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=18"
       },
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/read-pkg/node_modules/type-fest": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
-      "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
-      "license": "(MIT OR CC0-1.0)",
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/readable-stream": {
       "version": "4.7.0",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
@@ -11380,23 +11477,27 @@
       }
     },
     "node_modules/regjsparser": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz",
-      "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
+      "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
       "license": "BSD-2-Clause",
       "dependencies": {
-        "jsesc": "~0.5.0"
+        "jsesc": "~3.0.2"
       },
       "bin": {
         "regjsparser": "bin/parser"
       }
     },
     "node_modules/regjsparser/node_modules/jsesc": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-      "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+      "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+      "license": "MIT",
       "bin": {
         "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
       }
     },
     "node_modules/reka-ui": {
@@ -11710,9 +11811,9 @@
       "license": "MIT"
     },
     "node_modules/semver": {
-      "version": "7.6.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
-      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
       "license": "ISC",
       "bin": {
         "semver": "bin/semver.js"
@@ -12179,15 +12280,18 @@
       }
     },
     "node_modules/strip-indent": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
-      "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz",
+      "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==",
       "license": "MIT",
       "dependencies": {
-        "min-indent": "^1.0.0"
+        "min-indent": "^1.0.1"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/strip-json-comments": {
@@ -13766,15 +13870,15 @@
       }
     },
     "node_modules/vite-node": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.5.tgz",
-      "integrity": "sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.6.tgz",
+      "integrity": "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==",
       "license": "MIT",
       "dependencies": {
         "cac": "^6.7.14",
         "debug": "^4.4.0",
         "es-module-lexer": "^1.6.0",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "vite": "^5.0.0 || ^6.0.0"
       },
       "bin": {
@@ -14050,31 +14154,31 @@
       }
     },
     "node_modules/vitest": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.5.tgz",
-      "integrity": "sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==",
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.6.tgz",
+      "integrity": "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/expect": "3.0.5",
-        "@vitest/mocker": "3.0.5",
-        "@vitest/pretty-format": "^3.0.5",
-        "@vitest/runner": "3.0.5",
-        "@vitest/snapshot": "3.0.5",
-        "@vitest/spy": "3.0.5",
-        "@vitest/utils": "3.0.5",
-        "chai": "^5.1.2",
+        "@vitest/expect": "3.0.6",
+        "@vitest/mocker": "3.0.6",
+        "@vitest/pretty-format": "^3.0.6",
+        "@vitest/runner": "3.0.6",
+        "@vitest/snapshot": "3.0.6",
+        "@vitest/spy": "3.0.6",
+        "@vitest/utils": "3.0.6",
+        "chai": "^5.2.0",
         "debug": "^4.4.0",
         "expect-type": "^1.1.0",
         "magic-string": "^0.30.17",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "std-env": "^3.8.0",
         "tinybench": "^2.9.0",
         "tinyexec": "^0.3.2",
         "tinypool": "^1.0.2",
         "tinyrainbow": "^2.0.0",
         "vite": "^5.0.0 || ^6.0.0",
-        "vite-node": "3.0.5",
+        "vite-node": "3.0.6",
         "why-is-node-running": "^2.3.0"
       },
       "bin": {
@@ -14090,8 +14194,8 @@
         "@edge-runtime/vm": "*",
         "@types/debug": "^4.1.12",
         "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
-        "@vitest/browser": "3.0.5",
-        "@vitest/ui": "3.0.5",
+        "@vitest/browser": "3.0.6",
+        "@vitest/ui": "3.0.6",
         "happy-dom": "*",
         "jsdom": "*"
       },
diff --git a/package.json b/package.json
index 4748729435c5ba2a0c1f65f8d467455f55fac6c6..3ae171200f7888c5b8b75bfde7afedaffa47eb92 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
     "test": "node_modules/.bin/vitest run --passWithNoTests"
   },
   "dependencies": {
-    "@nuxt/eslint": "^1.0.1",
+    "@nuxt/eslint": "^1.1.0",
     "@nuxt/ui": "^3.0.0-alpha.13",
     "@nuxtjs/leaflet": "^1.2.6",
     "eslint": "^9.20.1",
@@ -29,13 +29,13 @@
     "@iconify-json/material-symbols": "^1.2.14",
     "@nuxt/test-utils": "^3.15.4",
     "@vue/test-utils": "^2.4.6",
-    "happy-dom": "^17.1.0",
+    "happy-dom": "^17.1.1",
     "typescript": "^5.7.3",
-    "vitest": "^3.0.5"
+    "vitest": "^3.0.6"
   },
   "overrides": {
     "glob": "^11.0.1",
-    "happy-dom": "^17.1.0",
+    "happy-dom": "^17.1.1",
     "esbuild": "^0.25.0"
   }
 }
diff --git a/plugins/api.ts b/plugins/api.ts
index c24ff4cf2a743ca08c5077be3b9fd7655fbfabc6..774cb8882b795880cb2333aa44f51d3937376c7b 100644
--- a/plugins/api.ts
+++ b/plugins/api.ts
@@ -1,15 +1,18 @@
 import ExerciseModule from "~/repository/module/exercise";
 import UserModule from '~/repository/module/user';
+import StepModule from "~/repository/module/step";
 
 interface IApiInstance {
-    users: UserModule;
     exercises: ExerciseModule;
+    step: StepModule;
+    users: UserModule;
 }
 
 export default defineNuxtPlugin(() => {
     const modules: IApiInstance = {
-        users: new UserModule(),
-        exercises: new ExerciseModule()
+        exercises: new ExerciseModule(),
+        step: new StepModule(),
+        users: new UserModule()
     };
 
     return {
diff --git a/repository/module/exercise.ts b/repository/module/exercise.ts
index 79b489ca7f1f1dffedfba26769fba287cb90e949..b7b72962d2a53ced6a0a1e729496e5cf8eabee27 100644
--- a/repository/module/exercise.ts
+++ b/repository/module/exercise.ts
@@ -1,11 +1,9 @@
-import type {IExercise} from "~/repository/model/IExercise";
 import {type Exercise, ExerciseClass} from "~/types/Exercise";
 import type {ResponseBody} from "~/types/ResponseBody";
-import {ExerciseMapperFrom} from "~/utils/mapper/ExerciseMapper";
 
 class ExerciseModule {
-    private readonly RESSOURCE: string = '/api/exercise'
-    private exercises: IExercise[] = [];
+    private readonly RESSOURCE: string = '/exercise'
+    private exercises: Exercise[] = [];
 
     /**
      * Get an exercise by its id
@@ -20,7 +18,7 @@ class ExerciseModule {
         if (!ex) {
             return new ExerciseClass(this.getNewId());
         }
-        return ExerciseMapperFrom(ex);
+        return ex;
     }
 
     /**
@@ -31,7 +29,7 @@ class ExerciseModule {
         if (!this.exercises.length) {
             await this.fetchExercises();
         }
-        return this.exercises.map((e) => ExerciseMapperFrom(e));
+        return this.exercises.map((e) => e);
     }
 
     /**
@@ -39,18 +37,18 @@ class ExerciseModule {
      * @param exercise the exercise to save
      * @return either a response as a string or the saved exercise with their associated status code
      */
-    async saveExercise(exercise: Exercise): Promise<ResponseBody<string | IExercise>> {
+    async saveExercise(exercise: Exercise): Promise<ResponseBody<string | Exercise>> {
         const method = this.exercises.find((e) => e.id === exercise.id) ? 'PATCH' : 'POST';
 
-        const data: ResponseBody<string | IExercise> = (await $fetch(this.RESSOURCE, {
+        const data: ResponseBody<string | Exercise> = (await $fetch(this.RESSOURCE, {
             method: method,
             body: JSON.stringify(exercise)
         }));
 
         if (data.statusCode == 200) {
-            this.exercises = this.exercises.map((e) => e.id === exercise.id ? data.message as IExercise : e);
+            this.exercises = this.exercises.map((e) => e.id === exercise.id ? data.message as Exercise: e);
         } else if (data.statusCode == 201) {
-            this.exercises.push(data.message as IExercise);
+            this.exercises.push(data.message as Exercise);
         }
         return data;
     }
diff --git a/repository/module/step.ts b/repository/module/step.ts
new file mode 100644
index 0000000000000000000000000000000000000000..26c9dc52dbfcaeeb9d16ea3d7eb920167dcd084a
--- /dev/null
+++ b/repository/module/step.ts
@@ -0,0 +1,37 @@
+import type {LatLngBounds} from "leaflet";
+import type {ResponseBody} from "~/types/ResponseBody";
+import type {Step} from "~/types/Step";
+
+type AreaBody = {
+    latMin: number;
+    latMax: number;
+    longMin: number;
+    longMax: number;
+}
+
+class StepModule {
+    private readonly RESOURCE = '/step';
+
+    /**
+     * Return the products as array
+     * @param body
+     * @returns
+     */
+    async postArea(body: LatLngBounds): Promise<ResponseBody<string | Step[]>> {
+        return await $fetch(`${this.RESOURCE}/fetch-in-area`, {
+            method: 'POST',
+            body: JSON.stringify(boundsToAreaBody(body))
+        })
+    }
+}
+
+export default StepModule;
+
+function boundsToAreaBody(bounds: LatLngBounds): AreaBody {
+    return {
+        latMin: bounds?.getSouthWest().lat,
+        latMax: bounds?.getNorthEast().lat,
+        longMin: bounds?.getSouthWest().lng,
+        longMax: bounds?.getNorthEast().lng
+    }
+}
\ No newline at end of file
diff --git a/repository/module/user.ts b/repository/module/user.ts
index ae83479158908a0406b366a9886714aaa197bc02..338a8ceb9c9ea95e53388ab617f2aabcc9a34891 100644
--- a/repository/module/user.ts
+++ b/repository/module/user.ts
@@ -3,7 +3,7 @@ import type {ResponseBody} from "~/types/ResponseBody";
 import type {IUser} from "~/repository/model/IUser";
 
 class UserModule {
-    private readonly RESOURCE = '/api/auth';
+    private readonly RESOURCE = '/auth';
 
     /**
      * Return the products as array
diff --git a/repository/model/IExercise.ts b/server/model/IExercise.ts
similarity index 100%
rename from repository/model/IExercise.ts
rename to server/model/IExercise.ts
diff --git a/server/model/IStep.ts b/server/model/IStep.ts
new file mode 100644
index 0000000000000000000000000000000000000000..98231a69f8c631fb08fcb773f104092a4c24e752
--- /dev/null
+++ b/server/model/IStep.ts
@@ -0,0 +1,27 @@
+import type {IExercise} from "~/repository/model/IExercise";
+
+export type ISpecificExercise = {
+    id: number;
+    exercise: IExercise;
+}
+
+export type IGenericExercise = {
+    id: number;
+    exercise: IExercise;
+}
+
+export type ITerrainType = {
+    id: number;
+    name: string;
+    description: string;
+    genericExercises: IGenericExercise[];
+}
+
+export type IStep = {
+    id: number;
+    latitude: number;
+    longitude: number;
+    radius: number;
+    specificExercise: ISpecificExercise[];
+    terrainType: ITerrainType;
+}
diff --git a/repository/model/IUser.ts b/server/model/IUser.ts
similarity index 100%
rename from repository/model/IUser.ts
rename to server/model/IUser.ts
diff --git a/repository/model/LoginBody.ts b/server/model/LoginBody.ts
similarity index 100%
rename from repository/model/LoginBody.ts
rename to server/model/LoginBody.ts
diff --git a/server/api/auth/login.post.ts b/server/routes/auth/login.post.ts
similarity index 82%
rename from server/api/auth/login.post.ts
rename to server/routes/auth/login.post.ts
index 86114ac3434727a37fb6bc5c623c54012e5b4359..3602675b41698be31d64e654412e24a3012a9ac9 100644
--- a/server/api/auth/login.post.ts
+++ b/server/routes/auth/login.post.ts
@@ -2,14 +2,13 @@ import {appendResponseHeader, defineEventHandler, readBody} from "h3";
 import {useRuntimeConfig} from "#imports";
 
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
     headers.set('Content-Type', 'application/json');
     headers.set('accept', '*/*');
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'POST',
         headers: headers,
         body: JSON.stringify(await readBody(event))
diff --git a/server/api/exercise/.delete.ts b/server/routes/exercise/.delete.ts
similarity index 85%
rename from server/api/exercise/.delete.ts
rename to server/routes/exercise/.delete.ts
index aaa9f5ab2ce5dd8ee415a591bc77e23819ab405d..fbcd077c616b984fd34e4fad3f3ac56372c0fcef 100644
--- a/server/api/exercise/.delete.ts
+++ b/server/routes/exercise/.delete.ts
@@ -4,14 +4,13 @@ import type {ResponseBody} from "~/types/ResponseBody";
 
 // TODO : TU des différents retours de l'api
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
     headers.set('accept', '*/*');
     headers.set('Cookie', event.headers.get('Cookie') as string);
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'DELETE',
         headers: headers
     })
diff --git a/server/api/exercise/.get.ts b/server/routes/exercise/.get.ts
similarity index 61%
rename from server/api/exercise/.get.ts
rename to server/routes/exercise/.get.ts
index e1eda3dba0304f1b14ae993dd8a20748f5d8fd60..90ce48a0c89b4772d39511af32b09756f10f7b1d 100644
--- a/server/api/exercise/.get.ts
+++ b/server/routes/exercise/.get.ts
@@ -1,24 +1,24 @@
 import {defineEventHandler} from "h3";
 import {useRuntimeConfig} from "#imports";
+import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper";
+import type {IExercise} from "~/server/model/IExercise";
 import type {ResponseBody} from "~/types/ResponseBody";
-import type {IExercise} from "~/repository/model/IExercise";
 
 // TODO : TU des différents retours de l'api
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
     headers.set('Content-Type', 'application/json');
     headers.set('accept', '*/*');
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'GET',
         headers: headers
     })
 
     return {
         statusCode: res.status,
-        message: await res.json()
-    } as ResponseBody<IExercise[]>;
+        message: (await res.json() as IExercise[]).map((e) => ExerciseMapperFrom(e))
+    } as ResponseBody<Exercise[]>;
 })
\ No newline at end of file
diff --git a/server/api/exercise/.patch.ts b/server/routes/exercise/.patch.ts
similarity index 79%
rename from server/api/exercise/.patch.ts
rename to server/routes/exercise/.patch.ts
index 7ae8d21f05b35fad63adb0a3c81142ada4a5e3c7..fbe5b8f7aee5aa0bb1258d414e3c0ef359587e96 100644
--- a/server/api/exercise/.patch.ts
+++ b/server/routes/exercise/.patch.ts
@@ -1,11 +1,11 @@
 import {defineEventHandler, readBody} from "h3";
 import {useRuntimeConfig} from "#imports";
+import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper";
+import type {IExercise} from "~/server/model/IExercise";
 import type {ResponseBody} from "~/types/ResponseBody";
-import type {IExercise} from "~/repository/model/IExercise";
 
 // TODO : TU des différents retours de l'api
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
@@ -13,7 +13,7 @@ export default defineEventHandler(async (event) => {
     headers.set('accept', '*/*');
     headers.set('Cookie', event.headers.get('Cookie') as string);
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'PATCH',
         headers: headers,
         body: ExerciseToPostBody(await readBody(event))
@@ -22,8 +22,8 @@ export default defineEventHandler(async (event) => {
     if(res.ok) {
         return {
             statusCode: res.status,
-            message: await res.json() as IExercise
-        } as ResponseBody<IExercise>
+            message: ExerciseMapperFrom(await res.json() as IExercise)
+        } as ResponseBody<Exercise>
     } else {
         return await res.json() as ResponseBody<string>
     }
diff --git a/server/api/exercise/.post.ts b/server/routes/exercise/.post.ts
similarity index 79%
rename from server/api/exercise/.post.ts
rename to server/routes/exercise/.post.ts
index 2dc97621310782244e69e52a93b269b120d07032..8874e8a12bcea3625300f5c204c80b2b91bfc159 100644
--- a/server/api/exercise/.post.ts
+++ b/server/routes/exercise/.post.ts
@@ -1,12 +1,12 @@
 import {defineEventHandler, readBody} from "h3";
 import {useRuntimeConfig} from "#imports";
-import type {ResponseBody} from "~/types/ResponseBody";
+import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper";
 import type {Exercise} from "~/types/Exercise";
-import type {IExercise} from "~/repository/model/IExercise";
+import type {IExercise} from "~/server/model/IExercise";
+import type {ResponseBody} from "~/types/ResponseBody";
 
 // TODO : TU des différents retours de l'api
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
@@ -14,7 +14,7 @@ export default defineEventHandler(async (event) => {
     headers.set('accept', '*/*');
     headers.set('Cookie', event.headers.get('Cookie') as string);
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'POST',
         headers: headers,
         body: ExerciseToPostBody(await readBody(event))
@@ -23,8 +23,8 @@ export default defineEventHandler(async (event) => {
     if(res.ok) {
         return {
             statusCode: res.status,
-            message: await res.json() as IExercise
-        } as ResponseBody<IExercise>
+            message: ExerciseMapperFrom(await res.json() as IExercise)
+        } as ResponseBody<Exercise>
     } else {
         return await res.json() as ResponseBody<string>
     }
diff --git a/server/api/exercise/fetch-sub-categories.get.ts b/server/routes/exercise/fetch-sub-categories.get.ts
similarity index 79%
rename from server/api/exercise/fetch-sub-categories.get.ts
rename to server/routes/exercise/fetch-sub-categories.get.ts
index 892e83b3d055f53b6b579133a983d5e343a2133c..725df11a311c83bcc08684473335ea5cbcf37d2e 100644
--- a/server/api/exercise/fetch-sub-categories.get.ts
+++ b/server/routes/exercise/fetch-sub-categories.get.ts
@@ -1,16 +1,15 @@
 import {defineEventHandler} from "h3";
 import {useRuntimeConfig} from "#imports";
-import type {ResponseBody} from "~/types/ResponseBody";
+import type {ResponseBody} from "../../../types/ResponseBody";
 
 export default defineEventHandler(async (event) => {
-    const url = event.path.replace('/api/', '');
     const config = useRuntimeConfig(event);
 
     const headers = new Headers();
     headers.set('Content-Type', 'application/json');
     headers.set('accept', '*/*');
 
-    const res = await fetch(`${config.public.apiBase}/${url}`, {
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
         method: 'GET',
         headers: headers
     })
diff --git a/server/routes/step/fetch-in-area.post.ts b/server/routes/step/fetch-in-area.post.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ad382bd5163c72c4253fecc5811ae98aa927dfdd
--- /dev/null
+++ b/server/routes/step/fetch-in-area.post.ts
@@ -0,0 +1,31 @@
+import {defineEventHandler, readBody} from "h3";
+import {useRuntimeConfig} from "#imports";
+import {StepMapperFrom} from "../../utils/mapper/StepMapper";
+import type {IStep} from "../../model/IStep";
+import type {ResponseBody} from "../../../types/ResponseBody";
+import type {Step} from "../../../types/Step";
+
+// TODO : TU des différents retours de l'api
+export default defineEventHandler(async (event) => {
+    const config = useRuntimeConfig(event);
+
+    const headers = new Headers();
+    headers.set('Content-Type', 'application/json');
+    headers.set('accept', '*/*');
+    headers.set('Cookie', event.headers.get('Cookie') as string);
+
+    const res = await fetch(`${config.public.apiBase}${event.path}`, {
+        method: 'POST',
+        headers: headers,
+        body: JSON.stringify(await readBody(event))
+    })
+
+    if(res.ok) {
+        return {
+            statusCode: res.status,
+            message: (await res.json() as IStep[]).map((s) => StepMapperFrom(s))
+        } as ResponseBody<Step[]>
+    } else {
+        return await res.json() as ResponseBody<string>
+    }
+})
\ No newline at end of file
diff --git a/utils/mapper/ExerciseMapper.test.ts b/server/utils/mapper/ExerciseMapper.test.ts
similarity index 93%
rename from utils/mapper/ExerciseMapper.test.ts
rename to server/utils/mapper/ExerciseMapper.test.ts
index c6bb06bbc91bcb26974b40b03504acbda59f90fd..60d1e6a58290ae15536fe0bedd118c2675e75a71 100644
--- a/utils/mapper/ExerciseMapper.test.ts
+++ b/server/utils/mapper/ExerciseMapper.test.ts
@@ -1,6 +1,8 @@
 import {expect, test} from 'vitest'
 import {ExerciseMapperFrom, ExerciseMapperTo} from './ExerciseMapper'
-import type {IExercise} from "~/repository/model/IExercise";
+import {ExerciseCategory} from "../../../types/enum/ExerciseCategory";
+import type {Exercise} from "../../../types/Exercise";
+import type {IExercise} from "../../model/IExercise";
 
 const iExercise: IExercise = {
     id: 1,
diff --git a/utils/mapper/ExerciseMapper.ts b/server/utils/mapper/ExerciseMapper.ts
similarity index 75%
rename from utils/mapper/ExerciseMapper.ts
rename to server/utils/mapper/ExerciseMapper.ts
index 3da9e52552e5e2cbc56e6b0a7abfdd11003b8c8d..cdf02a5c56c1f8b1a5f5dad50300052fc95d02fb 100644
--- a/utils/mapper/ExerciseMapper.ts
+++ b/server/utils/mapper/ExerciseMapper.ts
@@ -1,5 +1,7 @@
-import type {Exercise} from "~/types/Exercise";
-import type {IExercise} from "~/repository/model/IExercise";
+import type {Exercise} from "../../../types/Exercise";
+import type {ExerciseCategory} from "../../../types/enum/ExerciseCategory";
+import type {ExerciseSubCategory} from "../../../types/enum/ExerciseSubCategory";
+import type {IExercise} from "../../model/IExercise";
 
 export function ExerciseMapperFrom(iExercise: IExercise): Exercise {
     return {
@@ -10,7 +12,7 @@ export function ExerciseMapperFrom(iExercise: IExercise): Exercise {
         generalInstructions: iExercise.generalInstructions,
         diagram: iExercise.diagram,
         video: iExercise.video,
-        category: iExercise.category.name as ExerciseCategory,
+        category: iExercise.category?.name as ExerciseCategory,
         subCategory: iExercise.subCategory?.name as ExerciseSubCategory,
         selected: false
     }
diff --git a/server/utils/mapper/StepMapper.test.ts b/server/utils/mapper/StepMapper.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6a1036497ecfaa6fc7feb146456e326395e689d8
--- /dev/null
+++ b/server/utils/mapper/StepMapper.test.ts
@@ -0,0 +1,62 @@
+import {expect, test, describe} from 'vitest'
+import {StepMapperFrom, StepMapperTo} from "./StepMapper";
+import type {IStep} from "../../model/IStep";
+import type {Step} from "../../../types/Step";
+
+const iStep: IStep = {
+    id: 0, 
+    latitude: 0, 
+    longitude: 0, 
+    radius: 0, 
+    specificExercise: [],
+    terrainType: {
+        id: 0,
+        name: 'name',
+        description: 'description',
+        genericExercises: []
+    }
+}
+
+const step: Step = {
+    id: 0, 
+    latitude: 0, 
+    longitude: 0, 
+    radius: 0, 
+    specificExercises: [],
+    terrainType: {
+        id: 0,
+        name: 'name',
+        description: 'description',
+        genericExercises: []
+    }
+}
+
+describe.todo('unimplemented suite')
+// StepMapperFrom
+test('StepMapperFrom', () => {
+    const mappedStep = StepMapperFrom(iStep)
+
+    expect(mappedStep).toStrictEqual(step)
+})
+
+// StepMapperTo
+test('StepMapperTo', () => {
+    const mappedIStep = StepMapperTo(step)
+
+    expect(mappedIStep).toStrictEqual(iStep)
+})
+
+// StepMapperFlipFlop
+test('StepMapperFlipFlop', () => {
+    const mappedIStep = StepMapperTo(StepMapperFrom(iStep))
+    const mappedStep = StepMapperFrom(StepMapperTo(step))
+
+    expect(mappedIStep).toStrictEqual(iStep)
+    expect(mappedStep).toStrictEqual(step)
+})
+
+// StepMapperFromNull, should throw an error
+test('StepMapperNull', () => {
+    expect(() => StepMapperFrom(null)).toThrow(TypeError)
+    expect(() => StepMapperTo(null)).toThrow(TypeError)
+})
\ No newline at end of file
diff --git a/server/utils/mapper/StepMapper.ts b/server/utils/mapper/StepMapper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0a5c44adf480031e1a1e57a1fa697cdc1bb80265
--- /dev/null
+++ b/server/utils/mapper/StepMapper.ts
@@ -0,0 +1,55 @@
+import {ExerciseMapperFrom, ExerciseMapperTo} from "./ExerciseMapper";
+import type {IStep} from "../../model/IStep";
+import type {Step} from "../../../types/Step";
+
+export function StepMapperFrom(iStep: IStep): Step {
+    return {
+        id: iStep.id,
+        latitude: iStep.latitude,
+        longitude: iStep.longitude,
+        radius: iStep.radius,
+        specificExercises: iStep.specificExercise.map((se) => {
+            return {
+                ...ExerciseMapperFrom(se.exercise),
+                type: 'specific'
+            }
+        }),
+        terrainType: {
+            id: iStep.terrainType.id,
+            name: iStep.terrainType.name,
+            description: iStep.terrainType.description,
+            genericExercises: iStep.terrainType.genericExercises.map((ge) => {
+                return {
+                    ...ExerciseMapperFrom(ge.exercise),
+                    type: 'generic ' + iStep.terrainType.name
+                }
+            })
+        }
+    }
+}
+
+export function StepMapperTo(step: Step): IStep {
+    return {
+        id: step.id,
+        latitude: step.latitude,
+        longitude: step.longitude,
+        radius: step.radius,
+        specificExercise: step.specificExercises.map((se) => {
+            return {
+                id: se.id,
+                exercise: ExerciseMapperTo(se.exercise)
+            }
+        }),
+        terrainType: {
+            id: step.terrainType.id,
+            name: step.terrainType.name,
+            description: step.terrainType.description,
+            genericExercises: step.terrainType.genericExercises.map((ge) => {
+                return {
+                    id: ge.id,
+                    exercise: ExerciseMapperTo(ge.exercise)
+                }
+            })
+        }
+    }
+}
diff --git a/utils/mapper/UserMapper.test.ts b/server/utils/mapper/UserMapper.test.ts
similarity index 100%
rename from utils/mapper/UserMapper.test.ts
rename to server/utils/mapper/UserMapper.test.ts
diff --git a/utils/mapper/UserMapper.ts b/server/utils/mapper/UserMapper.ts
similarity index 100%
rename from utils/mapper/UserMapper.ts
rename to server/utils/mapper/UserMapper.ts
diff --git a/types/Exercise.ts b/types/Exercise.ts
index d6d3be0245543e8da2115b05c9dcad344ffd7817..8cf060dad54f664da5abb478fa1c7a73cf3eda81 100644
--- a/types/Exercise.ts
+++ b/types/Exercise.ts
@@ -10,9 +10,8 @@ export type Exercise = {
     generalInstructions?: string;
     diagram?: string;
     video?: string;
-    // FIXME: to remove
-    lat?: number;
-    lng?: number;
+
+    type?: string;
     selected?: boolean;
 };
 
diff --git a/types/Step.ts b/types/Step.ts
new file mode 100644
index 0000000000000000000000000000000000000000..829ac2e153d10177de4a7fc949f3f857c6956b0a
--- /dev/null
+++ b/types/Step.ts
@@ -0,0 +1,15 @@
+export type TerrainType = {
+    id: number;
+    name: string;
+    description: string;
+    genericExercises: Exercise[];
+}
+
+export type Step = {
+    id: number;
+    latitude: number;
+    longitude: number;
+    radius: number;
+    specificExercises: Exercise[];
+    terrainType: TerrainType;
+}