From dbf06d8c64201366410a87f65591db22458a66f7 Mon Sep 17 00:00:00 2001
From: Pierre Tellier <piair338@gmail.com>
Date: Fri, 7 Feb 2025 23:06:59 +0100
Subject: [PATCH 1/7] feat: configured authentification

---
 Makefile                                      |  8 +-
 .../myinpulse/MyinpulseApplication.java       | 43 ++------
 .../WebSecurityCustomConfiguration.java       | 50 ++++++++++
 .../security/KeycloakJwtRolesConverter.java   | 98 +++++++++++++++++++
 .../src/main/resources/application.properties |  3 +-
 front/MyINPulse-front/src/helpers.ts          | 26 -----
 6 files changed, 161 insertions(+), 67 deletions(-)
 create mode 100644 MyINPulse-back/src/main/java/enseirb/myinpulse/config/WebSecurityCustomConfiguration.java
 create mode 100644 MyINPulse-back/src/main/java/enseirb/myinpulse/security/KeycloakJwtRolesConverter.java
 delete mode 100644 front/MyINPulse-front/src/helpers.ts

diff --git a/Makefile b/Makefile
index a5606be..6944ef4 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ help:
 
 clean: 
 	@cp config/prod.docker-compose.yaml docker-compose.yaml
-	@docker compose down 2> /dev/null
+	@docker compose down
 	@rm -f docker-compose.yaml
 	@rm -f .env
 	@rm -f front/MyINPulse-front/.env
@@ -21,14 +21,14 @@ dev-front: clean vite
 	@cp config/frontdev.front.env front/MyINPulse-front/.env
 	@cp config/frontdev.main.env .env
 	@cp config/frontdev.docker-compose.yaml docker-compose.yaml
-	@docker compose up -d
+	@docker compose up -d --build
 	@cd ./front/MyINPulse-front/ && npm run dev
 
 prod: clean
 	@cp config/prod.front.env front/MyINPulse-front/.env
 	@cp config/prod.main.env .env
 	@cp config/frontdev.docker-compose.yaml docker-compose.yaml
-	@docker compose up -d
+	@docker compose up -d --build
 
 
 
@@ -36,6 +36,6 @@ dev-back:
 	@cp config/backdev.front.env front/MyINPulse-front/.env
 	@cp config/backdev.main.env .env
 	@cp config/backdev.docker-compose.yaml docker-compose.yaml
-	@docker compose up -d 
+	@docker compose up -d --build
 	@echo "cd MyINPulse-back"
 	@echo "./gradlew bootRun --args='--server.port=8081'"
\ No newline at end of file
diff --git a/MyINPulse-back/src/main/java/enseirb/myinpulse/MyinpulseApplication.java b/MyINPulse-back/src/main/java/enseirb/myinpulse/MyinpulseApplication.java
index b4b5e7b..23c2f28 100644
--- a/MyINPulse-back/src/main/java/enseirb/myinpulse/MyinpulseApplication.java
+++ b/MyINPulse-back/src/main/java/enseirb/myinpulse/MyinpulseApplication.java
@@ -1,22 +1,22 @@
 package enseirb.myinpulse;
 
+import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;
-import org.springframework.security.config.Customizer;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
+import org.springframework.security.oauth2.jwt.*;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.CorsConfigurationSource;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
-import java.util.Arrays;
+import java.util.*;
+import java.util.stream.Collectors;
 
-import static org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
+import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
 
 @SpringBootApplication
 public class MyinpulseApplication {
@@ -25,34 +25,5 @@ public class MyinpulseApplication {
 		SpringApplication.run(MyinpulseApplication.class, args);
 	}
 
-	// CORS configuration
-	// TODO: make sure to only accept our own domains
-	@Bean
-	public CorsConfigurationSource corsConfigurationSource() {
-		CorsConfiguration configuration = new CorsConfiguration();
-		configuration.setAllowedOrigins(Arrays.asList("*"));
-		configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
-		configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type",
-				"x-auth-token")); // Do not remove, this fixes the CORS errors when unauthenticated
-		//configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
-		UrlBasedCorsConfigurationSource source = new
-				UrlBasedCorsConfigurationSource();
-		source.registerCorsConfiguration("/**", configuration);
-
-		return source;
-	}
-
-	// TODO: add unauthenticated endpoint with server status
-	@Bean
-	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-		http
-				.authorizeHttpRequests(authorize -> authorize
-						.requestMatchers("/random2").access(hasScope("contacts"))
-						.requestMatchers("/getUserInfo").access(hasScope("messages"))
-						.anyRequest().authenticated()
-				)
-				.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
-		return http.build();
-	}
 
 }
diff --git a/MyINPulse-back/src/main/java/enseirb/myinpulse/config/WebSecurityCustomConfiguration.java b/MyINPulse-back/src/main/java/enseirb/myinpulse/config/WebSecurityCustomConfiguration.java
new file mode 100644
index 0000000..14c46b3
--- /dev/null
+++ b/MyINPulse-back/src/main/java/enseirb/myinpulse/config/WebSecurityCustomConfiguration.java
@@ -0,0 +1,50 @@
+package enseirb.myinpulse.config;
+
+import enseirb.myinpulse.security.KeycloakJwtRolesConverter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
+
+@Configuration
+public class WebSecurityCustomConfiguration {
+    // CORS configuration
+    // TODO: make sure to only accept our own domains
+    @Bean
+    public CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration configuration = new CorsConfiguration();
+        configuration.setAllowedOrigins(List.of("*"));
+        configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
+        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type",
+                "x-auth-token")); // Do not remove, this fixes the CORS errors when unauthenticated
+        UrlBasedCorsConfigurationSource source = new
+                UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", configuration);
+
+        return source;
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+        http
+                .authorizeHttpRequests(authorize -> authorize
+                        .requestMatchers("/random2").access(hasRole("REALM_MyINPulse-entrepreneur"))
+                        .requestMatchers("/random").access(hasRole("REALM_MyINPulse-admin"))
+                        .requestMatchers("/random3").permitAll()
+                        .anyRequest().authenticated()
+                )
+                .oauth2ResourceServer(oauth2 -> oauth2
+                        .jwt(jwt -> jwt.
+                                jwtAuthenticationConverter(new KeycloakJwtRolesConverter())));
+        return http.build();
+
+    }
+}
\ No newline at end of file
diff --git a/MyINPulse-back/src/main/java/enseirb/myinpulse/security/KeycloakJwtRolesConverter.java b/MyINPulse-back/src/main/java/enseirb/myinpulse/security/KeycloakJwtRolesConverter.java
new file mode 100644
index 0000000..fafbef5
--- /dev/null
+++ b/MyINPulse-back/src/main/java/enseirb/myinpulse/security/KeycloakJwtRolesConverter.java
@@ -0,0 +1,98 @@
+package enseirb.myinpulse.security;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toSet;
+
+
+public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthenticationToken> {
+    /**
+     * Prefix used for realm level roles.
+     */
+    public static final String PREFIX_REALM_ROLE = "ROLE_REALM_";
+    /**
+     * Prefix used in combination with the resource (client) name for resource level roles.
+     */
+    public static final String PREFIX_RESOURCE_ROLE = "ROLE_";
+
+    /**
+     * Name of the claim containing the realm level roles
+     */
+    private static final String CLAIM_REALM_ACCESS = "realm_access";
+    /**
+     * Name of the claim containing the resources (clients) the user has access to.
+     */
+    private static final String CLAIM_RESOURCE_ACCESS = "resource_access";
+    /**
+     * Name of the claim containing roles. (Applicable to realm and resource level.)
+     */
+    private static final String CLAIM_ROLES = "roles";
+
+    @Override
+    public AbstractAuthenticationToken convert(Jwt source)
+    {
+        return new JwtAuthenticationToken(source, Stream.concat(new JwtGrantedAuthoritiesConverter().convert(source)
+                        .stream(), TEMPORARNAME(source).stream())
+                .collect(toSet()));
+    }
+
+    /**
+     * Extracts the realm and resource level roles from a JWT token distinguishing between them using prefixes.
+     */
+    public Collection<GrantedAuthority> TEMPORARNAME(Jwt jwt) {
+        // Collection that will hold the extracted roles
+        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
+
+        // Realm roles
+        // Get the part of the access token that holds the roles assigned on realm level
+        Map<String, Collection<String>> realmAccess = jwt.getClaim(CLAIM_REALM_ACCESS);
+
+        // Verify that the claim exists and is not empty
+        if (realmAccess != null && !realmAccess.isEmpty()) {
+            // From the realm_access claim get the roles
+            Collection<String> roles = realmAccess.get(CLAIM_ROLES);
+            // Check if any roles are present
+            if (roles != null && !roles.isEmpty()) {
+                // Iterate of the roles and add them to the granted authorities
+                Collection<GrantedAuthority> realmRoles = roles.stream()
+                        // Prefix all realm roles with "ROLE_realm_"
+                        .map(role -> new SimpleGrantedAuthority(PREFIX_REALM_ROLE + role))
+                        .collect(Collectors.toList());
+                grantedAuthorities.addAll(realmRoles);
+            }
+        }
+
+        // Resource (client) roles
+        // A user might have access to multiple resources all containing their own roles. Therefore, it is a map of
+        // resource each possibly containing a "roles" property.
+        Map<String, Map<String, Collection<String>>> resourceAccess = jwt.getClaim(CLAIM_RESOURCE_ACCESS);
+
+        // Check if resources are assigned
+        if (resourceAccess != null && !resourceAccess.isEmpty()) {
+            // Iterate of all the resources
+            resourceAccess.forEach((resource, resourceClaims) -> {
+                // Iterate of the "roles" claim inside the resource claims
+                resourceClaims.get(CLAIM_ROLES).forEach(
+                        // Add the role to the granted authority prefixed with ROLE_ and the name of the resource
+                        role -> grantedAuthorities.add(new SimpleGrantedAuthority(PREFIX_RESOURCE_ROLE + resource + "_" + role))
+                );
+            });
+        }
+
+        return grantedAuthorities;
+    }
+
+
+}
diff --git a/MyINPulse-back/src/main/resources/application.properties b/MyINPulse-back/src/main/resources/application.properties
index 9264594..6d6825f 100644
--- a/MyINPulse-back/src/main/resources/application.properties
+++ b/MyINPulse-back/src/main/resources/application.properties
@@ -1,3 +1,4 @@
 spring.application.name=myinpulse
 spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:7080/realms/test/protocol/openid-connect/certs
-spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
\ No newline at end of file
+spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:7080/realms/test
+logging.level.org.springframework.security=DEBUG
diff --git a/front/MyINPulse-front/src/helpers.ts b/front/MyINPulse-front/src/helpers.ts
deleted file mode 100644
index 0bd894a..0000000
--- a/front/MyINPulse-front/src/helpers.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import axios from "axios";
-
-const backendUrl = "http://localhost:8080/"
-
-// TODO: spawn a error modal
-function defaultApiErrorHandler(err: String){
-    console.log(err)
-}
-
-function defaultApiSuccessHandler(response: () => void){
-    console.log(response)
-}
-/*
-function callApi(endpoint: string, onSuccessHandler: () => void, onErrorHandler: (err: String) => void): void {
-    console.log("callApi: "+ endpoint)
-    axios.get(backendUrl + endpoint).then(
-        onSuccessHandler == null ? defaultApiSuccessHandler : onSuccessHandler
-    ).catch(
-        (err) => {
-            onErrorHandler == null ? defaultApiErrorHandler(err): onErrorHandler(err);
-        }
-    )
-}
-
-export {callApi}
- */
\ No newline at end of file

From 3de90295bd7902cb011dc4f3cb2b398f0dc481a3 Mon Sep 17 00:00:00 2001
From: Pierre Tellier <piair338@gmail.com>
Date: Sat, 8 Feb 2025 12:08:02 +0100
Subject: [PATCH 2/7] fix: changed configs

---
 config/backdev.front.env                      |  1 +
 config/frontdev.front.env                     |  3 +-
 config/prod.front.env                         |  1 +
 .../src/components/HelloWorld.vue             | 41 --------
 .../src/components/TheWelcome.vue             | 94 -------------------
 .../src/components/WelcomeItem.vue            | 87 -----------------
 .../src/components/errorModal.vue             | 94 +++++++++++++++++++
 .../src/components/icons/IconCommunity.vue    |  7 --
 .../components/icons/IconDocumentation.vue    |  7 --
 .../src/components/icons/IconEcosystem.vue    |  7 --
 .../src/components/icons/IconSupport.vue      |  7 --
 .../src/components/icons/IconTooling.vue      | 19 ----
 front/MyINPulse-front/src/main.ts             | 74 +++++----------
 .../src/router/{index.ts => router.ts}        |  0
 front/MyINPulse-front/src/services/api.ts     | 56 +++++++++--
 .../src/services/popupDisplayer.ts            | 17 ++++
 .../MyINPulse-front/src/views/errorModal.vue  | 32 -------
 .../src/views/errorWrapper.vue                | 11 +++
 .../src/views/{Home.vue => test.vue}          | 28 ++++--
 19 files changed, 218 insertions(+), 368 deletions(-)
 delete mode 100644 front/MyINPulse-front/src/components/HelloWorld.vue
 delete mode 100644 front/MyINPulse-front/src/components/TheWelcome.vue
 delete mode 100644 front/MyINPulse-front/src/components/WelcomeItem.vue
 create mode 100644 front/MyINPulse-front/src/components/errorModal.vue
 delete mode 100644 front/MyINPulse-front/src/components/icons/IconCommunity.vue
 delete mode 100644 front/MyINPulse-front/src/components/icons/IconDocumentation.vue
 delete mode 100644 front/MyINPulse-front/src/components/icons/IconEcosystem.vue
 delete mode 100644 front/MyINPulse-front/src/components/icons/IconSupport.vue
 delete mode 100644 front/MyINPulse-front/src/components/icons/IconTooling.vue
 rename front/MyINPulse-front/src/router/{index.ts => router.ts} (100%)
 create mode 100644 front/MyINPulse-front/src/services/popupDisplayer.ts
 delete mode 100644 front/MyINPulse-front/src/views/errorModal.vue
 create mode 100644 front/MyINPulse-front/src/views/errorWrapper.vue
 rename front/MyINPulse-front/src/views/{Home.vue => test.vue} (58%)

diff --git a/config/backdev.front.env b/config/backdev.front.env
index 9db91ea..27cf54e 100644
--- a/config/backdev.front.env
+++ b/config/backdev.front.env
@@ -2,3 +2,4 @@ VITE_KEYCLOAK_URL=http://localhost:7080
 VITE_KEYCLOAK_CLIENT_ID=myinpulse
 VITE_KEYCLOAK_REALM=test
 VITE_APP_URL=http://localhost:8080
+VITE_BACKEND_URL=http://localhost:8081/
diff --git a/config/frontdev.front.env b/config/frontdev.front.env
index d6b7016..5eba221 100644
--- a/config/frontdev.front.env
+++ b/config/frontdev.front.env
@@ -1,4 +1,5 @@
 VITE_KEYCLOAK_URL=http://localhost:7080
-VITE_KEYCLOAK_CLIENT_ID=myinpulse
+VITE_KEYCLOAK_CLIENT_ID=myinpulse-dev
 VITE_KEYCLOAK_REALM=test
 VITE_APP_URL=http://localhost:5173
+VITE_BACKEND_URL=http://localhost:8081/
diff --git a/config/prod.front.env b/config/prod.front.env
index d5007dc..cb42a37 100644
--- a/config/prod.front.env
+++ b/config/prod.front.env
@@ -2,3 +2,4 @@ VITE_KEYCLOAK_URL=https://0549cd63f912d5dc9b31278d6f.eirb.fr
 VITE_KEYCLOAK_CLIENT_ID=myinpulse-eirb
 VITE_KEYCLOAK_REALM=test
 VITE_APP_URL=https://0549cd63f912d5dc9b31278d6f.piair.dev
+VITE_BACKEND_URL=http://TODO/
diff --git a/front/MyINPulse-front/src/components/HelloWorld.vue b/front/MyINPulse-front/src/components/HelloWorld.vue
deleted file mode 100644
index d174cf8..0000000
--- a/front/MyINPulse-front/src/components/HelloWorld.vue
+++ /dev/null
@@ -1,41 +0,0 @@
-<script setup lang="ts">
-defineProps<{
-  msg: string
-}>()
-</script>
-
-<template>
-  <div class="greetings">
-    <h1 class="green">{{ msg }}</h1>
-    <h3>
-      You’ve successfully created a project with
-      <a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
-      <a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
-    </h3>
-  </div>
-</template>
-
-<style scoped>
-h1 {
-  font-weight: 500;
-  font-size: 2.6rem;
-  position: relative;
-  top: -10px;
-}
-
-h3 {
-  font-size: 1.2rem;
-}
-
-.greetings h1,
-.greetings h3 {
-  text-align: center;
-}
-
-@media (min-width: 1024px) {
-  .greetings h1,
-  .greetings h3 {
-    text-align: left;
-  }
-}
-</style>
diff --git a/front/MyINPulse-front/src/components/TheWelcome.vue b/front/MyINPulse-front/src/components/TheWelcome.vue
deleted file mode 100644
index 674b490..0000000
--- a/front/MyINPulse-front/src/components/TheWelcome.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-<script setup lang="ts">
-import WelcomeItem from './WelcomeItem.vue'
-import DocumentationIcon from './icons/IconDocumentation.vue'
-import ToolingIcon from './icons/IconTooling.vue'
-import EcosystemIcon from './icons/IconEcosystem.vue'
-import CommunityIcon from './icons/IconCommunity.vue'
-import SupportIcon from './icons/IconSupport.vue'
-
-const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
-</script>
-
-<template>
-  <WelcomeItem>
-    <template #icon>
-      <DocumentationIcon />
-    </template>
-    <template #heading>Documentation</template>
-
-    Vue’s
-    <a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
-    provides you with all information you need to get started.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <ToolingIcon />
-    </template>
-    <template #heading>Tooling</template>
-
-    This project is served and bundled with
-    <a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
-    recommended IDE setup is
-    <a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
-    +
-    <a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
-    you need to test your components and web pages, check out
-    <a href="https://vitest.dev/" target="_blank" rel="noopener">Vite</a>
-    and
-    <a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
-    /
-    <a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
-
-    <br />
-
-    More instructions are available in
-    <a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
-    >.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <EcosystemIcon />
-    </template>
-    <template #heading>Ecosystem</template>
-
-    Get official tools and libraries for your project:
-    <a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
-    <a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
-    <a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
-    <a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
-    you need more resources, we suggest paying
-    <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
-    a visit.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <CommunityIcon />
-    </template>
-    <template #heading>Community</template>
-
-    Got stuck? Ask your question on
-    <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
-    (our official Discord server), or
-    <a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
-      >StackOverflow</a
-    >. You should also follow the official
-    <a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
-    Bluesky account or the
-    <a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
-    X account for latest news in the Vue world.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <SupportIcon />
-    </template>
-    <template #heading>Support Vue</template>
-
-    As an independent project, Vue relies on community backing for its sustainability. You can help
-    us by
-    <a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
-  </WelcomeItem>
-</template>
diff --git a/front/MyINPulse-front/src/components/WelcomeItem.vue b/front/MyINPulse-front/src/components/WelcomeItem.vue
deleted file mode 100644
index 6d7086a..0000000
--- a/front/MyINPulse-front/src/components/WelcomeItem.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-<template>
-  <div class="item">
-    <i>
-      <slot name="icon"></slot>
-    </i>
-    <div class="details">
-      <h3>
-        <slot name="heading"></slot>
-      </h3>
-      <slot></slot>
-    </div>
-  </div>
-</template>
-
-<style scoped>
-.item {
-  margin-top: 2rem;
-  display: flex;
-  position: relative;
-}
-
-.details {
-  flex: 1;
-  margin-left: 1rem;
-}
-
-i {
-  display: flex;
-  place-items: center;
-  place-content: center;
-  width: 32px;
-  height: 32px;
-
-  color: var(--color-text);
-}
-
-h3 {
-  font-size: 1.2rem;
-  font-weight: 500;
-  margin-bottom: 0.4rem;
-  color: var(--color-heading);
-}
-
-@media (min-width: 1024px) {
-  .item {
-    margin-top: 0;
-    padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
-  }
-
-  i {
-    top: calc(50% - 25px);
-    left: -26px;
-    position: absolute;
-    border: 1px solid var(--color-border);
-    background: var(--color-background);
-    border-radius: 8px;
-    width: 50px;
-    height: 50px;
-  }
-
-  .item:before {
-    content: ' ';
-    border-left: 1px solid var(--color-border);
-    position: absolute;
-    left: 0;
-    bottom: calc(50% + 25px);
-    height: calc(50% - 25px);
-  }
-
-  .item:after {
-    content: ' ';
-    border-left: 1px solid var(--color-border);
-    position: absolute;
-    left: 0;
-    top: calc(50% + 25px);
-    height: calc(50% - 25px);
-  }
-
-  .item:first-of-type:before {
-    display: none;
-  }
-
-  .item:last-of-type:after {
-    display: none;
-  }
-}
-</style>
diff --git a/front/MyINPulse-front/src/components/errorModal.vue b/front/MyINPulse-front/src/components/errorModal.vue
new file mode 100644
index 0000000..0d7dd57
--- /dev/null
+++ b/front/MyINPulse-front/src/components/errorModal.vue
@@ -0,0 +1,94 @@
+<script setup lang="ts">
+const props = defineProps(['data']);
+</script>
+
+<template>
+  <div :class='["red", "yellow", "blue", "green"][data.type]' class="error-modal">
+    <p>{{["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][data.type]}}</p>
+    <p>{{data.errorMessage}}</p>
+    <div class="loading" :class='["red-loader", "yellow-loader", "blue-loader", "green-loader"][data.type]'></div>
+  </div>
+</template>
+
+<style scoped>
+  .error-modal{
+    margin-bottom: 1em;
+    padding: 1em;
+    border-radius: 1em;
+    text-align: center;
+    overflow: hidden;
+    position: relative;
+    animation: disappear 5s linear forwards;
+  }
+
+  .red{
+    background-color: #ee6055;
+    color: white;
+  }
+  .red-loader {
+    background-color: #fa8383;
+  }
+
+  .yellow{
+    background-color: #FF9D23;
+     color: white;
+   }
+  .yellow-loader{
+    background-color: #ffbf81;
+  }
+
+  .blue {
+    background-color: #809bce;
+    color: white;
+  }
+  .blue-loader{
+    background-color: #95b8d1;
+  }
+
+  .green {
+    background-color: green;
+    color: white;
+  }
+  .green-loader {
+    background-color: darkgreen;
+  }
+
+  .loading {
+    box-sizing: border-box;
+    position: absolute;
+    padding: 0;
+    bottom: 0;
+    left: 0;
+    height: 1em;
+    width: 0;
+    animation: loading 4s linear forwards;
+  }
+
+  /* Animation for the loading bar */
+  @keyframes loading {
+    0% {
+      width: 100%;
+    }
+    100% {
+      width: 0;
+    }
+  }
+
+  @keyframes disappear {
+    0% {
+      height: 100px;
+      padding: 1em;
+      margin: 1em;
+    }
+    80% {
+      height: 100px;
+      padding: 1em;
+      margin: 1em;
+    }
+    100% {
+      height: 0;
+      margin: 0;
+      padding: 0;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/icons/IconCommunity.vue b/front/MyINPulse-front/src/components/icons/IconCommunity.vue
deleted file mode 100644
index 2dc8b05..0000000
--- a/front/MyINPulse-front/src/components/icons/IconCommunity.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
-    <path
-      d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
-    />
-  </svg>
-</template>
diff --git a/front/MyINPulse-front/src/components/icons/IconDocumentation.vue b/front/MyINPulse-front/src/components/icons/IconDocumentation.vue
deleted file mode 100644
index 6d4791c..0000000
--- a/front/MyINPulse-front/src/components/icons/IconDocumentation.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
-    <path
-      d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
-    />
-  </svg>
-</template>
diff --git a/front/MyINPulse-front/src/components/icons/IconEcosystem.vue b/front/MyINPulse-front/src/components/icons/IconEcosystem.vue
deleted file mode 100644
index c3a4f07..0000000
--- a/front/MyINPulse-front/src/components/icons/IconEcosystem.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
-    <path
-      d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
-    />
-  </svg>
-</template>
diff --git a/front/MyINPulse-front/src/components/icons/IconSupport.vue b/front/MyINPulse-front/src/components/icons/IconSupport.vue
deleted file mode 100644
index 7452834..0000000
--- a/front/MyINPulse-front/src/components/icons/IconSupport.vue
+++ /dev/null
@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
-    <path
-      d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
-    />
-  </svg>
-</template>
diff --git a/front/MyINPulse-front/src/components/icons/IconTooling.vue b/front/MyINPulse-front/src/components/icons/IconTooling.vue
deleted file mode 100644
index 660598d..0000000
--- a/front/MyINPulse-front/src/components/icons/IconTooling.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
-<template>
-  <svg
-    xmlns="http://www.w3.org/2000/svg"
-    xmlns:xlink="http://www.w3.org/1999/xlink"
-    aria-hidden="true"
-    role="img"
-    class="iconify iconify--mdi"
-    width="24"
-    height="24"
-    preserveAspectRatio="xMidYMid meet"
-    viewBox="0 0 24 24"
-  >
-    <path
-      d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
-      fill="currentColor"
-    ></path>
-  </svg>
-</template>
diff --git a/front/MyINPulse-front/src/main.ts b/front/MyINPulse-front/src/main.ts
index e33d5c1..198447d 100644
--- a/front/MyINPulse-front/src/main.ts
+++ b/front/MyINPulse-front/src/main.ts
@@ -1,69 +1,37 @@
 import { createApp } from 'vue'
 import App from './App.vue'
 import router from './router'
-//import VueKeyCloak from '@dsb-norge/vue-keycloak-js'
-//import { useKeycloak } from '@dsb-norge/vue-keycloak-js'
-//import axios from 'axios'
 import {createPinia} from "pinia";
 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
 import AuthStorePlugin from './plugins/authStore';
 import keycloakService from './services/keycloak';
+import axios from "axios";
+import {useAuthStore} from "@/stores/authStore.ts";
+let store: any;
 
 keycloakService.CallInit(() => {
+    try {
+        const app = createApp(App)
 
-    const app = createApp(App)
+        // Setup pinia store, allowing user to keep logged in status after refresh
+        const pinia = createPinia();
+        pinia.use(piniaPluginPersistedstate);
+        app.use(pinia);
+        app.use(AuthStorePlugin, { pinia });
+        store = useAuthStore();
+        app.use(router)
 
-
-// Setup pinia store, allowing user to keep logged in status after refresh
-    const pinia = createPinia();
-    pinia.use(piniaPluginPersistedstate);
-
-    app.use(pinia);
-    app.use(AuthStorePlugin, { pinia });
-    app.use(router)
-    app.mount('#app');
+        app.mount('#app');
+    } catch (e) {
+        console.error("Error while initiating Keycloak.")
+        console.error(e)
+        createApp(App).mount('#app');
+    }
 
 })
 
-createApp(App).mount('#app');
-
-// TODO: fix the comment
-/*
-function tokenInterceptor () {
-    axios.interceptors.request.use(config => {
-        const keycloak = useKeycloak()
-        if (keycloak.authenticated) {
-            // Note that this is a simple example.
-            // you should be careful not to leak tokens to third parties.
-            // in this example the token is added to all usage of axios.
-            config.headers.Authorization = `Bearer ${keycloak.token}`
-        }
-        return config
-    }, error => {
-        console.error("tokenInterceptor: Rejected")
-        return Promise.reject(error)
-    })
-}
-*/
-
-/*
-app.use(VueKeyCloak,{
-    onReady: (keycloak) => {
-        console.log("Ready !")
-        tokenInterceptor()
-    },
-    init: {
-        onLoad: 'login-required',
-        checkLoginIframe: false,
-
-    },
-
-    config: {
-        realm: 'test',
-        url: 'http://localhost:7080',
-        clientId: 'myinpulse'
-    }
-}  );
-*/
 
 
+
+
+export {store};
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/router/index.ts b/front/MyINPulse-front/src/router/router.ts
similarity index 100%
rename from front/MyINPulse-front/src/router/index.ts
rename to front/MyINPulse-front/src/router/router.ts
diff --git a/front/MyINPulse-front/src/services/api.ts b/front/MyINPulse-front/src/services/api.ts
index eb75333..d29273a 100644
--- a/front/MyINPulse-front/src/services/api.ts
+++ b/front/MyINPulse-front/src/services/api.ts
@@ -1,13 +1,55 @@
-// file: src/services/api.js
-
 import axios from "axios";
+import {store} from "@/main.ts";
 
-// Creating an instance for axios to be used by the token interceptor service
-const instance = axios.create({
-    baseURL: `${import.meta.env.VITE_BE_API_URL}/api`,
+const axiosInstance = axios.create({
+    baseURL: import.meta.env.VITE_BACKEND_URL,
     headers: {
-        "Content-Type": "application/json",
+        'Content-Type': 'application/json',
     },
 });
 
-export default instance;
\ No newline at end of file
+axiosInstance.interceptors.response.use(
+    response => response, // Directly return successful responses.
+    async error => {
+        const originalRequest = error.config;
+        if (error.response.status === 401 && !originalRequest._retry && store.authenticated) {
+            originalRequest._retry = true; // Mark the request as retried to avoid infinite loops.
+            try {
+                await store.refreshUserToken();
+                // Update the authorization header with the new access token.
+                axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${store.user.token}`;
+                return axiosInstance(originalRequest); // Retry the original request with the new access token.
+            } catch (refreshError) {
+                // Handle refresh token errors by clearing stored tokens and redirecting to the login page.
+                console.error('Token refresh failed:', refreshError);
+                localStorage.removeItem('accessToken');
+                localStorage.removeItem('refreshToken');
+                window.location.href = '/login';
+                return Promise.reject(refreshError);
+            }
+        }
+        return Promise.reject(error); // For all other errors, return the error as is.
+    }
+);
+
+// TODO: spawn a error modal
+function defaultApiErrorHandler(err: String){
+    console.log(err)
+}
+
+function defaultApiSuccessHandler(response: () => void){
+    console.log(response)
+}
+function callApi(endpoint: string, onSuccessHandler?: any, onErrorHandler?: any): void {
+    axiosInstance.get(endpoint).then(
+        onSuccessHandler == null ? defaultApiSuccessHandler : onSuccessHandler
+    ).catch(
+        (err) => {
+            onErrorHandler == null ? defaultApiErrorHandler(err): onErrorHandler(err);
+            throw err;
+        }
+    )
+}
+
+
+export {callApi}
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/services/popupDisplayer.ts b/front/MyINPulse-front/src/services/popupDisplayer.ts
new file mode 100644
index 0000000..61d02b9
--- /dev/null
+++ b/front/MyINPulse-front/src/services/popupDisplayer.ts
@@ -0,0 +1,17 @@
+import {ref} from "vue";
+enum errorType {Error, Warning}
+
+function addNewError(errorMessage: string, timeout?: number, type?: errorType){
+    if (timeout == null){
+        timeout = 5000;
+    }
+    if (type == null){
+        type = Error;
+    }
+    errorList.value.push({errorMessage: errorMessage, timeout: timeout, type: type})
+    setTimeout(() => errorList.value.pop(errorMessage), 5000)
+}
+
+const errorList = ref([])
+
+export {addNewError, errorList}
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/views/errorModal.vue b/front/MyINPulse-front/src/views/errorModal.vue
deleted file mode 100644
index 92722f1..0000000
--- a/front/MyINPulse-front/src/views/errorModal.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<script lang="ts">
-import {defineComponent} from 'vue'
-
-export default defineComponent({
-  name: "errorModal",
-  props: {
-    error: String
-  },
-  data(){
-    return {
-    }
-  }
-})
-</script>
-
-<template>
-<div class="error">
-  <p>Erreur :(</p>
-  <p>{{error}}</p>
-</div>
-</template>
-
-<style scoped>
-  .error{
-    background-color: darkred;
-    color: white;
-    padding: 1em;
-    border-radius: 0.5em;
-    text-align: center;
-    position: absolute;
-  }
-</style>
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/views/errorWrapper.vue b/front/MyINPulse-front/src/views/errorWrapper.vue
new file mode 100644
index 0000000..96c0baf
--- /dev/null
+++ b/front/MyINPulse-front/src/views/errorWrapper.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+
+</template>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/views/Home.vue b/front/MyINPulse-front/src/views/test.vue
similarity index 58%
rename from front/MyINPulse-front/src/views/Home.vue
rename to front/MyINPulse-front/src/views/test.vue
index 7fbe869..e879aef 100644
--- a/front/MyINPulse-front/src/views/Home.vue
+++ b/front/MyINPulse-front/src/views/test.vue
@@ -1,7 +1,16 @@
 <script setup lang="ts">
-import {useAuthStore} from "@/stores/authStore";
+import {store} from "../main.ts";
+import {callApi} from "@/services/api.ts";
+import ErrorModal from "@/views/errorModal.vue";
+import {errorList} from "@/services/popupDisplayer.ts";
+import TempModal from "@/views/temp-modal.vue";
+import ErrorWrapper from "@/App.vue";
+function addResToTable(id: any){
+  return (req: any) => {
+    console.log(req)
+  }
+}
 
-const store = useAuthStore()
 
 </script>
 
@@ -26,19 +35,26 @@ const store = useAuthStore()
       <td>{{store.user.refreshToken}}</td>
     </tr>
     <tr>
-      <td>Unauthenticated API call</td>
-      <td><button>call</button></td>
+      <td>Entrepreneur API call</td>
+      <td><button @click="callApi('random')">call</button></td>
       <td>res</td>
       <td></td>
     </tr>
     <tr>
-      <td>Authenticated API call</td>
-      <td><button>call</button></td>
+      <td>Admin API call</td>
+      <td><button @click="callApi('random2')">call</button></td>
       <td>res</td>
       <td></td>
     </tr>
+    <tr>
+      <td>Unauth API call</td>
+      <td><button @click="callApi('random3')">call</button></td>
+      <td>res</td>
+      <td id="3"></td>
+    </tr>
     </tbody>
   </table>
+  <temp-modal></temp-modal>
 </template>
 
 <style scoped>

From dfaa97346fced779b7d6fe5f4bea7346282d3ce1 Mon Sep 17 00:00:00 2001
From: Pierre Tellier <piair338@gmail.com>
Date: Sat, 8 Feb 2025 12:09:18 +0100
Subject: [PATCH 3/7] fix: git + docker maintenance

---
 .gitignore       | 3 ++-
 front/Dockerfile | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3e189ed..170ba0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 .env
 .idea
-keycloak/CAS/target
\ No newline at end of file
+keycloak/CAS/target
+docker-compose.yaml
diff --git a/front/Dockerfile b/front/Dockerfile
index 14faeb6..2a8d3c0 100644
--- a/front/Dockerfile
+++ b/front/Dockerfile
@@ -36,4 +36,4 @@ RUN chmod +x /start.sh
 EXPOSE 80
 
 # Set the entry point to the shell script
-ENTRYPOINT ["/start.sh"]
\ No newline at end of file
+ENTRYPOINT ["/start.sh"]

From b228b78e17dcf2463e433c1d03e8512ae325a26f Mon Sep 17 00:00:00 2001
From: Pierre Tellier <piair338@gmail.com>
Date: Sat, 8 Feb 2025 12:11:20 +0100
Subject: [PATCH 4/7] feat: add popop with awfuls colors and backend api call

---
 front/MyINPulse-front/src/App.vue                 | 10 ++++++----
 front/MyINPulse-front/src/main.ts                 |  3 +--
 front/MyINPulse-front/src/router/router.ts        | 10 +---------
 front/MyINPulse-front/src/services/api.ts         |  5 +++--
 .../src/services/popupDisplayer.ts                | 15 +++++++++------
 front/MyINPulse-front/src/views/errorWrapper.vue  | 13 ++++++++++++-
 front/MyINPulse-front/src/views/test.vue          |  4 ++--
 7 files changed, 34 insertions(+), 26 deletions(-)

diff --git a/front/MyINPulse-front/src/App.vue b/front/MyINPulse-front/src/App.vue
index 71701b5..8b3eee1 100644
--- a/front/MyINPulse-front/src/App.vue
+++ b/front/MyINPulse-front/src/App.vue
@@ -1,13 +1,11 @@
 <script setup lang="ts">
 import { RouterLink, RouterView } from 'vue-router'
-import HelloWorld from './components/HelloWorld.vue'
-import Header from './components/Header.vue';
-import ProjectComp from './components/Project-comp.vue';
+import ErrorWrapper from "@/views/errorWrapper.vue";
 </script>
 
 <template>
-  <RouterView />
   <Header />
+  <error-wrapper></error-wrapper>
   <div id="main">
       <ProjectComp 
         v-for="(project, index) in projects" 
@@ -15,12 +13,16 @@ import ProjectComp from './components/Project-comp.vue';
         :projectName="project.name"
       />
     </div>
+  <RouterView />
 </template>
 
 <style scoped>
 </style>
 
 <script lang="ts">
+import Header from "@/components/Header.vue";
+import ProjectComp from "@/components/Project-comp.vue";
+
 export default {
   name: 'App',
   components: {
diff --git a/front/MyINPulse-front/src/main.ts b/front/MyINPulse-front/src/main.ts
index 198447d..60f3509 100644
--- a/front/MyINPulse-front/src/main.ts
+++ b/front/MyINPulse-front/src/main.ts
@@ -1,11 +1,10 @@
 import { createApp } from 'vue'
 import App from './App.vue'
-import router from './router'
+import router from './router/router.ts'
 import {createPinia} from "pinia";
 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
 import AuthStorePlugin from './plugins/authStore';
 import keycloakService from './services/keycloak';
-import axios from "axios";
 import {useAuthStore} from "@/stores/authStore.ts";
 let store: any;
 
diff --git a/front/MyINPulse-front/src/router/router.ts b/front/MyINPulse-front/src/router/router.ts
index e9697d9..70bb58a 100644
--- a/front/MyINPulse-front/src/router/router.ts
+++ b/front/MyINPulse-front/src/router/router.ts
@@ -3,21 +3,13 @@ import { createRouter, createWebHistory } from 'vue-router'
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
   routes: [
-    {
-      path: '/about',
-      name: 'about',
-      // route level code-splitting
-      // this generates a separate chunk (About.[hash].js) for this route
-      // which is lazy-loaded when the route is visited.
-      component: () => import('../views/AboutView.vue'),
-    },
     {
       path: '/test',
       name: 'test',
       // route level code-splitting
       // this generates a separate chunk (About.[hash].js) for this route
       // which is lazy-loaded when the route is visited.
-      component: () => import('../views/Home.vue'),
+      component: () => import('../views/test.vue'),
     },
   ],
 })
diff --git a/front/MyINPulse-front/src/services/api.ts b/front/MyINPulse-front/src/services/api.ts
index d29273a..71e3194 100644
--- a/front/MyINPulse-front/src/services/api.ts
+++ b/front/MyINPulse-front/src/services/api.ts
@@ -1,5 +1,6 @@
 import axios from "axios";
 import {store} from "@/main.ts";
+import {addNewMessage, color} from "@/services/popupDisplayer.ts";
 
 const axiosInstance = axios.create({
     baseURL: import.meta.env.VITE_BACKEND_URL,
@@ -34,11 +35,11 @@ axiosInstance.interceptors.response.use(
 
 // TODO: spawn a error modal
 function defaultApiErrorHandler(err: String){
-    console.log(err)
+    addNewMessage(err, color.Red);
 }
 
 function defaultApiSuccessHandler(response: () => void){
-    console.log(response)
+    addNewMessage(response.data, color.green)
 }
 function callApi(endpoint: string, onSuccessHandler?: any, onErrorHandler?: any): void {
     axiosInstance.get(endpoint).then(
diff --git a/front/MyINPulse-front/src/services/popupDisplayer.ts b/front/MyINPulse-front/src/services/popupDisplayer.ts
index 61d02b9..77113f9 100644
--- a/front/MyINPulse-front/src/services/popupDisplayer.ts
+++ b/front/MyINPulse-front/src/services/popupDisplayer.ts
@@ -1,17 +1,20 @@
 import {ref} from "vue";
-enum errorType {Error, Warning}
 
-function addNewError(errorMessage: string, timeout?: number, type?: errorType){
+enum color {Red, Yellow, Blue, green}
+
+function addNewMessage(errorMessage: string, type?: color, timeout?: number){
     if (timeout == null){
         timeout = 5000;
     }
     if (type == null){
-        type = Error;
+        type = color.Red;
     }
-    errorList.value.push({errorMessage: errorMessage, timeout: timeout, type: type})
-    setTimeout(() => errorList.value.pop(errorMessage), 5000)
+
+    const data = {errorMessage: errorMessage, timeout: timeout, type: type, uid: Math.random()*100000};
+    errorList.value.push(data)
+    setTimeout(() => errorList.value.slice(0, 1), timeout)
 }
 
 const errorList = ref([])
 
-export {addNewError, errorList}
\ No newline at end of file
+export {addNewMessage, errorList, color}
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/views/errorWrapper.vue b/front/MyINPulse-front/src/views/errorWrapper.vue
index 96c0baf..1d56a2a 100644
--- a/front/MyINPulse-front/src/views/errorWrapper.vue
+++ b/front/MyINPulse-front/src/views/errorWrapper.vue
@@ -1,11 +1,22 @@
 <script setup lang="ts">
 
+import {errorList} from "@/services/popupDisplayer.ts";
+import ErrorModal from "@/components/errorModal.vue";
 </script>
 
 <template>
-
+<div class="error-wrapper">
+  <error-modal v-for="elm in errorList" :data=elm></error-modal>
+</div>
 </template>
 
 <style scoped>
+.error-wrapper{
+  position: absolute;
+  left: 70%;
+  //background-color: blue;
+  height: 100%;
+  width: 30%;
 
+}
 </style>
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/views/test.vue b/front/MyINPulse-front/src/views/test.vue
index e879aef..90db6d1 100644
--- a/front/MyINPulse-front/src/views/test.vue
+++ b/front/MyINPulse-front/src/views/test.vue
@@ -1,9 +1,9 @@
 <script setup lang="ts">
 import {store} from "../main.ts";
 import {callApi} from "@/services/api.ts";
-import ErrorModal from "@/views/errorModal.vue";
+import ErrorModal from "@/components/errorModal.vue";
 import {errorList} from "@/services/popupDisplayer.ts";
-import TempModal from "@/views/temp-modal.vue";
+import TempModal from "@/components/temp-modal.vue";
 import ErrorWrapper from "@/App.vue";
 function addResToTable(id: any){
   return (req: any) => {

From b5c9b4067228e267accfd6e1cffcd9c070146c9d Mon Sep 17 00:00:00 2001
From: Pierre Tellier <piair338@gmail.com>
Date: Sat, 8 Feb 2025 18:49:22 +0100
Subject: [PATCH 5/7] fix: fixed TS errors

---
 front/MyINPulse-front/src/services/api.ts            | 4 ++--
 front/MyINPulse-front/src/services/popupDisplayer.ts | 3 +--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/front/MyINPulse-front/src/services/api.ts b/front/MyINPulse-front/src/services/api.ts
index 71e3194..cea6a9e 100644
--- a/front/MyINPulse-front/src/services/api.ts
+++ b/front/MyINPulse-front/src/services/api.ts
@@ -34,11 +34,11 @@ axiosInstance.interceptors.response.use(
 );
 
 // TODO: spawn a error modal
-function defaultApiErrorHandler(err: String){
+function defaultApiErrorHandler(err: string){
     addNewMessage(err, color.Red);
 }
 
-function defaultApiSuccessHandler(response: () => void){
+function defaultApiSuccessHandler(response: any){
     addNewMessage(response.data, color.green)
 }
 function callApi(endpoint: string, onSuccessHandler?: any, onErrorHandler?: any): void {
diff --git a/front/MyINPulse-front/src/services/popupDisplayer.ts b/front/MyINPulse-front/src/services/popupDisplayer.ts
index 77113f9..3b222a2 100644
--- a/front/MyINPulse-front/src/services/popupDisplayer.ts
+++ b/front/MyINPulse-front/src/services/popupDisplayer.ts
@@ -1,5 +1,4 @@
 import {ref} from "vue";
-
 enum color {Red, Yellow, Blue, green}
 
 function addNewMessage(errorMessage: string, type?: color, timeout?: number){
@@ -15,6 +14,6 @@ function addNewMessage(errorMessage: string, type?: color, timeout?: number){
     setTimeout(() => errorList.value.slice(0, 1), timeout)
 }
 
-const errorList = ref([])
+const errorList: any= ref([])
 
 export {addNewMessage, errorList, color}
\ No newline at end of file

From b30e1196f4a062099a3b6494170ad2172027f296 Mon Sep 17 00:00:00 2001
From: ALAMI Adnane <Adnane.Alami@bordeaux-inp.fr>
Date: Sat, 8 Feb 2025 20:18:44 +0100
Subject: [PATCH 6/7] canvas included in the main page, still shiting with vue

---
 front/MyINPulse-front/src/App.vue             |  21 ++
 .../src/components/canvas/Avantage.vue        |  21 ++
 .../src/components/canvas/Canaux.vue          |  21 ++
 .../src/components/canvas/Couts.vue           |  21 ++
 .../src/components/canvas/Header.vue          |  37 ++++
 .../src/components/canvas/Indicateurs.vue     |  21 ++
 .../src/components/canvas/Lean-canvas.vue     |  42 ++++
 .../src/components/canvas/Probleme.vue        |  21 ++
 .../src/components/canvas/Revenus.vue         |  21 ++
 .../src/components/canvas/Segments.vue        |  21 ++
 .../src/components/canvas/Solution.vue        |  21 ++
 .../src/components/canvas/Valeur.vue          |  21 ++
 .../src/components/canvas/style-project.css   | 184 ++++++++++++++++++
 front/MyINPulse-front/src/main.ts             |   3 +-
 front/MyINPulse-front/src/router/index.ts     |   7 +
 .../MyINPulse-front/src/views/CanvasView.vue  |  12 ++
 16 files changed, 494 insertions(+), 1 deletion(-)
 create mode 100644 front/MyINPulse-front/src/components/canvas/Avantage.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Canaux.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Couts.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Header.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Indicateurs.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Lean-canvas.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Probleme.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Revenus.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Segments.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Solution.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/Valeur.vue
 create mode 100644 front/MyINPulse-front/src/components/canvas/style-project.css
 create mode 100644 front/MyINPulse-front/src/views/CanvasView.vue

diff --git a/front/MyINPulse-front/src/App.vue b/front/MyINPulse-front/src/App.vue
index 71701b5..6c3e95f 100644
--- a/front/MyINPulse-front/src/App.vue
+++ b/front/MyINPulse-front/src/App.vue
@@ -3,6 +3,7 @@ import { RouterLink, RouterView } from 'vue-router'
 import HelloWorld from './components/HelloWorld.vue'
 import Header from './components/Header.vue';
 import ProjectComp from './components/Project-comp.vue';
+import CanvasView from './components/canvas/Lean-canvas.vue';
 </script>
 
 <template>
@@ -15,9 +16,28 @@ import ProjectComp from './components/Project-comp.vue';
         :projectName="project.name"
       />
     </div>
+  <div id="canvas">
+      <button @click="$router.push('/canvas')">Voir Canvas</button>
+  </div>
 </template>
 
 <style scoped>
+
+#canvas { /* My shit */
+  margin-top: 20px;
+}
+button {
+  padding: 10px 15px;
+  background-color: #007bff;
+  color: white;
+  border: none;
+  cursor: pointer;
+  border-radius: 5px;
+}
+button:hover {
+  background-color: #0056b3;
+}
+
 </style>
 
 <script lang="ts">
@@ -26,6 +46,7 @@ export default {
   components: {
     Header,
     ProjectComp,
+    CanvasView, // My shit
   },
   data() {
     return {
diff --git a/front/MyINPulse-front/src/components/canvas/Avantage.vue b/front/MyINPulse-front/src/components/canvas/Avantage.vue
new file mode 100644
index 0000000..59532ce
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Avantage.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>9. Avantage déloyal</h3>
+        <p>Ce qui ne peut pas être facilement copié ou acheté</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Canaux.vue b/front/MyINPulse-front/src/components/canvas/Canaux.vue
new file mode 100644
index 0000000..6aee546
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Canaux.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>5. Canaux</h3>
+        <p>Chemins d'accès aux clients</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Couts.vue b/front/MyINPulse-front/src/components/canvas/Couts.vue
new file mode 100644
index 0000000..c232d3f
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Couts.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>7. Structure des coûts</h3>
+        <p>Coûts d'acquisition, distribution, hébergement, employés...</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Header.vue b/front/MyINPulse-front/src/components/canvas/Header.vue
new file mode 100644
index 0000000..e860400
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Header.vue
@@ -0,0 +1,37 @@
+<template>
+    <header>
+      <img src="@/assets/logo-inpulse.png" alt="INPulse Logo">
+      <div class="header-buttons">
+        <div class="contact-menu">
+          <button class="contact-button" @click="toggleDropdown">Contact</button>
+          <div class="contact-dropdown" v-show="isDropdownOpen">
+            <button>Contact All</button>
+            <button>Contact Person 1</button>
+            <button>Contact Person 2</button>
+            <button>Contact Person 3</button>
+          </div>
+          <div class="return"><a href="/">return to list project</a></div>
+        </div>
+      </div>
+    </header>
+  </template>
+  
+  <script>
+  export default {
+    data() {
+      return {
+        isDropdownOpen: false
+      };
+    },
+    methods: {
+      toggleDropdown() {
+        this.isDropdownOpen = !this.isDropdownOpen;
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Indicateurs.vue b/front/MyINPulse-front/src/components/canvas/Indicateurs.vue
new file mode 100644
index 0000000..0fd6d1a
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Indicateurs.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>8. Indicateurs clés</h3>
+        <p>Activités clés que vous souhaitez évaluer</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Lean-canvas.vue b/front/MyINPulse-front/src/components/canvas/Lean-canvas.vue
new file mode 100644
index 0000000..0141a17
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Lean-canvas.vue
@@ -0,0 +1,42 @@
+<template>
+    <div class="canvas">
+      <div class="row">
+        <Probleme />
+        <Segments />
+      </div>
+      <div class="row">
+        <Solution />
+        <Valeur />
+        <Canaux />
+      </div>
+      <div class="row">
+        <Couts />
+        <Revenus />
+      </div>
+      <div class="row">
+        <Indicateurs />
+        <Avantage />
+      </div>
+    </div>
+  </template>
+  
+  <script>
+  import Probleme from "./Probleme.vue";
+  import Segments from "./Segments.vue";
+  import Solution from "./Solution.vue";
+  import Valeur from "./Valeur.vue";
+  import Canaux from "./Canaux.vue";
+  import Revenus from "./Revenus.vue";
+  import Couts from "./Couts.vue";
+  import Indicateurs from "./Indicateurs.vue";
+  import Avantage from "./Avantage.vue";
+  
+  export default {
+    components: { Probleme, Segments, Solution, Valeur, Canaux, Revenus, Couts, Indicateurs, Avantage }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Probleme.vue b/front/MyINPulse-front/src/components/canvas/Probleme.vue
new file mode 100644
index 0000000..d36b983
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Probleme.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+      <h3>1. Problème</h3>
+      <p>3 problèmes essentiels à résoudre pour le client</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Revenus.vue b/front/MyINPulse-front/src/components/canvas/Revenus.vue
new file mode 100644
index 0000000..0b8b57e
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Revenus.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>6. Sources de revenus</h3>
+        <p>Modèle de revenus, durée, revenus espérés, marge espérée</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Segments.vue b/front/MyINPulse-front/src/components/canvas/Segments.vue
new file mode 100644
index 0000000..76eaba5
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Segments.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>2. Segments de clients</h3>
+        <p>Clients cibles</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Solution.vue b/front/MyINPulse-front/src/components/canvas/Solution.vue
new file mode 100644
index 0000000..b3d5a05
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Solution.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>4. Solution</h3>
+        <p>3 fonctionnalités essentielles pour le client</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/Valeur.vue b/front/MyINPulse-front/src/components/canvas/Valeur.vue
new file mode 100644
index 0000000..d577863
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/Valeur.vue
@@ -0,0 +1,21 @@
+<template>
+    <div class="cell produit" @click="toggleExpand">
+        <h3>3. Proposition de valeur unique</h3>
+        <p>Message simple, clair et persuasif expliquant en quoi votre produit est différent et mérite d'être acheté</p>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    methods: {
+      toggleExpand(event) {
+        event.currentTarget.classList.toggle("expanded");
+      }
+    }
+  };
+  </script>
+  
+  <style scoped>
+  @import "@/components/canvas/style-project.css";
+  </style>
+  
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/components/canvas/style-project.css b/front/MyINPulse-front/src/components/canvas/style-project.css
new file mode 100644
index 0000000..7761d40
--- /dev/null
+++ b/front/MyINPulse-front/src/components/canvas/style-project.css
@@ -0,0 +1,184 @@
+body {
+    font-family: Arial, sans-serif;
+    margin: 0;
+    padding: 10px;
+  }
+  
+  .canvas {
+    display: flex;
+    flex-direction: column;
+    max-width: 1200px;
+    margin: 20px auto;
+    border: 2px dashed #d33;
+    background: #fff;
+  }
+  
+  .row {
+    display: flex;
+  }
+  
+  .cell {
+    flex: 1;
+    border: 1px solid #ddd;
+    padding: 10px;
+    text-align: center;
+    background-color: #f1f1f1;
+  }
+  
+  .produit {
+    background-color: #f9e4e4;
+  }
+  
+  .marche {
+    background-color: #e4f1f9;
+  }
+  
+  .valeur {
+    background-color: #f9f4e4;
+  }
+  
+  h3 {
+    margin: 0;
+    font-size: 18px;
+    color: #333;
+  }
+  
+  p {
+    margin: 5px 0 0;
+    font-size: 14px;
+  }
+  
+
+  body {
+    font-family: Arial, sans-serif;
+    margin: 0;
+    padding: 0;
+    background-color: #f9f9f9;
+  }
+
+  h1 img {
+    height: 80px;
+  }
+
+  .canvas {
+    max-width: 1200px;
+    margin: 20px auto;
+    padding: 20px;
+    border: 2px dashed #d33;
+    background-color: #fff;
+  }
+
+  .row {
+    display: flex;
+    margin-bottom: 10px;
+  }
+
+  .cell {
+    flex: 1;
+    border: 1px solid #ddd;
+    padding: 20px;
+    text-align: center;
+    background-color: #f1f1f1;
+  }
+
+  #ade {
+    max-width: 1200px;
+    margin: 20px auto;
+    padding: 20px;
+    text-align: center;
+    background-color: #e8f5e9;
+    border: 2px solid #4caf50;
+    border-radius: 10px;
+  }
+
+  #ade h3 {
+    color: #2e7d32;
+  }
+
+  #ade p {
+    margin: 10px 0;
+    font-size: 16px;
+    color: #333;
+  }
+  header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px 20px;
+    background-color: #fff;
+    border-bottom: 2px solid #ddd;
+  }
+
+  header img {
+    height: 60px;
+  }
+
+  header .contact-menu {
+    position: relative;
+  }
+
+  .expanded {
+    transform: scale(1.2); /* L'élément reste agrandi */
+    transition: transform 0.3s ease; /* Animation fluide */
+  }
+
+  .contact-button, .return {
+    padding: 10px 15px;
+    border: none;
+    border-radius: 4px;
+    background-color: #2196f3;
+    color: #fff;
+    cursor: pointer;
+  }
+
+ .contact-button:hover, .return:hover {
+    background-color: #1976d2;
+  }
+
+  /* Dropdown styling */
+  .contact-dropdown {
+    position: absolute;
+    right: 0;
+    top: 50px;
+    display: none;
+    flex-direction: column;
+    gap: 10px;
+    padding: 15px;
+    background-color: #fff;
+    border: 1px solid #ddd;
+    border-radius: 8px;
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+    z-index: 10;
+  }
+
+  .contact-dropdown button {
+    padding: 8px 12px;
+    border: none;
+    border-radius: 4px;
+    background-color: #4caf50;
+    color: #fff;
+    cursor: pointer;
+  }
+
+  .contact-dropdown button:hover {
+    background-color: #388e3c;
+  }
+
+  .return {
+    background-color: #f44336;
+  }
+
+  .return:hover {
+    background-color: #d32f2f;
+  }
+
+  .header-buttons {
+    display: flex;
+    align-items: center;
+    gap: 15px;
+  }
+
+
+  a{
+    color: white;
+  }
\ No newline at end of file
diff --git a/front/MyINPulse-front/src/main.ts b/front/MyINPulse-front/src/main.ts
index e33d5c1..5bf00b7 100644
--- a/front/MyINPulse-front/src/main.ts
+++ b/front/MyINPulse-front/src/main.ts
@@ -25,7 +25,8 @@ keycloakService.CallInit(() => {
 
 })
 
-createApp(App).mount('#app');
+// this shit made by me so i can run the canva vue app
+createApp(App).use(router).mount('#app');
 
 // TODO: fix the comment
 /*
diff --git a/front/MyINPulse-front/src/router/index.ts b/front/MyINPulse-front/src/router/index.ts
index e9697d9..54cde30 100644
--- a/front/MyINPulse-front/src/router/index.ts
+++ b/front/MyINPulse-front/src/router/index.ts
@@ -19,6 +19,13 @@ const router = createRouter({
       // which is lazy-loaded when the route is visited.
       component: () => import('../views/Home.vue'),
     },
+
+      // route pour les canvas (made by adnane), in fact the two vue apps are separated for now
+    {
+      path: '/canvas',
+      name: 'canvas',
+      component: () => import('../views/CanvasView.vue'),
+    },
   ],
 })
 
diff --git a/front/MyINPulse-front/src/views/CanvasView.vue b/front/MyINPulse-front/src/views/CanvasView.vue
new file mode 100644
index 0000000..d87bd29
--- /dev/null
+++ b/front/MyINPulse-front/src/views/CanvasView.vue
@@ -0,0 +1,12 @@
+<!-- src/views/CanvasView.vue -->
+<template>
+    <div>
+      <h1>Page Canvas</h1>
+      <LeanCanvas />
+    </div>
+  </template>
+  
+  <script setup lang="ts">
+  import LeanCanvas from '@/components/canvas/Lean-canvas.vue';
+  </script>
+  
\ No newline at end of file

From 4fda5513a920e58e50419140abec3965fbe55f3c Mon Sep 17 00:00:00 2001
From: ALAMI Adnane <Adnane.Alami@bordeaux-inp.fr>
Date: Sat, 8 Feb 2025 20:33:03 +0100
Subject: [PATCH 7/7] error corrected

---
 front/MyINPulse-front/src/App.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/front/MyINPulse-front/src/App.vue b/front/MyINPulse-front/src/App.vue
index 65e6bf6..f187256 100644
--- a/front/MyINPulse-front/src/App.vue
+++ b/front/MyINPulse-front/src/App.vue
@@ -43,8 +43,8 @@ button:hover {
 </style>
 
 <script lang="ts">
-import Header from "@/components/Header.vue";
-import ProjectComp from "@/components/Project-comp.vue";
+//import Header from "@/components/Header.vue";
+//import ProjectComp from "@/components/Project-comp.vue";
 
 export default {
   name: 'App',