diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..5cc42d7bb391acc7a2dabb39c01f082a41421491
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto eol=lf
+CHANGELOG.md merge=union
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..636867290d6bb1c14a23e5cdbfcfc20b3553834c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+*.iws
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2631adff7392aad3efb19e737f5c976fabb7d844
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,107 @@
+variables:
+  ONLY:
+    value: ""
+    description: "List of components to build: common core calculs api-expositiondonneesentrees api-referentiel api-event-donneesentrees api-event-calculs"
+  MODE:
+    value: "build"
+    options: 
+      - "build"
+      - "dependency-check"
+    description: "Mode: build or dependency-check"
+     
+.maven-components: &maven-components
+  matrix:
+    - COMPONENT: [ api-expositiondonneesentrees, api-referentiel, api-event-donneesentrees, api-event-calculs ]
+
+.libraries: &libraries
+  matrix:
+    - COMPONENT: [ common, calculs ]
+
+workflow:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      when: never
+    - if: $CI_COMMIT_BRANCH =~ /doc.*/
+      when: never
+    - if: $CI_COMMIT_REF_NAME =~ /g4it.*/
+      when: always
+    - if: $CI_COMMIT_REF_NAME =~ /main|develop|\d+\.\d+\.\d+/
+      when: always
+
+clear cache maven:
+  stage: .pre
+  script:
+    - rm -rf .m2/
+  cache:
+    paths:
+      - .m2/
+
+core:
+  stage: .pre
+  variables:
+    COMPONENT: $COMPONENT
+    MODE: $MODE
+  trigger:
+    include: "services/common/.gitlab-ci-library.yml"
+    strategy: depend
+  rules:
+    - if: $COMPONENT =~ $ONLY
+      when: always
+    - if: $ONLY == ""
+      changes:
+        - services/$COMPONENT/**/*
+  parallel:
+    matrix:
+      - COMPONENT: [ core ]
+
+
+child-lib:
+  stage: build
+  variables:
+    COMPONENT: $COMPONENT
+    MODE: $MODE
+  trigger:
+    include: "services/common/.gitlab-ci-library.yml"
+    strategy: depend
+  rules:
+    - if: $COMPONENT =~ $ONLY
+      when: always
+    - if: $ONLY == ""
+      changes:
+        - services/$COMPONENT/**/*
+  parallel: *libraries
+
+child-mvn:
+  stage: deploy
+  variables:
+    COMPONENT: $COMPONENT
+    MODE: $MODE
+  trigger:
+    include: "services/common/.gitlab-ci-maven.yml"
+    strategy: depend
+  rules:
+    - if: $COMPONENT =~ $ONLY
+      when: always
+    - if: $ONLY == ""
+      changes:
+        - services/$COMPONENT/**/*
+  parallel: *maven-components
+
+
+#e2e:
+#  stage: deploy
+#  image: docker:latest
+#  services:
+#    - docker:dind
+#  only:
+#    - main
+#    - develop
+#    - tags
+#  before_script:
+#    - apk add --update curl && rm -rf /var/cache/apk/*
+#  script:
+#    - cd $CI_PROJECT_DIR/assets/docker-compose
+#    - docker-compose up -d postgresdb
+#    - docker-compose ps -a
+#    - cd $CI_PROJECT_DIR/e2e
+#    - cat .env
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..dbe3dd08cbee0507db1827e83f95e68d0ffd3c26
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,44 @@
+# NumEcoEval ChangeLog
+
+Tous les changements de ce projet seront documentés dans ce document.
+
+## [Non livré]
+
+- Defect: Libellé erreur erroné quand donnée de référence manquante
+- Ajout du mode d'utilisation et taux d'utilisation
+- Ajout d'une API /version pour récupérer la version courante de NumEcoEval dans le composant référentiel
+
+## [1.2.2] - 2024-01-11
+
+### Ajoutés
+- Ajout de multi-partition pour le topic de donnée principal pour permettre la lecture en parallèle
+- Amélioration des logs liés à Kafka et aux temps de traitement des équipements physiques
+
+## [1.2.1] - 2024-01-04
+
+### Corrigés
+- Augmentation de la taille maximum des fichiers en entrée de POST /import/csv
+- Remise en place des champs _discriminator
+- Déduplication des avertissements en sortie d'API /import/csv
+
+## [1.2.0] - 2023-12-11
+
+### Ajoutés
+- Contrôles sur les API d'entrées
+- API Referentiel : affichage des mix electriques pour un pays
+
+## [1.1.0] - 2023-11-21
+
+### Ajoutés
+
+### Corrigés
+- [Code non cohérent avec la spécification](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/api-event-enrichissement/-/issues/2)
+- [Aucun index lors de la récupération des sous-éléments - problème de performance ](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/api-event-donneesentrees/-/issues/1)
+
+### Supprimés
+- Composants api-event-enrichissement, api-event-indicateurs, api-rest-calculs (regroupés dans api-event-calculs)
+
+## [1.0.0] - 2023-06-01
+
+### Ajoutés
+- Initialisation des modules
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..7e131afa7da0169b169ddbbf4f1470b988a20be8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2023 pub / Numérique et Écologie / NumEcoEval - M4G
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
index 7c72fe27d6613699bf2ee5ea567dd5335e505618..a88efec57a6307e0f4f96dfeac8ea878af92204a 100644
--- a/README.md
+++ b/README.md
@@ -1,93 +1,205 @@
-# NumEcoEval
+<!-- Adapted from https://github.com/othneildrew/Best-README-Template/ -->
+<a name="readme-top"></a>
 
+<!-- PROJECT LOGO -->
+<div align="center">
 
+[![MIT License][license-shield]][license-url]
+[![Java][Java]][Java-url]
+[![Forge MTE][MTE]][MTE-url]
 
-## Getting started
+  <h3 align="center">NumEcoEval</h3>
 
-To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+  <p align="center">
+    Calcul de l’empreinte environnementale d'un système d'information
+    <br />
+  </p>
+</div>
 
-Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
 
-## Add your files
+<!-- TABLE OF CONTENTS -->
+<details>
+  <summary>Sommaire</summary>
+  <ol>
+    <li>
+      <a href="#le-projet">Le projet</a>
+    </li>
+    <li>
+      <a href="#demarrage-rapide">Démarrage rapide</a>
+    </li>
+    <li><a href="#feuille-de-route">Feuille de route</a></li>
+    <li><a href="#contributions">Contributions</a></li>
+    <li><a href="#licence">Licence</a></li>
+    <li><a href="#contact">Contact</a></li>
+  </ol>
+</details>
 
-- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
 
-```
-cd existing_repo
-git remote add origin https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval.git
-git branch -M main
-git push -uf origin main
-```
 
-## Integrate with your tools
+<!-- ABOUT THE PROJECT -->
 
-- [ ] [Set up project integrations](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/settings/integrations)
+## Le projet
 
-## Collaborate with your team
+**NumEcoEval** est une solution permettant de calculer l’empreinte environnementale d'un système d'information.
+Le système d'information est défini comme l'ensemble des équipements physiques, des machines virtuelles et des applications gérés par une organisation.
 
-- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
-- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
-- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
-- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
+Il suit les principes décrit dans la RCP Service Numérique et préfigure l'outillage qui pourrait être associé à une RCP "Système d'Information" qui est en cours d'élaboration par l'écosystème.
 
-## Test and Deploy
+Cet outil a été construit sur la base des travaux réalisés par Le Ministère de la transition écologique, Sopra Steria, l’ADEME, l’INR et BOAVIZTA.
 
-Use the built-in continuous integration in GitLab.
+Ce projet est construit en modules présent dans ce même repository Gitlab ou dans d'autres du même groupe.
 
-- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
-- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
-- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
-- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
-- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+<details><summary>Liste des modules de NumEcoEval</summary>
+<ul>
+  <li>[docs](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/docs)</li>
+  <li>[core](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/services/core)</li>
+  <li>[common](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/services/common)</li>
+  <li>[calculs](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/services/calculs)</li>
+  <li>[api-expositiondonneesentrees](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/services/api-expositiondonneesentrees)</li>
+  <li>[api-referentiel](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/services/api-referentiel)</li>
+  <li>[api-event-donneesentrees](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/api-event-donneesentrees)</li>
+  <li>[api-event-calculs](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/tree/develop/api-event-calculs)</li>
+</ul>
+</details>
 
-***
+<details><summary>Liste des modules hors de ce repository</summary>
+<ul>
+  <li>[ci-library](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/ci-library)</li>
+</ul>
+</details>
 
-# Editing this README
 
-When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
+> Pour tout renseignement complémentaire, contacter numerique-ecologie@developpement-durable.gouv.fr 
 
-## Suggestions for a good README
 
-Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
 
-## Name
-Choose a self-explaining name for your project.
+<!-- GETTING STARTED -->
 
-## Description
-Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+## Démarrage rapide
 
-## Badges
-On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+### Installation
 
-## Visuals
-Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+Le démarrage le plus rapide se fait via Docker-compose avec le [fichier mis à disposition](assets/docker-compose/docker-compose.yml).
 
-## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+La version par défaut est la version de développement `develop`.
 
-## Usage
-Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+Pour utiliser une version différente, il faut modifier le TAG présent dans le fichier [.env](assets/docker-compose/.env).
 
-## Support
-Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+La commande la plus simple pour démarrer le moteur : 
+````shell
+# Aller dans le dossier assets/docker-compose
+cd assets/docker-compose
 
-## Roadmap
-If you have ideas for releases in the future, it is a good idea to list them in the README.
+# Faire cette commande si vous voulez les ports en 808x
+# Par défaut, les ports sont en 1808x
+sed -i "s/PORT_PREFIX=.*/PORT_PREFIX=/g" .env
 
-## Contributing
-State if you are open to contributions and what your requirements are for accepting them.
+# Mode Live - Uniquement durant l'exécution de la commande
+docker-compose up
 
-For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+# Mode Deamon - Exécution en tâche de fond
+docker-compose up -d
+````
 
-You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+7 conteneurs doivent être démarrés :
+* Zookeeper
+* Kafka
+* Postgres
+* API REST Référentiels
+* API REST Expositions des données d'entrées
+* API Event données d'entrées
+* API Event calculs
 
-## Authors and acknowledgment
-Show your appreciation to those who have contributed to the project.
+Pour arrêter l'application :
+````shell
+cd assets/docker-compose
+docker-compose down
+````
+_Il suffit de couper le processus en mode Live._
 
-## License
-For open source projects, say how it is licensed.
+Exemple de démarrage avec une version production:
+````shell
+cd assets/docker-compose
+docker-compose -e TAG=1.2.0 up -d
+````
+
+*En cas d'initialisation, il peut arriver que le moteur ait besoin d'un redémarrage avant d'être utilisé.
+Si une des API REST ne répond pas sur son URL ou un ou plusieurs containers sont indisponibles: il faut procéder à un redémarrage en arrêtant puis en démarrant le moteur.*
+
+
+### Usage
+
+Une fois l'application démarrée, les API REST sont alors disponibles sur les URLs suivantes (contrats d'interface):
+- [API REST Référentiels](http://localhost:8080/swagger-ui/index.html)
+- [API REST Expositions des données d'entrées](http://localhost:8081/swagger-ui/index.html)
+- [API Event Calculs](http://localhost:8085/swagger-ui/index.html)
+
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
+
+<!-- ROADMAP -->
+
+## Feuille de route
+
+:construction: _En cours de rédaction_ :construction:
+
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
+
+
+
+<!-- CONTRIBUTING -->
+
+## Contributions
+
+Les contributions sont ce qui fait de la communauté open source un endroit incroyable pour
+apprendre, s'inspirer et de créer. Toutes les contributions que vous faites sont **grandement
+appréciées**.
+
+À ce jour, veuillez nous contacter au préalable à numerique-ecologie@developpement-durable.gouv.fr pour avoir accès en contribution à ce projet.
+
+Vous pouivez ensuite forker le dépôt et
+créer une pull request. Vous pouvez aussi simplement ouvrir une issue avec le tag "
+enhancement".
+N'oubliez pas de donner une étoile au projet ! Merci encore !
+
+1. Forkez le Project
+2. Créez votre branche de feature (`git checkout -b feature/AmazingFeature`)
+3. Commitez votre codes (`git commit -m 'Add some AmazingFeature'`)
+4. Pushez sur la branche (`git push origin feature/AmazingFeature`)
+5. Ouvrez Pull Request
+
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
+
+<!-- LICENSE -->
+
+## Licence
+
+Distribué sous la licence Apache 2.0. Voir `LICENSE` pour plus d'informations.
+
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
+
+
+<!-- CONTACT -->
+
+## Contact
+
+Programme Numérique et Écologie - numerique-ecologie@developpement-durable.gouv.fr
+
+<p align="right">(<a href="#readme-top">back to top</a>)</p>
+
+
+<!-- MARKDOWN LINKS & IMAGES -->
+<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
+
+[license-shield]: https://img.shields.io/gitlab/license/20519?gitlab_url=https%3A%2F%2Fgitlab-forge.din.developpement-durable.gouv.fr&style=for-the-badge
+
+[license-url]: https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/blob/develop/LICENSE
+
+[Java]: https://img.shields.io/badge/OpenJDK-000000?style=for-the-badge&logo=openjdk&logoColor=white&labelColor=C13D3C
+
+[Java-url]: https://openjdk.org/
+
+[MTE]: https://img.shields.io/badge/forge%20MTE-0000?color=00008f&style=for-the-badge&logo=gitlab
+
+[MTE-url]: https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval
 
-## Project status
-If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
diff --git a/assets/docker-compose/.env b/assets/docker-compose/.env
new file mode 100644
index 0000000000000000000000000000000000000000..1935e94ad1c824092cd21c97770db8ce81e69f75
--- /dev/null
+++ b/assets/docker-compose/.env
@@ -0,0 +1,7 @@
+REGISTRY_URL=registry.gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval
+PORT_PREFIX=1
+TAG=develop
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+LOGGING_LEVEL_ROOT=ERROR
+LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=ERROR
diff --git a/assets/docker-compose/docker-compose.yml b/assets/docker-compose/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f0eb0f0d8c5cb3132843d0c8c550c7467360a061
--- /dev/null
+++ b/assets/docker-compose/docker-compose.yml
@@ -0,0 +1,142 @@
+# Les variables globales sont présentes dans le fichier .env
+# - TAG
+# - REGISTRY_URL
+# - POSTGRES (user, password)
+# - LOGGING_LEVEL_*
+
+version: "3"
+
+services:
+  # Zookeeper basé sur la documentation officielle de Bitnami
+  ## https://github.com/bitnami/containers/blob/main/bitnami/zookeeper/docker-compose.yml
+  ## https://hub.docker.com/r/bitnami/zookeeper/
+  zookeeper:
+    image: docker.io/bitnami/zookeeper:3.9
+    container_name: zookeeper
+    ports:
+      - "2181:2181"
+    volumes:
+      - "numecoeval_zookeeper_data:/bitnami"
+    environment:
+      ALLOW_ANONYMOUS_LOGIN: "yes"
+  
+  # Kafka basé sur la documentation officielle de Bitnami
+  ## https://github.com/bitnami/containers/blob/main/bitnami/kafka/docker-compose.yml
+  ## https://hub.docker.com/r/bitnami/kafka/
+  kafka:
+    image: docker.io/bitnami/kafka:3.6
+    depends_on:
+      - zookeeper
+    container_name: kafka
+    ports:
+      - "9092:9092"
+    volumes:
+      - "numecoeval_kafka_data:/bitnami"
+    environment:
+      ALLOW_PLAINTEXT_LISTENER: "yes"
+      KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
+
+  # Postgres basé sur la documentation officielle de Postgres sur Dockerhub
+  ## https://hub.docker.com/_/postgres
+  postgresdb:
+    image: docker.io/postgres:15
+    container_name: postgresdb
+    ports:
+      - "5432:5432"
+    environment:
+      POSTGRES_USER: $POSTGRES_USER
+      POSTGRES_PASSWORD: $POSTGRES_PASSWORD
+    volumes:
+      - "numecoeval_postgres_data:/var/lib/postgresql/data"
+
+  api-rest-referentiels:
+    image: ${REGISTRY_URL}/api-referentiel:${TAG}
+    depends_on:
+      - postgresdb
+    ports:
+      - "${PORT_PREFIX}8080:8080"
+    environment:
+      SERVER_PORT: "8080"
+      MANAGEMENT_SERVER_PORT: "8080"
+      SPRING_JPA_HIBERNATE_DDL-AUTO: "update"
+      SPRING_DATASOURCE_URL: "jdbc:postgresql://postgresdb:5432/postgres?reWriteBatchedInserts=true"
+      SPRING_DATASOURCE_USERNAME: $POSTGRES_USER
+      SPRING_DATASOURCE_PASSWORD: $POSTGRES_PASSWORD
+      SPRING_SERVLET_MULTIPART_MAXREQUESTSIZE: "45MB"
+      SPRING_SERVLET_MULTIPART_MAXFILESIZE: "10MB"
+      SPRING_JPA_PROPERTIES_HIBERNATE_JDBC_BATCHSIZE: "1000"
+      SPRING_JPA_PROPERTIES_HIBERNATE_ORDERINSERTS: "true"
+      SPRING_JPA_SHOWSQL: "false"
+      NUMECOEVAL_URLS_ALLOWED: "http://localhost,http://api-rest-referentiels"
+      LOGGING_LEVEL_ROOT: $LOGGING_LEVEL_ROOT
+      LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: $LOGGING_LEVEL_ORG_SPRINGFRAMEWORK
+
+  api-rest-expositiondonneesentrees:
+    image:  ${REGISTRY_URL}/api-expositiondonneesentrees:${TAG}
+    depends_on:
+      - postgresdb
+      - api-rest-referentiels
+    ports:
+      - "${PORT_PREFIX}8081:8080"
+    environment:
+      SERVER_PORT: "8080"
+      MANAGEMENT_SERVER_PORT: "8080"
+      NUMECOEVAL_KAFKA_TOPIC_MAX_MESSAGES_SIZE: "52428800"
+      NUMECOEVAL_REFERENTIEL_SERVER_URL: "http://api-rest-referentiels:8080"
+      SPRING_SERVLET_MULTIPART_MAXREQUESTSIZE: "45MB"
+      SPRING_SERVLET_MULTIPART_MAXFILESIZE: "10MB"
+      SPRING_DATASOURCE_URL: "jdbc:postgresql://postgresdb:5432/postgres?reWriteBatchedInserts=true"
+      SPRING_DATASOURCE_USERNAME: $POSTGRES_USER
+      SPRING_DATASOURCE_PASSWORD: $POSTGRES_PASSWORD
+      SPRING_JPA_PROPERTIES_HIBERNATE_GENERATESTATISTICS: "true"
+      SPRING_JPA_PROPERTIES_HIBERNATE_ORDERINSERTS: "true"
+      SPRING_JPA_PROPERTIES_HIBERNATE_JDBC_BATCHSIZE: "1000"
+      SPRING_JPA_SHOWSQL: "false"
+      NUMECOEVAL_URLS_ALLOWED: "http://localhost,http://api-rest-expositiondonneesentrees"
+      LOGGING_LEVEL_ROOT: $LOGGING_LEVEL_ROOT
+      LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: $LOGGING_LEVEL_ORG_SPRINGFRAMEWORK
+
+  api-event-donneesentrees:
+    image: ${REGISTRY_URL}/api-event-donneesentrees:${TAG}
+    depends_on:
+      - kafka
+      - postgresdb
+      - api-rest-expositiondonneesentrees
+    ports:
+      - "${PORT_PREFIX}8083:8080"
+    environment:
+      SERVER_PORT: "8080"
+      MANAGEMENT_SERVER_PORT: "8080"
+      SPRING_KAFKA_BOOTSTRAPSERVERS: "kafka:9092"
+      SPRING_DATASOURCE_URL: "jdbc:postgresql://postgresdb:5432/postgres?reWriteBatchedInserts=true"
+      SPRING_DATASOURCE_USERNAME: $POSTGRES_USER
+      SPRING_DATASOURCE_PASSWORD: $POSTGRES_PASSWORD
+      LOGGING_LEVEL_ROOT: $LOGGING_LEVEL_ROOT
+      LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: $LOGGING_LEVEL_ORG_SPRINGFRAMEWORK
+
+  api-event-calculs:
+    image: ${REGISTRY_URL}/api-event-calculs:${TAG}
+    depends_on:
+      - kafka
+      - postgresdb
+    ports:
+      - "${PORT_PREFIX}8085:8080"
+    environment:
+      SERVER_PORT: "8080"
+      MANAGEMENT_SERVER_PORT: "8080"
+      NUMECOEVAL_URLS_ALLOWED: "http://localhost,http://api-event-calculs"
+      NUMECOEVAL_REFERENTIELS_URL: "http://api-rest-referentiels:8080"
+      SPRING_KAFKA_BOOTSTRAPSERVERS: "kafka:9092"
+      SPRING_DATASOURCE_URL: "jdbc:postgresql://postgresdb:5432/postgres?reWriteBatchedInserts=true"
+      SPRING_DATASOURCE_USERNAME: $POSTGRES_USER
+      SPRING_DATASOURCE_PASSWORD: $POSTGRES_PASSWORD
+      LOGGING_LEVEL_ROOT: $LOGGING_LEVEL_ROOT
+      LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: $LOGGING_LEVEL_ORG_SPRINGFRAMEWORK
+
+volumes:
+  numecoeval_zookeeper_data:
+    driver: local
+  numecoeval_kafka_data:
+    driver: local
+  numecoeval_postgres_data:
+    driver: local
diff --git a/assets/images/08BDB65B-73CA-4FF0-8C1C-1040DA20E7B3.png b/assets/images/08BDB65B-73CA-4FF0-8C1C-1040DA20E7B3.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1575ef89569b25578693f1061e190b6aeb2d6f0
Binary files /dev/null and b/assets/images/08BDB65B-73CA-4FF0-8C1C-1040DA20E7B3.png differ
diff --git a/assets/images/2A4575F4-EE3B-478D-A397-BD8B409390E0.png b/assets/images/2A4575F4-EE3B-478D-A397-BD8B409390E0.png
new file mode 100644
index 0000000000000000000000000000000000000000..3555a08ade0eced2a0361511cfe1084ab2f2fbb0
Binary files /dev/null and b/assets/images/2A4575F4-EE3B-478D-A397-BD8B409390E0.png differ
diff --git a/assets/images/3E1ED783-839A-4094-9A8B-8B02F6E5283E.png b/assets/images/3E1ED783-839A-4094-9A8B-8B02F6E5283E.png
new file mode 100644
index 0000000000000000000000000000000000000000..5eeecb145a43b97ddf695a4f110de4f4604a2ef0
Binary files /dev/null and b/assets/images/3E1ED783-839A-4094-9A8B-8B02F6E5283E.png differ
diff --git a/assets/images/56BC42EB-2AAF-4A9B-A98C-9D29DB8E2520.png b/assets/images/56BC42EB-2AAF-4A9B-A98C-9D29DB8E2520.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d7d2a007b81e64fe257c6e957eaccecbc6e7f79
Binary files /dev/null and b/assets/images/56BC42EB-2AAF-4A9B-A98C-9D29DB8E2520.png differ
diff --git a/assets/images/81945681-5CEB-4178-8AB8-4B9B6801FBC9.png b/assets/images/81945681-5CEB-4178-8AB8-4B9B6801FBC9.png
new file mode 100644
index 0000000000000000000000000000000000000000..69cb210d8e71138b010855c51431436da7eb4796
Binary files /dev/null and b/assets/images/81945681-5CEB-4178-8AB8-4B9B6801FBC9.png differ
diff --git a/assets/images/8B74D910-915C-46FD-9C46-34A44FD3CBBA.png b/assets/images/8B74D910-915C-46FD-9C46-34A44FD3CBBA.png
new file mode 100644
index 0000000000000000000000000000000000000000..54f875dad89af646c559fe128d33694f3c3e37b5
Binary files /dev/null and b/assets/images/8B74D910-915C-46FD-9C46-34A44FD3CBBA.png differ
diff --git a/assets/images/A8AF1630-6525-428D-85A6-E3C413982D97.png b/assets/images/A8AF1630-6525-428D-85A6-E3C413982D97.png
new file mode 100644
index 0000000000000000000000000000000000000000..493c303644239b67f5c629231757380e3bb34c4d
Binary files /dev/null and b/assets/images/A8AF1630-6525-428D-85A6-E3C413982D97.png differ
diff --git a/assets/images/BB5C2199-6CA3-4E0E-8899-A95FF625CE38.png b/assets/images/BB5C2199-6CA3-4E0E-8899-A95FF625CE38.png
new file mode 100644
index 0000000000000000000000000000000000000000..79b5c5438b6f087219c485561fc8c8019d810fdf
Binary files /dev/null and b/assets/images/BB5C2199-6CA3-4E0E-8899-A95FF625CE38.png differ
diff --git a/assets/images/DBBC8E31-4CED-497B-A53F-43D78BCB1523.png b/assets/images/DBBC8E31-4CED-497B-A53F-43D78BCB1523.png
new file mode 100644
index 0000000000000000000000000000000000000000..38e6919ff3d2e0e705c049f1ada86616f2b9cf2e
Binary files /dev/null and b/assets/images/DBBC8E31-4CED-497B-A53F-43D78BCB1523.png differ
diff --git a/assets/images/E64BA1C4-E956-4B54-9CDF-BA4F4E321807.png b/assets/images/E64BA1C4-E956-4B54-9CDF-BA4F4E321807.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f5117dd29d6c7f2d4555c6dfe2bace6f8a7697a
Binary files /dev/null and b/assets/images/E64BA1C4-E956-4B54-9CDF-BA4F4E321807.png differ
diff --git a/assets/images/FF00E9AF-13DC-409C-8512-975183F81063.png b/assets/images/FF00E9AF-13DC-409C-8512-975183F81063.png
new file mode 100644
index 0000000000000000000000000000000000000000..ae81b84e8de59d7267635a69feb00b4aad0c3679
Binary files /dev/null and b/assets/images/FF00E9AF-13DC-409C-8512-975183F81063.png differ
diff --git a/docs/DonneeEntree.plantuml b/docs/DonneeEntree.plantuml
new file mode 100644
index 0000000000000000000000000000000000000000..3c99b1cc885096047b4f106b9022c7934752ed0a
--- /dev/null
+++ b/docs/DonneeEntree.plantuml
@@ -0,0 +1,129 @@
+@startuml
+'les clés primaire sont désignées avec un point
+'les références entre tables sont désignées avec un carré
+
+class en_DonneesEntree {
+'Nom de l'organisation liée aux données
+String nomOrganisation
+'Le nom du lot permettant d’agréger les données provenant de différentes sources et d'en faire un suivi temporel
+LocalDate nomLot
+'La date du lot permet d’agréger les données provenant de différentes sources et d'en faire un suivi temporel
+LocalDate dateLot
+' le paramètre suivant est facultatif. Il liste les noms des critères souhaités dans le calcul, en cohérence avec la table ref_Critere . Son absence déclenchera le caclul sur l'ensemble des critères présents dans la table de référence ref_Critere
+List<String> criteresDemandees
+' le paramètre suivant est facultatif. Il liste les codes des étapes souhaitées dans le calcul, en cohérence avec la table ref_EtapeACV. Son absence déclenchera le caclul sur l'ensemble des étapes présentes dans la table de référence ref_EtapeACV.
+List<String> etapesDemandees
+List<en_EqP> equipementsPhysiques
+List<en_DC> dataCenters
+List<en_Messagerie> messageries
+List<en_Entite> entites
+}
+
+class en_Entite {
+String nomOrganisation
+LocalDate dateLot
+String nomEntite
+Integer nbCollaborateurs
+String responsableEntite
+String responsableNumeriqueDurable
+}
+
+'Equipement Physique
+class en_EqP {
+* String nomEquipementPhysique
+'le type fait référence au ref_typeEquipement présent dans les références
+String type
+' Pour type == Serveur, Référence au data center = en_DC.nomCourtDataCenter
+- String nomCourtDatacenter
+String modele
+String statut
+String paysDUtilisation
+String utilisateur
+Date dateAchat
+Data dateRetrait
+Double consoElecAnnuelle
+Float nbJourUtiliseAn
+Float goTelecharge
+Integer quantite
+String modeUtilisation
+Double tauxUtilisation
+'Nom de l'entité responsable de l'équipement physique
+String nomEntite
+String nomSourceDonnee
+List<en_EqV> machinesVirtuelles
+}
+
+
+'Equipement Virtuel
+class en_EqV {
+* String nomEquipementVirtuel
+'le type d'équipement virtuel contient "calcul", "stockage", "null"
+String typeEqV
+'nom de l'équipement physique sous jacent
+- String  nomEquipementPhysique
+Integer vCPU
+'en To
+Double capaciteStockage
+' la clé de repartition est exprimée comme une fraction 
+Double cleRepartition
+Double consoElecAnnuelle
+String cluster
+'Nom de l'entité responsable de l'équipement virtuel
+String nomEntite
+String nomSourceDonnee
+List<en_App> applications
+}
+
+'DataCenter
+class en_DC {
+*String nomCourtDatacenter
+String nomLongDatacenter
+Double PUE
+String localisation
+'Nom de l'entité responsable du datacenter
+String nomEntite
+String nomSourceDonnee
+}
+
+'Application = Une instance d'une application sur une VM
+class en_App {
+* String nomApplication
+'les type d'environnements permettent de distinguer les environnements de développement, de recette, de production..
+* String typeEnvironnement
+' Référence à l'équipement virtuel = en_EqV.nomVM
+- String nomEquipementVirtuel
+'les catégories permettent le classement par domaine applicatif
+String domaine
+String sousDomaine
+'Nom de l'entité associée
+' permet de retrouver des données liées à l'entité
+String nomEntite
+String nomSourceDonnee
+}
+
+'données de la messagerie
+class en_Messagerie {
+'nombre total des mails émis par les collaborateurs
+Double nombreMailEmis
+'nombre de mail émis multiplié par le nombre de destinataires
+Double nombreMailEmisXDestinataires
+'Volume total des mails dans les boites mails des collaborateurs
+Double volumeTotalMailEmis
+'date au format MMYY
+Date MoisAnnee
+'Nom de l'entité associée
+' Pas utile pour les applications
+' mais utile pour retrouver des données liées à l'entité
+String nomEntite
+String nomSourceDonnee
+}
+
+en_DonneesEntree "1"--- "0-*" en_DC : peut contenir >
+en_DonneesEntree "1"--- "0-*" en_EqP : peut contenir >
+en_DonneesEntree "1"--- "0-*" en_Messagerie : peut contenir >
+en_DonneesEntree "1"--- "0-*" en_Entite : peut contenir >
+en_App "1" - "1" en_EqV : est contenu dans >
+en_EqV "0-*" - "1" en_EqP : est contenu dans >
+
+
+@enduml
diff --git a/docs/Indicateurs.plantuml b/docs/Indicateurs.plantuml
new file mode 100644
index 0000000000000000000000000000000000000000..b64755f80085c939018d125cb10c397df32ef7a4
--- /dev/null
+++ b/docs/Indicateurs.plantuml
@@ -0,0 +1,97 @@
+@startuml
+
+'éléments communs à tous les indicateurs, ces attributs sont dans toutes les classes filles
+abstract class ind_Impact {
+'La date du lot permet d’agréger les données provenant de différentes sources et d'en faire un suivi temporel
+LocalDate dateLot
+'Date et Heure du calcul, même valeur pour tous les indicateurs créés avec le même lot d'objets d'entrées
+LocalDateTime dateCalcul
+'Version de l'application ayant réalisé le calcul
+String versionCalcul
+'Statut de l'indicateur : calculé, en erreur
+String statutIndicateur
+'Version du référentiel
+String versionReferentiel
+'Trace du calcul, résultat
+String trace
+'Nom de l'étape ACV associée à l'indicateur
+String etapeACV
+'Nom du critère associé à l'indicateur
+String critere
+String source
+String referentielsSources
+'Unite du critère
+String unite
+'Nom de l'organisation - Metadata
+String nomOrganisation
+'Nom de l'entité pouvant agir sur l'indicateur - Metadata
+String nomEntite
+}
+
+'Indicateurs d'empreinte environnemtale d'un équipement physique
+class ind_ImpactEquipementPhysique {
+' Nom de l'équipement physique présent dans les données d'entrée en_EqP
+String nomEquipement
+'le type présent dans les données d'entrée (en_EqP.type)
+String typeEquipement
+'Quantité de l'équipement associé à l'indicateur, uniquement pour les équipements physiques
+Integer quantite
+'Statut de l'équipement physique correspondant à en_EqP.statut. 
+String statutEquipementPhysique
+'Impact unitaire, le champ est null en cas d'erreur lors du calcul de l'indicateur
+Double impactUnitaire
+Double consoElecMoyenne
+}
+
+'Indicateurs d'empreinte environnemtale d'un équipement virtuel
+class ind_ImpactEquipementVirtuel {
+' Nom de la VM
+String nomVM
+' Nom de l'équipement physique ou de la VM présent dans les données d'entrée en_EqP et en_EqV
+String nomEquipement
+'Metadata - le cluster n'est pas obligatoire et permet de regrouper plusieurs VM
+String cluster
+'Impact unitaire, le champ est null en cas d'erreur lors du calcul de l'indicateur
+Double impactUnitaire
+Double consoElecMoyenne
+}
+
+'Indicateurs d'empreinte environnemtale d'un applicatif
+class ind_ImpactApplicatif {
+'correspond à une application présente dans donnée d'entrée en_App
+String nomApplication
+String typeEnvironnement
+String domaine
+String sousDomaine
+Double impactUnitaire
+Double consoElecMoyenne
+}
+
+
+'Indicateur Impact Réseau
+class ind_ImpactReseau {
+' Nom de l'équipement physique ou de la VM
+*String reference
+Double impactUnitaire
+}
+
+'Indicateur d'impact pour la messagerie
+'Le champ etapeACV n'est pas utilisé pour cet indicateur
+class ind_ImpactMessagerie {
+Double impactMensuel
+'date au format MMYY
+Date MoisAnnee
+'Volume total des mails dans les boites mails des collaborateurs
+Double volumeTotalMailEmis
+'nombre total des mails émis par les collaborateurs
+Double nombreMailEmis
+}
+
+ind_Impact <|-- "hérite de" ind_ImpactReseau
+ind_Impact <|-- "hérite de" ind_ImpactApplicatif
+ind_Impact <|-- "hérite de" ind_ImpactEquipementPhysique
+ind_Impact <|-- "hérite de" ind_ImpactEquipementVirtuel
+ind_Impact <|-- "hérite de" ind_ImpactMessagerie
+
+
+@enduml
diff --git a/docs/MoteurDeCalculG4IT_V1.1.adoc b/docs/MoteurDeCalculG4IT_V1.1.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..629844c141dd340b3ae4d6e242ac31ce34406065
--- /dev/null
+++ b/docs/MoteurDeCalculG4IT_V1.1.adoc
@@ -0,0 +1,865 @@
+= Spcécification des règles de calcul de G4IT
+:toc:
+:toclevels: 4 
+:sectnums:
+
+== Historique des modifications
+|===
+|type de changement|date|type de modification
+|majeur|28/06/2022|Création du document
+|majeur|Avril 2023|Ouverture en Open Source
+|===
+
+[#_documents_de_reference]
+== Documents de référence
+
+|===
+|identifiant|intitulé du document|source
+|1|G4IT|Sopra Steria
+|2|Référentiel services numériques_v1.0_FR|ADEME|Principes généraux pour
+l’affichage environnemental des produits de grande consommation
+|3|WeNR Methodology Note|weNR - https://wenr.isit-europe.org/wenr-methodology-note/|méthode de calcul
+|4|BOAVIZTA|https://boavizta.org/
+|===
+
+== Introduction
+
+NumEcoEval est une solution permettant, à partir de données de dimensionnement du SI et de données de références, de calculer l’empreinte environnementale d'un système d'information.
+Cet outil open source a été initialisé à partir des travaux de Sopra Steria [1], de l’ADEME [2],  de l’INR [3], de BOAVIZTA [4] (cf.Documents de référence), avec la contribution d'IJO. 
+Cet outil vise à déployer massivement le calcul de l'empreinte environnementale d'un système d'information au sein d'une organisation, en connectant NumEcoEval directement aux sources de données standard de celle-ci (notamment ses CMDB).
+Le volume de données pouvant être important, une attention particlière a donc été apportée à la performance de l'outil et explique certains choix d'architecture (notamment l'utilisation de l'asynchronisme).
+
+== Description des principaux concepts
+
+[#_analyse_de_cycle_de_vie]
+=== Analyse de cycle de vie
+Notre approche s’inspire des méthodes d'Analyse de Cycle de Vie (ACV), cadrées par les normes ISO 14040 et 14044. Ces normes structurent l’analyse d’impact tout au long du cycle de vie d’un produit ou d'un service.L’application de ces normes à un service numérique est encore jeune mais est à ce jour l’approche la plus poussée et celle retenue par les groupes de travail liés à la règlementation (AGEC).
+NumEcoEval a été conçu pour pouvoir intégrer d'autres étapes du cycle de vie des produits selon les besoins des organisations, sous réserve que les donnéées disponilbles et/ou les standards évoluent dans ce sens.
+
+4 étapes du cycle de vie d'un produit sont retenues actuellement :
+
+image::cycle_de_vie.jpg[]
+
+|===
+|Étape du cycle de vie |Traduction anglaise |description
+|Fabrication|Build|Phase de fabrication d'un composant de l'extraction des matières premières à la fin de sa phase de fabrication.
+|Utilisation|Use|Phase d'utilisation d'un équipement
+|Fin de vie|End Of Life (EOL)| Phase de fin de vie et de recyclage d'un équipement
+|Distribution|Dist| Phase d'acheminement du produit et des matières
+|===
+
+[#_criteres_dimpacts_environnementaux]
+=== Critères d'impacts environnementaux
+Les critères d'impact correspondent aux types d'impact environnementaux suivis par l'outil.
+Sont retenus actuellement les critères décris dans la PCR Service Numérique ([1] des <<_documents_de_reference>>) comme obligatoire :
+
+* Épuisement des ressources naturelles (minérales et métaux)
+* Changement climatique
+* Acidification
+* Émissions de particules fines
+* Radiations ionisantes
+* Consommation d’énergie primaire (indicateur de flux - complémentaire)
+
+Le raisonnement multicritère est important car il permet d'éviter les transferts d'impact lors de la planifaction du plan d'action suivant l'acte de mesure de l'empreinte.
+Comme pour les étapes ACV, ce moteur de calcul permet nativement l'ajout d'autres critères d'impact environnementaux.
+
+[#_Organisation]
+=== L'Organisation
+L'organisation regroupe l'ensemble des tiers utilisant NumEcoEval appartenant à une même structure. Une organisation peut contenir différentes entités.
+
+.Exemple
+Le Ministère de la Transition Écologique et de la Cohésion des Territoires est une organisation qui sollicite NumEcoEval pour calculer l'empreinte environnementale de son SI.
+
+[#_architecture_fonctionnelle]
+== Architecture fonctionnelle de la solution
+
+image::architecture_fonctionnelle_simplifiee_V1.png[]
+
+Comme indiqué dans le schéma d'architecture fonctionnel simplifié ci-dessus, il convient de distinguer différents types de données :
+
+* Les *données brutes* : ce sont les données stockées sans transformation, sous des formes très différentes, dans les outils d'une organisation. Ces données peuvent être statiques (elles ne varient pas ou peu et sont valables à l'échelle d'un an) ou dynamiques (elles varient souvent et doivent être mesurées régulièrement). Elle sont fournies par des sondes, des API... et ne sont pas structurées au format G4IT.
+* Les *données d'entrées* :  ce sont les données normalisées (format NumEcoEval), capables d'être comprises par G4IT et peuvent être interprétées par l'outil pour faire ses calculs. Ces données sont donc généralement issues de la transformation des données brutes (traduction, redressement, nettoyage...).
+* Les *indicateurs* : ce sont les données pouvant être affichées dans les dashboards SuperSet. Elles sont généralement calculées via les règles présentes dans ce document (exemple : impact en CO2 eq d'un équipement) ou sont issues des données brutes (exemple : nombre d'équipements). Ces indicateurs sont de deux types :
+
+	** Stratégiques : ils permettent au DSI ou aux sponsors des domaines d'avoir l'état de lieux et de fixer les objectifs
+    ** Opérationnels : ils permettent au responsable de secteur et AMOE de mettre en place les actions sur leur périmètre.
+
+* Les *références* : ce sont les données normalisées (format NumEcoEval), qui servent de base aux calculs des impacts pour les différentes phases du cycle de vie d'un équipement (cf. <<_analyse_de_cycle_de_vie>>) et pour les différents critères (cf. <<_criteres_dimpacts_environnementaux>>). Ces données peuvent provenir de base de référence externes (NegaOCtet, Base Impact de l'ADEME, base BOAVIZTA...), ou peuvent être calculées par le client (exemple : calcul de la consommation électrique moyenne annuelle d'un équipement).
+
+== Description des Modules
+
+=== Bloc Références
+[#_donnees_de_reference]
+==== Données de référence
+
+Les données de références correspondent aux données qui ne proviennent pas directement de l'organisation (<<_Organisation>>)souhaitant utiliser NumEcoEval. Ces données peuvent être issue de la littérature scientifique, de bases de données de références externes et reconnues (NegaOctet, Base IMPACT de l'ADEME, bases de données BOAVIZTA...), ou issue de travaux empiriques. Ces données doivent nécesairement être sourcées pour assurer la traçabilité des calculs.
+
+Le tableau suivant permet de connaitre les données de référence utilisées dans les différentes règles de calcul.Ces données seront précédées du préfixe "ref_" suivi d'une suite de lettre permettant d'identifier la table concernée.
+
+exemple :
+|===
+|Identifiant|Description des données
+|ref_Critere|Précise les critères pris en charges par l'outil, leur unité et d'autres informations qui leurs sont associées.
+|ref_Etape|Précise les étapes du cycle de vie prises en charge par l'outil.
+|ref_Hypothese |Précise les hypothèses nécessaires à certains calculs des indicateurs (par exemple les données par défaut)
+|ref_TypeEquipement |Précise les types d'équipements autorisés et leur durée de vie par defaut
+|ref_CorrespondanceRefEqP|Donne la correspondance entre les équipements présents dans les données d'entrées et les équipements de références présents dans la table ref_impactEquipement
+|ref_ImpactEquipement |Donne pour chaque type équipement référencé, son impact environnemental selon le critère (<<_criteres_dimpacts_environnementaux>>) et le cycle de vie (<<_analyse_de_cycle_de_vie>>) regardé.
+|ref_MixElec|Donne pour chaque pays référencé, l'impact environnemental d'un kWh d'électricité produit, selon les différents critères d'impact.
+|ref_ImpactReseau|Donne l'impact lié à l'utilisation du réseau selon les différents critères et l'étapes dans le cycle de vie.
+|===
+
+**Pour chaque type d'objet, des endpoints de CRUD (Create/Read/Update/Delete) sont disponibles**
+
+le format de ces références est contraint pour garantir la capacité du moteur de calul (cf.<<_moteur_de_calcul>>) à produire les indicateurs.
+
+link:./References.plantuml[Diagramme de classe des référentiels]
+
+Toutes ces données sont nécessaires au calcul des règles d'impact. Elles doivent être chargées par un administrateur NumEcoEval avant d'intégrer les données d'entrée.
+===== Précisions sur l'import CSV de certains référentiels
+
+*Référentiels dépendants d'une organisation* :
+
+Le référentiel est lié à une organisation donnée. L'import se fait avec 2 paramètres :
+
+* Le nom d'organisation pour laquelle les données sont établies
+* Le fichier CSV du référentiel
+
+Lors de l'import, les données précédentes de l'organisation pour le référentiel sont supprimées.
+
+_Concerne_: ref_CorrespondanceRefEqP
+
+*Référentiels généraux* :
+
+Le référentiel est global à tout le système. L'import se fait uniquement avec le fichier CSV du référentiel.
+
+Lors de l'import, les données précédentes sont supprimées.
+
+_Concerne_: ref_Critere, ref_Etape, ref_ImpactEquipement, ref_MixElec, ref_ImpactReseau
+
+==== Exposition du bloc
+
+Les données de ce bloc sont exposées via les points suivants :
+|===
+|Endpoint API REST|Description|Paramètres|Sortie
+|[[GET_Etapes]]GET /referentiels/etapes|Renvoie la liste des étapes de ref_EtapeACV|Aucuns| Liste d'objet ref_EtapeACV
+|[[GET_Criteres]]GET /referentiels/criteres|Renvoie la liste des Critères de ref_Critere|Aucuns| Liste d'objet ref_Critere
+|[[GET_ImpactsReseaux]]GET /referentiels/impactreseaux?etape=+{etape}+&critere=+{critere}+&reseau=+{refReseau}+|Renvoie l'impact d'un équipement sur le réseau selon les paramètres|Le nom du critère, le code de l'étape de cycle de vie et la référence de l'équipement|Un objet ref_ImpactReseau
+|[[GET_Hypotheses]]GET /referentiels/hypotheses?cle=+{cle}+|Renvoie l'objet ref_Hypothese correspondant à la clé|La clé unique de l'hypothèse|Un objet ref_Hypothese
+|[[GET_typeEquipement]]GET /referentiels/typeEquipement?type=+{type}+|Renvoie l'objet typeEquipement correspondant au type d'équipement|Le type d'équipement|Un objet ref_TypeEquipement
+|[[GET_impactMessagerie]]GET /referentiels/impactMessagerie?critere=+{critere}+|Renvoie l'objet ref_ImpactMessagerie correspondant au critère|La référence d'impact messagerie|Un objet ref_ImpactMessagerie
+|===
+
+**Pour chaque type d'objet, des endpoints de CRUD (Create/Read/Update/Delete) sont disponibles**
+
+_Tableau des endpoints CRUD en attente des retours sur Spring Data REST_
+_TODO Ajouter le tableau une fois les endpoints stabilisés_
+
+Pour certains référentiels compatibles, un endpoint d'import par fichier CSV est disponible
+pour permettre un chargement en masse.
+|===
+|Exemple d'endpoint d'import par CSV|Description|Paramètres|Sortie
+|POST /referentiels/<objet_ref>/import/csv|Importer plusieurs références. L'import fonctionne en annule-et-remplace (suppression de toutes les données avant import).|Le fichier CSV avec les données à insérer|Rapport du fichier CSV (nombre de lignes totales, nombre de lignes en erreur, nombre de lignes traitées, liste des erreurs par lignes).
+|===
+
+Ce endpoint est actuellement disponible pour les référentiels suivants :
+ref_Critere, ref_EtapeACV, ref_Hypothese, ref_TypeEquipement, ref_ImpactEquipement,
+ref_MixElec, ref_ImpactReseau, ref_ImpactMessagerie.
+
+**Points d'attention **
+
+- Par construction, une suppression sur le référentiel ref_EtapeACV supprime les référentiels référençant cette étape : ref_ImpactEquipement, ref_ImpactReseau et ref_ImpactMessagerie.
+- Par construction, un import CSV sur le référentiel ref_EtapeACV supprime les référentiels référençant les étapes : ref_ImpactEquipement, ref_ImpactReseau et ref_ImpactMessagerie.
+- Par construction, une suppression sur le référentiel ref_Critere supprime les référentiels référençant le critère : ref_ImpactEquipement, ref_ImpactReseau, ref_ImpactMessagerie et ref_MixElec.
+- Par construction, un import CSV sur le référentiel ref_Critere supprime les référentiels référençant les critères : ref_ImpactEquipement, ref_ImpactReseau, ref_ImpactMessagerie et ref_MixElec.
+
+==== Précision sur les hypothèses
+Les hypothèses de travail se trouvent dans la table "Hypothèses".
+Elles sont uniques pour une clé donnée.
+À l'usage dans la suite du document, une hypothèse peut être retrouvée via la formule :
+`ref_Hypothese(<clé d'hypothèse>)`
+
+.Exemple d'hypothèses :
+|===
+|clé|valeur|source
+|dureeVieParDefaut|1| dans le cas où la durée de vie d'un type d'équipement  ne serait pas renseigner on considère une hypothèse majorante d'une mise a rebut de l'équipement au bout de 1 an.
+|===
+
+[#_api_donnees_dentrees]
+=== API pour les données d'entrées
+
+L'API pour les données d'entrées permet d'importer des données dans le système NumEcoEval via des endpoints REST.
+
+Toutes les informations reçues sont envoyés simultanément :
+- Au bloc Données d'entrées pour historisation des données reçues si le module est activé
+- Au bloc Calcul afin de produire les indicateurs issus des règles de calculs décrites dans ce document.
+
+==== Endpoints de l'API
+
+Les données de ce bloc sont exposées via les points suivants :
+|===
+|Endpoint API REST|Description|Paramètres|Sortie
+|POST /entrees/csv|Envoi d'un objet en_DonneesEntree aux blocs Calculs (et enregistre ces Données Entrées si ce bloc "donnée d'entrée) est activé) | Les fichiers CSV correspondant aux différentes classes présentes dans les données d'entrée (équipement physiques, virtuels, datacenter...) 
+|Rapports par fichier CSV contenant le nombre de lignes en erreur, le nombre d'objets intégrés, la liste des erreurs par lignes).
+|===
+
+=== Bloc Données d'entrées (optionnel)
+Ce bloc est optionnel, il n'est pas nécessaire au calcul des indicateurs mais il permet d'historiser les données de dimensionnement de l'organisation, permettant de réaliser des rejeux de calculs et de connaitre les valeurs utilisé à un instant t.
+
+[#_donnees_dentrees]
+==== Données d'entrées
+
+Les données d'entrée du sytème se trouvent dans la base "Entree".
+Dans la spécification, les objets représentant des données d'entrées sont précédées du préfixe "en_"
+et sont classées en 4 catégories :
+
+* en_EqP: liste des équipements physiques (type, d'équipement)
+* en_EqV : liste des équipements virtuels (vCPU, équipement physique sous jacent...)
+* en_DC : liste des datacenters (identification, PUE)
+* en_App : liste des applications
+
+Tous ces objets sont groupées dans un objet en_DonneesEntree avant d'être envoyé dans l'outil.
+Dans un premier temps, il est possible d'envoyer les objets par groupes.
+
+le format de ces données d'entrée est contraint pour garantir la capacité du moteur de calul (cf.<<_moteur_de_calcul>>) à produire les indicateurs/
+link:./DonneeEntree.plantuml[Diagramme de classe des entrées]
+
+[#_bloc_calcul]
+=== Bloc Calcul
+Ce bloc représente le coeur de métier de la solution NumEcoEval.
+Il permet de produire des indicateurs en se basant sur :
+
+* Les référentiels exposés par le bloc Références (comprenant les critères, les étapes AVC, les hypothèses,... cf. <<_donnees_de_reference>>)
+* Les données d'entrées reçues via un objet en_DonneesEntree : cf <<_donnees_dentrees>>
+
+Le moteur de calcul permet d'intégrer toutes les règles de calcul (<<_regles_de_calcul>>) qui se basent sur les données de références et les données d'entrées.
+Il permet de calculer des indicateurs qui pourront ensuite être utilisés unitairement ou associés entre eux pour fournir une vision de l'empreinte environnementale d'un périmètre et aider les utilisateurs à piloter leurs plans d'action.
+
+cf.<<_moteur_de_calcul>>
+
+[#_bloc_indicateurs]
+=== Bloc Indicateurs
+==== Historisation des indicateurs
+
+Ce module permet d'historiser les indicateurs produits par le bloc de calcul.
+Les indicateurs sont stockés dans des tables dédiées.
+
+Tous les indicateurs sont autoporteurs, c'est-à-dire qu'ils sont compréhensibles et apportent de la valeur unitairement : ils font référence à un seul critère et une seule étape ACV, et la valeur de l'indicateur est toujours couplée avec une unité.
+
+link:./Indicateurs.plantuml[Diagramme de classes des indicateurs]
+
+==== Exposition du bloc
+
+Le bloc Indicateurs expose les points suivants :
+|===
+|Méthode d'exposition dans la spécification|Description|Paramètres|Sortie
+|[[sauvegarder_impact]]sauvegarder_impact(ind_Impact)|Persiste un objet ind_Impact (ou une des classes filles) en base de données|L'objet ind_Impact à sauvegarder en base de données| Aucunes
+|===
+
+
+[#_cles_de_lecture]
+== Clés de lectures du pseudocode
+
+* Pour faciliter la lecture des règles de calcul, chaque donnée est préfixée selon le module à laquelle elle appartient :
+** Les données en entrée du système sont préfixées par en_
+** Les données de référence sont préfixées par ref_ 
+
+* Les objects manipulés ont la forme suivante  `nomDeClasse nomObjet`
+** Exemple : `en_EqP EqP` indique qu'un objet `EqP` de classe `en_EqP` est disponible
+
+* Pour les référentiels et les hypothèses : les éléments entre `()` correspondent aux clés uniques de lecture
+** Exemples:
+*** `ref_Hypothese(dureeVieParDefaut)` correspond à utiliser l'API GET /referentiels/hypotheses?cle={cle} avec la clé `dureeVieParDefaut` (cf.<<GET_Hypotheses>>)
+pour obtenir l'objet ref_Hypothese correspondant
+*** `ref_ImpactReseau(etape,critere,refReseau)` (cf.<<GET_ImpactsReseaux>>) correspond à utiliser l'API GET /referentiels/impactreseaux?etape={etape}&critere={critere}&reseau={refReseau} avec les paramètres `Etape`,`Critere` et `refReseau` correspondant
+
+* Le "." derrière un objet (déclaré ou obtenu après une méthode d'exposition) indique l'accès à un attribut de l'objet.
+** Exemples :
+*** `ref_Hypothese(dureeVieParDefaut).valeur` correspond au champ valeur de l'objet ref_Hypothese de clé `dureeVieParDefaut`
+*** `ref_ImpactReseau(Etape,Critere,refReseau).valeur` correspond au champ valeur de l'objet ref_ImpactReseau correspondant à `Etape`,`Critere` et `refReseau`
+
+* Toutes les règles qui calculent des indicateurs l'enregistre en base de donnée grâce à la methode sauvegarder_impact(ImpactUnitaireReseau) : cf.<<sauvegarder_impact>>
+
+
+[#_moteur_de_calcul]
+== Moteur de calcul
+
+Le déclenchement des règles présentes dans le Bloc Calcul se réalise à la soumission des calculs sur un lot donné via le endpoint POST /entrees/calculs/soumission.
+NumEcoEval lance alors les calculs des indicateurs et les sauvegarde dans la base correspondante.
+
+La cinématique globale est décrite ci-dessous :
+
+image::cinématique.png[]
+
+Voici l'algorithme général permettant le caclul des indicateurs
+
+pseudocode
+----
+CalculDesIndicateurs(en_DonneesEntree) {
+	List<ref_EtapeACV> etapes = GET /referentiels/etapes;
+	SI en_DonneesEntree.etapesDemandees est renseigné
+		ALORS mettre à jour la liste etapes pour ne contenir que les étapes demandées
+	FIN SI
+
+	List<ref_Critere> criteres = GET /referentiels/criteres;
+	SI en_DonneesEntree.criteresDemandees est renseigné
+		ALORS mettre à jour la liste criteres pour ne contenir que les critères demandés
+	FIN SI
+
+    BOUCLE SUR CHAQUE etape DE LA LISTE ref_EtapeACV
+        BOUCLE SUR CHAQUE criteres DE LA LISTE ref_Critere
+
+			initialisation d'un compteur d'impact applicatif
+
+			BOUCLE SUR CHAQUE en_EqP DE en_DonneesEntree
+				// Exécutions des règles sur les équipements physiques
+				calculIndicateurImpactEquipementPhysique(etape, critere, en_DonneesEntree.nomOrganisation, en_EqP, en_DC, ind_ImpactEquipementPhysique)
+
+				SI en_EqP.type est un serveur (ref_TypeEquipement.serveur est vrai)
+					ALORS initialisation de la variable NbvCPU correspondant à la SOMME des vCPU de tous les équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire
+					ET initialisation de la variable stockageTotalVirtuel correspondant à la SOMME des capaciteStockage de tous les équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire
+					ET initialisation de la variable nbEqV correspondant au nombre de équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire
+					ET initialisation du bouléen vCPUoK indiquant que l'ensemble des équipements virtuels de l'équipement physique (si ce dernier est renseigné ou à l'équipement physique dans le cas contraire) possède un vCPU renseigné, entier et > à 0
+					ET initialisation du bouléen stockoK indiquant que l'ensemble des équipements virtuels de l'équipement physique (si ce dernier est renseigné ou à l'équipement physique dans le cas contraire) possède un vCPU renseigné, entier et > à 0
+
+					Soit ImpactEqP = ind_ImpactEquipementPhysique.ImpactUnitaire/ind_ImpactEquipementPhysique.quantite calculé dans cette boucle
+					Soit ConsoElecEqP = ind_ImpactEquipementPhysique.consoElecMoyenne/ind_ImpactEquipementPhysique.quantite calculé dans cette boucle calculée dans cette boucle
+
+					BOUCLE SUR CHAQUE en_EqV DE en_DonneesEntree dont l'équipement physique (en_EqV.nomEquipementPhysique) correspond à celui traité dans cette boucle
+						
+						ind_ImpactEquipementVirtuel = calculIndicateurImpactEquipementVirtuel(etape, critere, en_EqV, ImpactEqP, ConsoElecEqP, NbvCPU, nbEqV, vCPUoK, stockageTotalVirtuel, stockoK, ind_ImpactEquipement)
+						
+						// Calcul des impacts applicatifs : ils correspondent, pour l'impact unitaire, à la somme des impacts unitaires des équipements virtuels d'une application pour un type d'environnement, un critere et une étape ACV, et, pour la consommation electrique, à la somme des consommations électriques des équipements virtuels sous jacent.
+						BOUCLE SUR CHAQUE en_App  DE en_DonneesEntree pour en_App.nomEquipementVirtuel = en_EqV.nomEquipementVirtuel
+							SI AUCUN impact applicatif n'a été enregistré pour en_App.nomApplication, en_App.typEnvironnement, en_App.critere et en_App.etapeACV
+								ALORS ENREGISRER l'impact applicatif
+							SINON 
+								AJOUTER ind_ImpactEquipementVirtuel à l'impact applicatif précedemment enregirsté 
+							FIN SI
+
+						FIN BOUCLE
+					FIN BOUCLE			
+				FIN SI
+
+				// Calcul de l'impact réseau associé à ces équipements
+				CalculImpactReseau(en_EqP, etape, critere, ind_ImpactReseau)
+			
+			FIN BOUCLE
+
+        FIN BOUCLE
+
+    FIN BOUCLE
+
+    // Messagerie
+	BOUCLE SUR CHAQUE critere DE LA LISTE ref_Critere
+		SI ref_ImpactMessagerie.critere EXISTE pour le ref_Critere en cours
+			BOUCLE SUR CHAQUE en_Messagerie DE LA LISTE en_DonneesEntree.messageries
+				calculImpactMessagerie(en_Messagerie, critere, ref_ImpactMessagerie, ind_ImpactMessagerie)
+			FIN BOUCLE
+		FIN SI
+	FIN BOUCLE
+
+	SAUVERGARDER les indicateurs d'impact applicatif une fois l'ensemble des boucles terminées.
+}
+----
+
+Liens vers les principaux éléments de cet algorithme
+
+* <<GET_Etapes>>
+* <<GET_Criteres>>
+* <<_regles_de_calcul>>
+** <<_calcul_impact_EqP_unitaire>>
+** <<_calcul_impact_EqV_unitaire>>
+** <<_calculImpactReseau>>
+** <<_calculImpactMessagerie>>
+
+
+
+
+[#_regles_de_calcul]
+== Règles de calcul
+
+=== Règles Générales
+
+[#_rg_transfertdonnees]
+==== Transfert de données
+
+Certaines données reçues via les données d'entrées sont des données transmises
+en mode "passe-plat" de l'entrée jusqu'aux indicateurs.
+Ces données servent divers objectifs tels que :
+
+- Le regroupement des indicateurs par lot
+- La recherche dans les indicateurs
+- Permettre d'agréger les données qui concernent une même catégorie (Organisation, entité, type d'équipement...)
+- Les traces
+
+Les champs de même nom dans les objets d'entrées (en_*) et les objets indicateurs (ind_*)
+doivent être transmis à l'identique sans traitement particulier par le moteur de calcul.
+
+Les champs concernés sont les suivants :
+
+|===
+|Nom du champ|Obligatoire|Objet Source|Objet de Sortie|Description et usage
+|dateLot|Obligatoire|en_DonneesEntree|Tous les objets indicateurs|Date du lot de rattachement des données, permet de regrouper les données d'indicateurs. Définit une seule fois pour tous les objets.
+|nomOrganisation|Obligatoire|en_DonneesEntree|Tous les objets indicateurs|Nom de l'organisation rattachée aux données, permet de regrouper les données d'indicateurs. Définit une seule fois pour tous les objets.
+|nomEntite|Facultatif|Tous les objets d'entrées|Objets indicateurs du même niveau|Nom de l'entité responsable pouvant agir sur l'objet. Elle est définie dans les données d'entrées et alimente les indicateurs associés.
+|===
+
+
+
+[#_rg_traceCalcul]
+==== RG_TraceCalcul
+
+Pour chaque calcul produisant un indicateur (classe héritant de ind_Impact),
+le moteur de calcul produit une trace représentée par un objet d'une des classes suivantes :
+
+- TraceCalculImpactEquipementPhysique : la trace du calcul d'impact d'équipement physique cf. <<_calcul_impact_EqP_unitaire>>
+- TraceCalculImpactEquipementVirtuel : la trace du calcul d'impact d'équipement virtuel cf. <<_calcul_impact_EqV_unitaire>>
+- TraceCalculImpactMessagerie : la trace du calcul d'impact de la messagerie cf. <<_calculImpactMessagerie>>
+- TraceCalculImpactReseau : la trace du calcul d'impact du réseau cf. <<_calculImpactReseau>>
+
+Tous les objets de trace de calcul possèdent un champ "formule" permettant de vérifier le calcul de l'impact.
+La formule se présente comme un calcul mathématique avec le nom des variables et leurs valeurs entre parenthèses.
+
+_Exemple de valeur pour le champ formule :_
+`ImpactEquipementPhysique = (Quantité(1.0) * ConsoElecAnMoyenne(29.198638586342973) * MixElectrique(0.0813225) * NbJourUtiliseAn(365.0) * tauxUtilisation(1.0)) / 365`
+
+_Les formules originales (sans variable) sont visibles dans les différentes règles de calcul._
+
+En fonction des règles concernées, des champs supplémentaires sont alimentés pour faciliter la vérification.
+
+link:./Traces.plantuml[Diagramme de classes des objets relatifs aux traces]
+
+
+[#_rg_dureevieeqp]
+==== RG_DureeVieEqP : durée de vie d'un équipement physique
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+La durée de vie d'un équipement détermine la manière dont est amortie l'impact de sa fabrication.
+Elle est exprimée en année et autorise les décimales.
+
+
+|===
+|parametre|entree/sortie|Description
+|equipementPhysique|entrée|L'équipement physique dont on cherche à calculer la durée de Vie
+|dureeVieEqP|sortie|La durée de vie de l'équipement physique
+|===
+
+[pseudocode]
+----
+Règle RG_DureeVieEqP(equipementPhysique,dureeVieEqP) {
+	
+	'dans le cas où il est possible de calculer l'age réel de l'équipement, ce dernier fait foi
+	SI equipementPhysique.DateAchat est correcte et renseignée ET equipementPhysique.DateRetrait est correcte et renseignée
+	ALORS
+		SI (equipementPhysique.DateRetrait - equipementPhysique.DateAchat) < 1
+		ALORS RENVOYER 1
+		SINON RENVOYER ((equipementPhysique.DateRetrait - equipementPhysique.DateAchat) / 365)
+	
+	'dans le cas où seul la date d'achat est disponible, la règle du "Pseudo-amortissement" prévaut (impact de 100% sur l'année d'achat, 50% l'année 2, 33% l'année 3, etc... )
+	SINON SI equipementPhysique.DateAchat est correcte et equipementPhysique.DateRetrait non reseignée
+		ALORS RENVOYER ((equipementPhysique.DateAchat - date du jour) / 365)
+	
+	'dans les autres cas, une durée de vie moyenne de l'équipement est déduite
+	SINON
+			RENVOYER RG_DureeVieEqP_Defaut(equipementPhysique)
+	FIN SI
+}
+----
+
+cf.<<_rg_dureevieeqp_defaut>>
+
+[#_rg_dureevieeqp_defaut]
+==== RG_DureeVieEqP_Defaut : durée de vie des équipements par défaut
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+La durée de vie des équipements peut être déterminée par défaut dans le cas où la date d'acquisition ne serait pas renseignée. Elle est alors calculée sur la base suivante
+
+|===
+|paramètre|entree/sortie|Description
+|equipementPhysique|entrée|L'équipement physique dont on cherche à calculer la durée de Vie par défaut
+|dureeVieEqP_Defaut|sortie|La durée de vie par défaut de l'équipement physique
+|===
+
+[pseudocode]
+----
+Règle RG_DureeVieEqP_Defaut(equipementPhysique, dureeVieEqP_Defaut) {
+		'la durée de vie par défaut des équipements est celle renseignée dans la table des types d'équipements
+		SI l'équipement physique en entrée est présent dans la table des références d'équipement (ref_TypeEquipement.type) 
+			ALORS dureeVieEqP_Defaut = ref_TypeEquipement.dureeVieDefaut
+		'on retient l hypothèse d'une durée de vie par défaut des équipements égale à la durée de vie des équipements enregistrée dans les hypothèses
+		SINON SI ref_Hypothese(dureeVieParDefaut) existe
+			ALORS dureeVieEqP_Defaut = ref_Hypothese(dureeVieParDefaut).valeur
+		SINON
+			ErrCalcul("la durée de vie par défaut de l'équipement n'a pas pu être déterminée")
+		FIN SI
+}
+----
+
+[#_rg_correspondance_RefEquipement]
+==== RG Correspondance entre les équipements et leur références :
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle
+|===
+
+Cette règle permet de retrouver l'équipement de référence, c'est à dire celui dont les facteurs d'impact seront utilisés afin d'évaluer l'impact de l'équipement en court de traitement.
+
+|===
+|paramètre|entree/sortie|Description
+|organisation|entrée|l'organisation en cours de traitement
+|equipement|entrée|l'équipement dont on cherche la référence
+|refEquipementretenu|sortie|l'équipement dont l'impact servira de référence
+|===
+
+[pseudocode]
+----
+Règle RG_correspondanceRefEquipement(nomOrganisation, equipement, refEquipementretenu) { 
+	
+		SI ref_CorrespondanceRefEqP(nomOrganisation, equipement.modele) existe 
+			RENVOYER refEquipementretenu = ref_CorrespondanceRefEqP(nomOrganisation, equipement.modele).refEquipementCible
+		SINON SI ref_TypeEquipement(equipement.type).refEquipementParDefaut existe 
+			RENVOYER refEquipementretenu = ref_TypeEquipement(equipement.type).refEquipementParDefaut 
+		SINON
+			ErrCalcul("aucune correspondance avec un équipement de référence n'a pu être déterminée")
+		FIN SI
+
+}
+----
+
+=== Calculs d'impacts unitaires
+
+
+
+[#_calcul_impact_EqP_unitaire]
+==== Calcul impact unitaire équipement physique
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+Cette règle permet le calcul de l'impact moyen d'un équipement physique sur une année. Elle possède 3 paramètres : l'équipement dont on cherche à déterminer l'impact, l'étapeACV qui permet de déterminer quelle étape du cycle de vie de l'équipement est regardée et le critère d'impact que l'on souhaite extraire.
+
+|===
+|parametre|entree/sortie|Description
+|critere|entrée|le critere dont on cherche à calculer la durée de Vie par défaut
+|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par défaut
+|nomOrganisation|entrée|le nom de l'organisation en cours de traitement, récupéré de en_DonneesEntrees.nomOrganisation
+|equipementPhysique|entrée|l'équipement physique dont on cherche à calculer l'impact environnemental
+|en_DC|entrée|le PUE du datacenter lié à l'équipement physique.
+|ind_ImpactEquipementPhysique.nomEquipement|sortie|le nom de l'équipement physique calculé
+|ind_ImpactEquipementPhysique.critere|sortie|le critere calculé
+|ind_ImpactEquipementPhysique.etapeACV|sortie|l'étape ACV calculé
+|ind_ImpactEquipementPhysique.type|sortie|en_EqP.type
+|ind_ImpactEquipementPhysique.impactUnitaire|sortie|L'impact calculé pour le critère et l'étape ACV, vaut null en cas d'erreur
+|ind_ImpactEquipementPhysique.quantite|sortie|la quantité d'équipement physique
+|ind_ImpactEquipementPhysique.tauxUtilisation|sortie|le taux d'utilisation de l'équipement physique
+|ind_ImpactEquipementPhysique.modeUtilisation|sortie|le mode d'utilisation de l'équipement, il n'est utilisé que si le taux d'utilisation n'est pas renseigné. Les deux modes possibles sont (COPE & BYOD), les taux d'utilisation correspondants son enregistrés dans la table ref_hypotheses
+|ind_ImpactEquipementPhysique.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours
+|ind_ImpactEquipementPhysique.consoElecMoyenne|sortie|la consommation électrique déterminée par la règle suivante
+|===
+
+[pseudocode]
+----
+soit en_EqP(Equipement) = EqP
+
+Règle calculIndicateurImpactEquipementPhysique(critere, etape, nomOrganisation, EqP, en_DC, ind_ImpactEquipementPhysique) {
+'Récupération de la correspondance de refEquipement
+refEquipementRetenu = RG_correspondanceRefEquipement(nomOrganisation, equipementPhysique)
+
+	ind_ImpactEquipementPhysique(Equipement, EtapeACV, Critere) =
+	
+	SI EtapeACV.code = "UTILISATION"
+
+		EqP.quantité
+
+		SI EqP.consoElecAnnuelle est renseigné      
+			x EqP.consoElecAnnuelle
+			'enregistrement de la consommation electrique retenue
+			ind_ImpactEquipementPhysique.consoElecMoyenne = EqP.consoElecAnnuelle
+		SINON SI
+			'récupération de la consommation électrique de la référence de l'équipement retenue
+			x Ref_ImpactEquipement(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne
+			'enregistrement de la consommation electrique retenue
+			ind_ImpactEquipementPhysique.consoElecMoyenne = Ref_ImpactEquipement(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne
+		SINON 
+			ErrCalcFonc("donnée de consommation electrique manquante") 
+			Arret du calcul
+		FIN SI
+
+		SI EqP.NomCourtDatacenter est renseigné
+
+			SI n_DC(EqP.NomCourtDatacenter).PUE existe
+				x en_DC(EqP.NomCourtDatacenter).PUE
+			SINON SI ref_Hypothese(PUEParDefaut)
+				x ref_Hypothese(PUEParDefaut)
+			SINON 
+				ErrCalcFonc("le PUE est manquant et ne permet le calcul de l'impact à l'usage de l'équipement") 
+				Arret du calcul
+			FIN SI
+
+			x ref_MixElec(PaysDUtilisation = en_DC(NomCourtDatacenter).localisation).valeur
+		SINON
+			x ref_MixElec(PaysDUtilisation = EqP.PaysDUtilisation).valeur
+		FIN SI
+
+		SI EqP.tauxUtilisation est renseigné
+			x EqP.tauxUtilisation
+		SINON SI EqP.modeUtilisation est renseigné
+			SI ref_Hypothese(EqP.modeUtilisation) existe
+				EqP.tauxUtilisation = ref_Hypothese(EqP.modeUtilisation)
+				x EqP.tauxUtilisation
+			SINON 
+				EqP.tauxUtilisation = 1.0
+				x EqP.tauxUtilisation
+		SINON 
+			EqP.tauxUtilisation = 1.0
+			x EqP.tauxUtilisation
+		FIN SI
+
+	SINON
+		
+		EqP.quantité
+
+		SI EqP.tauxUtilisation est renseigné
+			x EqP.tauxUtilisation
+		SINON SI EqP.modeUtilisation est renseigné
+			SI ref_Hypothese(EqP.modeUtilisation) existe
+				EqP.tauxUtilisation = ref_Hypothese(EqP.modeUtilisation)
+				x EqP.tauxUtilisation
+			SINON 
+				EqP.tauxUtilisation = 1.0
+				x EqP.tauxUtilisation
+		SINON 
+			EqP.tauxUtilisation = 1.0
+			x EqP.tauxUtilisation
+		FIN SI
+
+		'récupération de l'impact pour le critère et l'étape ACV en cours, de la référence de l'équipement retenue
+		x Ref_ImpactEquipement(refEquipementretenu, EtapeACV, Critere).value
+		
+		/ RG_DureeVieEqP
+
+		'conso electrique retenue est null
+		ind_ImpactEquipementPhysique.consoElecMoyenne = null
+
+	FIN SI
+}
+----
+
+.Calcul de l'impact "moyen" en CO2 lié à l'utilisation d'un serveur sur 1 an
+====
+Equipement = exemple d'un serveur d'un client, sur une DataCenter possédant un PUE de 1.13
+
+EqP.quantité = 1
+x en_EqP.ConsoElecAnMoyenne= 1000 kWh
+x en_EqP.tauxUtilisation = 0,85
+x en_DC(NomCourtDatacenter = "googleCloud").PUE = 1,13
+x ref_MixElec("France","Changement Climatique").valeur = 0,0813225
+
+ImpactUnitaireEqP = 78,11 kg CO2eq /an
+====
+
+
+[#_calcul_impact_EqV_unitaire]
+==== Calcul d'impact d'une machine virtuel
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+Cette règle permet le calcul de l'impact moyen d'un équipement virtuel sur une année.
+L'impact alloué à la machine virtuelle correspond à une part de l'impact de l'équipement physique sous-jacent (décrit ici <<_calcul_impact_EqP_unitaire>>)
+
+|===
+|parametre|entree/sortie|Description
+|critere|entrée|le critère dont on cherche à calculer la durée de Vie par défaut
+|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par défaut
+|en_EqV|entrée|l'équipement virtuel dont on cherche à calculer l'impact environnemental
+|ImpactEqP|entrée|l'équipement physique dont l'impact est en cours de calcul
+|ConsoElecEqP|entrée|la consommation electrique retenue de l'équipement physique dont l'impact est en cours de calcul
+|NbvCPU|entrée|le nombre de vCPU total de l'ensemble des machines virtuelles associées à l'équipement physique sous-jacent de l'équipement virtuel en cours de calcul
+|nbEqV|entrée| le nombre total d'équipements virtuels associées à l'équipement physique sous-jacent de l'équipement virtuel en cours de calcul
+|vCPUoK|entrée| le booléen indiquant que l'ensemble des VM du serveur possèdent un vCPU correctement renseigné
+|ind_ImpactEquipementVirtuel.nomEquipement|sortie|le nom de l'équipement virtuel calculé
+|ind_ImpactEquipementVirtuel.critere|sortie|le critère calculé
+|ind_ImpactEquipementVirtuel.etapeACV|sortie|l'étape ACV calculée
+|ind_ImpactEquipementVirtuel.cluster|sortie|le cluster présent dans les données d'entrée pour cette équipements virtuels
+|ind_ImpactEquipementVirtuel.impactUnitaire|sortie|l'impact calculé pour le critère et l'étape ACV
+|ind_ImpactEquipementVirtuel.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours
+|ind_ImpactEquipementVirtuel.consoElecMoyenne|sortie|la consommation électrique renseignée en entrée 
+|===
+
+
+[pseudocode]
+----
+soit en_EqV(nomEquipementVirtuel) = EqV
+
+Règle calculIndicateurImpactEquipementVirtuel(critere, etape, en_EqV, ImpactEqP, ConsoElecEqP, NbvCPU, nbEqV, vCPUoK, stockageTotalVirtuel, ind_ImpactEquipementVirtuel) {
+
+	SI EqV.cleRepartition est renseigné
+		ind_ImpactEquipementVirtuel.ImpactUnitaire = ImpactEqP x EqV.cleRepartition 
+		ind_ImpactEquipementVirtuel.consoElecMoyenne = ConsoElecEqP x EqV.cleRepartition
+
+	SINON SI EqV.typeEqV = "calcul" et vCPUoK est vrai
+		ind_ImpactEquipementVirtuel.ImpactUnitaire = ImpactEqP x EqV.vCPU / NbvCPU
+		ind_ImpactEquipementVirtuel.consoElecMoyenne = ConsoElecEqP x EqV.vCPU / NbvCPU
+
+	SINON SI EqV.typeEqV = "stockage" et stockoK est vrai
+		ind_ImpactEquipementVirtuel.ImpactUnitaire = ImpactEqP x EqV.capaciteStockage / stockageTotalVirtuel
+		ind_ImpactEquipementVirtuel.consoElecMoyenne = ConsoElecEqP x EqV.capaciteStockage / stockageTotalVirtuel
+
+	SINON
+		'Si l'info des vCPU est manquante sur au moins un des équipement virtuel de l'équipement, on répartis l'impact à parts égale sur l'ensemble des équipements virtuels
+		ind_ImpactEquipementVirtuel.ImpactUnitaire = ImpactEqP / nbEqV
+		ind_ImpactEquipementVirtuel.consoElecMoyenne = ConsoElecEqP / nbEqV
+	FIN SI
+
+}
+----
+
+
+[#_calculIndicateurImpactApplicatif]
+==== Calcul impact associé à une application 
+
+|===
+|Version|Type de changement|Description
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+Cet indicateur correspond l'impact moyen annuel d'une application. 
+Il est calculé *directement dans le moteur de calcul* <<_moteur_de_calcul>> et part de l'hypothèse qu'un application tourne sur une ou plusieurs équipements virtuels dédiée(s). L'impact alloué à une application correspond alors l'impact des équipements virtuels sous-jacent (décrit ici <<_calcul_impact_EqV_unitaire>>).
+
+|===
+|parametre|entree/sortie|Description
+|critere|entrée|le critère dont on cherche à calculer la durée de Vie par defaut
+|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par defaut
+|nomApp|entrée|nom de l'applicaton 
+|typeEnvironnement|entrée|type d'environnement sur lequel
+|ind_ImpactApplicatif.nomApplication|sortie|en_App.nomApplication
+|ind_ImpactApplicatif.critere|sortie|critère calculé
+|ind_ImpactApplicatif.etapeACV|sortie|étape ACV calculée
+|ind_ImpactApplicatif.typeEnvironnement|sortie|en_App.typeEnvironnement
+|ind_ImpactApplicatif.domaine|sortie|en_App.domaine
+|ind_ImpactApplicatif.sousDomaine|sortie|en_App.sousDomaine
+|ind_ImpactApplicatif.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours
+|ind_ImpactApplicatif.consoElecMoyenne|sortie|la consomation électrique calculée (correspondant à la somme des consommations éléctriques des équipements virtuels sous-jacentes)
+|===
+
+
+[#_calculImpactReseau]
+==== Calcul impact lié à la sollicitation du réseau
+
+|===
+|version|type de changement|description 
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+*Note importante* : cette règle de calcul ne fait pas l'objet d'un consensus 
+Cette règle permet le calcul de l'impact lié à la sollicitation des différents type de réseaux permettant l'interconnexion des utilisateurs et des équipements. Il peut s'agir de flux internet mais on peut aussi considérer les données transitant entre deux sites par exemple client via une liaison louée par exemple, ou même au sein d'un datacenter.
+
+|===
+|parametre|entree/sortie|Description
+|equipementPhysique|entrée|l'équipement physique pour lequel l'impact réseau est calculé
+|critere|entrée|le critere dont on cherche à calculer la durée de Vie par defaut
+|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par defaut
+|ind_ImpactReseau.reference|sortie|type d'impact réseau
+|ind_ImpactReseau.ImpactUnitaire|sortie|impact calculé
+|ind_ImpactReseau.critere|sortie|critere calculé
+|ind_ImpactReseau.etapeACV|sortie|etape ACV calculé
+|ind_ImpactReseau.unite|sortie|l'unité présente dans le référentiel correspondant au critere en cours
+|===
+
+[pseudocode]
+----
+Règle calculImpactReseau(equipementPhysique, critere, etape, ind_ImpactReseau) {
+	
+	SI equipementPhysique.goTelecharge est renseigné ET ref_ImpactReseau(etape, critere, equipementPhysique) existe
+	
+	ALORS
+		
+		impactReseau = 
+		equipementPhysique.goTelecharge 
+		x ref_ImpactReseau(etape, critere, equipementPhysique).valeur
+
+		RENVOYER ImpactUnitaireReseau
+	
+	SINON SI ref_ImpactReseau("impactReseauMobileMoyen") n'existe pas ou ref_ImpactReseau("impactReseauMobileMoyen").valeur n'est pas renseigné
+
+		ErrCalcFonc("la référence impactReseauMobileMoyen n'existe pas")
+
+	FIN SI
+}
+----
+
+Références:
+
+* ref_ImpactReseau(etape, critere, equipementPhysique) : cf.<<GET_ImpactsReseaux>>
+* sauvegarder_impact(impact) : cf.<<sauvegarder_impact>>
+
+
+
+
+[#_calculImpactMessagerie]
+==== Calcul impact lié à la Messagerie
+
+|===
+|version|type de changement|description 
+|V1|création|Initialisation de la règle à dire d'expert
+|===
+
+*Note importante* : cette règle de calcul ne fait pas l'objet d'un consensus 
+Cette règle permet un calcul approximatif de l'impact lié à la messagerie. Il prend en compte l'impact moyen d'un mail établi à partir de différentes sources et en prenant en compte le poids des PJ (cf. sources)
+
+|===
+|parametre|entree/sortie|Description
+|en_Messagerie|entrée|les données d'entrée liées à la messagerie
+|ref_Critere|entrée|Critère d'impact en cours de travaux
+|ref_Messagerie|entrée|Les paramètres associées à la fonction affine pour le critère en cours.
+|ind_ImpactMessagerie.impactMensuel|sortie|l'impact calculé avec la fonction affine et les paramètre du référentiel
+|ind_ImpactMessagerie.MoisAnnee|sortie|en_Messagerie.MoisAnnee
+|ind_ImpactMessagerie.critere|sortie|ref_Critere.nomCritere
+|ind_ImpactMessagerie|sortie|Autant d'indicateurs qu'il y a d'objet en_Messagerie en entrée
+|===
+
+[pseudocode]
+----
+Règle calculImpactMessagerie(en_Messagerie, ref_Critere, ref_ImpactMessagerie, ind_ImpactMessagerie) {
+
+	'Production d'un indicateur ind_ImpactMessagerie par entrée en_Messagerie
+		'calcul du poids moyen d'un mail en Go
+		Double poidsMoyenMail = en_Messagerie.volumeTotalMailEmis/en_Messagerie.nombreMailEmis
+		'on applique la fonction affine en utilisant les éléments du ref_ImpactMessagerie pour connaitre l'impact d'un mail en C02 selon son poids, et on le multiplie par le volume de mail envoyés
+		ind_ImpactMessagerie.impactMensuel = (ref_ImpactMessagerie.constanteCoefficientDirecteur * poidsMoyenMail + ref_ImpactMessagerie.constanteOrdonneeOrigine) * en_Messagerie.nombreMailEmisXDestinataires
+		ind_ImpactMessagerie.MoisAnnee = en_Messagerie.MoisAnnee
+		ind_ImpactMessagerie.critere = ref_Critere.nomCritere
+
+}
+----
+
+== Gestion des erreurs
+
+=== ErrCalcFonc
+Les erreurs fonctionnelles sont de la forme suivante : "ErrCalcFonc : [règle calculée et paramètres de la fonction associée] ; [message d'erreur]"
+Au déclenchement de ce type d'erreur, une ligne s'affiche dans les logs, avec le nom de la règle où l'erreur s'est produite, les paramètres entrant de la règle et le message indiqués entre parenthèse.
+
+.Erreur de calcul de l'impact réseau
+====
+ "ErrCalcFonc : ImpactUnitaireReseau(equipement, etapeACV, critere) ; la référence "impactReseauMobileMoyen" n'existe pas"
+====
+
+=== ErrCalcTech
+Cette erreur se déclenche durant les calculs en cas d'erreurs non prévues et sont de la forme suivante : "ErrCalcTech : [règle calculée et paramètres de la fonction associée] ; [code de l'erreur technique]"
+
+
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d9bb705f63a9c8e6f6b6f3f7ef490c8101aedc41
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,4 @@
+# Fichiers
+
+Le Dossier d'architecture technique se trouve dans le wiki du Gitlab: 
+ - https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/wikis/MTE-DAT
diff --git a/docs/References.plantuml b/docs/References.plantuml
new file mode 100644
index 0000000000000000000000000000000000000000..3393d834b07b9bb314e1c047b269c9a6bb5fbfb9
--- /dev/null
+++ b/docs/References.plantuml
@@ -0,0 +1,97 @@
+@startuml
+
+'les hypotheses generique regroupe les hypothèses permettant le calcul de certains indicateurs
+class ref_Hypothese{
+*String clé
+String valeur
+String source
+}
+
+'liste des types d'équipements autorisés et de leur durée de vie par défaut
+class ref_TypeEquipement{
+*String type
+'le booléen "serveur" permet de distinguer les équipements inclus dans le calcul de l'impact d'un serveur applicatif à l'utilisation
+boolean serveur
+'le commentaire permet notamment de détailler les catégories équipements contenues dans un même type
+String commentaire
+Double dureeVieDefaut
+' la référence de l'équipement par defaut doit exister dans la table ref_ImpactEquipement.refEquipement
+String refEquipementParDefaut
+String source
+}
+
+'Impact environnementaux de référence
+class ref_ImpactEquipement {
+'identifiant de l'équipement
+* String refEquipement
+* String etape
+* String critere
+'description de l'équipement
+String description
+'le type doit correspondre à celui présent dans ref_TypeEquipement
+String type
+Double consoElecMoyenne
+Double valeur
+String source
+}
+
+class ref_CorrespondanceRefEqP {
+'modèle d'équipement de l'organisation, la valeur du champ doit exister dans en_EqP.modele
+* String modeleEquipementSource
+'Equipement de référence, la valeur du champ doit exister dans ref_ImpactEquipement.refEquipement
+String refEquipementCible
+}
+
+' Critère d'impact
+Class ref_Critere {
+*String nomCritere
+String unité
+String description
+}
+
+' étapes du cycle de vie des équipements pris en compte dans les calculs
+class ref_EtapeACV {
+* String code
+String libelle
+String description
+}
+
+class ref_MixElec {
+*String pays
+*String critere
+String raccourcisAnglais
+Double valeur
+String unité
+String source
+}
+
+'Impact environnementaux du réseau
+class ref_ImpactReseau{
+* String refReseau
+* String etape
+* String critere
+Double consoElecMoyenne
+Double valeur
+String source
+}
+
+'Impact environnemental Messagerie
+class ref_ImpactMessagerie{
+'L'équation d'impact est une fonction affine de la forme a * x + b
+'Cette constante correspond à "a" dans la fonction affine
+Double constanteCoefficientDirecteur
+'Cette constante correspond à "b" dans la fonction affine
+Double constanteOrdonneeOrigine
+'Critère associé à l'impact
+String critere
+String source
+}
+
+ref_EtapeACV "1" --- "0-*" ref_ImpactEquipement : dépend de >
+ref_Critere "1" --- "0-*" ref_ImpactEquipement : dépend de >
+ref_Critere "1" --- "0-*" ref_MixElec : dépend de >
+ref_Critere "1" --- "0-*" ref_ImpactReseau : dépend de >
+ref_Critere "1" --- "0-*" ref_ImpactMessagerie : dépend de >
+ref_EtapeACV "1" --- "0-*" ref_ImpactReseau : dépend de >
+
+@enduml
diff --git a/docs/Traces.plantuml b/docs/Traces.plantuml
new file mode 100644
index 0000000000000000000000000000000000000000..6798e03448ca8487a7aafeebf3ec8c423d921855
--- /dev/null
+++ b/docs/Traces.plantuml
@@ -0,0 +1,107 @@
+@startuml
+'Uniquement pour faciliter la lecture du diagramme, pas encore d'usage
+abstract class TraceCalculImpact{
+}
+hide TraceCalculImpact
+
+' Classes de trace
+
+
+class TraceCalculImpactEquipementPhysique {
+    String formule
+    Integer quantite
+    Double tauxUtilisation
+    String paysUtilisation
+    String nomCourtDataCenter
+    ConsoElecAnMoyenne consoElecAnMoyenne
+    MixElectrique mixElectrique
+    NbJourUtiliseAn nbJourUtiliseAn
+    Double valeurReferentielImpactEquipement
+    String sourceReferentielImpactEquipement
+    DureeDeVie dureeDeVie
+}
+
+class TraceCalculImpactEquipementVirtuel {
+    String formule
+    boolean vCPUok
+    Integer vCPU
+    Integer nbvCPU
+    Integer nbVM
+}
+
+class TraceCalculImpactMessagerie {
+    String formule
+    String critere
+    String sourceReferentielImpactMessagerie
+    Double volumeTotalMailEmis
+    Double nombreMailEmis
+    Double constanteCoefficientDirecteur
+    Double poidsMoyenMail
+    Double constanteOrdonneeOrigine
+    Double nombreMailEmisXDestinataires
+}
+
+class TraceCalculImpactReseau {
+    String formule
+    String critere
+    String etapeACV
+    String sourceReferentielReseau
+    String equipementPhysique
+    String impactReseauMobileMoyen
+    String goTelecharge
+}
+
+' Classes des objets associées aux calculs
+
+class ConsoElecAnMoyenne {
+    Double valeur
+    Double valeurEquipementConsoElecAnnuelle
+    Double valeurReferentielConsoElecMoyenne
+    String sourceReferentielImpactEquipement
+}
+
+ class DureeDeVie {
+    Double valeur
+    String dateAchat
+    String dateRetrait
+    DureeDeVieParDefaut dureeDeVieParDefaut
+}
+
+ class DureeDeVieParDefaut {
+    Double valeur
+    Double valeurEquipementDureeVieDefaut
+    Double valeurReferentielHypothese
+    String sourceReferentielHypothese
+    String typeEquipement
+}
+
+class MixElectrique {
+   Double valeur
+   boolean isServeur
+   Double dataCenterPue
+   Double valeurReferentiel
+   String sourceReferentiel
+   String pays
+}
+
+class NbJourUtiliseAn {
+    Double equipementNbJourUtiliseAn
+    Double valeurReferentielHypothese
+    String sourceReferentielHypothese
+    Double valeur
+}
+
+ConsoElecAnMoyenne "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir >
+DureeDeVie "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir >
+MixElectrique "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir >
+NbJourUtiliseAn "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir >
+
+DureeDeVieParDefaut "0-1" -up- "1" DureeDeVie : peut contenir >
+
+
+TraceCalculImpact <|-- "hérite de" TraceCalculImpactReseau
+TraceCalculImpact <|-- "hérite de" TraceCalculImpactMessagerie
+TraceCalculImpact <|-- "hérite de" TraceCalculImpactEquipementVirtuel
+TraceCalculImpact <|-- "hérite de" TraceCalculImpactEquipementPhysique
+
+@enduml
diff --git a/docs/archi_fonctionnelle_V4.png b/docs/archi_fonctionnelle_V4.png
new file mode 100644
index 0000000000000000000000000000000000000000..826a8eb0fcf37993acdac349d84d822a11f96dd7
Binary files /dev/null and b/docs/archi_fonctionnelle_V4.png differ
diff --git a/docs/architecture_fonctionnelle_simplifiee_V1.png b/docs/architecture_fonctionnelle_simplifiee_V1.png
new file mode 100644
index 0000000000000000000000000000000000000000..e3e532184a154fa93d604f521c7dc4f3fcec2581
Binary files /dev/null and b/docs/architecture_fonctionnelle_simplifiee_V1.png differ
diff --git "a/docs/cin\303\251matique.png" "b/docs/cin\303\251matique.png"
new file mode 100644
index 0000000000000000000000000000000000000000..4629fa24e74dd82a74b1fbf88df1b9ea3fe3dc18
Binary files /dev/null and "b/docs/cin\303\251matique.png" differ
diff --git a/docs/cycle_de_vie.jpg b/docs/cycle_de_vie.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..54bde5cdce29343e215ad084324b26cb1ec8d55a
Binary files /dev/null and b/docs/cycle_de_vie.jpg differ
diff --git a/e2e/.env b/e2e/.env
new file mode 100644
index 0000000000000000000000000000000000000000..9e2bfa2787b48a577729890fc30856b10c474db0
--- /dev/null
+++ b/e2e/.env
@@ -0,0 +1,31 @@
+REFERENTIEL_URL=http://localhost:18080
+ENTREE_URL=http://localhost:18081
+INDICATEUR_URL=http://localhost:18085
+
+### For dataset generation ###
+# Virtual Machine 
+VM_VCPU=4
+VM_TYPE_EQV=PY1ORA01,PY1LNX04
+# Application 
+APP_TYPE_ENV=Production,Recette,Pre-production,Developpement,Test
+
+### Dataset sizes ###
+# XX="EqPh EqPhSrv VmPerSrv AppPerVm"
+E2E="100 100 1 1"
+XS="100 100 4 2"
+S="1000 1000 8 4"
+M="10000 4000 12 6"
+L="20000 6000 16 8"
+XL="50000 10000 20 10"
+
+### Scenarios ###
+# SCENARIO_X="E2E XS S M L XL"
+SCENARIO_E2E="1 0 0 0 0 0"
+SCENARIO_1="0 10 5 1 0 0"
+SCENARIO_2="0 100 50 10 1 0"
+SCENARIO_3="0 200 100 20 2 1"
+SCENARIO_4="0 400 200 40 4 2"
+
+### Reports ###
+HEADER_RESULT="Dataset,Dataset size(MB),Dataset size (lines),Nb iteration,Average time (sec),Total time (sec)"
+HEADER_DETAIL="Dataset,Iteration,Total time (sec)"
diff --git a/e2e/.gitignore b/e2e/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a0d6c6975286dbc95ffd2f9e7ec66fe594c56c8b
--- /dev/null
+++ b/e2e/.gitignore
@@ -0,0 +1,6 @@
+expected
+input_ref
+data
+actual
+reports
+progress.log
diff --git a/e2e/1_load_ref.sh b/e2e/1_load_ref.sh
new file mode 100644
index 0000000000000000000000000000000000000000..194009545df531a94edc32e0fd987db7c8531b94
--- /dev/null
+++ b/e2e/1_load_ref.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# CONTANTS
+REFERENTIELS="criteres etapes hypotheses impactequipements impactreseaux mixelecs typeEquipement correspondanceRefEquipement"
+
+. ./.env
+. ./utils.sh
+
+log "Send referentiel data"
+for ref in $REFERENTIELS; do
+    log_n
+    curl -s -XPOST $REFERENTIEL_URL/referentiel/$ref/csv --form file=@input_ref/$ref.csv
+    echo ""
+done
diff --git a/e2e/2_generate_dataset.sh b/e2e/2_generate_dataset.sh
new file mode 100644
index 0000000000000000000000000000000000000000..54aac7a1f44f419535bb7cfde3ef06b235907c51
--- /dev/null
+++ b/e2e/2_generate_dataset.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+# Call: sh 2_generate_dataset.sh
+NB_EQ_PH_HORS_SRV=${1:-100}
+NB_EQ_PH_SRV=${2:-100}
+NB_VM_PAR_SRV=${3:-4}
+NB_APP_PAR_VM=${4:-2}
+
+. ./.env
+. ./utils.sh
+
+# CONTANTS
+NB_CSV_HORS_SRV=100
+NB_CSV_SRV=100
+
+set -f
+ARR_VM_TYPE_EQV=(${VM_TYPE_EQV//,/ })
+ARR_APP_TYPE_ENV=(${APP_TYPE_ENV//,/ })
+
+if [ -d data ]; then
+    rm -rf data
+fi
+mkdir data
+
+# *** GENERATE DATASET ***
+log "Generate input data in the 'data' local folder"
+log "NB_EQ_PH_HORS_SRV=$NB_EQ_PH_HORS_SRV, NB_EQ_PH_SRV=$NB_EQ_PH_SRV, NB_VM_PAR_SRV=$NB_VM_PAR_SRV, NB_APP_PAR_VM=$NB_APP_PAR_VM"
+
+# *** DataCenter.csv ***
+log "Generate input data : DataCenter.csv"
+cp -f input_template/DataCenter.csv data/
+
+# *** EquipementPhysique_hors_serveur.csv ***
+log "Generate input data : EquipementPhysique_hors_serveur.csv"
+head -n1 input_template/EquipementPhysique_hors_serveur.csv >data/EquipementPhysique.csv
+
+for ((i = 1; i <= $(($NB_EQ_PH_HORS_SRV / $NB_CSV_HORS_SRV)); i++)); do
+    tail -n $NB_CSV_HORS_SRV input_template/EquipementPhysique_hors_serveur.csv | sed s/physical-eq-/physical-eq-${i}/g >>data/EquipementPhysique.csv
+done
+
+# *** EquipementPhysique_serveur.csv ***
+log "Generate input data : EquipementPhysique_serveur.csv"
+
+for ((i = 1; i <= $(($NB_EQ_PH_SRV / $NB_CSV_SRV)); i++)); do
+    tail -n $NB_CSV_SRV input_template/EquipementPhysique_serveur.csv | sed s/physical-eq-srv-/physical-eq-srv-${i}/g >>data/EquipementPhysique.csv
+done
+
+# *** EquipementVirtuel.csv ***
+log "Generate input data : EquipementVirtuel.csv"
+head -n1 input_template/EquipementVirtuel.csv >data/EquipementVirtuel.csv
+
+VM_LINE=$(tail -n1 input_template/EquipementVirtuel.csv)
+
+n=0
+for ((i = 1; i <= $(($NB_EQ_PH_SRV / $NB_CSV_SRV)); i++)); do
+    for id in {001..100}; do
+        for ((vm = 1; vm <= $NB_VM_PAR_SRV; vm++)); do
+            type_eqv=${ARR_VM_TYPE_EQV[$((n % ${#ARR_VM_TYPE_EQV[@]}))]}
+            VM1=${VM_LINE//virtual-eq-/virtual-eq-$i$id-$vm}
+            VM2=${VM1//physical-eq-srv-/physical-eq-srv-$i$id}
+            VM3=${VM2//##VCPU##/$VM_VCPU}
+            echo ${VM3//##TYPE_EQV##/${type_eqv}}
+            n=$((n + 1))
+        done
+    done >>data/EquipementVirtuel.csv
+done
+
+# *** Application.csv ***
+log "Generate input data : Application.csv"
+head -n1 input_template/Application.csv >data/Application.csv
+
+APP_LINE=$(tail -n1 input_template/Application.csv)
+
+n=0
+for ((i = 1; i <= $(($NB_EQ_PH_SRV / $NB_CSV_SRV)); i++)); do
+    for id in {001..100}; do
+        for ((vm = 1; vm <= $NB_VM_PAR_SRV; vm++)); do
+            for ((app = 1; app <= $NB_APP_PAR_VM; app++)); do
+                type_env=${ARR_APP_TYPE_ENV[$((n % ${#ARR_APP_TYPE_ENV[@]}))]}
+                APP1=${APP_LINE//application-/application-$i$id-$vm-$app}
+                APP2=${APP1//virtual-eq-/virtual-eq-$i$id-$vm}
+                APP3=${APP2//physical-eq-srv-/physical-eq-srv-$i$id}
+                echo ${APP3//##TYPE_ENV##/${type_env}}
+                n=$((n + 1))
+            done
+        done
+    done >>data/Application.csv
+done
+
+log "Generate input data : End"
+
+echo "File,Size(MB),lines" >data/sizes.csv
+total=0
+lines=0
+for file in $(ls data/ | grep -v sizes); do
+    size=$(ls -l data/$file | cut -d' ' -f5)
+    size=$(awk "BEGIN {printf \"%.3f\",$size/(1024 * 1024)}")
+    line=$(wc -l data/$file | cut -d' ' -f1)
+    echo "$file,$size,$line" >>data/sizes.csv
+    total=$(awk "BEGIN {printf \"%.3f\",$total + $size}")
+    lines=$((lines + $line))
+done
+
+echo "TOTAL,$total,$lines" >>data/sizes.csv
+
+log "Report sizes generated in data/sizes.csv"
diff --git a/e2e/3_load_input.sh b/e2e/3_load_input.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1368dc3a89bf526dacead1cd8370ee43cc705d0d
--- /dev/null
+++ b/e2e/3_load_input.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+ORGANISATION=${1:-org1}
+NOM_LOT=$2
+SCENARIO=${3:-E2E}
+MODE=${4:-ASYNC}
+DATE_LOT=$(date +'%Y-%m-%d')
+
+. ./.env
+. ./utils.sh
+
+rm -f progress.log
+
+log_n "$ORGANISATION - $NOM_LOT - $DATE_LOT - Load Input - " | tee -a progress.log
+curl -s -XPOST "$ENTREE_URL/entrees/csv?nomLot=${NOM_LOT}&dateLot=${DATE_LOT}&nomOrganisation=${ORGANISATION}" \
+    --form csvDataCenter=@data/DataCenter.csv \
+    --form csvEquipementPhysique=@data/EquipementPhysique.csv \
+    --form csvEquipementVirtuel=@data/EquipementVirtuel.csv \
+    --form csvApplication=@data/Application.csv | tee -a progress.log
+echo "" | tee -a progress.log
+
+sleep 2
+
+log_n "$ORGANISATION - $NOM_LOT - $DATE_LOT - Soumission with mode=${MODE} - " | tee -a progress.log
+
+curl -s -XPOST "$ENTREE_URL/entrees/calculs/soumission?mode=$MODE" -d"{\"nomLot\":\"${NOM_LOT}\"}" -H "Content-Type: application/json" | tee -a progress.log
+echo "" | tee -a progress.log
diff --git a/e2e/4_check.sh b/e2e/4_check.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2d2013057c9d9648c3a4910d183d63ff59c8ab10
--- /dev/null
+++ b/e2e/4_check.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+ORGANISATION=${1:-org1}
+NOM_LOT=$2
+
+. ./.env
+. ./utils.sh
+
+while true; do
+    log_n "$ORGANISATION - $NOM_LOT - Statut - " | tee -a progress.log
+    response=$(curl -s "$ENTREE_URL/entrees/calculs/statut?nomLot=${NOM_LOT}&nomOrganisation=${ORGANISATION}")
+    if echo $response | grep -q "TERMINE"; then
+        echo $response | tee -a progress.log
+        echo "" | tee -a progress.log
+        break
+    fi
+
+    echo $response | tee -a progress.log
+    echo "" | tee -a progress.log
+    sleep 10
+done
diff --git a/e2e/5_assert.sh b/e2e/5_assert.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f61d80ec85b4847a9c4c35eeb7af0ab3485b7244
--- /dev/null
+++ b/e2e/5_assert.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+ORGANISATION=${1:-org1}
+NOM_LOT=${2:-lot1}
+
+# load INDICATEUR_URL
+. ./.env
+
+export_table() {
+    curl -s "$INDICATEUR_URL/indicateur/${1}Csv?nomLot=${NOM_LOT}&nomOrganisation=${ORGANISATION}&fields=${2}" >actual/${1}.csv
+}
+
+if [ -d actual ]; then rm -rf actual; fi
+mkdir actual
+
+export_table equipementPhysique conso_elec_moyenne,critere,etapeacv,impact_unitaire,nom_entite,nom_entite_discriminator,nom_equipement,nom_source_donnee,nom_source_donnee_discriminator,quantite,source,statut_equipement_physique,statut_indicateur,trace,type_equipement,unite,version_calcul
+export_table equipementVirtuel cluster,conso_elec_moyenne,critere,etapeacv,impact_unitaire,nom_entite,nom_entite_discriminator,nom_equipement,nom_equipement_virtuel,nom_source_donnee,nom_source_donnee_discriminator,source,statut_indicateur,trace,unite,version_calcul
+export_table application conso_elec_moyenne,critere,domaine,etapeacv,impact_unitaire,nom_application,nom_entite,nom_entite_discriminator,nom_equipement_physique,nom_equipement_virtuel,nom_source_donnee,nom_source_donnee_discriminator,source,sous_domaine,statut_indicateur,trace,type_environnement,unite,version_calcul
+export_table reseau etapeacv,critere,source,statut_indicateur,trace,version_calcul,impact_unitaire,unite,nom_entite,nom_equipement
+ALL_OK=true
+for file in $(ls actual/); do
+    echo -n "Check file $file : "
+    res=$(diff -qs actual/$file expected/$file)
+    if [ $? -eq 1 ]; then
+        echo "KO"
+        echo "*** REGRESSION : file $file is different from expected, see file: reports/diff_$file"
+        diff actual/$file expected/$files > reports/diff_$file
+        ALL_OK=false
+    else
+        echo "OK"
+    fi
+done
+
+if [ "${ALL_OK}" = "false" ]; then
+    exit 1
+fi
diff --git a/e2e/README.md b/e2e/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6c8109ce099f96564160c6275d5f50b1952696a4
--- /dev/null
+++ b/e2e/README.md
@@ -0,0 +1,37 @@
+# E2E et génération de JDD
+
+Dossiers :
+- input_ref : référentiel
+- input_template :
+    - DataCenter.csv : fichier classique
+    - EquipementPhysique_hors_serveur.csv : fichier avec 100 lignes d'équipements hors Server
+    - EquipementPhysique_serveur.csv : fichier avec 100 lignes d'équipements Server
+    - EquipementVirtuel.csv : 1 ligne variabilisé avec VCPU et TYPE_EQV
+    - Application.csv:  1 ligne variabilisé avec TYPE_ENV
+- expected: 
+    - export des tables indicateurs en mode csv, triés
+ 
+Le test E2E (non-reg) génère 100 équipements physiques hors serveur, 100 serveurs, 100 VM, 100 applications.
+
+Lancement du test E2E:
+- generic: `sh performance-test.sh E2E $NomOrg $NotLotPrefix`
+- exemple: `sh performance-test.sh E2E org perf`
+
+## Générer un JDD
+
+Le script 2_generate_dataset.sh permet de générer un dataset à partir des fichiers présents dans `input_template`.
+
+Il prend 4 paramètres:
+- NB_EQ_PH_HORS_SRV
+- NB_EQ_PH_SRV
+- NB_VM_PAR_SRV
+- NB_APP_PAR_VM
+
+Exemple d'appel : `sh 2_generate_dataset.sh 100 100 1 1`
+- Cela génère dans le dossier data :
+  - 100 EqPh hors server
+  - 100 EqPh server
+  - 100 EqPh * 1 VM         = 100 VM
+  - 100 EqPh * 1 VM * 1 APP = 100 APP
+
+
diff --git a/e2e/e2e.iml b/e2e/e2e.iml
new file mode 100644
index 0000000000000000000000000000000000000000..8021953ed9f8cc6cd6d71c79462bad4cd2b5394c
--- /dev/null
+++ b/e2e/e2e.iml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/e2e/input_template/Application.csv b/e2e/input_template/Application.csv
new file mode 100644
index 0000000000000000000000000000000000000000..f6d03dcd2a587361b88401bdd1d793cbcb72434c
--- /dev/null
+++ b/e2e/input_template/Application.csv
@@ -0,0 +1,2 @@
+nomApplication;typeEnvironnement;nomEquipementVirtuel;nomSourceDonneeEquipementVirtuel;domaine;sousDomaine;nomEntite;nomEquipementPhysique;nomSourceDonnee
+application-;##TYPE_ENV##;virtual-eq-;;Domain 1;Sub Domain 1;MY ENTERPRISE;physical-eq-srv-;;
diff --git a/e2e/input_template/DataCenter.csv b/e2e/input_template/DataCenter.csv
new file mode 100644
index 0000000000000000000000000000000000000000..11043f092ce8a6b463cce0b868d2cc2038f9ce12
--- /dev/null
+++ b/e2e/input_template/DataCenter.csv
@@ -0,0 +1,9 @@
+nomCourtDatacenter;nomLongDatacenter;pue;localisation;nomEntite;
+default;Default;1.75;France;;
+B1;B1;1.32;France;;
+F1;F1;1.43;France;;
+G1;G1;1.45;Spain;;
+X1;X1;1.42;Russia;;
+Y1;Y1;1.41;Germany;;
+Z2;Z2;1.75;France;;
+MAG;MAG;1.76;Belgium;;
diff --git a/e2e/input_template/EquipementPhysique_hors_serveur.csv b/e2e/input_template/EquipementPhysique_hors_serveur.csv
new file mode 100644
index 0000000000000000000000000000000000000000..09c3d4a9d0bce246d6e05f761f6980c5f90d7b6e
--- /dev/null
+++ b/e2e/input_template/EquipementPhysique_hors_serveur.csv
@@ -0,0 +1,101 @@
+nomEquipementPhysique;modele;quantite;nomCourtDatacenter;dateAchat;dateRetrait;type;statut;paysDUtilisation;consoElecAnnuelle;utilisateur;nomSourceDonnee;nomEntite;nbCoeur;nbJourUtiliseAn;goTelecharge;modeUtilisation;tauxUtilisation
+physical-eq-001;P2719;1;;2021-03-30;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;COPE;
+physical-eq-002;P2719;2;;2021-03-30;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;BYOD;
+physical-eq-003;P2719;4;;2021-03-30;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;COB;
+physical-eq-004;HUB USB;10;;2023-04-01;2023-06-16;Consumable;Consumed;France;;;;MY ENTERPRISE;;365;;BYOD;0.1
+physical-eq-005;P2720DC;2;;2022-11-04;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;BYOD;12.1
+physical-eq-006;PIXEL 6;1;;2022-10-18;2023-06-16;Communication Device;Missing;France;;;;MY ENTERPRISE;;365;;;test
+physical-eq-007;UP2516D;1;;2022-07-31;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-008;UP2516D;2;;2022-03-10;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-009;Unknown;3;;2021-08-09;2023-06-16;IP Router;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-010;Unknown;3;;2021-08-09;2023-06-16;IP Router;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-011;HP 8440p;1;;2021-08-05;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-012;HP 8440p;1;;2023-04-27;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-013;HP 8470w;2;;2025-08-23;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-014;OPPO A72;1;;2023-08-07;2023-06-16;Communication Device;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-015;CROSSCALL;1;;2022-08-20;2023-06-16;Communication Device;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-016;CROSSCALL;11;;2022-05-20;2023-06-16;Communication Device;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-017;CROSSCALL;8;;2022-05-28;2023-06-16;Communication Device;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-018;HUAWEI P9;11;;2021-01-28;2023-06-16;Communication Device;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-019;HUAWEI P9;4;;2022-08-18;2023-06-16;Communication Device;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-020;HUAWEI P9;1;;2023-06-18;2023-06-16;Communication Device;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-021;HUAWEI P9;32;;2021-01-28;2023-06-16;Communication Device;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-022;HUAWEI P9;9;;2024-08-18;2023-06-16;Communication Device;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-023;PRO MP242;50;;2022-06-21;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-024;SAC A DOS;534;;2023-02-18;2023-06-16;Consumable;Consumed;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-025;SAC A DOS;1;;2023-02-18;2023-06-16;Consumable;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-026;SPIDER X1;2;;2022-10-17;2023-06-16;Communication Device;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-027;DELL 1909W;5;;2022-11-20;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-028;DELL 1909W;1;;2021-12-20;2023-06-16;Monitor;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-029;DELL 1909W;14;;2025-10-17;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-030;DELL 2412M;1;;2022-12-26;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-031;DELL 2717H;19;;2021-04-08;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-032;DELL 2717H;1;;2024-11-23;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-033;DELL E7440;5;;2023-03-19;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-034;DELL E7440;31;;2025-10-27;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-035;DELL E7440;11;;2022-04-24;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-036;DELL E7450;2;;2022-12-21;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-037;DELL E7450;14;;2025-10-31;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-038;DELL E7450;6;;2022-04-22;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-039;DELL E7470;33;;2023-02-11;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-040;DELL E7470;23;;2022-03-16;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-041;DELL E7470;9;;2022-03-16;2023-06-16;Personal Computer;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-042;DELL E7470;4;;2022-03-16;2023-06-16;Personal Computer;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-043;DELL E7470;325;;2024-09-01;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-044;DELL E7470;2;;2025-03-03;2023-06-16;Personal Computer;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-045;DELL E7480;349;;2022-12-11;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-046;DELL E7480;49;;2021-10-26;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-047;DELL E7480;18;;2021-09-25;2023-06-16;Personal Computer;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-048;DELL E7480;141;;2023-11-04;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-049;DELL E7480;70;;2021-09-30;2023-06-16;Personal Computer;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-050;DELL E7480;1;;2025-06-03;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-051;DELL E7490;248;;2022-03-21;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-052;DELL E7490;52;;2021-06-17;2023-06-16;Personal Computer;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-053;DELL E7490;421;;2021-06-01;2023-06-16;Personal Computer;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-054;DELL E7490;51;;2021-06-19;2023-06-16;Personal Computer;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-055;DELL E7490;6;;2024-04-20;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-056;DELL P1911;8;;2022-07-25;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-057;DELL P1911;6;;2025-01-04;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-058;DELL P1913;4;;2022-11-02;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-059;DELL P1913;2;;2024-04-12;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-060;HUAWEI P20;1;;2021-12-24;2023-06-16;Communication Device;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-061;LENOVO M73;13;;2024-01-25;2023-06-16;Personal Computer;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-062;LENOVO M73;13;;2022-01-25;2023-06-16;Personal Computer;In Use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-063;ANTIVOL MAC;1;;2023-01-14;2023-06-16;Consumable;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-064;ANTIVOL MAC;1;;2023-01-14;2023-06-16;Consumable;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-065;ANTIVOL MAC;10;;2023-01-14;2023-06-16;Consumable;Consumed;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-066;AOC U2879VF;10;;2022-11-27;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-067;DELL P2210T;1;;2022-12-29;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-068;DELL P2217H;286;;2021-03-13;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-069;DELL P2217H;1;;2021-03-13;2023-06-16;Monitor;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-070;DELL P2217H;5;;2022-01-14;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-071;DELL P2217H;6;;2021-03-13;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-072;DELL P2217H;3;;2023-10-15;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-073;DELL P2319H;1;;2022-12-19;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-074;DELL P2319H;49;;2022-12-19;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-075;DELL P2412H;1;;2022-03-25;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-076;DELL P2412H;1;;2025-06-01;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-077;DELL P2415Q;7;;2022-03-13;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-078;DELL P2415Q;1;;2022-03-13;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-079;DELL P2417H;371;;2021-03-18;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-080;DELL P2417H;7;;2022-07-16;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-081;DELL P2417H;4;;2024-07-02;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-082;DELL P2417H;5;;2021-03-18;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-083;DELL P2419H;11;;2021-09-01;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-084;DELL P2419H;11;;2022-10-18;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-085;DELL P2419H;847;;2021-09-01;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-086;DELL P2419H;1;;2021-09-01;2023-06-16;Monitor;Missing;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-087;DELL P2419H;32;;2024-05-15;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-088;DELL P2422H;7;;2023-04-23;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-089;DELL P2422H;2;;2023-09-30;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-090;DELL P2422H;588;;2022-09-25;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-091;DELL P2719H;1;;2022-04-04;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-092;DELL P2719H;43;;2021-07-29;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-093;DELL P2719H;2;;2021-07-29;2023-06-16;Monitor;In stock;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-094;DELL P2721Q;2;;2023-02-24;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-095;DELL S2216H;2;;2024-11-27;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-096;DELL S2216H;17;;2021-05-21;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-097;DELL S2216H;1;;2022-11-22;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-098;DELL S2240L;28;;2021-06-26;2023-06-16;Monitor;In use;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-099;DELL S2240L;8;;2022-12-04;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
+physical-eq-100;DELL S2240L;4;;2024-12-09;2023-06-16;Monitor;Retired;France;;;;MY ENTERPRISE;;365;;;
diff --git a/e2e/input_template/EquipementPhysique_serveur.csv b/e2e/input_template/EquipementPhysique_serveur.csv
new file mode 100644
index 0000000000000000000000000000000000000000..21333d8a4f0c061d0502056dd0543e8799190eb9
--- /dev/null
+++ b/e2e/input_template/EquipementPhysique_serveur.csv
@@ -0,0 +1,101 @@
+nomEquipementPhysique;modele;quantite;nomCourtDatacenter;dateAchat;dateRetrait;type;statut;paysDUtilisation;consoElecAnnuelle;utilisateur;nomSourceDonnee;nomEntite;nbCoeur;nbJourUtiliseAn;goTelecharge;modeUtilisation;tauxUtilisation
+physical-eq-srv-001;blade-server--28;7;default;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-002;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;10;;
+physical-eq-srv-003;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;20;;
+physical-eq-srv-004;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;30;;
+physical-eq-srv-005;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;40;;
+physical-eq-srv-006;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;50;;
+physical-eq-srv-007;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-008;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-009;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-010;DATACENTER;2;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-011;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-012;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-013;DATACENTER;1;F1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-014;DATACENTER;1;G1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-015;DATACENTER;1;G1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-016;DATACENTER;1;G1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-017;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-018;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-019;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-020;DATACENTER;8;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-021;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-022;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-023;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-024;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-025;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-026;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-027;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-028;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-029;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-030;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-031;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-032;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-033;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-034;DATACENTER;1;X1;2016-06-17;2023-06-16;Server;In use;;;;;;;365;;;
+physical-eq-srv-035;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-036;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-037;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-038;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-039;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-040;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-041;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-042;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-043;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-044;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-045;DATACENTER;26;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-046;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-047;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-048;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-049;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-050;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-051;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-052;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-053;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-054;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-055;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-056;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-057;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-058;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-059;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-060;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-061;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-062;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-063;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-064;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-065;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-066;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-067;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-068;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-069;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-070;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-071;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-072;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-073;DATACENTER;1;Y1;2016-06-17;2023-06-16;Server;In use;Germany;;;;;;365;;;
+physical-eq-srv-074;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-075;DATACENTER;122;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-076;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-077;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-078;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-079;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-080;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-081;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-082;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-083;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-084;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-085;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-086;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-087;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-088;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-089;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-090;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-091;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-092;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-093;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-094;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-095;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-096;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-097;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-098;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-099;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
+physical-eq-srv-100;DATACENTER;1;Z2;2016-06-17;2023-06-16;Server;In use;France;;;;;;365;;;
diff --git a/e2e/input_template/EquipementVirtuel.csv b/e2e/input_template/EquipementVirtuel.csv
new file mode 100644
index 0000000000000000000000000000000000000000..c6754843426419c199945428bddb65f052f3ee2a
--- /dev/null
+++ b/e2e/input_template/EquipementVirtuel.csv
@@ -0,0 +1,2 @@
+nomEquipementVirtuel;nomEquipementPhysique;nomSourceDonneeEquipementPhysique;cleRepartition;vCPU;cluster;consoElecAnnuelle;typeEqv;capaciteStockage;nomEntite;nomSourceDonnee
+virtual-eq-;physical-eq-srv-;;;##VCPU##;##TYPE_EQV##;;calcul;;;;
diff --git a/e2e/performance-test.sh b/e2e/performance-test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..31a9b4a426a901a2b1026928d344cb732a3d6528
--- /dev/null
+++ b/e2e/performance-test.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Call: sh performance-test.sh
+# Call: sh performance-test.sh E2E auto auto SYNC
+# Call: sh performance-test.sh 1 orgX perf ASYNC
+
+SCENARIO=${1:-E2E}
+ORGANISATION=${2:-auto}
+LOT_PREFIX=${3:-auto}
+MODE=${4:-SYNC}
+
+. ./.env
+
+# CONSTANTS
+ARR_DATASET=(${E2E// /,} ${XS// /,} ${S// /,} ${M// /,} ${L// /,} ${XL// /,})
+ARR_MAPPING=(E2E XS S M L XL)
+
+if [ "${ORGANISATION}" = "auto" ];then ORGANISATION=org;fi
+if [ "${LOT_PREFIX}" = "auto" ];then LOT_PREFIX=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 5);fi
+
+if [ -d reports ]; then rm -rf reports; fi
+mkdir reports
+echo ${HEADER_RESULT} >reports/result.csv
+echo ${HEADER_DETAIL} >reports/detail.csv
+
+cfg_scenario="SCENARIO_${SCENARIO}"
+echo "Config scenario: $cfg_scenario = ${!cfg_scenario}"
+i=0
+for nbIt in ${!cfg_scenario}; do
+    dataset=${ARR_MAPPING[$i]}
+    dataset_detail=${ARR_DATASET[$i]}
+    i=$((i + 1))
+    if [ "${nbIt}" = "0" ]; then continue; fi
+    dataset_size_mb=0
+    dataset_size_line=0
+    ### Generate dataset ###
+    echo "launch dataset ($dataset), detail : $dataset_detail"
+    sh 2_generate_dataset.sh ${dataset_detail//,/ }
+    dataset_size_mb=$(cat data/sizes.csv | grep TOTAL | cut -d',' -f2)
+    dataset_size_line=$(cat data/sizes.csv | grep TOTAL | cut -d',' -f3)
+    mv data/sizes.csv reports/sizes_${dataset}.csv
+    start=$(date +%s)
+    for ((j = 1; j <= $nbIt; j++)); do
+        ### For each iteration load input, submit calculations and check ###
+        echo "*** Organisation: $ORGANISATION, NomLot: ${LOT_PREFIX}_${dataset}_${j} ***"
+        sh 3_load_input.sh $ORGANISATION ${LOT_PREFIX}_${dataset}_${j} $SCENARIO $MODE
+        start_it=$(date +%s)
+        sh 4_check.sh $ORGANISATION ${LOT_PREFIX}_${dataset}_${j}
+        end_it=$(date +%s)
+        elapsed_it_sec=$(($end_it - $start_it))
+        mv progress.log reports/${LOT_PREFIX}_${dataset}_${j}.log
+        echo "$dataset,$j,$elapsed_it_sec" >>reports/detail.csv
+    done
+    end=$(date +%s)
+    elapsed_sec=$(($end - $start))
+    echo "$dataset,$dataset_size_mb,$dataset_size_line,$nbIt,$(($elapsed_sec / $nbIt)),$elapsed_sec" >>reports/result.csv
+done
+
+cat reports/result.csv
+
+if [ "${SCENARIO}" = "E2E" ]; then
+    sh 5_assert.sh $ORGANISATION ${LOT_PREFIX}_E2E_1
+fi
diff --git a/e2e/utils.sh b/e2e/utils.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f20bcb4109d6c4b2ed15d5c5ef6d5064652a3706
--- /dev/null
+++ b/e2e/utils.sh
@@ -0,0 +1,7 @@
+function log() {
+    echo "$(date +'%Y-%m-%d %H:%M:%S.%3N') - $@"
+}
+
+function log_n() {
+    echo -n "$(date +'%Y-%m-%d %H:%M:%S.%3N') - $@"
+}
\ No newline at end of file
diff --git a/services/.workspace/.idea/.gitignore b/services/.workspace/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..9f6f15d55351c49ffc929ed6f50eedd95af38699
--- /dev/null
+++ b/services/.workspace/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+sonarlint/
+libraries/
\ No newline at end of file
diff --git a/services/.workspace/.idea/codeStyles/Project.xml b/services/.workspace/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000000000000000000000000000000000000..919ce1f1f77253454105acb2aad9997c1047a0e6
--- /dev/null
+++ b/services/.workspace/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <ScalaCodeStyleSettings>
+      <option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
+    </ScalaCodeStyleSettings>
+  </code_scheme>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/codeStyles/codeStyleConfig.xml b/services/.workspace/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a55e7a179bde3e4e772c29c0c85e53354aa54618
--- /dev/null
+++ b/services/.workspace/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+  </state>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/compiler.xml b/services/.workspace/.idea/compiler.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f846159834d25b6c569ec6503c8ee672b8e3994e
--- /dev/null
+++ b/services/.workspace/.idea/compiler.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="true" />
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+      </profile>
+      <profile name="Annotation profile for api-expositiondonneesentrees" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <processorPath useClasspath="false">
+          <entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct-processor/1.5.3.Final/mapstruct-processor-1.5.3.Final.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/mapstruct/mapstruct/1.5.3.Final/mapstruct-1.5.3.Final.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.26/lombok-1.18.26.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok-mapstruct-binding/0.2.0/lombok-mapstruct-binding-0.2.0.jar" />
+          <entry name="$MAVEN_REPOSITORY$/com/github/therapi/therapi-runtime-javadoc-scribe/0.15.0/therapi-runtime-javadoc-scribe-0.15.0.jar" />
+          <entry name="$MAVEN_REPOSITORY$/com/github/therapi/therapi-runtime-javadoc/0.15.0/therapi-runtime-javadoc-0.15.0.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/instancio/instancio-processor/2.2.0/instancio-processor-2.2.0.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/instancio/instancio-core/2.2.0/instancio-core-2.2.0.jar" />
+          <entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.1.0/annotations-23.1.0.jar" />
+        </processorPath>
+        <module name="api-referentiel" />
+        <module name="api-event-indicateurs" />
+        <module name="common" />
+        <module name="api-event-enrichissement" />
+        <module name="api-rest-caculs" />
+        <module name="calculs" />
+        <module name="api-expositiondonneesentrees" />
+        <module name="api-event-calculs" />
+        <module name="api-event-donneesEntrees" />
+      </profile>
+    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="api-event-calcul-indicateurs" target="17" />
+      <module name="api-event-enrichissement" target="17" />
+      <module name="api-expositionDonneesEntrees" target="17" />
+    </bytecodeTargetLevel>
+  </component>
+  <component name="JavacSettings">
+    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
+      <module name="api-event-calculs" options="-parameters" />
+      <module name="api-event-donneesEntrees" options="-parameters" />
+      <module name="api-expositiondonneesentrees" options="-parameters" />
+      <module name="api-referentiel" options="-parameters" />
+      <module name="api-rest-caculs" options="-parameters" />
+      <module name="calculs" options="-parameters" />
+      <module name="common" options="-parameters" />
+      <module name="core" options="-parameters" />
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/encodings.xml b/services/.workspace/.idea/encodings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1351da803246c3e4a2e67f186add05e231787aaf
--- /dev/null
+++ b/services/.workspace/.idea/encodings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/../api-event-calculs/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-event-calculs/target/generated-sources/src/gen/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-event-donneesentrees/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-expositiondonneesentrees/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-expositiondonneesentrees/target/generated-sources/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-expositiondonneesentrees/target/generated-sources/src/gen/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-referentiel/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../api-referentiel/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../calculs/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../calculs/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../common/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../common/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../common/target/generated-sources/src/gen/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../core/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/../core/src/main/resources" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/inspectionProfiles/Project_Default.xml b/services/.workspace/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..49881a89f8c15de04dedde5f1283f83076d0d428
--- /dev/null
+++ b/services/.workspace/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="MavenCoroutinesDeprecation" enabled="false" level="ERROR" enabled_by_default="false" />
+  </profile>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/jarRepositories.xml b/services/.workspace/.idea/jarRepositories.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6e9089d5710be85f86a10e8dd7857a972a3ed06
--- /dev/null
+++ b/services/.workspace/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="https://repo.maven.apache.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="gitlab-maven" />
+      <option name="name" value="gitlab-maven" />
+      <option name="url" value="https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/groups/5389/-/packages/maven" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="gitlab-maven" />
+      <option name="name" value="gitlab-maven" />
+      <option name="url" value="https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven" />
+    </remote-repository>
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/misc.xml b/services/.workspace/.idea/misc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7363f2addc2ae079b7a7bae6dc57cb306cd08ee4
--- /dev/null
+++ b/services/.workspace/.idea/misc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/../api-event-calculs/pom.xml" />
+        <option value="$PROJECT_DIR$/../common/pom.xml" />
+        <option value="$PROJECT_DIR$/../core/pom.xml" />
+        <option value="$PROJECT_DIR$/../api-event-donneesentrees/pom.xml" />
+        <option value="$PROJECT_DIR$/../api-expositiondonneesentrees/pom.xml" />
+        <option value="$PROJECT_DIR$/../calculs/pom.xml" />
+        <option value="$PROJECT_DIR$/../api-referentiel/pom.xml" />
+      </list>
+    </option>
+    <option name="workspaceImportForciblyTurnedOn" value="true" />
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/modules.xml b/services/.workspace/.idea/modules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b4f71b368614e1b88ac4fdfbdd5ea72860dd5bb4
--- /dev/null
+++ b/services/.workspace/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/../../e2e/e2e.iml" filepath="$PROJECT_DIR$/../../e2e/e2e.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/ApiEventCalculsApplication.xml b/services/.workspace/.idea/runConfigurations/ApiEventCalculsApplication.xml
new file mode 100644
index 0000000000000000000000000000000000000000..91c2210a2f2cfd137b33b8df9422cc393ecf19c4
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/ApiEventCalculsApplication.xml
@@ -0,0 +1,16 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ApiEventCalculsApplication" type="Application" factoryName="Application" nameIsGenerated="true">
+    <option name="MAIN_CLASS_NAME" value="org.mte.numecoeval.calculs.ApiEventCalculsApplication" />
+    <module name="api-event-calculs" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../api-event-calculs" />
+    <extension name="coverage">
+      <pattern>
+        <option name="PATTERN" value="org.mte.numecoeval.calculs.*" />
+        <option name="ENABLED" value="true" />
+      </pattern>
+    </extension>
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/ApiEventDonneesEntreesApplication.xml b/services/.workspace/.idea/runConfigurations/ApiEventDonneesEntreesApplication.xml
new file mode 100644
index 0000000000000000000000000000000000000000..371f810de8d61de48a880e5129ba629f2a35ae88
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/ApiEventDonneesEntreesApplication.xml
@@ -0,0 +1,16 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ApiEventDonneesEntreesApplication" type="Application" factoryName="Application" nameIsGenerated="true">
+    <option name="MAIN_CLASS_NAME" value="org.mte.numecoeval.donneesentrees.ApiEventDonneesEntreesApplication" />
+    <module name="api-event-donneesEntrees" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../api-event-donneesentrees" />
+    <extension name="coverage">
+      <pattern>
+        <option name="PATTERN" value="org.mte.numecoeval.donneesentrees.*" />
+        <option name="ENABLED" value="true" />
+      </pattern>
+    </extension>
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/ExpositionDonneesEntreesApplication.xml b/services/.workspace/.idea/runConfigurations/ExpositionDonneesEntreesApplication.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1887099d4cbdbbac06f593074c2259ca7401ff22
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/ExpositionDonneesEntreesApplication.xml
@@ -0,0 +1,16 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ExpositionDonneesEntreesApplication" type="Application" factoryName="Application" nameIsGenerated="true">
+    <option name="MAIN_CLASS_NAME" value="org.mte.numecoeval.expositiondonneesentrees.ExpositionDonneesEntreesApplication" />
+    <module name="api-expositiondonneesentrees" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../api-expositiondonneesentrees" />
+    <extension name="coverage">
+      <pattern>
+        <option name="PATTERN" value="org.mte.numecoeval.expositiondonneesentrees.*" />
+        <option name="ENABLED" value="true" />
+      </pattern>
+    </extension>
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/Init.xml b/services/.workspace/.idea/runConfigurations/Init.xml
new file mode 100644
index 0000000000000000000000000000000000000000..298b23be8ee2a0d00d7fa4216cfd3ef740e57359
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/Init.xml
@@ -0,0 +1,10 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="Init" type="CompoundRunConfigurationType">
+    <toRun name="api-event-calculs [gen-sources]" type="MavenRunConfiguration" />
+    <toRun name="api-expositiondonneesentrees [gen-sources]" type="MavenRunConfiguration" />
+    <toRun name="install calculs" type="MavenRunConfiguration" />
+    <toRun name="install common" type="MavenRunConfiguration" />
+    <toRun name="install core" type="MavenRunConfiguration" />
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/ReferentielApplication.xml b/services/.workspace/.idea/runConfigurations/ReferentielApplication.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0ad2a37b92ab3286bdde6a44d21c56e0aa9eb826
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/ReferentielApplication.xml
@@ -0,0 +1,16 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ReferentielApplication" type="Application" factoryName="Application" nameIsGenerated="true">
+    <option name="MAIN_CLASS_NAME" value="org.mte.numecoeval.referentiel.ReferentielApplication" />
+    <module name="api-referentiel" />
+    <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../api-referentiel" />
+    <extension name="coverage">
+      <pattern>
+        <option name="PATTERN" value="org.mte.numecoeval.referentiel.*" />
+        <option name="ENABLED" value="true" />
+      </pattern>
+    </extension>
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/Run.xml b/services/.workspace/.idea/runConfigurations/Run.xml
new file mode 100644
index 0000000000000000000000000000000000000000..02cda4ac1c8c18c24510e6be5b9b344736aa28a6
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/Run.xml
@@ -0,0 +1,9 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="Run" type="CompoundRunConfigurationType">
+    <toRun name="ApiEventCalculsApplication" type="Application" />
+    <toRun name="ApiEventDonneesEntreesApplication" type="Application" />
+    <toRun name="ExpositionDonneesEntreesApplication" type="Application" />
+    <toRun name="ReferentielApplication" type="Application" />
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/api_event_calculs__gen_sources_.xml b/services/.workspace/.idea/runConfigurations/api_event_calculs__gen_sources_.xml
new file mode 100644
index 0000000000000000000000000000000000000000..af7bfa9f7ac6f008811d8da85534a6f465b76adf
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/api_event_calculs__gen_sources_.xml
@@ -0,0 +1,47 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="api-event-calculs [gen-sources]" type="MavenRunConfiguration" factoryName="Maven">
+    <MavenSettings>
+      <option name="myGeneralSettings" />
+      <option name="myRunnerSettings">
+        <MavenRunnerSettings>
+          <option name="delegateBuildToMaven" value="false" />
+          <option name="environmentProperties">
+            <map />
+          </option>
+          <option name="jreName" value="temurin-17" />
+          <option name="mavenProperties">
+            <map />
+          </option>
+          <option name="passParentEnv" value="true" />
+          <option name="runMavenInBackground" value="true" />
+          <option name="skipTests" value="false" />
+          <option name="vmOptions" value="" />
+        </MavenRunnerSettings>
+      </option>
+      <option name="myRunnerParameters">
+        <MavenRunnerParameters>
+          <option name="cmdOptions" />
+          <option name="profiles">
+            <set />
+          </option>
+          <option name="goals">
+            <list>
+              <option value="generate-sources" />
+            </list>
+          </option>
+          <option name="multimoduleDir" />
+          <option name="pomFileName" />
+          <option name="profilesMap">
+            <map />
+          </option>
+          <option name="projectsCmdOptionValues">
+            <list />
+          </option>
+          <option name="resolveToWorkspace" value="false" />
+          <option name="workingDirPath" value="$PROJECT_DIR$/../api-event-calculs" />
+        </MavenRunnerParameters>
+      </option>
+    </MavenSettings>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/api_expositiondonneesentrees__gen_sources_.xml b/services/.workspace/.idea/runConfigurations/api_expositiondonneesentrees__gen_sources_.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89a394ebdd0c2167359695ce572b55d7013e2f4e
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/api_expositiondonneesentrees__gen_sources_.xml
@@ -0,0 +1,47 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="api-expositiondonneesentrees [gen-sources]" type="MavenRunConfiguration" factoryName="Maven">
+    <MavenSettings>
+      <option name="myGeneralSettings" />
+      <option name="myRunnerSettings">
+        <MavenRunnerSettings>
+          <option name="delegateBuildToMaven" value="false" />
+          <option name="environmentProperties">
+            <map />
+          </option>
+          <option name="jreName" value="temurin-17" />
+          <option name="mavenProperties">
+            <map />
+          </option>
+          <option name="passParentEnv" value="true" />
+          <option name="runMavenInBackground" value="true" />
+          <option name="skipTests" value="false" />
+          <option name="vmOptions" value="" />
+        </MavenRunnerSettings>
+      </option>
+      <option name="myRunnerParameters">
+        <MavenRunnerParameters>
+          <option name="cmdOptions" />
+          <option name="profiles">
+            <set />
+          </option>
+          <option name="goals">
+            <list>
+              <option value="generate-sources" />
+            </list>
+          </option>
+          <option name="multimoduleDir" />
+          <option name="pomFileName" />
+          <option name="profilesMap">
+            <map />
+          </option>
+          <option name="projectsCmdOptionValues">
+            <list />
+          </option>
+          <option name="resolveToWorkspace" value="false" />
+          <option name="workingDirPath" value="$PROJECT_DIR$/../api-expositiondonneesentrees" />
+        </MavenRunnerParameters>
+      </option>
+    </MavenSettings>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/install_calculs.xml b/services/.workspace/.idea/runConfigurations/install_calculs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d8b53028f2762392a24a01911a7bb5555cd6d5cf
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/install_calculs.xml
@@ -0,0 +1,47 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="install calculs" type="MavenRunConfiguration" factoryName="Maven">
+    <MavenSettings>
+      <option name="myGeneralSettings" />
+      <option name="myRunnerSettings">
+        <MavenRunnerSettings>
+          <option name="delegateBuildToMaven" value="false" />
+          <option name="environmentProperties">
+            <map />
+          </option>
+          <option name="jreName" value="temurin-17" />
+          <option name="mavenProperties">
+            <map />
+          </option>
+          <option name="passParentEnv" value="true" />
+          <option name="runMavenInBackground" value="true" />
+          <option name="skipTests" value="false" />
+          <option name="vmOptions" value="" />
+        </MavenRunnerSettings>
+      </option>
+      <option name="myRunnerParameters">
+        <MavenRunnerParameters>
+          <option name="cmdOptions" />
+          <option name="profiles">
+            <set />
+          </option>
+          <option name="goals">
+            <list>
+              <option value="install" />
+            </list>
+          </option>
+          <option name="multimoduleDir" />
+          <option name="pomFileName" />
+          <option name="profilesMap">
+            <map />
+          </option>
+          <option name="projectsCmdOptionValues">
+            <list />
+          </option>
+          <option name="resolveToWorkspace" value="false" />
+          <option name="workingDirPath" value="$PROJECT_DIR$/../calculs" />
+        </MavenRunnerParameters>
+      </option>
+    </MavenSettings>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/install_common.xml b/services/.workspace/.idea/runConfigurations/install_common.xml
new file mode 100644
index 0000000000000000000000000000000000000000..86ce6c8478833e04599599b7cf14b495f23f70ce
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/install_common.xml
@@ -0,0 +1,47 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="install common" type="MavenRunConfiguration" factoryName="Maven">
+    <MavenSettings>
+      <option name="myGeneralSettings" />
+      <option name="myRunnerSettings">
+        <MavenRunnerSettings>
+          <option name="delegateBuildToMaven" value="false" />
+          <option name="environmentProperties">
+            <map />
+          </option>
+          <option name="jreName" value="temurin-17" />
+          <option name="mavenProperties">
+            <map />
+          </option>
+          <option name="passParentEnv" value="true" />
+          <option name="runMavenInBackground" value="true" />
+          <option name="skipTests" value="false" />
+          <option name="vmOptions" value="" />
+        </MavenRunnerSettings>
+      </option>
+      <option name="myRunnerParameters">
+        <MavenRunnerParameters>
+          <option name="cmdOptions" />
+          <option name="profiles">
+            <set />
+          </option>
+          <option name="goals">
+            <list>
+              <option value="install" />
+            </list>
+          </option>
+          <option name="multimoduleDir" />
+          <option name="pomFileName" />
+          <option name="profilesMap">
+            <map />
+          </option>
+          <option name="projectsCmdOptionValues">
+            <list />
+          </option>
+          <option name="resolveToWorkspace" value="false" />
+          <option name="workingDirPath" value="$PROJECT_DIR$/../common" />
+        </MavenRunnerParameters>
+      </option>
+    </MavenSettings>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/runConfigurations/install_core.xml b/services/.workspace/.idea/runConfigurations/install_core.xml
new file mode 100644
index 0000000000000000000000000000000000000000..104f7ef69e0b2a705a3034cce45e074cd9d0864f
--- /dev/null
+++ b/services/.workspace/.idea/runConfigurations/install_core.xml
@@ -0,0 +1,47 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="install core" type="MavenRunConfiguration" factoryName="Maven">
+    <MavenSettings>
+      <option name="myGeneralSettings" />
+      <option name="myRunnerSettings">
+        <MavenRunnerSettings>
+          <option name="delegateBuildToMaven" value="false" />
+          <option name="environmentProperties">
+            <map />
+          </option>
+          <option name="jreName" value="temurin-17" />
+          <option name="mavenProperties">
+            <map />
+          </option>
+          <option name="passParentEnv" value="true" />
+          <option name="runMavenInBackground" value="true" />
+          <option name="skipTests" value="false" />
+          <option name="vmOptions" value="" />
+        </MavenRunnerSettings>
+      </option>
+      <option name="myRunnerParameters">
+        <MavenRunnerParameters>
+          <option name="cmdOptions" />
+          <option name="profiles">
+            <set />
+          </option>
+          <option name="goals">
+            <list>
+              <option value="install" />
+            </list>
+          </option>
+          <option name="multimoduleDir" />
+          <option name="pomFileName" />
+          <option name="profilesMap">
+            <map />
+          </option>
+          <option name="projectsCmdOptionValues">
+            <list />
+          </option>
+          <option name="resolveToWorkspace" value="false" />
+          <option name="workingDirPath" value="$PROJECT_DIR$/../core" />
+        </MavenRunnerParameters>
+      </option>
+    </MavenSettings>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/services/.workspace/.idea/saveactions_settings.xml b/services/.workspace/.idea/saveactions_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..898dbf8532d66ffc2f4694b0f05eb607626ebe1d
--- /dev/null
+++ b/services/.workspace/.idea/saveactions_settings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="SaveActionSettings">
+    <option name="actions">
+      <set>
+        <option value="activate" />
+        <option value="organizeImports" />
+        <option value="reformat" />
+      </set>
+    </option>
+    <option name="configurationPath" value="" />
+    <option name="exclusions">
+      <set>
+        <option value=".*\.yaml" />
+        <option value=".*\.yml" />
+      </set>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/uiDesigner.xml b/services/.workspace/.idea/uiDesigner.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2b63946d5b31084bbb7dda418ceb3d75eb686373
--- /dev/null
+++ b/services/.workspace/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/.idea/vcs.xml b/services/.workspace/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b2bdec2d71b6a5ce4ae49efc37516809c50e4d5e
--- /dev/null
+++ b/services/.workspace/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/services/.workspace/settings.xml b/services/.workspace/settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9a2cc6f3efa9dd1e37462aa6e66e685c52f5c4b5
--- /dev/null
+++ b/services/.workspace/settings.xml
@@ -0,0 +1,19 @@
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
+    <localRepository/>
+    <interactiveMode/>
+    <offline/>
+    <pluginGroups/>
+    <servers/>
+    <mirrors/>
+    <proxies>
+        <!--<proxy>
+            <id>proxy</id>
+            <active>true</active>
+            <protocol>http</protocol>
+            <host>host</host>
+            <port>8080</port>
+        </proxy>-->
+    </proxies>
+    <activeProfiles/>
+</settings>
\ No newline at end of file
diff --git a/services/api-event-calculs/.gitignore b/services/api-event-calculs/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..549e00a2a96fa9d7c5dbc9859664a78d980158c2
--- /dev/null
+++ b/services/api-event-calculs/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/api-event-calculs/LICENSE.txt b/services/api-event-calculs/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/services/api-event-calculs/LICENSE.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/services/api-event-calculs/README.md b/services/api-event-calculs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..09cb1504dd39ba316d6125a9775961523c03b872
--- /dev/null
+++ b/services/api-event-calculs/README.md
@@ -0,0 +1,2 @@
+# api-event-calculs
+
diff --git a/services/api-event-calculs/dependency_check_suppressions.xml b/services/api-event-calculs/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15f53bbc9ca0caa969e8cf94333045ac34dbd899
--- /dev/null
+++ b/services/api-event-calculs/dependency_check_suppressions.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-security-crypto-5.7.3.jar
+   La librairie Spring Security est en version 5.7.3.
+   Cette CVE est marquée uniquement jusqu'à la version 5.2.4 (exclus)
+   https://nvd.nist.gov/vuln/detail/CVE-2020-5408
+   ]]></notes>
+        <cve>CVE-2020-5408</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-web-5.3.22.jar
+   Dans notre contexte, nous ne recevons pas de code Java de l'extérieur et n'effectuons pas de dé-sérialisation de code Java
+   Côté Spring, le point est déjà remonté comme un faux-positif : https://github.com/spring-projects/spring-framework/issues/24434#issuecomment-744519525
+   ]]></notes>
+        <cve>CVE-2016-1000027</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: snakeyaml-1.33.jar
+   Faux-positif : la version de Snakeyaml est la 1.33, la CVE existe uniquement sur les versions < 1.32
+   https://nvd.nist.gov/vuln/detail/CVE-2022-38752
+   ]]></notes>
+        <cve>CVE-2022-38752</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif sur toutes les librairies utils: https://github.com/jeremylong/DependencyCheck/issues/5213
+   Concerne : software.amazon.awssdk:utils qui n'est pas utilisé
+   ]]></notes>
+        <cve>CVE-2021-4277</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif : matchent à tort sur tous les commons : https://github.com/jeremylong/DependencyCheck/issues/5132
+   ]]></notes>
+        <cve>CVE-2021-37533</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+    et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-1471</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-3064</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2021-4235</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Concerne hutool-json et json-java qui ne sont pas utilisés.
+   Le faux-positif se trouve sur json-path, jackson-core, accessors-smart et json-smart.
+   cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2022-45688</cve>
+    </suppress>
+
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Conformément au lien, nous ne sommes pas dans un des cas de vulnérabilité.
+   cf. cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2023-20862</cve>
+    </suppress>
+</suppressions>
diff --git a/services/api-event-calculs/pom.xml b/services/api-event-calculs/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a8e43c638ead97e0a46b84428cfab9b2db372366
--- /dev/null
+++ b/services/api-event-calculs/pom.xml
@@ -0,0 +1,288 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <artifactId>api-event-calculs</artifactId>
+    <name>api-event-calculs</name>
+    <version>1.2.3-SNAPSHOT</version>
+    <description>api-event-calculs</description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>calculs</artifactId>
+            <version>1.2.3-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- Security -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- Mapping -->
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+        </dependency>
+
+        <!-- Utilitaire -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Swagger-UI -->
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.openapitools</groupId>
+                <artifactId>openapi-generator-maven-plugin</artifactId>
+                <version>${openapi-generator-version}</version>
+                <executions>
+                    <execution>
+                        <id>generation_client_referentiel</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/../common/src/main/resources/static/api-referentiels-openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.calculs.referentiels.generated.api.model</modelPackage>
+                            <apiPackage>org.mte.numecoeval.calculs.referentiels.generated.api.client</apiPackage>
+                            <invokerPackage>org.mte.numecoeval.calculs.referentiels.generated.api.invoker
+                            </invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>true</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>java</generatorName>
+                            <library>webclient</library>
+                            <configOptions>
+                                <useJakartaEe>true</useJakartaEe>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>true</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>generation_calculs_rest</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/../common/src/main/resources/static/api-event-calculs-async-openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.calculs.rest.generated.api.model</modelPackage>
+                            <apiPackage>org.mte.numecoeval.calculs.rest.generated.api.server</apiPackage>
+                            <invokerPackage>org.mte.numecoeval.calculs.rest.generated.api.invoker</invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>false</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>spring</generatorName>
+                            <library>spring-boot</library>
+                            <configOptions>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <dateLibrary>java8-localdatetime</dateLibrary>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>false</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                                <additionalModelTypeAnnotations>
+                                    @lombok.AllArgsConstructor;@lombok.Builder;@lombok.NoArgsConstructor
+                                </additionalModelTypeAnnotations>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>generation_sync_calculs_rest</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/../common/src/main/resources/static/api-event-calculs-sync-openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.calculs.sync.generated.api.model</modelPackage>
+                            <apiPackage>org.mte.numecoeval.calculs.sync.generated.api.server</apiPackage>
+                            <invokerPackage>org.mte.numecoeval.calculs.sync.generated.api.invoker</invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>false</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>spring</generatorName>
+                            <library>spring-boot</library>
+                            <configOptions>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <dateLibrary>java8-localdatetime</dateLibrary>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>false</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                                <additionalModelTypeAnnotations>
+                                    @lombok.AllArgsConstructor;@lombok.Builder;@lombok.NoArgsConstructor
+                                </additionalModelTypeAnnotations>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/ApiEventCalculsApplication.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/ApiEventCalculsApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..83f4e5af70dacde70128180c62c2ec66b4ca2ac2
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/ApiEventCalculsApplication.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.calculs;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ApiEventCalculsApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ApiEventCalculsApplication.class, args);
+    }
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/DatabaseException.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/DatabaseException.java
new file mode 100644
index 0000000000000000000000000000000000000000..76f005a73dcd94625a67f3fceb05e795981cba3a
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/DatabaseException.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.calculs.domain.exception;
+
+public class DatabaseException extends RuntimeException {
+
+    /**
+     * Constructor with no arg
+     */
+    public DatabaseException() {
+        super();
+    }
+
+    /**
+     * Constructor with cause
+     */
+    public DatabaseException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/ExternalApiException.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/ExternalApiException.java
new file mode 100644
index 0000000000000000000000000000000000000000..484324187a879042c5b8e0281426848c20832b70
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/ExternalApiException.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.calculs.domain.exception;
+
+public class ExternalApiException extends RuntimeException {
+
+    /**
+     * Constructor with no arg
+     */
+    public ExternalApiException() {
+        super();
+    }
+
+    /**
+     * Constructor with cause
+     */
+    public ExternalApiException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculEquipementPhysique.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..170b5cd6c8be19d23c70ea9ed1e14e2d61ab1472
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculEquipementPhysique.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.calculs.domain.model;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.*;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+
+import java.util.List;
+
+@NoArgsConstructor
+@Getter
+@Setter
+public class CalculEquipementPhysique {
+    private List<EtapeDTO> etapes;
+    private List<CritereDTO> criteres;
+    private List<HypotheseDTO> hypotheses;
+    private CorrespondanceRefEquipementDTO correspondanceRefEquipement;
+    private EquipementPhysiqueDTO equipementPhysique;
+    private TypeEquipementDTO typeEquipement;
+    private List<MixElectriqueDTO> mixElectriques;
+    private List<ImpactReseauDTO> impactsReseau;
+    private List<ImpactEquipementDTO> impactsEquipement;
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculMessagerie.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4ff1d57509db49bc7194a26e13d738eabdee7ac
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculMessagerie.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.calculs.domain.model;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.CritereDTO;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.ImpactMessagerieDTO;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+
+import java.util.List;
+
+@NoArgsConstructor
+@Getter
+@Setter
+public class CalculMessagerie {
+    private MessagerieDTO messagerie;
+    private List<CritereDTO> criteres;
+    private List<ImpactMessagerieDTO> impactsMessagerie;
+}
+
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd90d22d26ce0924e171aee5bad07cbfd30d997a
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.calculs.domain.model;
+
+import lombok.Data;
+
+@Data
+public class CalculSizes {
+    private long nbEquipementPhysique;
+    private long nbEquipementVirtuel;
+    private long nbApplication;
+    private long nbMessagerie;
+    private long nbIndicateurEquipementPhysique;
+    private long nbIndicateurEquipementVirtuel;
+    private long nbIndicateurApplication;
+    private long nbIndicateurReseau;
+    private long nbIndicateurMessagerie;
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..92f1d225ca88f9bfc4996c7ead8aec7a343267a5
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java
@@ -0,0 +1,133 @@
+package org.mte.numecoeval.calculs.infrastructure.client;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.exception.ExternalApiException;
+import org.mte.numecoeval.calculs.referentiels.generated.api.client.InterneNumEcoEvalApi;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.*;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class ReferentielClient {
+
+    private InterneNumEcoEvalApi interneNumEcoEvalApi;
+
+    @Cacheable("Etapes")
+    public List<EtapeDTO> getEtapes() {
+
+        try {
+            var result = interneNumEcoEvalApi.getAllEtapes().collectList().block();
+            return result == null ? List.of() : result;
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return List.of();
+    }
+
+    @Cacheable("Criteres")
+    public List<CritereDTO> getCriteres() {
+        try {
+            var result = interneNumEcoEvalApi.getAllCriteres().collectList().block();
+            return result == null ? List.of() : result;
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return List.of();
+    }
+
+    @Cacheable(value = "Hypothese")
+    public HypotheseDTO getHypothese(String code) {
+        try {
+            return interneNumEcoEvalApi.getHypothese(code).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "CorrespondanceRefEquipement")
+    public CorrespondanceRefEquipementDTO getCorrespondanceRefEquipement(String modele) {
+        try {
+            return interneNumEcoEvalApi.getCorrespondanceRefEquipement(modele).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "TypeEquipement")
+    public TypeEquipementDTO getTypeEquipement(String type) {
+        try {
+            return interneNumEcoEvalApi.getTypeEquipement(type).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "ImpactEquipement")
+    public ImpactEquipementDTO getImpactEquipement(String refEquipement, String critere, String etape) {
+        try {
+            return interneNumEcoEvalApi.getImpactEquipement(refEquipement, critere, etape).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "ImpactReseau")
+    public ImpactReseauDTO getImpactReseau(String refReseau, String critere, String etape) {
+        try {
+            return interneNumEcoEvalApi.getImpactReseau(refReseau, critere, etape).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "MixElectrique")
+    public MixElectriqueDTO getMixElectrique(String pays, String critere) {
+        if (pays == null || critere == null) return null;
+        try {
+            return interneNumEcoEvalApi.getMixElectrique(pays, critere).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+
+    @Cacheable(value = "ImpactMessagerie")
+    public ImpactMessagerieDTO getMessagerie(String critere) {
+        try {
+            return interneNumEcoEvalApi.getImpactMessagerie(critere).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatusCode.valueOf(404)) {
+                throw new ExternalApiException(e);
+            }
+        }
+        return null;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab24eb9dae3b196dd930f13184bd9d683861350f
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@EnableCaching
+@EnableScheduling
+@Configuration
+@Profile("!test")
+public class CacheConfig {
+
+    @CacheEvict(value = {
+            "Etapes",
+            "Criteres",
+            "Hypothese",
+            "TypeEquipement",
+            "CorrespondanceRefEquipement",
+            "ImpactEquipement",
+            "ImpactReseau",
+            "MixElectrique",
+            "ImpactMessagerie",
+    }, allEntries = true)
+    @Scheduled(fixedRateString = "${numecoeval.cache.ttl}", timeUnit = TimeUnit.MINUTES)
+    public void emptyAllCaches() {
+        log.info("Nettoyage de tous les caches internes");
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CommonIntegrationConfig.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CommonIntegrationConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..13f7154b4bbebce5b2bb5138daa8207674db7cef
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CommonIntegrationConfig.java
@@ -0,0 +1,31 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.referentiels.generated.api.client.InterneNumEcoEvalApi;
+import org.mte.numecoeval.calculs.referentiels.generated.api.invoker.ApiClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Configuration
+@Slf4j
+public class CommonIntegrationConfig {
+
+    @Value("${numecoeval.referentiels.url}")
+    String referentielUrl;
+
+    @Bean
+    public InterneNumEcoEvalApi clientAPIReferentiel() {
+        InterneNumEcoEvalApi interneNumEcoEvalApi = new InterneNumEcoEvalApi();
+        ApiClient apiClient = new ApiClient(WebClient.builder()
+                .baseUrl(referentielUrl)
+                .build());
+        apiClient.setBasePath(referentielUrl);
+        interneNumEcoEvalApi.setApiClient(apiClient);
+
+        log.info("Création du client d'API Référentiel sur l'URL {}", referentielUrl);
+
+        return interneNumEcoEvalApi;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..0986a1d432c9c31a0044b6d0794c73a835021b1a
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.mte.numecoeval.calculs.domain.port.input.service.*;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DomainConfiguration {
+
+    @Bean
+    public DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService() {
+        return new DureeDeVieEquipementPhysiqueServiceImpl();
+    }
+
+    @Bean
+    public CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService(DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService, ObjectMapper objectMapper) {
+        return new CalculImpactEquipementPhysiqueServiceImpl(
+                dureeDeVieEquipementPhysiqueService,
+                objectMapper
+        );
+    }
+
+    @Bean
+    CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService(ObjectMapper objectMapper) {
+        return new CalculImpactEquipementVirtuelServiceImpl(objectMapper);
+    }
+
+    @Bean
+    CalculImpactApplicationService calculImpactApplicationService(ObjectMapper objectMapper) {
+        return new CalculImpactApplicationServiceImpl(objectMapper);
+    }
+
+
+    @Bean
+    public CalculImpactReseauService calculImpactReseauService(ObjectMapper objectMapper) {
+        return new CalculImpactReseauServiceImpl(
+                objectMapper
+        );
+    }
+
+    @Bean
+    CalculImpactMessagerieService calculImpactMessagerieService(ObjectMapper objectMapper) {
+        return new CalculImpactMessagerieServiceImpl(objectMapper);
+    }
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/KafkaConfiguration.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/KafkaConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a23a8d1d72256fb6312671b2ead4b4d6a1dd5bd
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/KafkaConfiguration.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.listener.DefaultErrorHandler;
+import org.springframework.util.backoff.FixedBackOff;
+
+@Configuration
+@Slf4j
+public class KafkaConfiguration {
+
+    @Value("${spring.kafka.back-off-sec}")
+    private String backOffSec;
+
+    @Bean
+    DefaultErrorHandler defaultErrorHandler() {
+        return new DefaultErrorHandler(
+                (rec, ex) -> log.error("Erreur kafka: {}", rec, ex),
+                new FixedBackOff(Long.parseLong(backOffSec), Integer.MAX_VALUE)
+        );
+    }
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/OpenApiConfiguration.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/OpenApiConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..85e6d7f0a80eabba58397efe9d0673eb544d5929
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/OpenApiConfiguration.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class OpenApiConfiguration {
+
+    @Bean
+    GroupedOpenApi calculsApi() {
+        return GroupedOpenApi.builder().group("calculs").pathsToMatch("/calculs/**").build();
+    }
+
+    @Bean
+    GroupedOpenApi syncApi() {
+        return GroupedOpenApi.builder().group("sync").pathsToMatch("/sync/**").build();
+    }
+
+    @Bean
+    GroupedOpenApi indicateurApi() {
+        return GroupedOpenApi.builder().group("indicateurs").pathsToMatch("/indicateur/**").build();
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/SecurityConfiguration.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/SecurityConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1ba34b5741f0b5b21dfbbf234505213ce002b10
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/SecurityConfiguration.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.calculs.infrastructure.config;
+
+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.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.SecurityFilterChain;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfiguration {
+
+    @Bean
+    SecurityFilterChain globalFilterChain(HttpSecurity http) throws Exception {
+        http
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+                .and()
+                .cors()
+                .and()
+                .authorizeHttpRequests(authz -> authz
+                        .requestMatchers("/health").permitAll()
+                        .requestMatchers("/**").permitAll()
+                )
+                .csrf().disable()
+                .formLogin().disable()
+        ;
+        return http.build();
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/ExceptionHandler.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/ExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9bd236f0749bf3557ae5e533e058d680b86ce9c
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/ExceptionHandler.java
@@ -0,0 +1,65 @@
+package org.mte.numecoeval.calculs.infrastructure.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactRuntimeException;
+import org.mte.numecoeval.calculs.rest.generated.api.model.ErreurRest;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.context.request.WebRequest;
+
+import java.time.LocalDateTime;
+
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+
+@Slf4j
+@RestControllerAdvice
+public class ExceptionHandler {
+
+    /**
+     * writer error message
+     *
+     * @param ex     excepetion
+     * @param status le statut http
+     * @return l'objet erreur
+     */
+    private static ErreurRest writeErrorResponse(Exception ex, HttpStatus status) {
+        return ErreurRest.builder()
+                .status(status.value())
+                .code(status.name())
+                .timestamp(LocalDateTime.now())
+                .message(ex.getLocalizedMessage()).build();
+    }
+
+    @org.springframework.web.bind.annotation.ExceptionHandler(value = {CalculImpactException.class})
+    @ResponseStatus(value = BAD_REQUEST)
+    public ErreurRest calculImpactException(Exception ex, WebRequest request) {
+        return writeErrorResponse(ex, BAD_REQUEST);
+    }
+
+    @org.springframework.web.bind.annotation.ExceptionHandler(value = {CalculImpactRuntimeException.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErreurRest calculImpactRuntimeException(Exception ex, WebRequest request) {
+        return writeErrorResponse(ex, INTERNAL_SERVER_ERROR);
+    }
+
+    @org.springframework.web.bind.annotation.ExceptionHandler(value = {RuntimeException.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErreurRest runtimeException(Exception ex, WebRequest request) {
+        log.error("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        log.debug("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
+    }
+
+    @org.springframework.web.bind.annotation.ExceptionHandler(value = {Exception.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErreurRest exception(Exception ex, WebRequest request) {
+        log.error("Exception lors d'un traitement sur l'URI {} : {}", request.getContextPath(), ex.getMessage());
+        log.debug("Exception lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
+    }
+
+}
+
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3b51d7325945f1397e17058fbe5199df32975de
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java
@@ -0,0 +1,159 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.export;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@RestController
+@Slf4j
+@Profile("!prod & !test")
+@RequestMapping("indicateur")
+public class IndicateurController {
+
+    private static final int MAX_ROWS = 100_000;
+
+    @Autowired
+    private DataSource dataSource;
+
+    @GetMapping("/equipementPhysiqueCsv")
+    public String getEquipementPhysiqueList(
+            @RequestParam String nomLot,
+            @RequestParam String nomOrganisation,
+            @RequestParam String fields
+    ) {
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement(String.format("""
+                    SELECT %s
+                    FROM ind_indicateur_impact_equipement_physique
+                    WHERE nom_lot = ? AND nom_organisation = ?
+                    ORDER BY nom_equipement, critere, etapeacv;
+                    """, fields))) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomOrganisation);
+                return resultSetToCsv(ps.executeQuery());
+            }
+        } catch (SQLException e) {
+            log.error("SQl exception", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    @GetMapping("/equipementVirtuelCsv")
+    public String getEquipementVirtuelList(
+            @RequestParam String nomLot,
+            @RequestParam String nomOrganisation,
+            @RequestParam String fields
+    ) {
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement(String.format("""
+                    SELECT %s
+                    FROM ind_indicateur_impact_equipement_virtuel
+                    WHERE nom_lot = ? AND nom_organisation = ?
+                    ORDER BY nom_equipement, nom_equipement_virtuel, critere, etapeacv;
+                    """, fields))) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomOrganisation);
+                return resultSetToCsv(ps.executeQuery());
+            }
+        } catch (SQLException e) {
+            log.error("SQl exception", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    @GetMapping("/applicationCsv")
+    public String getApplicationList(
+            @RequestParam String nomLot,
+            @RequestParam String nomOrganisation,
+            @RequestParam String fields
+    ) {
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement(String.format("""
+                    SELECT %s
+                    FROM ind_indicateur_impact_application
+                    WHERE nom_lot = ? AND nom_organisation = ?
+                    ORDER BY nom_equipement_physique, nom_equipement_virtuel, nom_application, critere, etapeacv;
+                    """, fields))) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomOrganisation);
+                return resultSetToCsv(ps.executeQuery());
+            }
+        } catch (SQLException e) {
+            log.error("SQl exception", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    @GetMapping("/reseauCsv")
+    public String getReseauList(
+            @RequestParam String nomLot,
+            @RequestParam String nomOrganisation,
+            @RequestParam String fields
+    ) {
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement(String.format("""
+                    SELECT %s
+                    FROM ind_indicateur_impact_reseau
+                    WHERE nom_lot = ? AND nom_organisation = ?
+                    ORDER BY nom_equipement, critere, etapeacv;
+                    """, fields))) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomOrganisation);
+                return resultSetToCsv(ps.executeQuery());
+            }
+        } catch (SQLException e) {
+            log.error("SQl exception", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String resultSetToCsv(ResultSet rs) throws SQLException {
+        List<String> lines = new ArrayList<>();
+
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int numCols = rsmd.getColumnCount();
+
+        List<String> header = new ArrayList<>();
+        for (int i = 1; i <= numCols; i++) header.add(rsmd.getColumnLabel(i));
+        lines.add(String.join(",", header));
+
+        int rows = 0;
+        while (rs.next()) {
+            rows++;
+            List<String> values = new ArrayList<>();
+            for (int i = 1; i <= numCols; i++) {
+                try {
+                    var value = rs.getDouble(i);
+                    values.add(String.valueOf(value));
+                } catch (Exception e) {
+                    var value = rs.getString(i);
+                    if (value == null) value = "";
+                    values.add(value);
+                }
+            }
+            lines.add(String.join(",", values));
+            if (rows >= MAX_ROWS) break;
+        }
+        return String.join("\n", lines);
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4b664a9246facabff8596ee11db75cca923a299
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactApplicationServiceImpl;
+import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper;
+import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService;
+import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculApplicationRest;
+import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactApplicationRest;
+import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsApplicationApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class CalculsApplicationController implements CalculsApplicationApi {
+
+    DomainMapper domainMapper;
+
+    ObjectMapper objectMapper;
+
+    CheckIndicateurService checkIndicateurService;
+
+    /**
+     * POST /calculs/application
+     *
+     * @param demandeCalculApplicationRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<IndicateurImpactApplicationRest> calculerImpactApplication(DemandeCalculApplicationRest demandeCalculApplicationRest) {
+        var demandeCalcul = domainMapper.toDomain(demandeCalculApplicationRest);
+
+        var indicateur = new CalculImpactApplicationServiceImpl(
+                objectMapper
+        ).calculImpactApplicatif(demandeCalcul);
+
+        return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ?
+                ResponseEntity.ok(domainMapper.toRest(indicateur)) :
+                ResponseEntity.badRequest().body(domainMapper.toRest(indicateur));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a74e53bba840542455b3c7bc349c8003cd49adfd
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementPhysiqueServiceImpl;
+import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper;
+import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService;
+import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculImpactEquipementPhysiqueRest;
+import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactEquipementPhysiqueRest;
+import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsEquipementPhysiqueApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class CalculsEquipementPhysiqueController implements CalculsEquipementPhysiqueApi {
+
+    DomainMapper domainMapper;
+
+    ObjectMapper objectMapper;
+
+    DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService;
+
+    CheckIndicateurService checkIndicateurService;
+    
+    /**
+     * POST /calculs/equipementPhysique
+     *
+     * @param demandeCalculImpactEquipementPhysiqueRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<IndicateurImpactEquipementPhysiqueRest> calculerImpactEquipementPhysique(DemandeCalculImpactEquipementPhysiqueRest demandeCalculImpactEquipementPhysiqueRest) {
+        var demandeCalcul = domainMapper.toDomain(demandeCalculImpactEquipementPhysiqueRest);
+
+        var indicateur = new CalculImpactEquipementPhysiqueServiceImpl(
+                dureeDeVieEquipementPhysiqueService,
+                objectMapper
+        ).calculerImpactEquipementPhysique(demandeCalcul);
+
+        return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ?
+                ResponseEntity.ok(domainMapper.toRest(indicateur)) :
+                ResponseEntity.badRequest().body(domainMapper.toRest(indicateur));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java
new file mode 100644
index 0000000000000000000000000000000000000000..66ee73ecc2cfa991cd242b33b5ae2914be564567
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementVirtuelServiceImpl;
+import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper;
+import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService;
+import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculEquipementVirtuelRest;
+import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactEquipementVirtuelRest;
+import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsEquipementVirtuelApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class CalculsEquipementVirtuelController implements CalculsEquipementVirtuelApi {
+
+    DomainMapper domainMapper;
+
+    ObjectMapper objectMapper;
+
+    CheckIndicateurService checkIndicateurService;
+    
+    /**
+     * POST /calculs/equipementVirtuel
+     *
+     * @param demandeCalculEquipementVirtuelRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<IndicateurImpactEquipementVirtuelRest> calculerImpactEquipementVirtuel(DemandeCalculEquipementVirtuelRest demandeCalculEquipementVirtuelRest) {
+        var demandeCalcul = domainMapper.toDomain(demandeCalculEquipementVirtuelRest);
+
+        var indicateur = new CalculImpactEquipementVirtuelServiceImpl(
+                objectMapper
+        ).calculerImpactEquipementVirtuel(demandeCalcul);
+
+        return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ?
+                ResponseEntity.ok(domainMapper.toRest(indicateur)) :
+                ResponseEntity.badRequest().body(domainMapper.toRest(indicateur));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java
new file mode 100644
index 0000000000000000000000000000000000000000..79ad2e4b542d225c16ee84ab94ea42efec0949a0
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactMessagerieServiceImpl;
+import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper;
+import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService;
+import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculMessagerieRest;
+import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactMessagerieRest;
+import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsMessagerieApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class CalculsMessagerieController implements CalculsMessagerieApi {
+
+    DomainMapper domainMapper;
+
+    ObjectMapper objectMapper;
+
+    CheckIndicateurService checkIndicateurService;
+
+    /**
+     * POST /calculs/messagerie
+     *
+     * @param demandeCalculMessagerieRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<IndicateurImpactMessagerieRest> calculerImpactMessagerie(DemandeCalculMessagerieRest demandeCalculMessagerieRest) {
+        var demandeCalcul = domainMapper.toDomain(demandeCalculMessagerieRest);
+
+        var indicateur = new CalculImpactMessagerieServiceImpl(
+                objectMapper
+        ).calculerImpactMessagerie(demandeCalcul);
+
+        return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ?
+                ResponseEntity.ok(domainMapper.toRest(indicateur)) :
+                ResponseEntity.badRequest().body(domainMapper.toRest(indicateur));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e7f8f8912cb2b3736076b48c4279ea85620bd03
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactReseauServiceImpl;
+import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper;
+import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService;
+import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculImpactReseauEquipementPhysiqueRest;
+import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactReseauRest;
+import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsReseauApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class CalculsReseauController implements CalculsReseauApi {
+
+    DomainMapper domainMapper;
+
+    ObjectMapper objectMapper;
+
+    CheckIndicateurService checkIndicateurService;
+    
+    /**
+     * POST /calculs/reseau/equipementPhysique
+     *
+     * @param demandeCalculImpactReseauEquipementPhysiqueRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<IndicateurImpactReseauRest> calculerImpactReseau(DemandeCalculImpactReseauEquipementPhysiqueRest demandeCalculImpactReseauEquipementPhysiqueRest) {
+        var demandeCalcul = domainMapper.toDomain(demandeCalculImpactReseauEquipementPhysiqueRest);
+
+        var indicateur = new CalculImpactReseauServiceImpl(
+                objectMapper
+        ).calculerImpactReseau(demandeCalcul);
+
+        return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ?
+                ResponseEntity.ok(domainMapper.toRest(indicateur)) :
+                ResponseEntity.badRequest().body(domainMapper.toRest(indicateur));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b1df0092404ef452c172c5602d5ec849c33c5d9
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.calculs.infrastructure.controller.sync.calculs;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.infrastructure.service.sync.calculs.SyncCalculService;
+import org.mte.numecoeval.calculs.sync.generated.api.model.ReponseCalculRest;
+import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest;
+import org.mte.numecoeval.calculs.sync.generated.api.server.CalculsEquipementPhysiqueEtMessagerieApi;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+public class SyncCalculsController implements CalculsEquipementPhysiqueEtMessagerieApi {
+
+    SyncCalculService syncCalculService;
+
+    /**
+     * POST /sync/calcul
+     *
+     * @param syncCalculRest (required)
+     * @return la liste d'indicateurs calcules
+     */
+    @Override
+    public ResponseEntity<ReponseCalculRest> syncCalculByIds(SyncCalculRest syncCalculRest) {
+        return ResponseEntity.ok(syncCalculService.calcul(syncCalculRest));
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenEquipementPhysique.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a4ed0778e1bae5d523431818c567d1092f19ea4
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenEquipementPhysique.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.calculs.infrastructure.kafkalistener;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+public class ListenEquipementPhysique {
+
+    private MainEquipementPhysiqueService mainEquipementPhysiqueService;
+
+    @KafkaListener(topics = "${numecoeval.topic.equipementPhysique}", concurrency = "${numecoeval.topic.partition}")
+    public void consume(EquipementPhysiqueDTO equipementPhysiqueDTO) {
+        mainEquipementPhysiqueService.calcul(equipementPhysiqueDTO);
+    }
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenMessagerie.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c94e031a3332550f20b8645128daac1b20f8692
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenMessagerie.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.calculs.infrastructure.kafkalistener;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+public class ListenMessagerie {
+
+    private MainMessagerieService mainMessagerieService;
+
+    @KafkaListener(topics = "${numecoeval.topic.messagerie}")
+    public void consume(MessagerieDTO messagerieDTO) {
+        mainMessagerieService.calcul(messagerieDTO);
+    }
+}
+
+
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5c6c049c9ec4b54b8de7e4e5b7475ec65e687dd
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java
@@ -0,0 +1,78 @@
+package org.mte.numecoeval.calculs.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mte.numecoeval.calculs.domain.data.demande.*;
+import org.mte.numecoeval.calculs.domain.data.entree.*;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.*;
+import org.mte.numecoeval.calculs.domain.data.referentiel.*;
+import org.mte.numecoeval.calculs.rest.generated.api.model.*;
+
+@Mapper(componentModel = "spring")
+public interface DomainMapper {
+
+    /*Entrées*/
+    EquipementPhysique toDomain(EquipementPhysiqueRest rest);
+
+    DataCenter toDomain(DataCenterRest rest);
+
+    EquipementVirtuel toDomain(EquipementVirtuelRest rest);
+
+    Application toDomain(ApplicationRest rest);
+
+    Messagerie toDomain(MessagerieRest rest);
+
+    /*Référentiels*/
+
+    ReferentielTypeEquipement toDomain(TypeEquipementRest rest);
+
+    ReferentielCorrespondanceRefEquipement toDomain(CorrespondanceRefEquipementRest rest);
+
+    ReferentielHypothese toDomain(HypotheseRest rest);
+
+    ReferentielEtapeACV toDomain(EtapeRest rest);
+
+    ReferentielCritere toDomain(CritereRest rest);
+
+    ReferentielImpactEquipement toDomain(ImpactEquipementRest rest);
+
+    @Mapping(source = "valeur", target = "impactReseauMobileMoyen")
+    ReferentielImpactReseau toDomain(ImpactReseauRest rest);
+
+    ReferentielMixElectrique toDomain(MixElectriqueRest rest);
+
+    ReferentielImpactMessagerie toDomain(ImpactMessagerieRest rest);
+
+    /*Indicateurs*/
+    ImpactEquipementPhysique toDomain(IndicateurImpactEquipementPhysiqueRest rest);
+
+    ImpactEquipementVirtuel toDomain(IndicateurImpactEquipementVirtuelRest rest);
+
+    ImpactApplication toDomain(IndicateurImpactApplicationRest rest);
+
+    IndicateurImpactEquipementPhysiqueRest toRest(ImpactEquipementPhysique domain);
+
+    IndicateurImpactEquipementVirtuelRest toRest(ImpactEquipementVirtuel domain);
+
+    IndicateurImpactApplicationRest toRest(ImpactApplication domain);
+
+    IndicateurImpactReseauRest toRest(ImpactReseau domain);
+
+    IndicateurImpactMessagerieRest toRest(ImpactMessagerie domain);
+
+    /*Demandes*/
+    @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())")
+    DemandeCalculImpactEquipementPhysique toDomain(DemandeCalculImpactEquipementPhysiqueRest rest);
+
+    @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())")
+    DemandeCalculImpactReseau toDomain(DemandeCalculImpactReseauEquipementPhysiqueRest rest);
+    
+    @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())")
+    DemandeCalculImpactEquipementVirtuel toDomain(DemandeCalculEquipementVirtuelRest rest);
+
+    @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())")
+    DemandeCalculImpactApplication toDomain(DemandeCalculApplicationRest rest);
+
+    @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())")
+    DemandeCalculImpactMessagerie toDomain(DemandeCalculMessagerieRest rest);
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..be2c6c0b8abde8a9f04c54f6d5109218c17f355c
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.calculs.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.calculs.domain.data.entree.DataCenter;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.entree.Messagerie;
+import org.mte.numecoeval.topic.data.DataCenterDTO;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+
+@Mapper(componentModel = "spring")
+public interface EntreesMapper {
+
+    EquipementPhysique toDomain(EquipementPhysiqueDTO dto);
+
+    DataCenter toDomain(DataCenterDTO dto);
+
+    Messagerie toDomain(MessagerieDTO messagerieDTO);
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6937550fd7a1828959e8792c1c29fe90ff8ba3d
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java
@@ -0,0 +1,41 @@
+package org.mte.numecoeval.calculs.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mte.numecoeval.calculs.domain.data.referentiel.*;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.*;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface ReferentielMapper {
+
+    ReferentielEtapeACV toEtape(EtapeDTO etapeDTO);
+
+    ReferentielCritere toCritere(CritereDTO critereDTO);
+
+    @Mapping(source = "valeur", target = "impactReseauMobileMoyen")
+    ReferentielImpactReseau toImpactReseau(ImpactReseauDTO impactReseauDTO);
+
+    List<ReferentielImpactReseau> toListImpactReseau(List<ImpactReseauDTO> impactReseauDTO);
+
+    ReferentielHypothese toHypothese(HypotheseDTO hypotheseDTO);
+
+    List<ReferentielHypothese> toListHypothese(List<HypotheseDTO> hypotheseDTO);
+
+    ReferentielImpactEquipement toImpactEquipement(ImpactEquipementDTO impactEquipementDTO);
+
+    List<ReferentielImpactEquipement> toListImpactEquipement(List<ImpactEquipementDTO> impactEquipementDTO);
+
+    ReferentielMixElectrique toMixElectrique(MixElectriqueDTO mixElectriqueDTO);
+
+    List<ReferentielMixElectrique> toListMixElectrique(List<MixElectriqueDTO> mixElectriqueDTO);
+
+    ReferentielImpactMessagerie toImpactMessagerie(ImpactMessagerieDTO impactMessagerieDTO);
+
+    List<ReferentielImpactMessagerie> toListImpactMessagerie(List<ImpactMessagerieDTO> impactMessagerieDTO);
+
+    ReferentielCorrespondanceRefEquipement toCorrespondanceRefEquipement(CorrespondanceRefEquipementDTO dto);
+
+    ReferentielTypeEquipement toTypeEquipement(TypeEquipementDTO dto);
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/ApplicationRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/ApplicationRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..574d05764f732caf79ca66be68ded28b90c637d2
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/ApplicationRepository.java
@@ -0,0 +1,66 @@
+package org.mte.numecoeval.calculs.infrastructure.repository;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Slf4j
+public class ApplicationRepository {
+
+    @Autowired
+    private DataSource dataSource;
+
+    public List<Application> findApplications(String nomOrganisation, String nomLot, String nomEquipementPhysique, String nomEquipementVirtuel) {
+        List<Application> result = new ArrayList<>();
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                    SELECT *
+                    FROM en_application
+                    WHERE
+                        nullif(nom_lot, ?) is null
+                        AND nom_equipement_virtuel = ?
+                        AND nom_equipement_physique = ?
+                        AND nullif(nom_organisation, ?) is null
+                    """)) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementVirtuel);
+                ps.setString(3, nomEquipementPhysique);
+                ps.setString(4, nomOrganisation);
+
+                var rs = ps.executeQuery();
+                while (rs.next()) {
+                    result.add(Application.builder()
+                            .nomLot(rs.getString("nom_lot"))
+                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                            .nomOrganisation(rs.getString("nom_organisation"))
+                            .nomEntite(rs.getString("nom_entite"))
+                            .nomEquipementPhysique(rs.getString("nom_equipement_physique"))
+                            .nomEquipementVirtuel(rs.getString("nom_equipement_virtuel"))
+                            .nomApplication(rs.getString("nom_application"))
+                            .typeEnvironnement(rs.getString("type_environnement"))
+                            .domaine(rs.getString("domaine"))
+                            .sousDomaine(rs.getString("sous_domaine"))
+                            .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                            .build());
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+
+        return result;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementPhysiqueRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementPhysiqueRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..11864627976fb6634c256a55dbb189a254781329
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementPhysiqueRepository.java
@@ -0,0 +1,110 @@
+package org.mte.numecoeval.calculs.infrastructure.repository;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.mte.numecoeval.topic.data.DataCenterDTO;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Slf4j
+public class EquipementPhysiqueRepository {
+
+    @Autowired
+    private DataSource dataSource;
+
+    private static final String COLUMN_NAME_NOM_COURT_DATACENTER = "nom_court_datacenter";
+
+    public List<EquipementPhysiqueDTO> findEquipementPhysiqueDTOs(List<Long> ids) {
+        List<EquipementPhysiqueDTO> result = new ArrayList<>();
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                       SELECT eqp.*,
+                          dc.id as dc_id,
+                          dc.date_creation as dc_date_creation,
+                          dc.date_update as dc_date_update,
+                          dc.localisation as dc_localisation,
+                          dc.nom_long_datacenter as dc_nom_long_datacenter,
+                          dc.pue as dc_pue,
+                          dc.nom_entite as dc_nom_entite
+                        FROM en_equipement_physique eqp
+                        LEFT JOIN en_data_center dc ON dc.nom_lot = eqp.nom_lot and dc.nom_court_datacenter = eqp.nom_court_datacenter
+                        WHERE eqp.id = ANY (?)
+                    """)) {
+
+                ps.setArray(1, conn.createArrayOf("long", ids.toArray(new Long[0])));
+
+                var rs = ps.executeQuery();
+                while (rs.next()) {
+                    result.add(EquipementPhysiqueDTO.builder()
+                            .id(rs.getLong("id"))
+                            .nomLot(rs.getString("nom_lot"))
+                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                            .nomOrganisation(rs.getString("nom_organisation"))
+                            .nomEntite(rs.getString("nom_entite"))
+                            .nomEquipementPhysique(rs.getString("nom_equipement_physique"))
+                            .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle"))
+                            .dateAchat(ResultSetUtils.getLocalDate(rs, "date_achat"))
+                            .dateRetrait(ResultSetUtils.getLocalDate(rs, "date_retrait"))
+                            .goTelecharge(ResultSetUtils.getFloat(rs, "go_telecharge"))
+                            .modele(rs.getString("modele"))
+                            .nbCoeur(rs.getString("nb_coeur"))
+                            .paysDUtilisation(rs.getString("pays_utilisation"))
+                            .quantite(ResultSetUtils.getDouble(rs, "quantite"))
+                            .serveur(rs.getBoolean("serveur"))
+                            .statut(rs.getString("statut"))
+                            .type(rs.getString("type"))
+                            .utilisateur(rs.getString("utilisateur"))
+                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
+                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
+                            .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                            .modeUtilisation(rs.getString("mode_utilisation"))
+                            .tauxUtilisation(ResultSetUtils.getDouble(rs, "taux_utilisation"))
+                            .dataCenter(
+                                    DataCenterDTO.builder()
+                                            .id(rs.getLong("dc_id"))
+                                            .localisation(rs.getString("dc_localisation"))
+                                            .nomLongDatacenter(rs.getString("dc_nom_long_datacenter"))
+                                            .pue(ResultSetUtils.getDouble(rs, "dc_pue"))
+                                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
+                                            .nomEntite(rs.getString("dc_nom_entite"))
+                                            .nomOrganisation(rs.getString("nom_organisation"))
+                                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                                            .build()
+                            )
+                            .build());
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+
+        return result;
+    }
+
+    public void setStatutToTraite(Long id) {
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                    UPDATE en_equipement_physique
+                    SET statut_traitement = 'TRAITE', date_update = now()
+                    WHERE id = ?
+                    """)) {
+                ps.setLong(1, id);
+                ps.execute();
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementVirtuelRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementVirtuelRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..574c2c8c595bca2261f9b89e9eca28cdd4251bfd
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/EquipementVirtuelRepository.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.calculs.infrastructure.repository;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Slf4j
+public class EquipementVirtuelRepository {
+
+    @Autowired
+    private DataSource dataSource;
+
+    public List<EquipementVirtuel> findEquipementVirtuels(String nomOrganisation, String nomLot, String nomEquipementPhysique) {
+        List<EquipementVirtuel> result = new ArrayList<>();
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                     SELECT *
+                     FROM en_equipement_virtuel
+                     WHERE
+                         nullif(nom_lot, ?) is null
+                         AND nom_equipement_physique = ?
+                         AND nullif(nom_organisation, ?) is null
+                    """)) {
+
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementPhysique);
+                ps.setString(3, nomOrganisation);
+
+                var rs = ps.executeQuery();
+                while (rs.next()) {
+                    result.add(EquipementVirtuel.builder()
+                            .id(rs.getLong("id"))
+                            .nomLot(rs.getString("nom_lot"))
+                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                            .nomOrganisation(rs.getString("nom_organisation"))
+                            .nomEntite(rs.getString("nom_entite"))
+                            .nomEquipementPhysique(rs.getString("nom_equipement_physique"))
+                            .nomEquipementVirtuel(rs.getString("nom_equipement_virtuel"))
+                            .cluster(rs.getString("cluster"))
+                            .vCPU(ResultSetUtils.getInteger(rs, "vcpu"))
+                            .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle"))
+                            .typeEqv(rs.getString("type_eqv"))
+                            .capaciteStockage(ResultSetUtils.getDouble(rs, "capacite_stockage"))
+                            .cleRepartition(ResultSetUtils.getDouble(rs, "cle_repartition"))
+                            .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                            .build());
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+
+        return result;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..388d866fb95fbd6ececfd17160af9fd1a51f0faf
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java
@@ -0,0 +1,327 @@
+package org.mte.numecoeval.calculs.infrastructure.repository;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.*;
+import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
+import org.mte.numecoeval.common.utils.PreparedStatementUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Optional;
+
+@Component
+@Slf4j
+public class IndicateurRepository {
+
+    @Autowired
+    private DataSource dataSource;
+
+    private static final String INSERT_EQUIPEMENT_PHYSIQUE_QUERY = """
+               INSERT INTO ind_indicateur_impact_equipement_physique
+                         (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator, etapeacv,
+                           critere, nom_equipement, nom_entite, nom_entite_discriminator, source,
+                           statut_indicateur, trace, version_calcul, conso_elec_moyenne,
+                           impact_unitaire, quantite, type_equipement, unite,
+                           statut_equipement_physique, nom_lot, nom_source_donnee, nom_source_donnee_discriminator)
+                         VALUES (?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?)
+            """;
+
+    private static final String INSERT_EQUIPEMENT_VIRTUEL_QUERY = """
+               INSERT INTO ind_indicateur_impact_equipement_virtuel
+                    (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator,
+                      etapeacv, critere, nom_equipement, nom_equipement_virtuel, nom_entite, nom_entite_discriminator, 
+                      source, statut_indicateur, trace, version_calcul, impact_unitaire, unite, conso_elec_moyenne, 
+                      cluster, nom_lot, nom_source_donnee, nom_source_donnee_discriminator )
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+            """;
+
+    private static final String INSERT_APPLICATION_QUERY = """
+            INSERT INTO ind_indicateur_impact_application
+                    (date_calcul, date_lot, date_lot_discriminator, etapeacv, critere, nom_organisation,
+                     nom_organisation_discriminator, nom_application, type_environnement, nom_equipement_physique,
+                     nom_equipement_virtuel, nom_entite, nom_entite_discriminator, source, statut_indicateur, trace,
+                     version_calcul, domaine, sous_domaine, impact_unitaire, unite, conso_elec_moyenne, nom_lot,
+                     nom_source_donnee, nom_source_donnee_discriminator)
+                VALUES (?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?,?, ?, ?, ?)
+            """;
+
+    private static final String INSERT_MESSAGERIE_QUERY = """
+            INSERT INTO ind_indicateur_impact_messagerie
+                (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator,
+                critere, mois_annee, nom_entite, nom_entite_discriminator, source, statut_indicateur, trace,
+                version_calcul, impact_mensuel, unite, nombre_mail_emis, volume_total_mail_emis, nom_lot,
+                nom_source_donnee, nom_source_donnee_discriminator)
+                VALUES (?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?)
+            """;
+
+    private static final String INSERT_RESEAU_QUERY = """
+                INSERT INTO ind_indicateur_impact_reseau
+                        (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator,
+                        etapeacv, critere, nom_equipement, nom_entite, nom_entite_discriminator, source, statut_indicateur,
+                        trace, version_calcul, impact_unitaire, unite, nom_lot, nom_source_donnee, nom_source_donnee_discriminator)
+                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+            """;
+
+    /**
+     * Sauvegarde tous les indicateurs en base de données e
+     *
+     * @param impactsEquipementPhysique liste des impacts Eq Ph
+     * @param impactsEquipementVirtuels liste des impacts Eq Virt
+     * @param impactsApplications       liste des impacts applications
+     */
+    public void saveIndicateursEquipements(
+            List<ImpactEquipementPhysique> impactsEquipementPhysique,
+            List<ImpactEquipementVirtuel> impactsEquipementVirtuels,
+            List<ImpactApplication> impactsApplications,
+            List<ImpactReseau> impactsReseau
+    ) {
+        if (impactsEquipementPhysique.isEmpty()) return;
+
+        try (Connection conn = dataSource.getConnection()) {
+            conn.setAutoCommit(false);
+
+            try (var ps = conn.prepareStatement(INSERT_EQUIPEMENT_PHYSIQUE_QUERY)) {
+                for (ImpactEquipementPhysique indicateur : impactsEquipementPhysique) {
+                    ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul()));
+                    ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot()));
+                    ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH)));
+                    ps.setString(4, indicateur.getNomOrganisation());
+                    ps.setString(5, StringUtils.defaultString(indicateur.getNomOrganisation()));
+                    ps.setString(6, indicateur.getEtapeACV());
+                    ps.setString(7, indicateur.getCritere());
+                    ps.setString(8, indicateur.getNomEquipement());
+                    ps.setString(9, indicateur.getNomEntite());
+                    ps.setString(10, StringUtils.defaultString(indicateur.getNomEntite()));
+                    ps.setString(11, indicateur.getSource());
+                    ps.setString(12, indicateur.getStatutIndicateur());
+                    ps.setString(13, indicateur.getTrace());
+                    ps.setString(14, indicateur.getVersionCalcul());
+                    PreparedStatementUtils.setDoubleValue(ps, 15, indicateur.getConsoElecMoyenne());
+                    PreparedStatementUtils.setDoubleValue(ps, 16, indicateur.getImpactUnitaire());
+                    PreparedStatementUtils.setIntValue(ps, 17, indicateur.getQuantite().intValue());
+                    ps.setString(18, indicateur.getTypeEquipement());
+                    ps.setString(19, indicateur.getUnite());
+                    ps.setString(20, indicateur.getStatutEquipementPhysique());
+                    ps.setString(21, indicateur.getNomLot());
+                    ps.setString(22, indicateur.getNomSourceDonnee());
+                    ps.setString(23, StringUtils.defaultString(indicateur.getNomSourceDonnee()));
+                    ps.addBatch();
+                }
+
+                ps.executeBatch();
+            }
+            try (var ps = conn.prepareStatement(INSERT_EQUIPEMENT_VIRTUEL_QUERY)) {
+                for (ImpactEquipementVirtuel indicateur : impactsEquipementVirtuels) {
+                    ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul()));
+                    ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot()));
+                    ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH)));
+                    ps.setString(4, indicateur.getNomOrganisation());
+                    ps.setString(5, StringUtils.defaultString(indicateur.getNomOrganisation()));
+                    ps.setString(6, indicateur.getEtapeACV());
+                    ps.setString(7, indicateur.getCritere());
+                    ps.setString(8, indicateur.getNomEquipement());
+                    ps.setString(9, indicateur.getNomEquipementVirtuel());
+                    ps.setString(10, indicateur.getNomEntite());
+                    ps.setString(11, StringUtils.defaultString(indicateur.getNomEntite()));
+                    ps.setString(12, indicateur.getSource());
+                    ps.setString(13, indicateur.getStatutIndicateur());
+                    ps.setString(14, indicateur.getTrace());
+                    ps.setString(15, indicateur.getVersionCalcul());
+                    PreparedStatementUtils.setDoubleValue(ps, 16, indicateur.getImpactUnitaire());
+                    ps.setString(17, indicateur.getUnite());
+                    PreparedStatementUtils.setDoubleValue(ps, 18, indicateur.getConsoElecMoyenne());
+                    ps.setString(19, indicateur.getCluster());
+                    ps.setString(20, indicateur.getNomLot());
+                    ps.setString(21, indicateur.getNomSourceDonnee());
+                    ps.setString(22, StringUtils.defaultString(indicateur.getNomSourceDonnee()));
+                    ps.addBatch();
+                }
+
+                ps.executeBatch();
+            }
+
+            try (var ps = conn.prepareStatement(INSERT_APPLICATION_QUERY)) {
+                for (ImpactApplication indicateur : impactsApplications) {
+                    ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul()));
+                    ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot()));
+                    ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH)));
+                    ps.setString(4, indicateur.getEtapeACV());
+                    ps.setString(5, indicateur.getCritere());
+                    ps.setString(6, indicateur.getNomOrganisation());
+                    ps.setString(7, StringUtils.defaultString(indicateur.getNomOrganisation()));
+                    ps.setString(8, indicateur.getNomApplication());
+                    ps.setString(9, indicateur.getTypeEnvironnement());
+                    ps.setString(10, indicateur.getNomEquipementPhysique());
+                    ps.setString(11, indicateur.getNomEquipementVirtuel());
+                    ps.setString(12, indicateur.getNomEntite());
+                    ps.setString(13, StringUtils.defaultString(indicateur.getNomEntite()));
+                    ps.setString(14, indicateur.getSource());
+                    ps.setString(15, indicateur.getStatutIndicateur());
+                    ps.setString(16, indicateur.getTrace());
+                    ps.setString(17, indicateur.getVersionCalcul());
+                    ps.setString(18, indicateur.getDomaine());
+                    ps.setString(19, indicateur.getSousDomaine());
+                    PreparedStatementUtils.setDoubleValue(ps, 20, indicateur.getImpactUnitaire());
+                    ps.setString(21, indicateur.getUnite());
+                    PreparedStatementUtils.setDoubleValue(ps, 22, indicateur.getConsoElecMoyenne());
+                    ps.setString(23, indicateur.getNomLot());
+                    ps.setString(24, indicateur.getNomSourceDonnee());
+                    ps.setString(25, StringUtils.defaultString(indicateur.getNomSourceDonnee()));
+                    ps.addBatch();
+                }
+
+                ps.executeBatch();
+            }
+
+            try (var ps = conn.prepareStatement(INSERT_RESEAU_QUERY)) {
+
+                for (ImpactReseau indicateur : impactsReseau) {
+                    ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul()));
+                    ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot()));
+                    ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH)));
+                    ps.setString(4, indicateur.getNomOrganisation());
+                    ps.setString(5, StringUtils.defaultString(indicateur.getNomOrganisation()));
+                    ps.setString(6, indicateur.getEtapeACV());
+                    ps.setString(7, indicateur.getCritere());
+                    ps.setString(8, indicateur.getNomEquipement());
+                    ps.setString(9, indicateur.getNomEntite());
+                    ps.setString(10, StringUtils.defaultString(indicateur.getNomEntite()));
+                    ps.setString(11, indicateur.getSource());
+                    ps.setString(12, indicateur.getStatutIndicateur());
+                    ps.setString(13, indicateur.getTrace());
+                    ps.setString(14, indicateur.getVersionCalcul());
+                    PreparedStatementUtils.setDoubleValue(ps, 15, indicateur.getImpactUnitaire());
+                    ps.setString(16, indicateur.getUnite());
+                    ps.setString(17, indicateur.getNomLot());
+                    ps.setString(18, indicateur.getNomSourceDonnee());
+                    ps.setString(19, StringUtils.defaultString(indicateur.getNomSourceDonnee()));
+                    ps.addBatch();
+                }
+
+                ps.executeBatch();
+            }
+
+            conn.commit();
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de l'insertion dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+    }
+
+    /**
+     * Sauvegarde tous les indicateurs 'messagerie' en base de données
+     *
+     * @param impactMessageries liste indicateurs messagerie
+     */
+    public void saveIndicateursMessagerie(List<ImpactMessagerie> impactMessageries) {
+        if (impactMessageries.isEmpty()) return;
+
+        try (Connection conn = dataSource.getConnection()) {
+            conn.setAutoCommit(false);
+
+            try (var ps = conn.prepareStatement(INSERT_MESSAGERIE_QUERY)) {
+
+                for (ImpactMessagerie indicateur : impactMessageries) {
+                    ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul()));
+                    ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot()));
+                    ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH)));
+                    ps.setString(4, indicateur.getNomOrganisation());
+                    ps.setString(5, StringUtils.defaultString(indicateur.getNomOrganisation()));
+                    ps.setString(6, indicateur.getCritere());
+                    ps.setDate(7, PreparedStatementUtils.getDateFromLocalDate(moisAnneeToLocalDate(indicateur.getMoisAnnee())));
+                    ps.setString(8, indicateur.getNomEntite());
+                    ps.setString(9, StringUtils.defaultString(indicateur.getNomEntite()));
+                    ps.setString(10, indicateur.getSource());
+                    ps.setString(11, indicateur.getStatutIndicateur());
+                    ps.setString(12, indicateur.getTrace());
+                    ps.setString(13, indicateur.getVersionCalcul());
+                    PreparedStatementUtils.setDoubleValue(ps, 14, indicateur.getImpactMensuel());
+                    ps.setString(15, indicateur.getUnite());
+                    PreparedStatementUtils.setDoubleValue(ps, 16, indicateur.getNombreMailEmis());
+                    PreparedStatementUtils.setDoubleValue(ps, 17, indicateur.getVolumeTotalMailEmis());
+                    ps.setString(18, indicateur.getNomLot());
+                    ps.setString(19, indicateur.getNomSourceDonnee());
+                    ps.setString(20, StringUtils.defaultString(indicateur.getNomSourceDonnee()));
+                    ps.addBatch();
+                }
+
+                ps.executeBatch();
+            }
+
+            conn.commit();
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de l'insertion dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+    }
+
+    private LocalDate moisAnneeToLocalDate(Integer moisAnnee) {
+        if (moisAnnee == null) return null;
+        try {
+            return LocalDate.parse(moisAnnee + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+        } catch (DateTimeParseException ignored) {
+            return null;
+        }
+    }
+
+    /**
+     * Supprime les indicateurs des equipements physiques, virtuel et applications
+     *
+     * @param nomEquipementPhysique le nom de l'equipement physique
+     * @param nomLot                le nomLot
+     */
+    public void clearIndicateurs(String nomEquipementPhysique, String nomLot) {
+
+        try (Connection conn = dataSource.getConnection()) {
+            conn.setAutoCommit(false);
+
+            try (var ps = conn.prepareStatement("""
+                    DELETE FROM ind_indicateur_impact_equipement_physique
+                    WHERE nom_lot = ? AND nom_equipement = ?
+                    """)) {
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementPhysique);
+                ps.execute();
+            }
+
+            try (var ps = conn.prepareStatement("""
+                    DELETE FROM ind_indicateur_impact_equipement_virtuel
+                    WHERE nom_lot = ? AND nom_equipement = ?
+                    """)) {
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementPhysique);
+                ps.execute();
+            }
+
+            try (var ps = conn.prepareStatement("""
+                    DELETE FROM ind_indicateur_impact_application
+                    WHERE nom_lot = ? AND nom_equipement_physique = ?
+                    """)) {
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementPhysique);
+                ps.execute();
+            }
+
+            try (var ps = conn.prepareStatement("""
+                    DELETE FROM ind_indicateur_impact_reseau
+                    WHERE nom_lot = ? AND nom_equipement = ?
+                    """)) {
+                ps.setString(1, nomLot);
+                ps.setString(2, nomEquipementPhysique);
+                ps.execute();
+            }
+            conn.commit();
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de l'insertion dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/MessagerieRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/MessagerieRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..eab0052022f69c8aaa21fd4d0b0c3a2f4f533a2e
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/MessagerieRepository.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.calculs.infrastructure.repository;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Slf4j
+public class MessagerieRepository {
+
+    @Autowired
+    private DataSource dataSource;
+
+    public List<MessagerieDTO> findMessagerieDTOList(List<Long> ids) {
+        List<MessagerieDTO> result = new ArrayList<>();
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                        SELECT *
+                        FROM en_messagerie mes
+                        WHERE id = ANY (?)
+                    """)) {
+
+                ps.setArray(1, conn.createArrayOf("long", ids.toArray(new Long[0])));
+
+                var rs = ps.executeQuery();
+                while (rs.next()) {
+                    result.add(MessagerieDTO.builder()
+                            .id(rs.getLong("id"))
+                            .nomLot(rs.getString("nom_lot"))
+                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                            .nomOrganisation(rs.getString("nom_organisation"))
+                            .nomEntite(rs.getString("nom_entite"))
+                            .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                            .moisAnnee(rs.getInt("mois_annee"))
+                            .nombreMailEmis(ResultSetUtils.getInteger(rs, "nombre_mail_emis"))
+                            .nombreMailEmisXDestinataires(ResultSetUtils.getInteger(rs, "nombre_mail_emisxdestinataires"))
+                            .volumeTotalMailEmis(ResultSetUtils.getInteger(rs, "volume_total_mail_emis"))
+                            .build());
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+
+        return result;
+    }
+
+    public void setStatutToTraite(Long id) {
+        try (Connection conn = dataSource.getConnection()) {
+            try (var ps = conn.prepareStatement("""
+                    UPDATE en_messagerie
+                    SET statut_traitement = 'TRAITE', date_update = now()
+                    WHERE id = ?
+                    """)) {
+                ps.setLong(1, id);
+                ps.execute();
+            }
+        } catch (SQLException e) {
+            log.error("Une erreur s'est produite lors de la mise a jour dans PostgreSQL. Exception: ", e);
+            throw new DatabaseException(e);
+        }
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculApplicationService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculApplicationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..04c5481c265e3f1ea2eebedae287893d00e097ed
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculApplicationService.java
@@ -0,0 +1,45 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactApplicationService;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class CalculApplicationService {
+
+    CalculImpactApplicationService calculImpactApplicationService;
+
+    /**
+     * Calcule les impacts d'une application
+     * Returne la liste d'impacts à partir des impacts de son equipement virtuel
+     *
+     * @param impactEquipementVirtuelList la liste d'impact de l'equipement virtuel
+     * @param application                 l'application
+     * @param nbApplications              nombre d'application de l'équipement virtuel
+     * @return la liste d'impacts
+     */
+    public List<ImpactApplication> calculImpactApplication(List<ImpactEquipementVirtuel> impactEquipementVirtuelList, Application application, Integer nbApplications) {
+
+        if (impactEquipementVirtuelList.isEmpty()) return new ArrayList<>();
+
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        return impactEquipementVirtuelList.stream()
+                .map(impact -> calculImpactApplicationService.calculImpactApplicatif(
+                        DemandeCalculImpactApplication.builder()
+                                .dateCalcul(dateCalcul)
+                                .application(application)
+                                .nbApplications(nbApplications)
+                                .impactEquipementVirtuel(impact)
+                                .build()))
+                .toList();
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementPhysiqueService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementPhysiqueService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee3e0b4b7ca536e8de721301eead3d703323a7a1
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementPhysiqueService.java
@@ -0,0 +1,64 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.infrastructure.mapper.EntreesMapper;
+import org.mte.numecoeval.calculs.infrastructure.mapper.ReferentielMapper;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.CritereDTO;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.EtapeDTO;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class CalculEquipementPhysiqueService {
+
+    EntreesMapper entreesMapper;
+
+    ReferentielMapper referentielMapper;
+
+    CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService;
+
+    /**
+     * Calcule les impacts d'un equipement physique
+     * Returne la liste d'impacts en iterant par (etape, critere)
+     *
+     * @param calculEquipementPhysique l'equipement physique enrichi
+     * @return la liste d'impacts
+     */
+    public List<ImpactEquipementPhysique> calculImpactEquipementPhysique(CalculEquipementPhysique calculEquipementPhysique) {
+
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        List<ImpactEquipementPhysique> impactEquipementPhysiqueList = new ArrayList<>();
+
+        for (EtapeDTO etapeDTO : calculEquipementPhysique.getEtapes()) {
+            for (CritereDTO critereDTO : calculEquipementPhysique.getCriteres()) {
+
+                DemandeCalculImpactEquipementPhysique demandeCalculImpactEquipementPhysique = DemandeCalculImpactEquipementPhysique.builder()
+                        .dateCalcul(dateCalcul)
+                        .equipementPhysique(entreesMapper.toDomain(calculEquipementPhysique.getEquipementPhysique()))
+                        .etape(referentielMapper.toEtape(etapeDTO))
+                        .critere(referentielMapper.toCritere(critereDTO))
+                        .typeEquipement(referentielMapper.toTypeEquipement(calculEquipementPhysique.getTypeEquipement()))
+                        .correspondanceRefEquipement(referentielMapper.toCorrespondanceRefEquipement(calculEquipementPhysique.getCorrespondanceRefEquipement()))
+                        .hypotheses(referentielMapper.toListHypothese(calculEquipementPhysique.getHypotheses()))
+                        .mixElectriques(referentielMapper.toListMixElectrique(calculEquipementPhysique.getMixElectriques()))
+                        .impactEquipements(referentielMapper.toListImpactEquipement(calculEquipementPhysique.getImpactsEquipement()))
+                        .build();
+
+                impactEquipementPhysiqueList.add(
+                        calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalculImpactEquipementPhysique)
+                );
+            }
+        }
+        return impactEquipementPhysiqueList;
+
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b21fb270bb5ca5502ec23986c9403a9e5aa44d6
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelService.java
@@ -0,0 +1,88 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementVirtuelService;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Service
+@AllArgsConstructor
+public class CalculEquipementVirtuelService {
+
+    CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService;
+
+
+    /**
+     * Calcule les impacts d'un equipement virtuel
+     * Returne la liste d'impacts à partir des impacts de son equipement physique
+     *
+     * @param impactEquipementPhysiqueList la liste d'impact de l'equipement physique
+     * @param equipementVirtuel            l'equipement virtuel
+     * @param nbEquipementsVirtuels        nombre d'equipement virtuels lies a l'equipement physique
+     * @param nbTotalVCPU                  nombre total de vcpu de l'equipement physique
+     * @param stockageTotalVirtuel         stockage total
+     * @return la liste d'impacts
+     */
+    public List<ImpactEquipementVirtuel> calculImpactEquipementVirtuel(
+            List<ImpactEquipementPhysique> impactEquipementPhysiqueList,
+            EquipementVirtuel equipementVirtuel,
+            Integer nbEquipementsVirtuels,
+            Integer nbTotalVCPU,
+            Double stockageTotalVirtuel) {
+
+        if (impactEquipementPhysiqueList.isEmpty()) return new ArrayList<>();
+
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        return impactEquipementPhysiqueList.stream()
+                .map(impact -> calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(
+                        DemandeCalculImpactEquipementVirtuel.builder()
+                                .dateCalcul(dateCalcul)
+                                .equipementVirtuel(equipementVirtuel)
+                                .nbEquipementsVirtuels(nbEquipementsVirtuels)
+                                .nbTotalVCPU(nbTotalVCPU)
+                                .stockageTotalVirtuel(stockageTotalVirtuel)
+                                .impactEquipement(impact)
+                                .build()))
+                .toList();
+    }
+
+    /**
+     * Calcule le totalVCPU d'une liste d'équipements virtuels
+     * Somme le champs VCPU
+     *
+     * @param equipementVirtuelList la liste d'equipements virtuels
+     * @return le total de VCPU
+     */
+    public Integer getTotalVCPU(List<EquipementVirtuel> equipementVirtuelList) {
+        Integer totalVCPU = null;
+        if (equipementVirtuelList.stream().noneMatch(vm -> vm.getVCPU() == null || vm.getVCPU() == 0)) {
+            totalVCPU = equipementVirtuelList.stream().mapToInt(EquipementVirtuel::getVCPU).sum();
+        }
+
+        return totalVCPU;
+    }
+
+    /**
+     * Calcule le totalStockage d'une liste d'équipements virtuels
+     * Somme le champs capaciteStockage
+     *
+     * @param equipementVirtuelList la liste d'equipements virtuels
+     * @return le total de capaciteStockage
+     */
+    public Double getTotalStockage(List<EquipementVirtuel> equipementVirtuelList) {
+        Double totalStockage = null;
+        if (equipementVirtuelList.stream().noneMatch(vm -> vm.getCapaciteStockage() == null || vm.getCapaciteStockage() == 0)) {
+            totalStockage = equipementVirtuelList.stream().mapToDouble(EquipementVirtuel::getCapaciteStockage).sum();
+        }
+        return totalStockage;
+    }
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculMessagerieService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculMessagerieService.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c08209170f34fdd8a8bce795c612fd1a3e6588f
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculMessagerieService.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.model.CalculMessagerie;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactMessagerieService;
+import org.mte.numecoeval.calculs.infrastructure.mapper.EntreesMapper;
+import org.mte.numecoeval.calculs.infrastructure.mapper.ReferentielMapper;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class CalculMessagerieService {
+
+    EntreesMapper entreesMapper;
+    ReferentielMapper referentielMapper;
+
+    CalculImpactMessagerieService calculImpactMessagerieService;
+
+    /**
+     * Calcule les impacts d'une messagerie
+     * Returne la liste d'impacts
+     *
+     * @param calculMessagerie la messagerie enrichie
+     * @return la liste d'impacts
+     */
+    public List<ImpactMessagerie> calculImpactEquipementVirtuel(CalculMessagerie calculMessagerie) {
+
+        if (calculMessagerie.getCriteres() == null) return new ArrayList<>();
+
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        return calculMessagerie.getCriteres().stream()
+                .map(critereDTO -> calculImpactMessagerieService.calculerImpactMessagerie(DemandeCalculImpactMessagerie.builder()
+                        .dateCalcul(dateCalcul)
+                        .messagerie(entreesMapper.toDomain(calculMessagerie.getMessagerie()))
+                        .critere(referentielMapper.toCritere(critereDTO))
+                        .impactsMessagerie(referentielMapper.toListImpactMessagerie(calculMessagerie.getImpactsMessagerie()))
+                        .build())
+                ).toList();
+
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauService.java
new file mode 100644
index 0000000000000000000000000000000000000000..307fc4a6ba5fe596ac4b6337759eac36410e6e77
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauService.java
@@ -0,0 +1,58 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactReseauService;
+import org.mte.numecoeval.calculs.infrastructure.mapper.EntreesMapper;
+import org.mte.numecoeval.calculs.infrastructure.mapper.ReferentielMapper;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.CritereDTO;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.EtapeDTO;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class CalculReseauService {
+
+    EntreesMapper entreesMapper;
+    ReferentielMapper referentielMapper;
+
+    CalculImpactReseauService calculImpactReseauService;
+
+    /**
+     * Calcule les impacts réseau d'un équipement physique
+     * Returne la liste d'impacts
+     *
+     * @param calculEquipementPhysique l'equipement physique
+     * @return la liste d'impacts
+     */
+    public List<ImpactReseau> calculImpactReseau(CalculEquipementPhysique calculEquipementPhysique) {
+
+        List<ImpactReseau> impactReseauList = new ArrayList<>();
+
+        if (calculEquipementPhysique == null ||
+                calculEquipementPhysique.getEquipementPhysique() == null ||
+                calculEquipementPhysique.getEquipementPhysique().getGoTelecharge() == null) return impactReseauList;
+
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        for (EtapeDTO etape : calculEquipementPhysique.getEtapes()) {
+            for (CritereDTO critere : calculEquipementPhysique.getCriteres()) {
+                impactReseauList.add(calculImpactReseauService.calculerImpactReseau(DemandeCalculImpactReseau.builder()
+                        .dateCalcul(dateCalcul)
+                        .equipementPhysique(entreesMapper.toDomain(calculEquipementPhysique.getEquipementPhysique()))
+                        .etape(referentielMapper.toEtape(etape))
+                        .critere(referentielMapper.toCritere(critere))
+                        .impactsReseau(referentielMapper.toListImpactReseau(calculEquipementPhysique.getImpactsReseau()))
+                        .build()));
+            }
+        }
+
+        return impactReseauList;
+    }
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java
new file mode 100644
index 0000000000000000000000000000000000000000..28a5d72b2d11c71c07aadd6f5a36c906ae47a2a2
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java
@@ -0,0 +1,130 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.repository.ApplicationRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.EquipementVirtuelRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.IndicateurRepository;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class IntegrationCalculEquipementsService {
+
+    IndicateurRepository indicateurRepository;
+
+    EquipementPhysiqueRepository equipementPhysiqueRepository;
+    EquipementVirtuelRepository equipementVirtuelRepository;
+    ApplicationRepository applicationRepository;
+    CalculEquipementPhysiqueService calculEquipementPhysiqueService;
+    CalculEquipementVirtuelService calculEquipementVirtuelService;
+    CalculApplicationService calculApplicationService;
+    CalculReseauService calculReseauService;
+
+    /**
+     * Calcul les impacts d'un équipement physique enrichi, liste des impacts:
+     * - equipement physique
+     * - ses équipements virtuels
+     * - les applications sur ses équipements virtuels
+     * - réseaux
+     *
+     * @param calculEquipementPhysique l'équipement physique enrichi
+     * @return le nombre d'elements traites sous forme CalculSizes
+     */
+    public CalculSizes calculImpactEquipementPhysique(CalculEquipementPhysique calculEquipementPhysique) {
+
+        if (calculEquipementPhysique == null) return null;
+
+        var ttStart = System.currentTimeMillis();
+
+        EquipementPhysiqueDTO equipementPhysiqueDTO = calculEquipementPhysique.getEquipementPhysique();
+        String nomLot = equipementPhysiqueDTO.getNomLot();
+        String nomOrganisation = equipementPhysiqueDTO.getNomOrganisation();
+        String nomEquipementPhysique = equipementPhysiqueDTO.getNomEquipementPhysique();
+
+        // delete existing indicateurs
+        indicateurRepository.clearIndicateurs(nomEquipementPhysique, nomLot);
+
+        var ttAfterClear = System.currentTimeMillis();
+
+        List<ImpactEquipementPhysique> impactEquipementPhysiqueList = calculEquipementPhysiqueService.calculImpactEquipementPhysique(calculEquipementPhysique);
+        List<ImpactReseau> impactReseauList = calculReseauService.calculImpactReseau(calculEquipementPhysique);
+
+        // get equipements virtuels
+        List<EquipementVirtuel> equipementVirtuelList = equipementVirtuelRepository.findEquipementVirtuels(nomOrganisation, nomLot, nomEquipementPhysique);
+        var ttAfterFindEqV = System.currentTimeMillis();
+
+        List<ImpactEquipementVirtuel> allImpactVirtuel = new ArrayList<>();
+        List<ImpactApplication> allImpactApplication = new ArrayList<>();
+        var totalNbApplication = 0;
+
+        var totalVCPU = calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList);
+        var totalStockage = calculEquipementVirtuelService.getTotalStockage(equipementVirtuelList);
+
+        for (EquipementVirtuel equipementVirtuel : equipementVirtuelList) {
+            List<ImpactEquipementVirtuel> impactEquipementVirtuelList = calculEquipementVirtuelService.calculImpactEquipementVirtuel(
+                    impactEquipementPhysiqueList, equipementVirtuel,
+                    equipementVirtuelList.size(), totalVCPU, totalStockage
+            );
+
+            allImpactVirtuel.addAll(impactEquipementVirtuelList);
+
+            List<Application> applicationList = applicationRepository.findApplications(nomOrganisation, nomLot, nomEquipementPhysique, equipementVirtuel.getNomEquipementVirtuel());
+
+            totalNbApplication += applicationList.size();
+            for (Application application : applicationList) {
+                List<ImpactApplication> impactApplicationList = calculApplicationService.calculImpactApplication(impactEquipementVirtuelList, application, applicationList.size());
+                allImpactApplication.addAll(impactApplicationList);
+            }
+        }
+
+        var ttAfterEqVAndApp = System.currentTimeMillis();
+
+        // save impacts into db
+        indicateurRepository.saveIndicateursEquipements(impactEquipementPhysiqueList, allImpactVirtuel, allImpactApplication, impactReseauList);
+
+        var ttAfterSave = System.currentTimeMillis();
+
+        // set statut of equipement physique to TRAITE
+        equipementPhysiqueRepository.setStatutToTraite(equipementPhysiqueDTO.getId());
+
+        var ttAfterSaveStatus = System.currentTimeMillis();
+
+        log.info("{} - {} - {} : Calcul impacts equipement physique: {} [{}, {}]. Temps (ms): total={}, clear={}, eqV={} finEqVApp={}, saveInd={}, saveStatus={}",
+                nomOrganisation, nomLot, equipementPhysiqueDTO.getDateLot(),
+                nomEquipementPhysique,
+                equipementVirtuelList.size(),
+                totalNbApplication,
+                ttAfterSaveStatus - ttStart,
+                ttAfterClear - ttStart,
+                ttAfterFindEqV -ttAfterClear,
+                ttAfterEqVAndApp - ttAfterFindEqV,
+                ttAfterSave - ttAfterEqVAndApp,
+                ttAfterSaveStatus - ttAfterSave
+            );
+
+        CalculSizes result = new CalculSizes();
+        result.setNbEquipementPhysique(1);
+        result.setNbEquipementVirtuel(equipementVirtuelList.size());
+        result.setNbApplication(totalNbApplication);
+        result.setNbIndicateurEquipementPhysique(impactEquipementPhysiqueList.size());
+        result.setNbIndicateurEquipementVirtuel(allImpactVirtuel.size());
+        result.setNbIndicateurApplication(allImpactApplication.size());
+        result.setNbIndicateurReseau(impactReseauList.size());
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculMessagerieService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculMessagerieService.java
new file mode 100644
index 0000000000000000000000000000000000000000..73897447d105b61e9f22cdb3e57a999139642040
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculMessagerieService.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.model.CalculMessagerie;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.repository.IndicateurRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class IntegrationCalculMessagerieService {
+
+    IndicateurRepository indicateurRepository;
+
+    CalculMessagerieService calculMessagerieService;
+
+    MessagerieRepository messagerieRepository;
+
+    public CalculSizes calculImpactMessagerie(CalculMessagerie calculMessagerie) {
+        if (calculMessagerie == null) return null;
+
+        var messagerie = calculMessagerie.getMessagerie();
+
+        log.debug("{} - {} - {} : Calcul impact messagerie : {}, Nombre de Critère : {}",
+                messagerie.getNomOrganisation(), messagerie.getNomLot(), messagerie.getDateLot(),
+                messagerie.getId(),
+                calculMessagerie.getCriteres().size()
+        );
+
+        var impactsMessagerie = calculMessagerieService.calculImpactEquipementVirtuel(calculMessagerie);
+        indicateurRepository.saveIndicateursMessagerie(impactsMessagerie);
+        messagerieRepository.setStatutToTraite(messagerie.getId());
+
+        var result = new CalculSizes();
+        result.setNbMessagerie(1);
+        result.setNbIndicateurMessagerie(impactsMessagerie.size());
+        return result;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainEquipementPhysiqueService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainEquipementPhysiqueService.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a070d3aeca0846fbcfd3d37387f8839ec617625
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainEquipementPhysiqueService.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementEquipementPhysiqueService;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class MainEquipementPhysiqueService {
+
+    private EnrichissementEquipementPhysiqueService enrichissementEquipementPhysiqueService;
+    private IntegrationCalculEquipementsService integrationCalculEquipementsService;
+
+    public CalculSizes calcul(EquipementPhysiqueDTO equipementPhysiqueDTO) {
+
+        var eqPhEnrichi = enrichissementEquipementPhysiqueService.serviceEnrichissementEquipementPhysique(equipementPhysiqueDTO);
+        return integrationCalculEquipementsService.calculImpactEquipementPhysique(eqPhEnrichi);
+
+    }
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainMessagerieService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainMessagerieService.java
new file mode 100644
index 0000000000000000000000000000000000000000..fda3ab9c5cbcfaedd8acff9c63e3d89be61ad997
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainMessagerieService.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementMessagerieService;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class MainMessagerieService {
+
+    private EnrichissementMessagerieService enrichissementMessagerieService;
+    private IntegrationCalculMessagerieService integrationCalculMessagerieService;
+
+    public CalculSizes calcul(MessagerieDTO messagerieDTO) {
+
+        var messagerieEnrichie = enrichissementMessagerieService.serviceEnrichissementMessagerie(messagerieDTO);
+        return integrationCalculMessagerieService.calculImpactMessagerie(messagerieEnrichie);
+
+    }
+
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a23d86f413e12af269fa25a1b424d6a11af2520
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java
@@ -0,0 +1,97 @@
+package org.mte.numecoeval.calculs.infrastructure.service.enrichissement;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.HypotheseDTO;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+public class EnrichissementEquipementPhysiqueService {
+
+    private ReferentielClient referentielClient;
+
+    public CalculEquipementPhysique serviceEnrichissementEquipementPhysique(EquipementPhysiqueDTO equipementPhysiqueDTO) {
+        if (equipementPhysiqueDTO == null) return null;
+
+        log.debug("{} - {} - {} : Enrichissement d'un équipement physique : Nom Equipement: {}, Type: {}, Modele: {}",
+                equipementPhysiqueDTO.getNomOrganisation(), equipementPhysiqueDTO.getNomLot(), equipementPhysiqueDTO.getDateLot(),
+                equipementPhysiqueDTO.getNomEquipementPhysique(), equipementPhysiqueDTO.getType(), equipementPhysiqueDTO.getModele());
+
+        CalculEquipementPhysique calculEquipementPhysique = new CalculEquipementPhysique();
+
+        calculEquipementPhysique.setEquipementPhysique(equipementPhysiqueDTO);
+
+        calculEquipementPhysique.setEtapes(referentielClient.getEtapes());
+        calculEquipementPhysique.setCriteres(referentielClient.getCriteres());
+
+        var hypotheses = new ArrayList<HypotheseDTO>();
+        var hDuree = referentielClient.getHypothese("dureeVieParDefaut");
+        var hPue = referentielClient.getHypothese("PUEParDefaut");
+        var tuBYOD = referentielClient.getHypothese("taux_utilisation_BYOD");
+        var tuCOPE = referentielClient.getHypothese("taux_utilisation_COPE");
+
+        if (hDuree != null) hypotheses.add(hDuree);
+        if (hPue != null) hypotheses.add(hPue);
+        if (tuBYOD != null) hypotheses.add(tuBYOD);
+        if (tuCOPE != null) hypotheses.add(tuCOPE);
+
+        calculEquipementPhysique.setHypotheses(hypotheses);
+
+        calculEquipementPhysique.setCorrespondanceRefEquipement(referentielClient.getCorrespondanceRefEquipement(equipementPhysiqueDTO.getModele()));
+        calculEquipementPhysique.setTypeEquipement(referentielClient.getTypeEquipement(equipementPhysiqueDTO.getType()));
+
+        calculEquipementPhysique.setImpactsEquipement(new ArrayList<>());
+        calculEquipementPhysique.setImpactsReseau(new ArrayList<>());
+        calculEquipementPhysique.setMixElectriques(new ArrayList<>());
+        for (var critere : calculEquipementPhysique.getCriteres()) {
+            for (var etape : calculEquipementPhysique.getEtapes()) {
+                if (calculEquipementPhysique.getCorrespondanceRefEquipement() != null) {
+                    calculEquipementPhysique.getImpactsEquipement().add(
+                            referentielClient.getImpactEquipement(
+                                    calculEquipementPhysique.getCorrespondanceRefEquipement().getRefEquipementCible(),
+                                    critere.getNomCritere(),
+                                    etape.getCode()
+                            )
+                    );
+                } else if (calculEquipementPhysique.getTypeEquipement() != null
+                        && StringUtils.isNotBlank(calculEquipementPhysique.getTypeEquipement().getRefEquipementParDefaut())) {
+                    calculEquipementPhysique.getImpactsEquipement().add(
+                            referentielClient.getImpactEquipement(
+                                    calculEquipementPhysique.getTypeEquipement().getRefEquipementParDefaut(),
+                                    critere.getNomCritere(),
+                                    etape.getCode()
+                            )
+                    );
+                }
+                calculEquipementPhysique.getImpactsReseau().add(
+                        referentielClient.getImpactReseau(
+                                "impactReseauMobileMoyen",
+                                critere.getNomCritere(),
+                                etape.getCode()
+                        )
+                );
+            }
+
+            var mixElec = referentielClient.getMixElectrique(equipementPhysiqueDTO.getPaysDUtilisation(), critere.getNomCritere());
+            if (mixElec != null) calculEquipementPhysique.getMixElectriques().add(mixElec);
+
+            if (equipementPhysiqueDTO.getDataCenter() != null
+                    && StringUtils.isNotBlank(equipementPhysiqueDTO.getDataCenter().getLocalisation())
+                    && !StringUtils.equals(equipementPhysiqueDTO.getPaysDUtilisation(), equipementPhysiqueDTO.getDataCenter().getLocalisation())) {
+
+                var mixElecDataCenter = referentielClient.getMixElectrique(equipementPhysiqueDTO.getDataCenter().getLocalisation(), critere.getNomCritere());
+                if (mixElecDataCenter != null) calculEquipementPhysique.getMixElectriques().add(mixElecDataCenter);
+            }
+        }
+
+        return calculEquipementPhysique;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementMessagerieService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementMessagerieService.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4c823ddcde874b00aa4e9f9cafa599c3527044f
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementMessagerieService.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.calculs.infrastructure.service.enrichissement;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.model.CalculMessagerie;
+import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+@Service
+@AllArgsConstructor
+public class EnrichissementMessagerieService {
+
+    private ReferentielClient referentielClient;
+
+    public CalculMessagerie serviceEnrichissementMessagerie(MessagerieDTO messagerieDTO) {
+
+        if (Objects.isNull(messagerieDTO)) return null;
+
+        CalculMessagerie calculMessagerie = new CalculMessagerie();
+        calculMessagerie.setMessagerie(messagerieDTO);
+
+        calculMessagerie.setCriteres(referentielClient.getCriteres());
+        calculMessagerie.setImpactsMessagerie(new ArrayList<>());
+
+        calculMessagerie.setImpactsMessagerie(calculMessagerie.getCriteres().stream()
+                .map(critereDTO -> referentielClient.getMessagerie(critereDTO.getNomCritere()))
+                .filter(Objects::nonNull)
+                .toList());
+
+        return calculMessagerie;
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurService.java
new file mode 100644
index 0000000000000000000000000000000000000000..37a48364a0c67b3b346016b741695c49dc2a3fee
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurService.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.calculs.infrastructure.service.rest.calculs;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class CheckIndicateurService {
+
+    public boolean isOk(String statutIndicateur) {
+        return "OK".equals(statutIndicateur);
+    }
+}
diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7afd35344fd1abee4707a2d308cf521b332fc464
--- /dev/null
+++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java
@@ -0,0 +1,51 @@
+package org.mte.numecoeval.calculs.infrastructure.service.sync.calculs;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService;
+import org.mte.numecoeval.calculs.sync.generated.api.model.ReponseCalculRest;
+import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+
+@Service
+@AllArgsConstructor
+public class SyncCalculService {
+
+    private EquipementPhysiqueRepository equipementPhysiqueRepository;
+    private MessagerieRepository messagerieRepository;
+    private MainEquipementPhysiqueService mainEquipementPhysiqueService;
+    private MainMessagerieService mainMessagerieService;
+
+
+    public ReponseCalculRest calcul(SyncCalculRest syncCalculRest) {
+        var result = new ReponseCalculRest();
+
+        if (syncCalculRest.getEquipementPhysiqueIds() != null && !syncCalculRest.getEquipementPhysiqueIds().isEmpty()) {
+            List<CalculSizes> calculSizesList = equipementPhysiqueRepository.findEquipementPhysiqueDTOs(syncCalculRest.getEquipementPhysiqueIds()).stream()
+                    .map(equipementPhysiqueDTO -> mainEquipementPhysiqueService.calcul(equipementPhysiqueDTO))
+                    .filter(Objects::nonNull)
+                    .toList();
+
+            result.setNbrEquipementPhysique(calculSizesList.stream().map(CalculSizes::getNbEquipementPhysique).reduce(0L, Long::sum));
+            result.setNbrEquipementVirtuel(calculSizesList.stream().map(CalculSizes::getNbEquipementVirtuel).reduce(0L, Long::sum));
+            result.setNbrApplication(calculSizesList.stream().map(CalculSizes::getNbApplication).reduce(0L, Long::sum));
+        }
+
+        if (syncCalculRest.getMessagerieIds() != null && !syncCalculRest.getMessagerieIds().isEmpty()) {
+            List<CalculSizes> calculSizesMessagerieList = messagerieRepository.findMessagerieDTOList(syncCalculRest.getMessagerieIds()).stream()
+                    .map(messagerieDTO -> mainMessagerieService.calcul(messagerieDTO))
+                    .filter(Objects::nonNull)
+                    .toList();
+
+            result.setNbrMessagerie(calculSizesMessagerieList.stream().map(CalculSizes::getNbMessagerie).reduce(0L, Long::sum));
+        }
+
+        return result;
+    }
+}
diff --git a/services/api-event-calculs/src/main/resources/application.yaml b/services/api-event-calculs/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9be26cc42717c5b2bea44eace88446a76609714d
--- /dev/null
+++ b/services/api-event-calculs/src/main/resources/application.yaml
@@ -0,0 +1,59 @@
+spring:
+  sql:
+    init:
+      mode: always
+  # Base de données
+  datasource:
+    generate-unique-name: true
+    url: "jdbc:postgresql://localhost:5432/postgres?reWriteBatchedInserts=true"
+    username: postgres
+    password: postgres
+    driver-class-name: org.postgresql.Driver
+    tomcat:
+      test-on-borrow: false
+      jmx-enabled: false
+      max-active: 100
+  # Kafka
+  kafka:
+    bootstrap-servers: localhost:9092
+    back-off-sec: 10
+    consumer:
+      group-id: api-event-calculs
+      auto-offset-reset: earliest
+      enable-auto-commit: false
+      max-poll-records: 50
+      isolation.level: read_committed
+      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
+      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
+      properties:
+        spring.json.trusted.packages: "org.mte.numecoeval.*"
+
+# Application
+numecoeval:
+  topic:
+    partition: "4"
+    equipementPhysique: "entree_equipementPhysique"
+    messagerie: "entree_messagerie"
+  referentiels:
+    url: "http://localhost:18080"
+  cache:
+    ttl: "20"
+
+server:
+  port: 18085
+  shutdown: graceful
+
+# Actuator
+management:
+  server:
+    port: 18085
+  security:
+    user:
+      name: "actuator"
+      password: "actuator"
+      roles: ACTUATOR_ADMIN
+  endpoints:
+    web:
+      base-path: /
+      exposure:
+        include: health,prometheus,httptrace,info,metrics,mappings
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/resources/logback.xml b/services/api-event-calculs/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f10f3276b681057c636481f554c6f1a5d609e57b
--- /dev/null
+++ b/services/api-event-calculs/src/main/resources/logback.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%t]){faint} %clr(%-42.42logger{0}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+    <logger name="org.springframework.integration" level="INFO"/>
+    <logger name="org.springframework.kafka" level="WARN"/>
+    <logger name="org.apache.kafka" level="WARN"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-event-calculs/src/main/resources/schema.sql b/services/api-event-calculs/src/main/resources/schema.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c5b6cb8ea42e2ee86b292f2a5c2a022a66e8df3f
--- /dev/null
+++ b/services/api-event-calculs/src/main/resources/schema.sql
@@ -0,0 +1,164 @@
+-- Creation des tables indicateurs
+CREATE TABLE IF NOT EXISTS ind_indicateur_impact_equipement_physique
+(
+    date_calcul                timestamp    NULL,
+    date_lot                   date         NULL,
+    nom_lot                    varchar(255) NULL,
+    etapeacv                   varchar(255) NULL,
+    critere                    varchar(255) NULL,
+    "source"                   varchar(255) NULL,
+    statut_indicateur          varchar(255) NULL,
+    trace                      text         NULL,
+    version_calcul             varchar(255) NULL,
+    conso_elec_moyenne         float8       NULL,
+    impact_unitaire            float8       NULL,
+    quantite                   int4         NULL,
+    statut_equipement_physique varchar(255) NULL,
+    type_equipement            varchar(255) NULL,
+    unite                      varchar(255) NULL,
+    nom_entite                 varchar(255) NULL,
+    nom_organisation           varchar(255) NULL,
+    nom_source_donnee          varchar(255) NULL,
+    nom_equipement             varchar(255) NULL
+);
+
+CREATE TABLE IF NOT EXISTS ind_indicateur_impact_equipement_virtuel
+(
+    date_calcul            timestamp    NULL,
+    date_lot               date         NULL,
+    nom_lot                varchar(255) NULL,
+    etapeacv               varchar(255) NULL,
+    critere                varchar(255) NULL,
+    nom_organisation       varchar(255) NULL,
+    nom_source_donnee      varchar(255) NULL,
+    nom_equipement         varchar(255) NULL,
+    nom_equipement_virtuel varchar(255) NULL,
+    nom_entite             varchar(255) NULL,
+    "source"               varchar(255) NULL,
+    statut_indicateur      varchar(255) NULL,
+    trace                  text         NULL,
+    version_calcul         varchar(255) NULL,
+    impact_unitaire        float8       NULL,
+    unite                  varchar(255) NULL,
+    conso_elec_moyenne     float8       NULL,
+    "cluster"              varchar(255) NULL
+);
+
+CREATE TABLE IF NOT EXISTS ind_indicateur_impact_application
+(
+    date_calcul               timestamp    NULL,
+    date_lot                  date         NULL,
+    nom_lot                   varchar(255) NULL,
+    etapeacv                  varchar(255) NULL,
+    critere                   varchar(255) NULL,
+    nom_organisation          varchar(255) NULL,
+    nom_source_donnee         varchar(255) NULL,
+    nom_application           varchar(255) NULL,
+    type_environnement        varchar(255) NULL,
+    nom_equipement_physique   varchar(255) NULL,
+    nom_equipement_virtuel    varchar(255) NULL,
+    nom_entite                varchar(255) NULL,
+    "source"                  varchar(255) NULL,
+    statut_indicateur         varchar(255) NULL,
+    trace                     text         NULL,
+    version_calcul            varchar(255) NULL,
+    domaine                   varchar(255) NULL,
+    sous_domaine              varchar(255) NULL,
+    impact_unitaire           float8       NULL,
+    unite                     varchar(255) NULL,
+    conso_elec_moyenne        float8       NULL
+);
+
+CREATE TABLE IF NOT EXISTS ind_indicateur_impact_messagerie
+(
+    date_calcul            timestamp    NULL,
+    date_lot               date         NULL,
+    nom_lot                varchar(255) NULL,
+    nom_organisation       varchar(255) NULL,
+    nom_source_donnee      varchar(255) NULL,
+    critere                varchar(255) NULL,
+    mois_annee             date         NULL,
+    nom_entite             varchar(255) NULL,
+    "source"               varchar(255) NULL,
+    statut_indicateur      varchar(255) NULL,
+    trace                  text         NULL,
+    version_calcul         varchar(255) NULL,
+    impact_mensuel         float8       NULL,
+    unite                  varchar(255) NULL,
+    nombre_mail_emis       float8       NULL,
+    volume_total_mail_emis float8       NULL
+);
+
+CREATE TABLE IF NOT EXISTS ind_indicateur_impact_reseau
+(
+    date_calcul          timestamp    NULL,
+    date_lot             date         NULL,
+    nom_lot              varchar(255) NULL,
+    etapeacv             varchar(255) NULL,
+    critere              varchar(255) NULL,
+    "source"             varchar(255) NULL,
+    statut_indicateur    varchar(255) NULL,
+    trace                text         NULL,
+    version_calcul       varchar(255) NULL,
+    impact_unitaire      float8       NULL,
+    unite                varchar(255) NULL,
+    nom_entite           varchar(255) NULL,
+    nom_organisation     varchar(255) NULL,
+    nom_source_donnee    varchar(255) NULL,
+    nom_equipement       varchar(255) NULL
+);
+
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_physique ADD COLUMN IF NOT EXISTS date_lot_discriminator DATE NOT NULL DEFAULT '1970-01-01';
+UPDATE                ind_indicateur_impact_equipement_physique SET date_lot_discriminator = coalesce(date_lot, '1970-01-01') where date_lot_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_reseau              ADD COLUMN IF NOT EXISTS date_lot_discriminator DATE NOT NULL DEFAULT '1970-01-01';
+UPDATE                ind_indicateur_impact_reseau              SET date_lot_discriminator = coalesce(date_lot, '1970-01-01') where date_lot_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_virtuel  ADD COLUMN IF NOT EXISTS date_lot_discriminator DATE NOT NULL DEFAULT '1970-01-01';
+UPDATE                ind_indicateur_impact_equipement_virtuel  SET date_lot_discriminator = coalesce(date_lot, '1970-01-01') where date_lot_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_application         ADD COLUMN IF NOT EXISTS date_lot_discriminator DATE NOT NULL DEFAULT '1970-01-01';
+UPDATE                ind_indicateur_impact_application         SET date_lot_discriminator = coalesce(date_lot, '1970-01-01') where date_lot_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_messagerie          ADD COLUMN IF NOT EXISTS date_lot_discriminator DATE NOT NULL DEFAULT '1970-01-01';
+UPDATE                ind_indicateur_impact_messagerie          SET date_lot_discriminator = coalesce(date_lot, '1970-01-01') where date_lot_discriminator is null;
+
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_physique ADD COLUMN IF NOT EXISTS nom_organisation_discriminator varchar(255) NOT NULL DEFAULT '';
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_physique ALTER COLUMN nom_organisation_discriminator SET NOT NULL;
+ALTER TABLE IF EXISTS ind_indicateur_impact_reseau              ADD COLUMN IF NOT EXISTS nom_organisation_discriminator varchar(255) NOT NULL DEFAULT '';
+ALTER TABLE IF EXISTS ind_indicateur_impact_reseau              ALTER COLUMN nom_organisation_discriminator SET NOT NULL;
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_virtuel  ADD COLUMN IF NOT EXISTS nom_organisation_discriminator varchar(255) NOT NULL DEFAULT '';
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_virtuel  ALTER COLUMN nom_organisation_discriminator SET NOT NULL;
+ALTER TABLE IF EXISTS ind_indicateur_impact_application         ADD COLUMN IF NOT EXISTS nom_organisation_discriminator varchar(255) NOT NULL DEFAULT '';
+ALTER TABLE IF EXISTS ind_indicateur_impact_application         ALTER COLUMN nom_organisation_discriminator SET NOT NULL;
+ALTER TABLE IF EXISTS ind_indicateur_impact_messagerie          ADD COLUMN IF NOT EXISTS nom_organisation_discriminator varchar(255) NOT NULL DEFAULT '';
+ALTER TABLE IF EXISTS ind_indicateur_impact_messagerie          ALTER COLUMN nom_organisation_discriminator SET NOT NULL;
+
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_physique ADD COLUMN IF NOT EXISTS nom_entite_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_equipement_physique SET nom_entite_discriminator = coalesce(nom_entite, '') where nom_entite_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_reseau              ADD COLUMN IF NOT EXISTS nom_entite_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_reseau              SET nom_entite_discriminator = coalesce(nom_entite, '') where nom_entite_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_virtuel  ADD COLUMN IF NOT EXISTS nom_entite_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_equipement_virtuel  SET nom_entite_discriminator = coalesce(nom_entite, '') where nom_entite_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_application         ADD COLUMN IF NOT EXISTS nom_entite_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_application         SET nom_entite_discriminator = coalesce(nom_entite, '') where nom_entite_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_messagerie          ADD COLUMN IF NOT EXISTS nom_entite_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_messagerie          SET nom_entite_discriminator = coalesce(nom_entite, '') where nom_entite_discriminator is null;
+
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_physique ADD COLUMN IF NOT EXISTS nom_source_donnee_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_equipement_physique SET nom_source_donnee_discriminator = coalesce(nom_source_donnee, '') where nom_source_donnee_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_reseau              ADD COLUMN IF NOT EXISTS nom_source_donnee_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_reseau              SET nom_source_donnee_discriminator = coalesce(nom_source_donnee, '') where nom_source_donnee_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_equipement_virtuel  ADD COLUMN IF NOT EXISTS nom_source_donnee_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_equipement_virtuel  SET nom_source_donnee_discriminator = coalesce(nom_source_donnee, '') where nom_source_donnee_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_application         ADD COLUMN IF NOT EXISTS nom_source_donnee_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_application         SET nom_source_donnee_discriminator = coalesce(nom_source_donnee, '') where nom_source_donnee_discriminator is null;
+ALTER TABLE IF EXISTS ind_indicateur_impact_messagerie          ADD COLUMN IF NOT EXISTS nom_source_donnee_discriminator varchar(255) NOT NULL DEFAULT '';
+UPDATE                ind_indicateur_impact_messagerie          SET nom_source_donnee_discriminator = coalesce(nom_source_donnee, '') where nom_source_donnee_discriminator is null;
+
+
+CREATE INDEX IF NOT EXISTS idx_ind_eq_p__nom_lot_nom_equipement   ON ind_indicateur_impact_equipement_physique (nom_lot, nom_equipement);
+CREATE INDEX IF NOT EXISTS idx_ind_eq_v__nom_lot_nom_equipement   ON ind_indicateur_impact_equipement_virtuel (nom_lot, nom_equipement);
+CREATE INDEX IF NOT EXISTS idx_ind_app__nom_lot_nom_equipement    ON ind_indicateur_impact_application (nom_lot, nom_equipement_physique);
+CREATE INDEX IF NOT EXISTS idx_ind_reseau__nom_lot_nom_equipement ON ind_indicateur_impact_reseau (nom_lot, nom_equipement);
+
+-- Lignes a supprimer dans les futures versions
+ALTER TABLE ind_indicateur_impact_equipement_virtuel ADD COLUMN IF NOT EXISTS nom_equipement_virtuel VARCHAR(255);
+ALTER TABLE ind_indicateur_impact_application        ADD COLUMN IF NOT EXISTS nom_equipement_virtuel VARCHAR(255);
+
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/ApiEventCalculsApplicationTests.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/ApiEventCalculsApplicationTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c4949fd14d524a72e63c6ba0ef7aba2f6124de7
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/ApiEventCalculsApplicationTests.java
@@ -0,0 +1,165 @@
+package org.mte.numecoeval.calculs;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.*;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.model.CalculMessagerie;
+import org.mte.numecoeval.calculs.infrastructure.repository.*;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.IntegrationCalculEquipementsService;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.IntegrationCalculMessagerieService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.ActiveProfiles;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+
+@SpringBootTest
+@ActiveProfiles(profiles = {"test"})
+@Slf4j
+@EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class, DataSourceAutoConfiguration.class, KafkaAutoConfiguration.class})
+class ApiEventCalculsApplicationTests {
+
+
+    @Autowired
+    IntegrationCalculEquipementsService integrationCalculEquipementsService;
+    @Autowired
+    IntegrationCalculMessagerieService integrationCalculMessagerieService;
+
+    @MockBean
+    EquipementPhysiqueRepository equipementPhysiqueRepository;
+    @MockBean
+    EquipementVirtuelRepository equipementVirtuelRepository;
+    @MockBean
+    ApplicationRepository applicationRepository;
+    @MockBean
+    MessagerieRepository messagerieRepository;
+    @MockBean
+    DataSource dataSource;
+
+    private static final String RESOURCES = "src/test/resources";
+    private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+
+    @MockBean
+    IndicateurRepository indicateurRepository;
+
+    ArgumentCaptor<List<ImpactEquipementPhysique>> captorImpactEqPh = ArgumentCaptor.forClass((Class) List.class);
+    ArgumentCaptor<List<ImpactEquipementVirtuel>> captorImpactEqV = ArgumentCaptor.forClass((Class) List.class);
+    ArgumentCaptor<List<ImpactApplication>> captorImpactApp = ArgumentCaptor.forClass((Class) List.class);
+    ArgumentCaptor<List<ImpactReseau>> captorImpactReseau = ArgumentCaptor.forClass((Class) List.class);
+
+    ArgumentCaptor<List<ImpactMessagerie>> captorImpactMsg = ArgumentCaptor.forClass((Class) List.class);
+
+    @Test
+    void testIntegrationCalculEquipementsService() throws IOException {
+
+        assertNotNull(ApiEventCalculsApplication.class);
+
+        // check null case
+        integrationCalculEquipementsService.calculImpactEquipementPhysique(null);
+
+        /* DEFINE INPUT DATA */
+        var calculEquipementPhysique = mapper.readValue(
+                Files.readString(Path.of(RESOURCES).resolve("input").resolve("equipementPhysique.json")),
+                CalculEquipementPhysique.class
+        );
+
+        // mock equipements virtuels
+        List<EquipementVirtuel> equipementVirtuelList = List.of(EquipementVirtuel.builder()
+                .id(79302L)
+                .nomEquipementVirtuel("virtual-eq-1001-1")
+                .nomEquipementPhysique("physical-eq-srv-1001")
+                .cluster("PY1ORA01")
+                .nomLot("lot1")
+                .dateLot(LocalDate.of(2023, 10, 26))
+                .nomOrganisation("org")
+                .typeEqv("calcul")
+                .vCPU(4)
+                .build());
+        Mockito.when(equipementVirtuelRepository.findEquipementVirtuels(any(), any(), any())).thenReturn(equipementVirtuelList);
+
+        // mock applications
+        List<Application> applicationList = List.of(Application.builder()
+                .nomApplication("application-1001-1-1")
+                .typeEnvironnement("Production")
+                .nomEquipementVirtuel("virtual-eq-1001-1")
+                .nomEquipementPhysique("physical-eq-srv-1001")
+                .domaine("Domain 1")
+                .sousDomaine("Sub Domain 1")
+                .nomLot("lot1")
+                .dateLot(LocalDate.of(2023, 10, 26))
+                .nomOrganisation("org")
+                .nomEntite("Entite de test")
+                .build());
+        Mockito.when(applicationRepository.findApplications(any(), any(), any(), any())).thenReturn(applicationList);
+
+        /* EXECUTE */
+        integrationCalculEquipementsService.calculImpactEquipementPhysique(calculEquipementPhysique);
+
+        /* CAPTURE Impacts lists */
+        Mockito.verify(indicateurRepository, times(1)).saveIndicateursEquipements(captorImpactEqPh.capture(), captorImpactEqV.capture(), captorImpactApp.capture(), captorImpactReseau.capture());
+
+        List<ImpactEquipementPhysique> actualImpactEqPh = captorImpactEqPh.getValue();
+        List<ImpactEquipementVirtuel> actualImpactEqV = captorImpactEqV.getValue();
+        List<ImpactApplication> actualImpactApp = captorImpactApp.getValue();
+        List<ImpactReseau> actualImpactReseau = captorImpactReseau.getValue();
+
+        /* Check EXPECTED */
+        Assertions.assertEquals(4, actualImpactEqPh.size());
+        Assertions.assertEquals(4, actualImpactEqV.size());
+        Assertions.assertEquals(4, actualImpactApp.size());
+        Assertions.assertEquals(4, actualImpactReseau.size());
+
+        /* Check all statutIndicateur = OK */
+        // Assertions.assertTrue(actualImpactEqPh.stream().allMatch(i -> "OK".equals(i.getStatutIndicateur())));
+        // Assertions.assertTrue(actualImpactEqV.stream().allMatch(i -> "OK".equals(i.getStatutIndicateur())));
+        // Assertions.assertTrue(actualImpactApp.stream().allMatch(i -> "OK".equals(i.getStatutIndicateur())));
+        // Assertions.assertTrue(actualImpactReseau.stream().allMatch(i -> "OK".equals(i.getStatutIndicateur())));
+    }
+
+
+    @Test
+    void testIntegrationCalculMessagerieService() throws IOException {
+        // check null case
+        integrationCalculMessagerieService.calculImpactMessagerie(null);
+
+        /* DEFINE INPUT DATA */
+        var calculMessagerie = mapper.readValue(
+                Files.readString(Path.of(RESOURCES).resolve("input").resolve("messagerie.json")),
+                CalculMessagerie.class
+        );
+
+        integrationCalculMessagerieService.calculImpactMessagerie(calculMessagerie);
+
+        /* CAPTURE Impacts lists */
+        Mockito.verify(indicateurRepository, times(1)).saveIndicateursMessagerie(captorImpactMsg.capture());
+        List<ImpactMessagerie> actualImpactMsg = captorImpactMsg.getValue();
+
+        /* Check EXPECTED */
+        Assertions.assertEquals(2, actualImpactMsg.size());
+
+        /* Check all statutIndicateur = ERREUR */
+        Assertions.assertTrue(actualImpactMsg.stream().allMatch(i -> "ERREUR".equals(i.getStatutIndicateur())));
+    }
+}
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..84b9dceddecf07174424977009f8680a5b9fb7c1
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculEquipementVirtuelServiceTest.java
@@ -0,0 +1,68 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+
+import java.util.List;
+
+@ExtendWith(MockitoExtension.class)
+class CalculEquipementVirtuelServiceTest {
+
+    @InjectMocks
+    CalculEquipementVirtuelService calculEquipementVirtuelService;
+
+    @Test
+    void testCalculEquipementVirtuelService_getTotalVCPU_nominal() {
+        List<EquipementVirtuel> equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().vCPU(2).build(),
+                EquipementVirtuel.builder().vCPU(6).build()
+        );
+
+        Assertions.assertEquals(8, calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList));
+    }
+
+    @Test
+    void testCalculEquipementVirtuelService_getTotalVCPU_null() {
+        List<EquipementVirtuel> equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().vCPU(2).build(),
+                EquipementVirtuel.builder().vCPU(0).build()
+        );
+        Assertions.assertNull(calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList));
+
+        equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().vCPU(2).build(),
+                EquipementVirtuel.builder().build()
+        );
+        Assertions.assertNull(calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList));
+    }
+
+
+    @Test
+    void testCalculEquipementVirtuelService_getTotalStockage_nominal() {
+        List<EquipementVirtuel> equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().capaciteStockage(2.1).build(),
+                EquipementVirtuel.builder().capaciteStockage(6.2).build()
+        );
+
+        Assertions.assertEquals(8.3, calculEquipementVirtuelService.getTotalStockage(equipementVirtuelList));
+    }
+
+    @Test
+    void testCalculEquipementVirtuelService_getTotalStockage_null() {
+        List<EquipementVirtuel> equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().capaciteStockage(2.1).build(),
+                EquipementVirtuel.builder().capaciteStockage(0.0).build()
+        );
+        Assertions.assertNull(calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList));
+
+        equipementVirtuelList = List.of(
+                EquipementVirtuel.builder().capaciteStockage(2.0).build(),
+                EquipementVirtuel.builder().build()
+        );
+        Assertions.assertNull(calculEquipementVirtuelService.getTotalVCPU(equipementVirtuelList));
+    }
+}
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..836abbc15b11d2b42e83e7b5984069c39b85da00
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculReseauServiceTest.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique;
+
+import java.util.List;
+
+@ExtendWith(MockitoExtension.class)
+class CalculReseauServiceTest {
+
+    @InjectMocks
+    CalculReseauService calculReseauService;
+
+    private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+
+    @Test
+    void testCalculImpactReseau_nullCases() throws JsonProcessingException {
+        Assertions.assertEquals(List.of(), calculReseauService.calculImpactReseau(null));
+
+        Assertions.assertEquals(List.of(), calculReseauService.calculImpactReseau(new CalculEquipementPhysique()));
+
+        Assertions.assertEquals(List.of(), calculReseauService.calculImpactReseau(mapper.readValue("""
+                { "equipementPhysique": {} }
+                """, CalculEquipementPhysique.class)));
+
+        Assertions.assertEquals(List.of(), calculReseauService.calculImpactReseau(mapper.readValue("""
+                {
+                    "equipementPhysique": {
+                       "goTelecharge": null
+                    }
+                }
+                """, CalculEquipementPhysique.class)));
+    }
+
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9751e08259dda7214b9e85b678b2d9cd11d22e0f
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java
@@ -0,0 +1,164 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient;
+import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.*;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+
+import java.util.Arrays;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+
+@ExtendWith(MockitoExtension.class)
+class EnrichissementEquipementPhysiqueServiceTest {
+
+    private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+
+    @InjectMocks
+    EnrichissementEquipementPhysiqueService enrichissementEquipementPhysiqueService;
+
+    @Mock
+    ReferentielClient referentielClient;
+
+    EquipementPhysiqueDTO equipementPhysiqueDTO = mapper.readValue("""
+            {
+              "id": 43702,
+              "nomEquipementPhysique": "physical-eq-srv-1001",
+              "modele": "blade-server--28",
+              "type": "Server",
+              "statut": "In use",
+              "paysDUtilisation": null,
+              "dateAchat": "2016-06-17",
+              "dateRetrait": "2023-06-16",
+              "nomCourtDatacenter": "default",
+              "nbJourUtiliseAn": null,
+              "goTelecharge": 0.0,
+              "quantite": 7.0,
+              "consoElecAnnuelle": null,
+              "serveur": true,
+              "nomLot": "lot1",
+              "dateLot": "2023-10-26",
+              "nomOrganisation": "org",
+              "nbEquipementsVirtuels": 1,
+              "nbTotalVCPU": 4,
+              "dataCenter": {
+                "id": 5026,
+                "nomCourtDatacenter": "default",
+                "nomLongDatacenter": "Default",
+                "pue": 1.75,
+                "localisation": "France",
+                "dateLot": "2023-10-26",
+                "nomOrganisation": "org"
+              }
+            }
+            """, EquipementPhysiqueDTO.class);
+
+    EnrichissementEquipementPhysiqueServiceTest() throws JsonProcessingException {
+    }
+
+    @BeforeEach
+    void initMocksReferentiel() throws JsonProcessingException {
+        /* MOCK REFERENTIEL : Etapes */
+        Mockito.lenient().when(referentielClient.getEtapes()).thenReturn(Arrays.asList(mapper.readValue("""
+                [{ "code": "UTILISATION", "libelle": "Using" }]
+                """, EtapeDTO[].class)));
+
+        /* MOCK REFERENTIEL : Criteres */
+        Mockito.lenient().when(referentielClient.getCriteres()).thenReturn(Arrays.asList(mapper.readValue("""
+                [{
+                  "nomCritere": "Climate change",
+                  "unite": "kg CO2 eq",
+                  "description": "Greenhouse gases (GHG)"
+                }]
+                """, CritereDTO[].class)));
+
+        /* MOCK REFERENTIEL : Hypothese */
+        Mockito.lenient().when(referentielClient.getHypothese(any())).thenReturn(mapper.readValue("""
+                {
+                  "code": "hyp code",
+                  "valeur": "val",
+                  "source": "test"
+                }
+                """, HypotheseDTO.class));
+
+        /* MOCK REFERENTIEL : ImpactReseau */
+        Mockito.lenient().when(referentielClient.getImpactReseau(any(), any(), any())).thenReturn(new ImpactReseauDTO());
+
+        /* MOCK REFERENTIEL : MixElectrique */
+        var mixFr = new MixElectriqueDTO();
+        mixFr.setPays("FR");
+        Mockito.lenient().when(referentielClient.getMixElectrique("France", "Climate change")).thenReturn(mixFr);
+        Mockito.lenient().when(referentielClient.getMixElectrique(null, "Climate change")).thenReturn(null);
+    }
+
+    @Test
+    void testServiceEnrichissementEquipementPhysqique_null() {
+        Assertions.assertNull(enrichissementEquipementPhysiqueService.serviceEnrichissementEquipementPhysique(null));
+    }
+
+    @Test
+    void testServiceEnrichissementEquipementPhysqique_correspondanceRefEquipement() throws JsonProcessingException {
+
+        /* MOCK REFERENTIEL : CorrespondanceRefEquipement */
+        Mockito.when(referentielClient.getCorrespondanceRefEquipement("blade-server--28")).thenReturn(mapper.readValue("""
+                {
+                  "modeleEquipementSource": "srv",
+                  "refEquipementCible": "cible"
+                }
+                """, CorrespondanceRefEquipementDTO.class));
+
+        /* MOCK REFERENTIEL : ImpactEquipement */
+        var impactEquipementDTO = new ImpactEquipementDTO();
+        impactEquipementDTO.setValeur(1.1);
+
+        Mockito.when(referentielClient.getImpactEquipement(eq("cible"), any(), any())).thenReturn(impactEquipementDTO);
+
+        var actual = enrichissementEquipementPhysiqueService.serviceEnrichissementEquipementPhysique(equipementPhysiqueDTO);
+
+        Assertions.assertEquals(1, actual.getEtapes().size());
+        Assertions.assertEquals(1, actual.getCriteres().size());
+        Assertions.assertEquals(4, actual.getHypotheses().size());
+        Assertions.assertEquals(1, actual.getMixElectriques().size());
+        Assertions.assertEquals("FR", actual.getMixElectriques().get(0).getPays());
+        Assertions.assertEquals(1.1, actual.getImpactsEquipement().get(0).getValeur());
+    }
+
+
+    @Test
+    void testServiceEnrichissementEquipementPhysqique_typeEquipement() throws JsonProcessingException {
+
+        /* MOCK REFERENTIEL : CorrespondanceRefEquipement */
+        Mockito.when(referentielClient.getTypeEquipement("Server")).thenReturn(mapper.readValue("""
+                {
+                  "refEquipementParDefaut": "default-ref-server"
+                }
+                """, TypeEquipementDTO.class));
+
+        /* MOCK REFERENTIEL : ImpactEquipement */
+        var impactEquipementDTO = new ImpactEquipementDTO();
+        impactEquipementDTO.setValeur(2.2);
+
+        Mockito.when(referentielClient.getImpactEquipement(eq("default-ref-server"), any(), any())).thenReturn(impactEquipementDTO);
+
+        var actual = enrichissementEquipementPhysiqueService.serviceEnrichissementEquipementPhysique(equipementPhysiqueDTO);
+
+        Assertions.assertEquals(1, actual.getEtapes().size());
+        Assertions.assertEquals(1, actual.getCriteres().size());
+        Assertions.assertEquals(4, actual.getHypotheses().size());
+        Assertions.assertEquals(1, actual.getMixElectriques().size());
+        Assertions.assertEquals("FR", actual.getMixElectriques().get(0).getPays());
+        Assertions.assertEquals(2.2, actual.getImpactsEquipement().get(0).getValeur());
+    }
+}
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementMessagerieServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementMessagerieServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4ffe6ff77875bf1b501a0dbb14e5fe996b1b021
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementMessagerieServiceTest.java
@@ -0,0 +1,60 @@
+package org.mte.numecoeval.calculs.infrastructure.service.calcul;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient;
+import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementMessagerieService;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.CritereDTO;
+import org.mte.numecoeval.calculs.referentiels.generated.api.model.ImpactMessagerieDTO;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+
+import java.util.List;
+
+@ExtendWith(MockitoExtension.class)
+class EnrichissementMessagerieServiceTest {
+
+    @InjectMocks
+    EnrichissementMessagerieService enrichissementMessagerieService;
+
+    @Mock
+    ReferentielClient referentielClient;
+
+    @Test
+    void testServiceEnrichissementMessagerie_null() {
+        Assertions.assertNull(enrichissementMessagerieService.serviceEnrichissementMessagerie(null));
+    }
+
+    @Test
+    void testServiceEnrichissementMessagerie() {
+
+        /* INPUT DATA */
+        var messagerieDTO = new MessagerieDTO();
+        messagerieDTO.setId(1L);
+
+        var critereDTO = new CritereDTO();
+        critereDTO.setNomCritere("critere");
+
+        Mockito.when(referentielClient.getCriteres()).thenReturn(List.of(critereDTO));
+
+        var impactMessagerieDTO = new ImpactMessagerieDTO();
+        impactMessagerieDTO.setCritere("critere");
+        impactMessagerieDTO.setConstanteCoefficientDirecteur(1.1);
+
+        Mockito.when(referentielClient.getMessagerie("critere")).thenReturn(impactMessagerieDTO);
+
+        /* EXECUTE */
+        var actual = enrichissementMessagerieService.serviceEnrichissementMessagerie(messagerieDTO);
+        Assertions.assertEquals(1, actual.getCriteres().size());
+        Assertions.assertEquals(1, actual.getImpactsMessagerie().size());
+        Assertions.assertEquals(1L, actual.getMessagerie().getId());
+
+        Assertions.assertEquals(1.1, actual.getImpactsMessagerie().get(0).getConstanteCoefficientDirecteur());
+        Assertions.assertEquals("critere", actual.getImpactsMessagerie().get(0).getCritere());
+    }
+
+}
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb674a420353542de6efa6543a16abcee38fc4ff
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/rest/calculs/CheckIndicateurServiceTest.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.calculs.infrastructure.service.rest.calculs;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class CheckIndicateurServiceTest {
+
+    @InjectMocks
+    CheckIndicateurService checkIndicateurService;
+
+    @Test
+    void testCheckIndicateurService_isOk() {
+        Assertions.assertTrue(checkIndicateurService.isOk("OK"));
+        Assertions.assertFalse(checkIndicateurService.isOk("ERREUR"));
+    }
+
+}
diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee05e985989cad00d2cf384551e943618da73567
--- /dev/null
+++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java
@@ -0,0 +1,100 @@
+package org.mte.numecoeval.calculs.infrastructure.service.sync.calculs;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.model.CalculSizes;
+import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService;
+import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+
+@ExtendWith(MockitoExtension.class)
+class SyncCalculServiceTest {
+
+    @InjectMocks
+    SyncCalculService syncCalculService;
+
+    @Mock
+    EquipementPhysiqueRepository equipementPhysiqueRepository;
+    @Mock
+    MainEquipementPhysiqueService mainEquipementPhysiqueService;
+
+    @Mock
+    MessagerieRepository messagerieRepository;
+    @Mock
+    MainMessagerieService mainMessagerieService;
+
+    private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+
+    @Test
+    void testSyncCalculService_withListEquipementPhysique() throws JsonProcessingException {
+        /* MOCKS */
+        Mockito.when(equipementPhysiqueRepository.findEquipementPhysiqueDTOs(any())).thenReturn(List.of(
+                new EquipementPhysiqueDTO(),
+                new EquipementPhysiqueDTO()
+        ));
+
+        var calculSizes = new CalculSizes();
+        calculSizes.setNbEquipementPhysique(1);
+        calculSizes.setNbEquipementVirtuel(2);
+        calculSizes.setNbApplication(3);
+
+        Mockito.when(mainEquipementPhysiqueService.calcul(any())).thenReturn(calculSizes);
+
+        var syncCalculRest = mapper.readValue("""
+                {
+                    "equipementPhysiqueIds": [1,2]
+                }
+                """, SyncCalculRest.class);
+
+        /* EXECUTE */
+        var actual = syncCalculService.calcul(syncCalculRest);
+
+        /* ASSERT */
+        Assertions.assertEquals(2, actual.getNbrEquipementPhysique());
+        Assertions.assertEquals(4, actual.getNbrEquipementVirtuel());
+        Assertions.assertEquals(6, actual.getNbrApplication());
+    }
+
+    @Test
+    void testSyncCalculService_withListMessagerie() throws JsonProcessingException {
+        /* MOCKS */
+        Mockito.when(messagerieRepository.findMessagerieDTOList(any())).thenReturn(List.of(
+                new MessagerieDTO(),
+                new MessagerieDTO(),
+                new MessagerieDTO()
+        ));
+
+        var calculSizes = new CalculSizes();
+        calculSizes.setNbMessagerie(1);
+
+        Mockito.when(mainMessagerieService.calcul(any())).thenReturn(calculSizes);
+
+        var syncCalculRest = mapper.readValue("""
+                {
+                    "messagerieIds": [10,20,30]
+                }
+                """, SyncCalculRest.class);
+
+        /* EXECUTE */
+        var actual = syncCalculService.calcul(syncCalculRest);
+
+        /* ASSERT */
+        Assertions.assertEquals(3, actual.getNbrMessagerie());
+    }
+}
diff --git a/services/api-event-calculs/src/test/resources/application-test.yaml b/services/api-event-calculs/src/test/resources/application-test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..843fe39bab1af65e7ea4fd7346196ef80e9649ac
--- /dev/null
+++ b/services/api-event-calculs/src/test/resources/application-test.yaml
@@ -0,0 +1,2 @@
+spring:
+  jackson.serialization.write-dates-as-timestamps: false
diff --git a/services/api-event-calculs/src/test/resources/input/equipementPhysique.json b/services/api-event-calculs/src/test/resources/input/equipementPhysique.json
new file mode 100644
index 0000000000000000000000000000000000000000..30d28311c0a2de8d7ffc71bfd6d7a7011ec122d5
--- /dev/null
+++ b/services/api-event-calculs/src/test/resources/input/equipementPhysique.json
@@ -0,0 +1,194 @@
+{
+  "etapes": [
+    {
+      "code": "FABRICATION",
+      "libelle": "Manufacturing"
+    },
+    {
+      "code": "UTILISATION",
+      "libelle": "Using"
+    }
+  ],
+  "criteres": [
+    {
+      "nomCritere": "Climate change",
+      "unite": "kg CO2 eq",
+      "description": "Greenhouse gases (GHG) are gaseous components which absorb the infrared radiation emitted by the earth's surface 1 and thus contribute to the greenhouse effect."
+    },
+    {
+      "nomCritere": "Particulate matter and respiratory inorganics",
+      "unite": "Disease incidence",
+      "description": "The presence of small-diameter fine particles in the air - especially those with a diameter of less than 10 microns - represents a human health problem, since their inhalation can cause respiratory and cardiovascular problems."
+    }
+  ],
+  "hypotheses": [],
+  "correspondanceRefEquipement": null,
+  "equipementPhysique": {
+    "id": 43702,
+    "nomEquipementPhysique": "physical-eq-srv-1001",
+    "modele": "blade-server--28",
+    "type": "Server",
+    "statut": "In use",
+    "paysDUtilisation": null,
+    "utilisateur": null,
+    "dateAchat": "2016-06-17",
+    "dateRetrait": "2023-06-16",
+    "nbCoeur": null,
+    "nomCourtDatacenter": "default",
+    "nbJourUtiliseAn": null,
+    "goTelecharge": 0.0,
+    "quantite": 7.0,
+    "consoElecAnnuelle": null,
+    "serveur": true,
+    "nomEntite": null,
+    "nomSourceDonnee": null,
+    "nomLot": "lot1",
+    "dateLot": "2023-10-26",
+    "nomOrganisation": "org",
+    "nbEquipementsVirtuels": 1,
+    "nbTotalVCPU": 4,
+    "dataCenter": {
+      "id": 5026,
+      "nomCourtDatacenter": "default",
+      "nomLongDatacenter": "Default",
+      "pue": 1.75,
+      "localisation": "France",
+      "nomEntite": null,
+      "nomSourceDonnee": null,
+      "nomLot": null,
+      "dateLot": "2023-10-26",
+      "nomOrganisation": "org"
+    },
+    "stockageTotalVirtuel": null
+  },
+  "typeEquipement": {
+    "type": "Server",
+    "serveur": true,
+    "commentaire": "Lifetime par defaut Sopra Steria",
+    "dureeVieDefaut": 7.0,
+    "source": "",
+    "refEquipementParDefaut": "blade-server--28"
+  },
+  "mixElectriques": [
+    null,
+    {
+      "pays": "France",
+      "raccourcisAnglais": "FR",
+      "critere": "Climate change",
+      "valeur": 0.0813225,
+      "source": "Base IMPACTS®2.02"
+    },
+    null,
+    {
+      "pays": "France",
+      "raccourcisAnglais": "FR",
+      "critere": "Particulate matter and respiratory inorganics",
+      "valeur": 4.15844e-9,
+      "source": "Base IMPACTS®2.02"
+    },
+    null,
+    {
+      "pays": "France",
+      "raccourcisAnglais": "FR",
+      "critere": "Ionising radiation",
+      "valeur": 3.23443,
+      "source": "Base IMPACTS®2.02"
+    },
+    null,
+    {
+      "pays": "France",
+      "raccourcisAnglais": "FR",
+      "critere": "Acidification",
+      "valeur": 0.000209809,
+      "source": "Base IMPACTS®2.02"
+    },
+    null,
+    {
+      "pays": "France",
+      "raccourcisAnglais": "FR",
+      "critere": "Resource use (minerals and metals)",
+      "valeur": 4.85798e-8,
+      "source": "Base IMPACTS®2.02"
+    }
+  ],
+  "impactsReseau": [
+    {
+      "refReseau": "impactReseauMobileMoyen",
+      "etapeACV": "FABRICATION",
+      "critere": "Climate change",
+      "unite": null,
+      "source": "Test V1.00",
+      "valeur": 518.28,
+      "consoElecMoyenne": null
+    },
+    {
+      "refReseau": "impactReseauMobileMoyen",
+      "etapeACV": "UTILISATION",
+      "critere": "Climate change",
+      "unite": null,
+      "source": "Test V1.00",
+      "valeur": 76.28,
+      "consoElecMoyenne": null
+    },
+    {
+      "refReseau": "impactReseauMobileMoyen",
+      "etapeACV": "FABRICATION",
+      "critere": "Particulate matter and respiratory inorganics",
+      "unite": null,
+      "source": "Test V1.00",
+      "valeur": 148.28,
+      "consoElecMoyenne": null
+    },
+    {
+      "refReseau": "impactReseauMobileMoyen",
+      "etapeACV": "UTILISATION",
+      "critere": "Particulate matter and respiratory inorganics",
+      "unite": null,
+      "source": "Test V1.00",
+      "valeur": 18.8,
+      "consoElecMoyenne": null
+    }
+  ],
+  "impactsEquipement": [
+    {
+      "refEquipement": "blade-server--28",
+      "etape": "FABRICATION",
+      "critere": "Climate change",
+      "source": "test",
+      "type": "",
+      "valeur": 2935.5392,
+      "consoElecMoyenne": 3504.0,
+      "description": "Blade server  2 processor high-end  1 SSD: 1024 GB each  0 HDD  16 RAM, 16 GB each  0 GPU"
+    },
+    {
+      "refEquipement": "blade-server--28",
+      "etape": "UTILISATION",
+      "critere": "Climate change",
+      "source": "test",
+      "type": "",
+      "valeur": 234.62784,
+      "consoElecMoyenne": 3504.0,
+      "description": "Blade server  2 processor high-end  1 SSD: 1024 GB each  0 HDD  16 RAM, 16 GB each  0 GPU"
+    },
+    {
+      "refEquipement": "blade-server--28",
+      "etape": "FABRICATION",
+      "critere": "Particulate matter and respiratory inorganics",
+      "source": "test",
+      "type": "",
+      "valeur": 0.0000917808,
+      "consoElecMoyenne": 3504.0,
+      "description": "Blade server  2 processor high-end  1 SSD: 1024 GB each  0 HDD  16 RAM, 16 GB each  0 GPU"
+    },
+    {
+      "refEquipement": "blade-server--28",
+      "etape": "UTILISATION",
+      "critere": "Particulate matter and respiratory inorganics",
+      "source": "test",
+      "type": "",
+      "valeur": 0.000052475904,
+      "consoElecMoyenne": 3504.0,
+      "description": "Blade server  2 processor high-end  1 SSD: 1024 GB each  0 HDD  16 RAM, 16 GB each  0 GPU"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/test/resources/input/messagerie.json b/services/api-event-calculs/src/test/resources/input/messagerie.json
new file mode 100644
index 0000000000000000000000000000000000000000..188e9f9b2545f056290430040f916d78b89f8b43
--- /dev/null
+++ b/services/api-event-calculs/src/test/resources/input/messagerie.json
@@ -0,0 +1,16 @@
+{
+  "criteres": [
+    {
+      "nomCritere": "Climate change",
+      "unite": "kg CO2 eq",
+      "description": "Greenhouse gases (GHG) are gaseous components which absorb the infrared radiation emitted by the earth's surface 1 and thus contribute to the greenhouse effect."
+    },
+    {
+      "nomCritere": "Particulate matter and respiratory inorganics",
+      "unite": "Disease incidence",
+      "description": "The presence of small-diameter fine particles in the air - especially those with a diameter of less than 10 microns - represents a human health problem, since their inhalation can cause respiratory and cardiovascular problems."
+    }
+  ],
+  "messagerie": {},
+  "impactsMessagerie": []
+}
\ No newline at end of file
diff --git a/services/api-event-calculs/src/test/resources/logback-test.xml b/services/api-event-calculs/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e264d815b05450f63b3e9d87baf4674483f41311
--- /dev/null
+++ b/services/api-event-calculs/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%t]){faint} %clr(%-42.42logger{0}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/.gitignore b/services/api-event-donneesentrees/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..549e00a2a96fa9d7c5dbc9859664a78d980158c2
--- /dev/null
+++ b/services/api-event-donneesentrees/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/api-event-donneesentrees/README.md b/services/api-event-donneesentrees/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d12766d16afed97dddfc02d4c8828d6b970ee102
--- /dev/null
+++ b/services/api-event-donneesentrees/README.md
@@ -0,0 +1,3 @@
+# api-event-donneesentrees
+
+Application de gestion d'événement vers kafka
diff --git a/services/api-event-donneesentrees/dependency_check_suppressions.xml b/services/api-event-donneesentrees/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15f53bbc9ca0caa969e8cf94333045ac34dbd899
--- /dev/null
+++ b/services/api-event-donneesentrees/dependency_check_suppressions.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-security-crypto-5.7.3.jar
+   La librairie Spring Security est en version 5.7.3.
+   Cette CVE est marquée uniquement jusqu'à la version 5.2.4 (exclus)
+   https://nvd.nist.gov/vuln/detail/CVE-2020-5408
+   ]]></notes>
+        <cve>CVE-2020-5408</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-web-5.3.22.jar
+   Dans notre contexte, nous ne recevons pas de code Java de l'extérieur et n'effectuons pas de dé-sérialisation de code Java
+   Côté Spring, le point est déjà remonté comme un faux-positif : https://github.com/spring-projects/spring-framework/issues/24434#issuecomment-744519525
+   ]]></notes>
+        <cve>CVE-2016-1000027</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: snakeyaml-1.33.jar
+   Faux-positif : la version de Snakeyaml est la 1.33, la CVE existe uniquement sur les versions < 1.32
+   https://nvd.nist.gov/vuln/detail/CVE-2022-38752
+   ]]></notes>
+        <cve>CVE-2022-38752</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif sur toutes les librairies utils: https://github.com/jeremylong/DependencyCheck/issues/5213
+   Concerne : software.amazon.awssdk:utils qui n'est pas utilisé
+   ]]></notes>
+        <cve>CVE-2021-4277</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif : matchent à tort sur tous les commons : https://github.com/jeremylong/DependencyCheck/issues/5132
+   ]]></notes>
+        <cve>CVE-2021-37533</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+    et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-1471</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-3064</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2021-4235</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Concerne hutool-json et json-java qui ne sont pas utilisés.
+   Le faux-positif se trouve sur json-path, jackson-core, accessors-smart et json-smart.
+   cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2022-45688</cve>
+    </suppress>
+
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Conformément au lien, nous ne sommes pas dans un des cas de vulnérabilité.
+   cf. cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2023-20862</cve>
+    </suppress>
+</suppressions>
diff --git a/services/api-event-donneesentrees/pom.xml b/services/api-event-donneesentrees/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6921d7b6baca2d9bae61ca00ff40effa55e8a70
--- /dev/null
+++ b/services/api-event-donneesentrees/pom.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <artifactId>api-event-donneesEntrees</artifactId>
+    <name>api-event-donneesEntrees</name>
+    <version>1.2.3-SNAPSHOT</version>
+    <description>api-event-donneesEntrees</description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-integration</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+
+        <!-- JPA -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.integration</groupId>
+            <artifactId>spring-integration-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.integration</groupId>
+            <artifactId>spring-integration-kafka</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.integration</groupId>
+            <artifactId>spring-integration-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Base de données de tests -->
+        <dependency>
+            <groupId>io.zonky.test</groupId>
+            <artifactId>embedded-database-spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.zonky.test</groupId>
+            <artifactId>embedded-postgres</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Données de tests -->
+        <dependency>
+            <groupId>org.instancio</groupId>
+            <artifactId>instancio-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Tests avec attente minimum -->
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>
diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/ApiEventDonneesEntreesApplication.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/ApiEventDonneesEntreesApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..7164ee93c5ebf4590e5728ee689c96278576ae42
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/ApiEventDonneesEntreesApplication.java
@@ -0,0 +1,17 @@
+package org.mte.numecoeval.donneesentrees;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.integration.config.EnableIntegration;
+import org.springframework.kafka.annotation.EnableKafka;
+
+@SpringBootApplication
+@EnableIntegration
+@EnableKafka
+public class ApiEventDonneesEntreesApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ApiEventDonneesEntreesApplication.class, args);
+    }
+
+}
diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b83082f995d92062240004c5b5c00dcfb6da5ed
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java
@@ -0,0 +1,167 @@
+package org.mte.numecoeval.donneesentrees.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.mte.numecoeval.donneesentrees.infrastructure.utils.Constants;
+import org.mte.numecoeval.topic.data.DataCenterDTO;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.expression.common.LiteralExpression;
+import org.springframework.integration.annotation.InboundChannelAdapter;
+import org.springframework.integration.annotation.Poller;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.annotation.Splitter;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.expression.FunctionExpression;
+import org.springframework.integration.expression.ValueExpression;
+import org.springframework.integration.jdbc.JdbcPollingChannelAdapter;
+import org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHandler;
+import org.springframework.messaging.support.GenericMessage;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.Function;
+
+@Slf4j
+@Configuration
+@ConditionalOnProperty(
+        value = "numecoeval.features.eqp"
+)
+public class EquipementPhysiqueIntegrationConfig {
+
+    private static final String COLUMN_NAME_NOM_COURT_DATACENTER = "nom_court_datacenter";
+
+    @Value("${numecoeval.topic.entree.equipementPhysique}")
+    String topicEntreeEquipementPhysique;
+
+    @Value("${numecoeval.topic.partition}")
+    Integer topicPartition;
+
+    /**
+     * Topic Kafka pour les équipements physiques
+     *
+     * @return Topic à créer dans Kafka
+     */
+    @Bean
+    public NewTopic topicEntreeEquipementPhysique() {
+        return new NewTopic(topicEntreeEquipementPhysique, topicPartition, (short) 1);
+    }
+
+    @Bean
+    public MessageChannel entreeEquipementPhysique() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    public MessageChannel entreeEquipementPhysiqueSplitter() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    @ServiceActivator(inputChannel = "entreeEquipementPhysique")
+    public MessageHandler equipementPhysiqueHandler(KafkaTemplate<String, EquipementPhysiqueDTO> kafkaTemplate) {
+        KafkaProducerMessageHandler<String, EquipementPhysiqueDTO> handler =
+                new KafkaProducerMessageHandler<>(kafkaTemplate);
+        handler.setMessageKeyExpression(new LiteralExpression(UUID.randomUUID().toString()));
+        handler.setTopicExpression(new ValueExpression<>(topicEntreeEquipementPhysique));
+        Function<Message<?>, Long> partitionIdRandomFn = (m) -> (long) (Math.random() * topicPartition);
+        handler.setPartitionIdExpression(new FunctionExpression<>(partitionIdRandomFn));
+        return handler;
+    }
+
+    @Bean
+    @InboundChannelAdapter(
+            value = "entreeEquipementPhysiqueSplitter",
+            poller = @Poller(fixedDelay = "5000")
+    )
+    @SuppressWarnings("java:S1452") // La classe JdbcPollingChannelAdapter n'est pas compatible avec une classe fixe
+    public MessageSource<?> getEquipementPhysiqueToProcess(DataSource dataSource) {
+        JdbcPollingChannelAdapter adapter = new JdbcPollingChannelAdapter(dataSource,
+                """
+                        SELECT eqp.*,
+                          dc.id as dc_id,
+                          dc.date_creation as dc_date_creation,
+                          dc.date_update as dc_date_update,
+                          dc.localisation as dc_localisation,
+                          dc.nom_long_datacenter as dc_nom_long_datacenter,
+                          dc.pue as dc_pue,
+                          dc.nom_entite as dc_nom_entite
+                        FROM en_equipement_physique eqp
+                        LEFT JOIN en_data_center dc ON dc.nom_lot = eqp.nom_lot and dc.nom_court_datacenter = eqp.nom_court_datacenter
+                        WHERE eqp.statut_traitement = 'A_INGERER'
+                        ORDER BY nom_lot ASC, date_lot ASC, nom_organisation ASC
+                        LIMIT 1000
+                        """
+        );
+        adapter.setUpdateSql("UPDATE en_equipement_physique SET statut_traitement = 'INGERE', date_update = now() WHERE id in (:id)");
+        adapter.setRowMapper((rs, index) ->
+                EquipementPhysiqueDTO.builder()
+                        .id(rs.getLong("id"))
+                        .nomLot(rs.getString("nom_lot"))
+                        .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                        .nomOrganisation(rs.getString("nom_organisation"))
+                        .nomEntite(rs.getString("nom_entite"))
+                        .nomEquipementPhysique(rs.getString("nom_equipement_physique"))
+                        .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle"))
+                        .dateAchat(ResultSetUtils.getLocalDate(rs, "date_achat"))
+                        .dateRetrait(ResultSetUtils.getLocalDate(rs, "date_retrait"))
+                        .goTelecharge(ResultSetUtils.getFloat(rs, "go_telecharge"))
+                        .modele(rs.getString("modele"))
+                        .nbCoeur(rs.getString("nb_coeur"))
+                        .modeUtilisation(rs.getString("mode_utilisation"))
+                        .tauxUtilisation(rs.getDouble("taux_utilisation"))
+                        .paysDUtilisation(rs.getString("pays_utilisation"))
+                        .quantite(ResultSetUtils.getDouble(rs, "quantite"))
+                        .serveur(rs.getBoolean("serveur"))
+                        .statut(rs.getString("statut"))
+                        .type(rs.getString("type"))
+                        .utilisateur(rs.getString("utilisateur"))
+                        .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
+                        .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                        .dataCenter(
+                                DataCenterDTO.builder()
+                                        .id(rs.getLong("dc_id"))
+                                        .localisation(rs.getString("dc_localisation"))
+                                        .nomLongDatacenter(rs.getString("dc_nom_long_datacenter"))
+                                        .pue(ResultSetUtils.getDouble(rs, "dc_pue"))
+                                        .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
+                                        .nomEntite(rs.getString("dc_nom_entite"))
+                                        .nomOrganisation(rs.getString("nom_organisation"))
+                                        .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                                        .build()
+                        )
+                        .build()
+        );
+        return adapter;
+    }
+
+    @Splitter(
+            inputChannel = "entreeEquipementPhysiqueSplitter",
+            outputChannel = "entreeEquipementPhysique"
+    )
+    public List<Message<EquipementPhysiqueDTO>> splitListEquipementPhysique(Message<List<EquipementPhysiqueDTO>> messageList) {
+        if (messageList == null) return List.of();
+
+        return messageList.getPayload().stream()
+                .map((EquipementPhysiqueDTO equipementPhysiqueDTO) -> {
+                    var headers = new HashMap<String, Object>();
+                    headers.put(Constants.NOM_LOT, equipementPhysiqueDTO.getNomLot());
+                    headers.put(Constants.DATELOT, Objects.toString(equipementPhysiqueDTO.getDateLot(), ""));
+                    headers.put(Constants.NOM_ORGANISATION, equipementPhysiqueDTO.getNomOrganisation());
+                    return (Message<EquipementPhysiqueDTO>) new GenericMessage<>(equipementPhysiqueDTO, headers);
+                })
+                .toList();
+    }
+}
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..371fa3d976269198c7f976aa0a10f2162bb97e98
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java
@@ -0,0 +1,121 @@
+package org.mte.numecoeval.donneesentrees.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.mte.numecoeval.common.utils.ResultSetUtils;
+import org.mte.numecoeval.donneesentrees.infrastructure.utils.Constants;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.expression.common.LiteralExpression;
+import org.springframework.integration.annotation.InboundChannelAdapter;
+import org.springframework.integration.annotation.Poller;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.annotation.Splitter;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.expression.ValueExpression;
+import org.springframework.integration.jdbc.JdbcPollingChannelAdapter;
+import org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHandler;
+import org.springframework.messaging.support.GenericMessage;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+@Slf4j
+@Configuration
+@ConditionalOnProperty(
+        value = "numecoeval.features.mes"
+)
+public class MessagerieIntegrationConfig {
+
+    @Value("${numecoeval.topic.entree.messagerie}")
+    String topicEntreeMessagerie;
+
+    @Bean
+    public NewTopic topicEntreeMessagerie() {
+        return new NewTopic(topicEntreeMessagerie, 1, (short) 1);
+    }
+
+    @Bean
+    public MessageChannel entreeMessagerie() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    public MessageChannel entreeMessagerieSplitter() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    @ServiceActivator(inputChannel = "entreeMessagerie")
+    public MessageHandler messagerieHandler(KafkaTemplate<String, MessagerieDTO> kafkaTemplate) {
+        KafkaProducerMessageHandler<String, MessagerieDTO> handler =
+                new KafkaProducerMessageHandler<>(kafkaTemplate);
+        handler.setMessageKeyExpression(new LiteralExpression(UUID.randomUUID().toString()));
+        handler.setTopicExpression(new ValueExpression<>(topicEntreeMessagerie));
+        return handler;
+    }
+
+    @Bean
+    @InboundChannelAdapter(
+            value = "entreeMessagerieSplitter",
+            poller = @Poller(fixedDelay = "5000")
+    )
+    @SuppressWarnings("java:S1452") // La classe JdbcPollingChannelAdapter n'est pas compatible avec une classe fixe
+    public MessageSource<?> getMessagerieToProcess(DataSource dataSource) {
+        JdbcPollingChannelAdapter adapter = new JdbcPollingChannelAdapter(dataSource,
+                """
+                        SELECT *
+                        FROM en_messagerie mes
+                        WHERE mes.statut_traitement = 'A_INGERER'
+                        ORDER BY nom_lot ASC, date_lot ASC, nom_organisation ASC
+                        LIMIT 1000
+                        """
+        );
+        adapter.setUpdateSql("UPDATE en_messagerie SET statut_traitement = 'INGERE', date_update = now() WHERE id in (:id)");
+        adapter.setRowMapper((rs, index) ->
+                MessagerieDTO.builder()
+                        .id(rs.getLong("id"))
+                        .nomLot(rs.getString("nom_lot"))
+                        .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
+                        .nomOrganisation(rs.getString("nom_organisation"))
+                        .nomEntite(rs.getString("nom_entite"))
+                        .nomSourceDonnee(rs.getString("nom_source_donnee"))
+                        .moisAnnee(rs.getInt("mois_annee"))
+                        .nombreMailEmis(ResultSetUtils.getInteger(rs, "nombre_mail_emis"))
+                        .nombreMailEmisXDestinataires(ResultSetUtils.getInteger(rs, "nombre_mail_emisxdestinataires"))
+                        .volumeTotalMailEmis(ResultSetUtils.getInteger(rs, "volume_total_mail_emis"))
+                        .build()
+        );
+        return adapter;
+    }
+
+    @Splitter(
+            inputChannel = "entreeMessagerieSplitter",
+            outputChannel = "entreeMessagerie"
+    )
+    public List<Message<MessagerieDTO>> splitListMessagerie(Message<List<MessagerieDTO>> messageList) {
+        if (messageList == null) return List.of();
+
+        return messageList.getPayload().stream()
+                .map(messagerieDTO -> {
+                    var headers = new HashMap<String, Object>();
+                    headers.put(Constants.NOM_LOT, messagerieDTO.getNomLot());
+                    headers.put(Constants.DATELOT, Objects.toString(messagerieDTO.getDateLot(), ""));
+                    headers.put(Constants.NOM_ORGANISATION, messagerieDTO.getNomOrganisation());
+                    return (Message<MessagerieDTO>) new GenericMessage<>(messagerieDTO, headers);
+                })
+                .toList();
+    }
+
+}
diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/utils/Constants.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/utils/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..6544cd6e8f79ee9dc9bdcf0dd011d798e29732cc
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/utils/Constants.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.donneesentrees.infrastructure.utils;
+
+public class Constants {
+    public static final String NOM_LOT = "nomLot";
+    public static final String DATELOT = "dateLot";
+    public static final String NOM_ORGANISATION = "nomOrganisation";
+}
diff --git a/services/api-event-donneesentrees/src/main/resources/application.yaml b/services/api-event-donneesentrees/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ab6e3fc682194d83a75f141313bdea90719e4667
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/resources/application.yaml
@@ -0,0 +1,55 @@
+spring:
+  sql:
+    init:
+      mode: always
+  # Base de données
+  datasource:
+    generate-unique-name: true
+    url: "jdbc:postgresql://localhost:5432/postgres?reWriteBatchedInserts=true"
+    username: postgres
+    password: postgres
+    driver-class-name: org.postgresql.Driver
+    tomcat:
+      test-on-borrow: false
+      jmx-enabled: false
+      max-active: 100
+  # Kafka
+  kafka:
+    bootstrap-servers: localhost:9092
+    producer:
+      batch-size: 16384
+      buffer-memory: 33554432
+      retries: 0
+      key-serializer: org.apache.kafka.common.serialization.StringSerializer
+      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
+
+# Application
+numecoeval:
+ topic:
+   partition: "4"
+   entree:
+     equipementPhysique: "entree_equipementPhysique"
+     messagerie: "entree_messagerie"
+ features:
+   eqp: true
+   mes: true
+
+
+server:
+  port: 18090
+  shutdown: graceful
+
+# Actuator
+management:
+  server:
+    port: 18090
+  security:
+    user:
+      name: "actuator"
+      password: "actuator"
+      roles: ACTUATOR_ADMIN
+  endpoints:
+    web:
+      base-path: /
+      exposure:
+        include: health,prometheus,httptrace,info,metrics,mappings
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/main/resources/logback.xml b/services/api-event-donneesentrees/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1171d0e2406ccc2017de65f5378a5fdac94b105b
--- /dev/null
+++ b/services/api-event-donneesentrees/src/main/resources/logback.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+
+    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%t]){faint} %clr(%-42.42logger{0}){cyan} %clr(:){faint} %clr(%X{nomLot} - %X{dateLot} - %X{nomOrganisation}){magenta} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE" />
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+    <logger name="org.springframework.kafka" level="WARN"/>
+    <logger name="org.apache.kafka" level="WARN"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationEquipementPhysiqueTest.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationEquipementPhysiqueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..50171dc7538c3c0387bf92162cea6a8bc980f7ca
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationEquipementPhysiqueTest.java
@@ -0,0 +1,71 @@
+package org.mte.numecoeval.donneesentrees;
+
+import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.donneesentrees.test.jdbc.ScriptUtils;
+import org.mte.numecoeval.donneesentrees.test.kafka.KafkaConsumerEquipementPhysique;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static org.awaitility.Awaitility.await;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(profiles = {"test"})
+@AutoConfigureEmbeddedDatabase
+@EmbeddedKafka(
+        bootstrapServersProperty = "spring.kafka.bootstrap-servers",
+        partitions = 1
+)
+class IntegrationEquipementPhysiqueTest {
+
+    @Autowired
+    JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    KafkaConsumerEquipementPhysique kafkaConsumer;
+
+    @BeforeEach
+    void setup() {
+        ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/schema.sql");
+        jdbcTemplate.batchUpdate("DELETE FROM en_data_center");
+        jdbcTemplate.batchUpdate("DELETE FROM en_equipement_physique");
+    }
+
+    @Test
+    void whenDataAvailable_shouldUpdateStatusAndSendMessage() {
+        ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/equipment_physique.sql");
+
+        // Given
+        var queryResultCountEntrees = jdbcTemplate.query(
+                "SELECT count(*) as nbr from en_equipement_physique",
+                (rs, rowNum) -> rs.getInt("nbr")
+        );
+        var nbrEntrees = queryResultCountEntrees.get(0);
+
+        // When
+        jdbcTemplate.batchUpdate("UPDATE en_equipement_physique SET statut_traitement = 'A_INGERER'");
+
+        // Then
+        await().atMost(10, TimeUnit.SECONDS)
+                .until(() -> {
+                    var queryResultCountEntreesIngerees = jdbcTemplate.query(
+                            "SELECT count(*) as nbr from en_equipement_physique WHERE statut_traitement = 'INGERE'",
+                            (rs, rowNum) -> rs.getInt("nbr")
+                    );
+
+                    return !queryResultCountEntreesIngerees.isEmpty() && Objects.equals(nbrEntrees, queryResultCountEntreesIngerees.get(0));
+                });
+
+        await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> nbrEntrees == kafkaConsumer.getPayloads().size());
+
+    }
+
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationMessagerieTest.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationMessagerieTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9dad59a8646f2c6e9f602f5872e4fa0cfd965c6
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationMessagerieTest.java
@@ -0,0 +1,71 @@
+package org.mte.numecoeval.donneesentrees;
+
+import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.donneesentrees.test.jdbc.ScriptUtils;
+import org.mte.numecoeval.donneesentrees.test.kafka.KafkaConsumerMessagerie;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(profiles = {"test"})
+@AutoConfigureEmbeddedDatabase
+@EmbeddedKafka(
+        bootstrapServersProperty = "spring.kafka.bootstrap-servers",
+        partitions = 1
+)
+class IntegrationMessagerieTest {
+
+    @Autowired
+    JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    KafkaConsumerMessagerie kafkaConsumer;
+
+    @BeforeEach
+    void setup() {
+        ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/schema.sql");
+        jdbcTemplate.batchUpdate("DELETE FROM en_messagerie");
+    }
+
+    @Test
+    void whenDataAvailable_shouldUpdateStatusAndSendMessage() {
+        ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/messagerie.sql");
+
+        // Given
+        var queryResultCountEntrees = jdbcTemplate.query(
+                "SELECT count(*) as nbr from en_messagerie",
+                (rs, rowNum) -> rs.getInt("nbr")
+        );
+        var nbrEntrees = queryResultCountEntrees.get(0);
+
+        // When
+        jdbcTemplate.batchUpdate("UPDATE en_messagerie SET statut_traitement = 'A_INGERER'");
+
+        // Then
+        assertEquals(1, nbrEntrees);
+        await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> {
+                    var queryResultCountEntreesIngerees = jdbcTemplate.query(
+                            "SELECT count(*) as nbr from en_messagerie WHERE statut_traitement = 'INGERE'",
+                            (rs, rowNum) -> rs.getInt("nbr")
+                    );
+
+                    return !queryResultCountEntreesIngerees.isEmpty() && Objects.equals(nbrEntrees, queryResultCountEntreesIngerees.get(0));
+                });
+
+        await().atMost(5, TimeUnit.SECONDS)
+                .until(() -> nbrEntrees == kafkaConsumer.getPayloads().size());
+    }
+
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/jdbc/ScriptUtils.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/jdbc/ScriptUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d45a48b1feb42b47295a4c1c3330ba7307560c26
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/jdbc/ScriptUtils.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.donneesentrees.test.jdbc;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+
+import javax.sql.DataSource;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class ScriptUtils {
+
+    public static void loadScript(DataSource dataSource, String scriptSql) {
+        loadScripts(dataSource, Collections.singletonList(scriptSql));
+    }
+
+    public static void loadScripts(DataSource dataSource, List<String> scriptsSqls) {
+        assertNotNull(dataSource);
+
+        var populator = new ResourceDatabasePopulator();
+        for(var scriptSQL : scriptsSqls) {
+            populator.addScripts(
+                    new ClassPathResource(scriptSQL)
+            );
+        }
+        populator.execute(dataSource);
+    }
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumer.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..c76ac1d7fe240cf7dc587f5783f7600ff5ba002d
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumer.java
@@ -0,0 +1,32 @@
+package org.mte.numecoeval.donneesentrees.test.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@Slf4j
+public abstract class KafkaConsumer<T> {
+    List<T> payloads = new ArrayList<>();
+    protected CountDownLatch latch = new CountDownLatch(1);
+
+    abstract public void consumeMessage(T message);
+
+    public  void reset() {
+        payloads = new ArrayList<>();
+        resetLatch();
+    }
+
+    public CountDownLatch getLatch() {
+        return latch;
+    }
+
+    public void resetLatch() {
+        latch = new CountDownLatch(1);
+    }
+
+    public List<T> getPayloads() {
+        return payloads;
+    }
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..546cbec0223a5a5c62ec1b94a51879121a184904
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java
@@ -0,0 +1,39 @@
+package org.mte.numecoeval.donneesentrees.test.kafka;
+
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.annotation.EnableKafka;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.core.ConsumerFactory;
+
+@Configuration
+@EnableKafka
+public class KafkaConsumerConfig {
+
+    @Bean
+    public ConcurrentKafkaListenerContainerFactory<String, EquipementPhysiqueDTO> kafkaListenerContainerFactoryEquipementPhysique(ConsumerFactory<String, EquipementPhysiqueDTO> consumerFactory) {
+        ConcurrentKafkaListenerContainerFactory<String, EquipementPhysiqueDTO> factory = new ConcurrentKafkaListenerContainerFactory<>();
+        factory.setConsumerFactory(consumerFactory);
+        return factory;
+    }
+
+    @Bean
+    public KafkaConsumer<EquipementPhysiqueDTO> kafkaConsumerEquipementPhysique() {
+        return new KafkaConsumerEquipementPhysique();
+    }
+
+    @Bean
+    public ConcurrentKafkaListenerContainerFactory<String, MessagerieDTO> kafkaListenerContainerFactoryMessagerie(ConsumerFactory<String, MessagerieDTO> consumerFactory) {
+        ConcurrentKafkaListenerContainerFactory<String, MessagerieDTO> factory = new ConcurrentKafkaListenerContainerFactory<>();
+        factory.setConsumerFactory(consumerFactory);
+        return factory;
+    }
+
+    @Bean
+    public KafkaConsumer<MessagerieDTO> kafkaConsumerMessagerie() {
+        return new KafkaConsumerMessagerie();
+    }
+
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerEquipementPhysique.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..c19382c7b6173ab1222e7fb3410001e83160b8c4
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerEquipementPhysique.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.donneesentrees.test.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
+import org.springframework.kafka.annotation.KafkaListener;
+
+@Slf4j
+public class KafkaConsumerEquipementPhysique extends KafkaConsumer<EquipementPhysiqueDTO> {
+
+    @Override
+    @KafkaListener(topics = "${numecoeval.topic.entree.equipementPhysique}")
+    public void consumeMessage(EquipementPhysiqueDTO message) {
+        log.info("#############  Playload = {}", message);
+        payloads.add(message);
+        latch.countDown();
+
+    }
+}
diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerMessagerie.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..63e21045765749039f0233d101ac4894e246de53
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerMessagerie.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.donneesentrees.test.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.topic.data.MessagerieDTO;
+import org.springframework.kafka.annotation.KafkaListener;
+
+@Slf4j
+public class KafkaConsumerMessagerie extends KafkaConsumer<MessagerieDTO> {
+
+    @Override
+    @KafkaListener(topics = "${numecoeval.topic.entree.messagerie}")
+    public void consumeMessage(MessagerieDTO message) {
+        log.info("#############  Playload = {}", message);
+        payloads.add(message);
+        latch.countDown();
+
+    }
+}
diff --git a/services/api-event-donneesentrees/src/test/resources/application-test.yaml b/services/api-event-donneesentrees/src/test/resources/application-test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..16c24052ed3309bd193727bd4ab1023bc0e7bd1f
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/resources/application-test.yaml
@@ -0,0 +1,33 @@
+spring:
+  kafka:
+    bootstrap-servers: localhost:9092
+    consumer:
+      group-id: api-event-donneesentrees
+      auto-offset-reset: earliest
+      enable-auto-commit: false
+      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
+      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
+      properties:
+        spring.json.trusted.packages: org.mte.numecoeval.*
+    producer:
+      batch-size: 16384
+      buffer-memory: 33554432
+      retries: 0
+      key-serializer: org.apache.kafka.common.serialization.StringSerializer
+      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
+
+# Application
+numecoeval:
+  features:
+    eqp: true
+    mes: true
+
+#CONFIGURATION BASES
+zonky:
+  test:
+    database:
+      postgres:
+        server:
+          properties:
+            max_connections: 100
+      provider: zonky
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/test/resources/logback-test.xml b/services/api-event-donneesentrees/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d01f3999ae16b4fd46c9d99b3af8393037806812
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%t]){faint} %clr(%-42.42logger{0}){cyan} %clr(:){faint} %clr(%X{nomLot} - %X{dateLot} - %X{nomOrganisation}){magenta} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+    <logger name="org.springframework.kafka" level="ERROR"/>
+    <logger name="org.apache.kafka" level="ERROR"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/test/resources/sql/equipment_physique.sql b/services/api-event-donneesentrees/src/test/resources/sql/equipment_physique.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4d532f98f7ad3b40923028332393225f3bec6522
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/resources/sql/equipment_physique.sql
@@ -0,0 +1,14 @@
+INSERT INTO en_data_center (id, date_creation, nom_lot, date_lot, nom_organisation, localisation, nom_court_datacenter,
+                            nom_entite, nom_long_datacenter, pue, statut_traitement, date_update, nom_source_donnee)
+VALUES (6002, '2023-03-08 19:45:39.484539', 'ENTITE|2022-01-01', '2022-01-01', 'ENTITE', 'France', 'TestDataCenter', 'ENTITE', 'TEST', 1.44,
+        'EN_ATTENTE', NULL, 'SOURCE_A');
+
+INSERT INTO en_equipement_physique (id, date_creation, nom_lot, date_lot, nom_organisation, conso_elec_annuelle,
+                                    date_achat, date_retrait, duree_vie_defaut, go_telecharge, modele, nb_coeur, mode_utilisation, taux_utilisation,
+                                    nb_jour_utilise_an, nom_court_datacenter, nom_entite,
+                                    nom_equipement_physique, pays_utilisation, quantite, serveur, statut, "type",
+                                    utilisateur, statut_traitement, date_update, nom_source_donnee)
+VALUES (376826, '2023-03-23 15:53:51.179031', 'ENTITE|2022-01-01', '2022-01-01', 'ENTITE', NULL, '2022-01-01', NULL, 8.0, 0.0,
+        'computer monitor-01-55', '','BYOD',0.4, 365.0, '', 'ENTITE', '2023-03-09-Ecran-105', 'France', 13.0, false, 'actif', 'Ecran',
+        '', 'EN_ATTENTE', NULL, 'SOURCE_A');
+
diff --git a/services/api-event-donneesentrees/src/test/resources/sql/messagerie.sql b/services/api-event-donneesentrees/src/test/resources/sql/messagerie.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4d5957a7e9bd03c91cd71f8c3a249e7b705fe390
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/resources/sql/messagerie.sql
@@ -0,0 +1,6 @@
+
+
+INSERT INTO en_messagerie (id, date_creation, nom_lot, date_lot, nom_organisation, mois_annee, nom_entite, nombre_mail_emis,
+                           nombre_mail_emisxdestinataires, volume_total_mail_emis, statut_traitement, date_update, nom_source_donnee)
+VALUES (11002, '2023-03-23 15:53:37.073851', 'ENTITE|01-01-2022', '2022-01-01', 'ENTITE', 201901, 'ENTITE', 123456, 513, 84351385,
+        'EN_ATTENTE', NULL, 'SOURCE_F');
\ No newline at end of file
diff --git a/services/api-event-donneesentrees/src/test/resources/sql/schema.sql b/services/api-event-donneesentrees/src/test/resources/sql/schema.sql
new file mode 100644
index 0000000000000000000000000000000000000000..32f7442baecbd02dcd6d646bf55c533a63c0c0e3
--- /dev/null
+++ b/services/api-event-donneesentrees/src/test/resources/sql/schema.sql
@@ -0,0 +1,138 @@
+CREATE TABLE IF NOT EXISTS en_donnees_entrees
+(
+    id                        int8         NOT NULL,
+    date_update               timestamp    NULL,
+    date_creation             timestamp    NULL,
+    date_lot                  date         NULL,
+    nom_organisation          varchar(255) NULL,
+    nom_lot                   varchar(255) NULL,
+    nbr_applications          int8         NULL,
+    nbr_data_center           int8         NULL,
+    nbr_equipements_physiques int8         NULL,
+    nbr_equipements_virtuels  int8         NULL,
+    nbr_messageries           int8         NULL,
+    CONSTRAINT en_donnees_entrees_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_data_center
+(
+    id                   int8         NOT NULL,
+    date_creation        timestamp    NULL,
+    date_update          timestamp    NULL,
+    date_lot             date         NULL,
+    nom_lot              varchar(255) NULL,
+    nom_organisation     varchar(255) NULL,
+    nom_source_donnee    varchar(255) NULL,
+    localisation         varchar(255) NULL,
+    nom_court_datacenter varchar(255) NULL,
+    nom_entite           varchar(255) NULL,
+    nom_long_datacenter  varchar(255) NULL,
+    pue                  float8       NULL,
+    CONSTRAINT en_data_center_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_equipement_physique
+(
+    id                        int8         NOT NULL,
+    date_creation             timestamp    NULL,
+    date_update               timestamp    NULL,
+    date_lot                  date         NULL,
+    nom_lot                   varchar(255) NULL,
+    nom_organisation          varchar(255) NULL,
+    nom_source_donnee         varchar(255) NULL,
+    conso_elec_annuelle       float8       NULL,
+    date_achat                date         NULL,
+    date_retrait              date         NULL,
+    duree_vie_defaut          float8       NULL,
+    go_telecharge             float4       NULL,
+    modele                    varchar(255) NULL,
+    nb_coeur                  varchar(255) NULL,
+    nb_jour_utilise_an        float8       NULL,
+    nom_court_datacenter      varchar(255) NULL,
+    nom_entite                varchar(255) NULL,
+    nom_equipement_physique   varchar(255) NULL,
+    pays_utilisation          varchar(255) NULL,
+    quantite                  float8       NULL,
+    serveur                   bool         NOT NULL,
+    statut                    varchar(255) NULL,
+    mode_utilisation          varchar(255) NULL,
+    taux_utilisation          float8       NULL,
+    "type"                    varchar(255) NULL,
+    utilisateur               varchar(255) NULL,
+    CONSTRAINT en_equipement_physique_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_equipement_virtuel
+(
+    id                      int8         NOT NULL,
+    date_creation           timestamp    NULL,
+    date_lot                date         NULL,
+    nom_lot                 varchar(255) NULL,
+    nom_organisation        varchar(255) NULL,
+    nom_source_donnee       varchar(255) NULL,
+    "cluster"               varchar(255) NULL,
+    nom_entite              varchar(255) NULL,
+    nom_equipement_physique varchar(255) NULL,
+    nom_equipement_virtuel  varchar(255) NULL,
+    vcpu                    int4         NULL,
+    CONSTRAINT en_equipement_virtuel_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_application
+(
+    id                      int8         NOT NULL,
+    date_creation           timestamp    NULL,
+    date_lot                date         NULL,
+    nom_lot                 varchar(255) NULL,
+    nom_organisation        varchar(255) NULL,
+    nom_source_donnee       varchar(255) NULL,
+    domaine                 varchar(255) NULL,
+    nom_application         varchar(255) NULL,
+    nom_entite              varchar(255) NULL,
+    nom_equipement_virtuel  varchar(255) NULL,
+    nom_equipement_physique varchar(255) NULL,
+    sous_domaine            varchar(255) NULL,
+    type_environnement      varchar(255) NULL,
+    CONSTRAINT en_application_pkey PRIMARY KEY (id)
+);
+
+
+CREATE TABLE IF NOT EXISTS en_entite
+(
+    id                                  int8         NOT NULL,
+    date_creation                       timestamp    NULL,
+    date_update                         timestamp    NULL,
+    date_lot                            date         NULL,
+    nom_lot                             varchar(255) NULL,
+    nom_organisation                    varchar(255) NULL,
+    nom_source_donnee                   varchar(255) NULL,
+    nom_entite                          varchar(255) NULL,
+    nb_collaborateurs                   int4         NULL,
+    responsable_entite                  varchar(255) NULL,
+    responsable_numerique_durable       varchar(255) NULL,
+    CONSTRAINT en_entite_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_messagerie
+(
+    id                             int8         NOT NULL,
+    date_creation                  timestamp    NULL,
+    date_update                    timestamp    NULL,
+    date_lot                       date         NULL,
+    nom_lot                        varchar(255) NULL,
+    nom_organisation               varchar(255) NULL,
+    nom_source_donnee              varchar(255) NULL,
+    mois_annee                     int4         NULL,
+    nom_entite                     varchar(255) NULL,
+    nombre_mail_emis               int4         NULL,
+    nombre_mail_emisxdestinataires int4         NULL,
+    volume_total_mail_emis         int4         NULL,
+    CONSTRAINT en_messagerie_pkey PRIMARY KEY (id)
+);
+
+ALTER TABLE IF EXISTS en_donnees_entrees ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_data_center ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_application ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_messagerie ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
diff --git a/services/api-expositiondonneesentrees/.gitignore b/services/api-expositiondonneesentrees/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..549e00a2a96fa9d7c5dbc9859664a78d980158c2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/api-expositiondonneesentrees/LICENSE.txt b/services/api-expositiondonneesentrees/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/services/api-expositiondonneesentrees/LICENSE.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/services/api-expositiondonneesentrees/README.md b/services/api-expositiondonneesentrees/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..628853ac3b5589c2ed8a7d691bbda05c25a89473
--- /dev/null
+++ b/services/api-expositiondonneesentrees/README.md
@@ -0,0 +1,64 @@
+# api-expositiondonneesentrees
+
+API permettant d'envoyer des données d'entrées dans le système NumEcoEval.
+L'import de données peut se faire via des fichiers CSV respectant un format spécifique ou au format JSON.
+Le contrat d'interface est disponible au format [OpenAPI 3](src/main/resources/static/openapi.yaml).
+
+## Pré-requis
+
+- JDK 17
+    - [Open JDK](https://jdk.java.net/java-se-ri/17)
+    - [Coretto](https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/downloads-list.html)
+- [Maven 3](https://maven.apache.org/download.cgi)
+- Un IDE compatible avec Maven 3 et JDK 17
+
+## Build
+
+Pour compiler l'application, utilisez la commande suivante :
+
+```bash
+mvn clean install
+```
+
+### API REST et Contrat OpenAPI
+
+Le contrat OpenAPI 3 est disponible dans les ressources du
+projet : [openapi.yaml](src/main/resources/static/openapi.yaml)
+
+Ce contrat est utilisé pour générer les interfaces et POJOs utilisés dans les communications REST via le plugin
+Maven [openapi-generator-maven-plugin](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin)
+
+#### Profiles Maven
+
+- DEPENDENCY-CHECK : Un profile permettant un scan local des dépendances Maven avec le dependency-check Maven plugin
+  d'OWASP.
+
+### Configuration de l'application
+
+Editer le fichier [application.yml](src/main/resources/application.yaml)
+
+### Démarrer l'application
+
+Pour démarrer l'application avec la configuration actuelle, utilisez la commande suivante:
+
+```bash
+mvn spring-boot:run
+```
+
+Avec la configuration par défaut, l'API REST sera disponible sur l'URL
+suivante : [http://localhost:18081](http://localhost:18081)
+
+L'application utilise Springdoc-openapi permettant un affichage via Swagger-UI sur l'
+URL [http://localhost:18081/api/swagger-ui/index.html](http://localhost:18081/api/swagger-ui/index.html).
+
+* Par défaut, le contrat d'interface OpenAPI est également disponible sur l'
+  URL [http://localhost:18081/openapi.yaml](http://localhost:18081/openapi.yaml).
+
+## Licences
+
+[Apache 2.0](LICENSE.txt)
+
+## Liens utiles
+
+- [Spring Documentation (version courante)](https://docs.spring.io/spring-framework/docs/current/reference/html/)
+- [Spring Boot Documentation (version courante)](https://docs.spring.io/spring-boot/docs/current/reference/html/index.html)
\ No newline at end of file
diff --git a/services/api-expositiondonneesentrees/dependency_check_suppressions.xml b/services/api-expositiondonneesentrees/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7937ced36578ad474a7a2d84af4a487d30b95bf1
--- /dev/null
+++ b/services/api-expositiondonneesentrees/dependency_check_suppressions.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-security-crypto-5.7.3.jar
+   La librairie Spring Security est en version 5.7.3.
+   Cette CVE est marquée uniquement jusqu'à la version 5.2.4 (exclus)
+   https://nvd.nist.gov/vuln/detail/CVE-2020-5408
+   ]]></notes>
+        <cve>CVE-2020-5408</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-web-5.3.22.jar
+   Dans notre contexte, nous ne recevons pas de code Java de l'extérieur et n'effectuons pas de dé-sérialisation de code Java
+   Côté Spring, le point est déjà remonté comme un faux-positif : https://github.com/spring-projects/spring-framework/issues/24434#issuecomment-744519525
+   ]]></notes>
+        <cve>CVE-2016-1000027</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: snakeyaml-1.33.jar
+   Faux-positif : la version de Snakeyaml est la 1.33, la CVE existe uniquement sur les versions < 1.32
+   https://nvd.nist.gov/vuln/detail/CVE-2022-38752
+   ]]></notes>
+        <cve>CVE-2022-38752</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif sur toutes les librairies utils: https://github.com/jeremylong/DependencyCheck/issues/5213
+   Concerne : software.amazon.awssdk:utils qui n'est pas utilisé
+   ]]></notes>
+        <cve>CVE-2021-4277</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif : matchent à tort sur tous les commons : https://github.com/jeremylong/DependencyCheck/issues/5132
+   ]]></notes>
+        <cve>CVE-2021-37533</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+    et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-1471</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-3064</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2021-4235</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Concerne hutool-json et json-java qui ne sont pas utilisés.
+   Le faux-positif se trouve sur json-path, jackson-core, accessors-smart et json-smart.
+   cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2022-45688</cve>
+    </suppress>
+
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Conformément au lien, nous ne sommes pas dans un des cas de vulnérabilité.
+   cf. cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2023-20862</cve>
+    </suppress>
+
+
+</suppressions>
diff --git a/services/api-expositiondonneesentrees/pom.xml b/services/api-expositiondonneesentrees/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..353bd2a1ba30fb0738f090bd247dfb87210e1c3c
--- /dev/null
+++ b/services/api-expositiondonneesentrees/pom.xml
@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <artifactId>api-expositiondonneesentrees</artifactId>
+    <version>1.2.3-SNAPSHOT</version>
+    <name>api-expositiondonneesentrees</name>
+    <description>API Exposition des données d'entrées - Exposition par API pour injecter des données d'entrées
+    </description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <properties>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+
+        <!-- REST -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+
+        <!-- JPA -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+
+        <!-- Driver pour base de données -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Nécessaire avec Spring Boot 3 pour Hibernate -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+
+        <!-- Security -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- Mapping -->
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+        </dependency>
+
+        <!-- Utilitaire -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+        </dependency>
+
+        <!-- Monitoring -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- Code généré-->
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+        </dependency>
+
+        <!-- TU/TI -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-suite</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.meanbean</groupId>
+            <artifactId>meanbean</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>nl.jqno.equalsverifier</groupId>
+            <artifactId>equalsverifier</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests d'API REST -->
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests avec attente minimum -->
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Base de données de tests -->
+        <dependency>
+            <groupId>io.zonky.test</groupId>
+            <artifactId>embedded-database-spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.zonky.test</groupId>
+            <artifactId>embedded-postgres</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Données de tests -->
+        <dependency>
+            <groupId>org.instancio</groupId>
+            <artifactId>instancio-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests fonctionnels -->
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-junit-platform-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock-jre8-standalone</artifactId>
+            <version>2.33.2</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.openapitools</groupId>
+                <artifactId>openapi-generator-maven-plugin</artifactId>
+                <version>${openapi-generator-version}</version>
+                <executions>
+                    <execution>
+                        <id>generation_serveur</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/src/main/resources/static/openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.expositiondonneesentrees.generated.api.model</modelPackage>
+                            <apiPackage>org.mte.numecoeval.expositiondonneesentrees.generated.api.server</apiPackage>
+                            <invokerPackage>org.mte.numecoeval.expositiondonneesentrees.generated.api.invoker
+                            </invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>false</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>spring</generatorName>
+                            <library>spring-boot</library>
+                            <configOptions>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>false</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                                <additionalModelTypeAnnotations>
+                                    @lombok.AllArgsConstructor;@lombok.Builder;@lombok.NoArgsConstructor
+                                </additionalModelTypeAnnotations>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>generation_client_sync_calculs</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/../common/src/main/resources/static/api-event-calculs-sync-openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model
+                            </modelPackage>
+                            <apiPackage>org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client
+                            </apiPackage>
+                            <invokerPackage>
+                                org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.invoker
+                            </invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>true</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>java</generatorName>
+                            <library>webclient</library>
+                            <configOptions>
+                                <useJakartaEe>true</useJakartaEe>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>true</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>generation_client_referentiel</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/../common/src/main/resources/static/api-referentiels-openapi.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model
+                            </modelPackage>
+                            <apiPackage>org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.client
+                            </apiPackage>
+                            <invokerPackage>
+                                org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.invoker
+                            </invokerPackage>
+                            <generateApis>true</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>true</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>java</generatorName>
+                            <library>webclient</library>
+                            <configOptions>
+                                <useJakartaEe>true</useJakartaEe>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <reactive>false</reactive>
+                                <useBeanValidation>true</useBeanValidation>
+                                <performBeanValidation>true</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>true</serviceInterface>
+                                <serviceImplementation>true</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                </executions>
+
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/ExpositionDonneesEntreesApplication.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/ExpositionDonneesEntreesApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ee08d0d37f2276bd2e8bacdabedf8c5490beb13
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/ExpositionDonneesEntreesApplication.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.expositiondonneesentrees;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@EnableScheduling
+public class ExpositionDonneesEntreesApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ExpositionDonneesEntreesApplication.class, args);
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/NotFoundException.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/NotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..51b50b6fff05195c9bec9209823056f2ad2802bf
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/NotFoundException.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.exception;
+
+public class NotFoundException extends RuntimeException {
+
+    /**
+     * Constructor with no arg
+     */
+    public NotFoundException() {
+        super();
+    }
+
+}
+
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ReferentielRuntimeException.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ReferentielRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..b81b3654d211e8474de366c546e3fa3d49fbc795
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ReferentielRuntimeException.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReferentielRuntimeException extends RuntimeException{
+
+    private final String errorType;
+
+    public ReferentielRuntimeException(String errorType, String message ) {
+        super(message);
+        this.errorType = errorType;
+
+        Logger logger = LoggerFactory.getLogger(ReferentielRuntimeException.class);
+        logger.error("{}: [ {} ]",errorType,message);
+    }
+
+    public String getErrorType() {
+        return errorType;
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/RestException.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/RestException.java
new file mode 100644
index 0000000000000000000000000000000000000000..eba76eb4de19da689f8d8e9c159d32df9d4def97
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/RestException.java
@@ -0,0 +1,8 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.exception;
+
+public class RestException extends RuntimeException {
+
+    public RestException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ValidationException.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ValidationException.java
new file mode 100644
index 0000000000000000000000000000000000000000..555e056f0093be457dd3d0d03a2066eed6818747
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/exception/ValidationException.java
@@ -0,0 +1,12 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ValidationException extends RuntimeException {
+
+    final String erreur;
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/AbstractEntree.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/AbstractEntree.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ca5495167fcd42e9a30e1a736603af0706e73ca
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/AbstractEntree.java
@@ -0,0 +1,53 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@AllArgsConstructor
+@SuperBuilder
+@NoArgsConstructor
+public abstract class AbstractEntree {
+
+    protected String idLot;
+    protected Long id;
+    /**
+     * Nom du lot de données
+     */
+    protected String nomLot;
+    /**
+     * Nom de l'organisation liée aux données - Metadata
+     */
+    protected String nomOrganisation;
+    /**
+     * Nom de la source de données - Metadata
+     */
+    protected String nomSourceDonnee;
+    /**
+     * La date du lot permet d’agréger les données provenant de différentes sources et d'en faire un suivi temporel
+     */
+    protected LocalDate dateLot;
+    /**
+     * Date de création
+     */
+    protected LocalDateTime dateCreation;
+    /**
+     * Date de dernière mise à jour
+     */
+    protected LocalDateTime dateUpdate;
+    /**
+     * Statut du traitement de la donnée dans NumEcoEval
+     */
+    protected String statutTraitement;
+
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Application.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Application.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc7bb1c31c5eab2406a7590da3a467275cd4af73
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Application.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class Application extends AbstractEntree {
+    String nomApplication;
+    String typeEnvironnement;
+    String nomEquipementVirtuel;
+    String nomSourceDonneeEquipementVirtuel;
+    String domaine;
+    String sousDomaine;
+    String nomEntite;
+    String nomEquipementPhysique;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DataCenter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DataCenter.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc5a9929178546d03ed5d350bf50e87d505ded73
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DataCenter.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class DataCenter extends AbstractEntree {
+
+    String nomCourtDatacenter;
+    String nomLongDatacenter;
+    Double pue;
+    String localisation;
+    String nomEntite;
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DemandeCalcul.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DemandeCalcul.java
new file mode 100644
index 0000000000000000000000000000000000000000..97babf49679362f1b40fb4a3ba148e4aa9a8aa74
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DemandeCalcul.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class DemandeCalcul {
+    String nomLot;
+    String dateLot;
+    String nomOrganisation;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1fc6b302b4d2be80a4559bd0927dd71e7df6e77
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.*;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Accessors(chain = true)
+public class DonneesEntree extends AbstractEntree {
+
+    List<DataCenter> dataCenters = new ArrayList<>();
+
+    List<EquipementPhysique> equipementsPhysiques = new ArrayList<>();
+
+    List<EquipementVirtuel> equipementsVirtuels = new ArrayList<>();
+
+    List<Application> applications = new ArrayList<>();
+
+    List<Messagerie> messageries = new ArrayList<>();
+
+    List<Entite> entites = new ArrayList<>();
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Entite.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Entite.java
new file mode 100644
index 0000000000000000000000000000000000000000..899c0ad789d6ec2ecdd446f339387d1f571370b7
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Entite.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class Entite extends AbstractEntree{
+    String nomEntite;
+    Integer nbCollaborateurs;
+    String responsableEntite;
+    String responsableNumeriqueDurable;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementPhysique.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..cab21accd9f24190b11765b2b48c839f6798f9f2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementPhysique.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class EquipementPhysique extends AbstractEntree {
+    String nomEquipementPhysique;
+    String modele;
+    String type;
+    String statut;
+    String paysDUtilisation;
+    String utilisateur;
+    LocalDate dateAchat;
+    LocalDate dateRetrait;
+    String nbCoeur;
+    String nomCourtDatacenter;
+    Double nbJourUtiliseAn;
+    Float goTelecharge;
+    Double consoElecAnnuelle;
+    boolean serveur;
+    String nomEntite;
+    Double quantite;
+    String modeUtilisation;
+    Double tauxUtilisation;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementVirtuel.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementVirtuel.java
new file mode 100644
index 0000000000000000000000000000000000000000..e93006d002a0d5c1f7cd6c6ca1d95a24cfef98ff
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/EquipementVirtuel.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class EquipementVirtuel extends AbstractEntree {
+    String nomEquipementVirtuel;
+    String nomEquipementPhysique;
+    String nomSourceDonneeEquipementPhysique;
+    Integer vCPU;
+    String cluster;
+    String nomEntite;
+    Double consoElecAnnuelle;
+    String typeEqv;
+    Double capaciteStockage;
+    Double cleRepartition;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Messagerie.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Messagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..d638959108d3c81fae2e53d78133e72b25a9febb
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Messagerie.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class Messagerie extends AbstractEntree {
+    Integer nombreMailEmis;
+    Integer nombreMailEmisXDestinataires;
+    Integer volumeTotalMailEmis;
+    Integer moisAnnee;
+    String nomEntite;
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java
new file mode 100644
index 0000000000000000000000000000000000000000..34dcdd17e3e5ff51a5b6822f4627ea18d2b1b324
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@NoArgsConstructor
+@SuperBuilder
+@Accessors(chain = true)
+public class RapportDemandeCalcul {
+    String nomLot;
+    String dateLot;
+    String nomOrganisation;
+    Integer nbrDataCenter;
+    Integer nbrEquipementPhysique;
+    Integer nbrEquipementVirtuel;
+    Integer nbrApplication;
+    Integer nbrMessagerie;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportImport.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportImport.java
new file mode 100644
index 0000000000000000000000000000000000000000..a35d0635c504c65af8a58223e9be7c16b715bb40
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportImport.java
@@ -0,0 +1,26 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.*;
+import lombok.experimental.SuperBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@AllArgsConstructor
+@SuperBuilder
+@NoArgsConstructor
+public class RapportImport {
+
+    String fichier;
+
+    String type;
+
+    List<String> erreurs = new ArrayList<>();
+
+    List<String> avertissements = new ArrayList<>();
+
+    long nbrLignesImportees = 0;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/ResultatImport.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/ResultatImport.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef4b0c8086fa4a141597a2e8df81fd6d38da7aa0
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/ResultatImport.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@AllArgsConstructor
+@SuperBuilder
+@NoArgsConstructor
+public class ResultatImport {
+
+    List<RapportImport> rapports = new ArrayList<>();
+
+    DonneesEntree donneesEntree = new DonneesEntree();
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Volume.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Volume.java
new file mode 100644
index 0000000000000000000000000000000000000000..a33955010a8ba5420db007e0133c74790997eaf7
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/Volume.java
@@ -0,0 +1,4 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.model;
+
+public record Volume(long nbEnCours, long nbTraite) {
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..311996e6b49d378f9c4cec73c423fa26d5a95753
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java
@@ -0,0 +1,52 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input;
+
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang3.tuple.Pair;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@SuppressWarnings("java:S107")
+// Obligatoire à cause de la gestion des fichiers différents au niveau contrat d'interface
+public interface ImportDonneesEntreePort {
+    String EQUIPEMENT_PHYSIQUE_CSV_HEADER = "modele;quantite;nomEquipementPhysique;type;statut;paysDUtilisation;utilisateur;dateAchat;dateRetrait;nbCoeur;nomCourtDatacenter;goTelecharge;nbJourUtiliseAn;consoElecAnnuelle";
+    String CSV_SEPARATOR = ";";
+    String DATA_CENTER_CSV_HEADER = "nomCourtDatacenter;nomLongDatacenter;pue;localisation";
+
+    String EQUIPEMENT_VIRTUEL_CSV_HEADER = "nomEquipementPhysique;vCPU;cluster";
+
+    String APPLICATION_CSV_HEADER = "nomApplication;typeEnvironnement;nomEquipementPhysique;domaine;sousDomaine";
+    String MESSAGERIE_CSV_HEADER = "nombreMailEmis;nombreMailEmisXDestinataires;volumeTotalMailEmis;MoisAnnee";
+    String ENTITE_CSV_HEADER = "nomEntite;nbCollaborateurs;responsableEntite;responsableNumeriqueDurable";
+
+    ResultatImport importCsv(MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel,
+                             MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite,
+                             String dateLot, String nomOrganisation, String nomLot);
+
+    Pair<RapportImport, List<DataCenter>> importDataCenter(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvDataCenter);
+
+    Pair<RapportImport, List<EquipementPhysique>> importEquipementsPhysiques(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementPhysique);
+
+    Pair<RapportImport, List<EquipementVirtuel>> importEquipementsVirtuels(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementVirtuel);
+
+    Pair<RapportImport, List<Application>> importApplications(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvApplication);
+
+    Pair<RapportImport, List<Messagerie>> importMessageries(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie);
+
+    Pair<RapportImport, List<Entite>> importEntite(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie);
+
+    default boolean isFieldIsMappedAtLeastOnce(CSVRecord csvRecord, String mainName, String... alternativeNames) {
+        if (csvRecord.isMapped(mainName)) {
+            return true;
+        }
+
+        for (String alternativeName : alternativeNames) {
+            if (csvRecord.isMapped(alternativeName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculPort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..79354f2c17373467347efac6768afaf726eade52
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculPort.java
@@ -0,0 +1,41 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportDemandeCalcul;
+
+import java.util.Objects;
+
+public interface SoumissionCalculPort {
+
+    /**
+     * Envoie la demande de calcul pour traitement.
+     * Met à jour le statut de tous les objets d'entrées correspondant et en attente (statut = "EN_ATTENTE") au statut "A_INGERER".
+     * @param demandeCalcul {@link DemandeCalcul} à traiter
+     * @return {@link RapportDemandeCalcul} traçant les modifications effectuées
+     */
+    RapportDemandeCalcul soumissionCalcul(DemandeCalcul demandeCalcul);
+
+    /**
+     * Mets à jour les statuts de données d'entrées pour un rejeu de calcul.
+     * Fait passer tous les objets d'entrées correspondant au statut "A_INGERER" indépendamment de leur statut actuel.
+     * @param demandeCalcul {@link DemandeCalcul} à traiter
+     * @return {@link RapportDemandeCalcul} traçant les modifications effectuées
+     */
+    RapportDemandeCalcul rejeuCalcul(DemandeCalcul demandeCalcul);
+
+    /**
+     * Validation de la demande de calcul
+     * @param demandeCalcul {@link DemandeCalcul} à traiter
+     * @throws ValidationException en cas d'erreur de validation de l'objet {@link DemandeCalcul}
+     */
+    default void validate(DemandeCalcul demandeCalcul) throws ValidationException {
+        if(Objects.isNull(demandeCalcul)) {
+            throw new ValidationException("Corps de la demande obligatoire");
+        }
+
+        if(Objects.isNull(demandeCalcul.getNomLot())) {
+            throw new ValidationException("Nom de lot obligatoire");
+        }
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculSyncPort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculSyncPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..d80a3b20c4390a7fce25ea5c33c0f573ac9a625e
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/SoumissionCalculSyncPort.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportDemandeCalcul;
+
+import java.util.Objects;
+
+public interface SoumissionCalculSyncPort {
+
+    /**
+     * Envoie la demande de calcul pour traitement.
+     * Met à jour le statut de tous les objets d'entrées correspondant et en attente (statut = "EN_ATTENTE") au statut "A_INGERER".
+     *
+     * @param demandeCalcul {@link DemandeCalcul} à traiter
+     * @return {@link RapportDemandeCalcul} traçant les modifications effectuées
+     */
+    RapportDemandeCalcul soumissionCalcul(DemandeCalcul demandeCalcul);
+
+    /**
+     * Validation de la demande de calcul
+     *
+     * @param demandeCalcul {@link DemandeCalcul} à traiter
+     * @throws ValidationException en cas d'erreur de validation de l'objet {@link DemandeCalcul}
+     */
+    default void validate(DemandeCalcul demandeCalcul) throws ValidationException {
+        if (Objects.isNull(demandeCalcul)) {
+            throw new ValidationException("Corps de la demande obligatoire");
+        }
+
+        if (Objects.isNull(demandeCalcul.getNomLot())) {
+            throw new ValidationException("Nom de lot obligatoire");
+        }
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/StatutPourCalculPort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/StatutPourCalculPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..181c022a3561725bb9dfbc24678791b3c41904d9
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/StatutPourCalculPort.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input;
+
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutCalculRest;
+
+public interface StatutPourCalculPort {
+
+    /**
+     * Génère le statut global des calculs
+     *
+     * @param nomLot          nom du lot
+     * @param nomOrganisation nom organisation
+     * @return le StatutCalculRest
+     */
+    StatutCalculRest statutDesCalculs(String nomLot, String nomOrganisation);
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a5978c9bf92e023b48f91fe6de2d8ba8eb7523f
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java
@@ -0,0 +1,510 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl;
+
+import lombok.AllArgsConstructor;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.*;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.ImportDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutTraitement;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper.CSVHelper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementService;
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.TypeEquipementDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.time.LocalDate;
+import java.util.*;
+
+@AllArgsConstructor
+public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort {
+
+    private static final String LABEL_NOM_EQUIPEMENT_PHYSIQUE = "nomEquipementPhysique";
+    private static final String LABEL_NOM_VM = "nomVM";
+    private static final String LABEL_NOM_EQUIPEMENT_VIRTUEL = "nomEquipementVirtuel";
+
+    private static final String[] EQUIPEMENT_PHYSIQUE_HEADER = EQUIPEMENT_PHYSIQUE_CSV_HEADER.split(CSV_SEPARATOR);
+
+    private static final String[] DATA_CENTER_HEADER = DATA_CENTER_CSV_HEADER.split(CSV_SEPARATOR);
+
+    private static final String[] EQUIPEMENT_VIRTUEL_HEADER = EQUIPEMENT_VIRTUEL_CSV_HEADER.split(CSV_SEPARATOR);
+
+    private static final String[] APPLICATION_HEADER = APPLICATION_CSV_HEADER.split(CSV_SEPARATOR);
+    private static final String[] MESSAGERIE_HEADER = MESSAGERIE_CSV_HEADER.split(CSV_SEPARATOR);
+    private static final String[] ENTITE_HEADER = ENTITE_CSV_HEADER.split(CSV_SEPARATOR);
+    private static final String HEADER_NOM_ENTITE = "nomEntite";
+    private static final String HEADER_NOM_SOURCE_DONNEE = "nomSourceDonnee";
+    private static final String LIGNE_INCONSISTENTE = "LIGNE_INCONSISTENTE";
+
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ImportDonneesEntreePortImpl.class);
+    private static final String STATUT_TRAITEMENT_EN_ATTENTE = StatutTraitement.EN_ATTENTE.getValue();
+
+    final ReferentielServicePort referentielServicePort;
+
+    final ErrorManagementService errorManagementService;
+
+    final Map<String, String> errorMessages;
+
+    @Override
+    public ResultatImport importCsv(MultipartFile csvDataCenter,
+                                    MultipartFile csvEquipementPhysique,
+                                    MultipartFile csvEquipementVirtuel,
+                                    MultipartFile csvApplication,
+                                    MultipartFile csvMessagerie,
+                                    MultipartFile csvEntite,
+                                    String dateLot, String nomOrganisation, String nomLot) {
+
+        LocalDate dateLotAsDate = dateLot == null || "".equals(dateLot) ? null : LocalDate.parse(dateLot);
+        ResultatImport resultatImport = new ResultatImport();
+        resultatImport.getDonneesEntree().setStatutTraitement(STATUT_TRAITEMENT_EN_ATTENTE);
+        resultatImport.getDonneesEntree().setDateLot(dateLotAsDate);
+        resultatImport.getDonneesEntree().setNomOrganisation(nomOrganisation);
+        resultatImport.getDonneesEntree().setNomLot(nomLot);
+
+        if (csvDataCenter != null) {
+            Pair<RapportImport, List<DataCenter>> importDataCenter = importDataCenter(nomLot, dateLotAsDate, nomOrganisation, csvDataCenter);
+            resultatImport.getRapports().add(importDataCenter.getKey());
+            resultatImport.getDonneesEntree().setDataCenters(importDataCenter.getValue());
+        }
+
+        if (csvEquipementPhysique != null) {
+            Pair<RapportImport, List<EquipementPhysique>> importEquipementsPhysiques = importEquipementsPhysiques(nomLot, dateLotAsDate, nomOrganisation, csvEquipementPhysique);
+            resultatImport.getRapports().add(importEquipementsPhysiques.getKey());
+            resultatImport.getDonneesEntree().setEquipementsPhysiques(importEquipementsPhysiques.getValue());
+        }
+
+        if (csvEquipementVirtuel != null) {
+            Pair<RapportImport, List<EquipementVirtuel>> importEquipementVirtuel = importEquipementsVirtuels(nomLot, dateLotAsDate, nomOrganisation, csvEquipementVirtuel);
+            resultatImport.getRapports().add(importEquipementVirtuel.getKey());
+            resultatImport.getDonneesEntree().getEquipementsVirtuels().addAll(importEquipementVirtuel.getValue());
+        }
+
+        if (csvApplication != null) {
+            Pair<RapportImport, List<Application>> importApplications = importApplications(nomLot, dateLotAsDate, nomOrganisation, csvApplication);
+            resultatImport.getRapports().add(importApplications.getKey());
+            resultatImport.getDonneesEntree().getApplications().addAll(importApplications.getValue());
+        }
+
+        if (csvMessagerie != null) {
+            Pair<RapportImport, List<Messagerie>> importMessagerie = importMessageries(nomLot, dateLotAsDate, nomOrganisation, csvMessagerie);
+            resultatImport.getRapports().add(importMessagerie.getKey());
+            resultatImport.getDonneesEntree().setMessageries(importMessagerie.getValue());
+        }
+
+        if (csvEntite != null) {
+            Pair<RapportImport, List<Entite>> importEntites = importEntite(nomLot, dateLotAsDate, nomOrganisation, csvEntite);
+            resultatImport.getRapports().add(importEntites.getKey());
+            resultatImport.getDonneesEntree().setEntites(importEntites.getValue());
+        }
+        return resultatImport;
+    }
+
+    @Override
+    public Pair<RapportImport, List<DataCenter>> importDataCenter(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvDataCenter) {
+        List<DataCenter> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvDataCenter.getOriginalFilename());
+        rapportImport.setType("datacenter");
+
+        try (Reader reader = new InputStreamReader(csvDataCenter.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                if (!Arrays.stream(DATA_CENTER_HEADER).allMatch(csvRecord::isMapped)) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvDataCenter.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else {
+                    String localisation = CSVHelper.safeString(csvRecord, "localisation");
+                    String nomLongDataCenter = CSVHelper.safeString(csvRecord, "nomLongDatacenter");
+                    var dataCenter = DataCenter.builder()
+                            .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE)
+                            .nomLot(nomLot)
+                            .dateLot(dateLot)
+                            .nomOrganisation(nomOrganisation)
+                            .nomCourtDatacenter(CSVHelper.safeString(csvRecord, "nomCourtDatacenter"))
+                            .nomLongDatacenter(nomLongDataCenter)
+                            .pue(CSVHelper.safeDouble(csvRecord, "pue"))
+                            .localisation(localisation)
+                            .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                            .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                            .build();
+
+                    domainModels.add(dataCenter);
+                    rapportImport.getErreurs().addAll(errorManagementService.checkDataCenter(dataCenter));
+
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour des DataCenters introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des DataCenters n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour des DataCenters", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des DataCenter n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+
+        return Pair.of(rapportImport, domainModels);
+    }
+
+    @Override
+    public Pair<RapportImport, List<EquipementPhysique>> importEquipementsPhysiques(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementPhysique) {
+        List<EquipementPhysique> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvEquipementPhysique.getOriginalFilename());
+        rapportImport.setType("equipement_physique");
+        List<TypeEquipementDTO> typesEquipement = referentielServicePort.getAllTypesEquipement();
+        Set<String> avertissements = new HashSet<>();
+
+        try (Reader reader = new InputStreamReader(csvEquipementPhysique.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setAllowMissingColumnNames(true)
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord ->
+            {
+                String typeEquipement = csvRecord.get("type");
+                var refTypeEquipementOpt = typesEquipement.stream()
+                        .filter(refType -> refType.getType().equals(typeEquipement))
+                        .findFirst();
+
+                if (!Arrays.stream(EQUIPEMENT_PHYSIQUE_HEADER).allMatch(csvRecord::isMapped)) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvEquipementPhysique.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else if (refTypeEquipementOpt.isEmpty()) {
+                    // CA 1.1
+                    rapportImport.getErreurs().add(errorMessages.get("TYPE_EQUIPEMENT_INCONNU").formatted(csvRecord.get("type"), CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE, "equipement")));
+                } else {
+                    var goTelechargeStr = CSVHelper.safeString(csvRecord, "goTelecharge");
+                    Float goTelecharge = goTelechargeStr == null ? null : NumberUtils.toFloat(goTelechargeStr);
+                    var tauxUtilisationStr = CSVHelper.safeString(csvRecord, "tauxUtilisation");
+                    Double tauxUtilisation = tauxUtilisationStr == null ? null : NumberUtils.toDouble(tauxUtilisationStr);
+
+
+                    EquipementPhysique equipementToAdd = EquipementPhysique.builder()
+                            .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE)
+                            .nomLot(nomLot)
+                            .dateLot(dateLot)
+                            .nomOrganisation(nomOrganisation)
+                            .modele(CSVHelper.safeString(csvRecord, "modele", "refEquipement"))
+                            .type(csvRecord.get("type"))
+                            .quantite(CSVHelper.safeDouble(csvRecord, "quantite"))
+                            .nomEquipementPhysique(CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE, "equipement"))
+                            .statut(CSVHelper.safeString(csvRecord, "statut"))
+                            .paysDUtilisation(CSVHelper.safeString(csvRecord, "paysDUtilisation"))
+                            .utilisateur(CSVHelper.safeString(csvRecord, "utilisateur"))
+                            .dateAchat(CSVHelper.safeParseLocalDate(csvRecord, "dateAchat"))
+                            .dateRetrait(CSVHelper.safeParseLocalDate(csvRecord, "dateRetrait"))
+                            .nbCoeur(CSVHelper.safeString(csvRecord, "nbCoeur"))
+                            .nomCourtDatacenter(CSVHelper.safeString(csvRecord, "nomCourtDatacenter", "refDatacenter"))
+                            .goTelecharge(goTelecharge)
+                            .modeUtilisation(CSVHelper.safeString(csvRecord, "modeUtilisation"))
+                            .tauxUtilisation(tauxUtilisation)
+                            .nbJourUtiliseAn(CSVHelper.safeDouble(csvRecord, "nbJourUtiliseAn"))
+                            .consoElecAnnuelle(CSVHelper.safeDouble(csvRecord, "consoElecAnnuelle"))
+                            .serveur(refTypeEquipementOpt.get().isServeur())
+                            .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                            .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                            .build();
+
+                    var erreurs = errorManagementService.checkEquipementPhysique(equipementToAdd, refTypeEquipementOpt.get().getRefEquipementParDefaut());
+                    rapportImport.getErreurs().addAll(erreurs.getKey());
+                    avertissements.addAll(erreurs.getValue());
+
+                    domainModels.add(equipementToAdd);
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour des équipements physiques introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des équipements physiques n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour des équipements physiques", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des équipements physiques n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+        rapportImport.setAvertissements(avertissements.stream().toList());
+
+        return Pair.of(rapportImport, domainModels);
+    }
+
+    @Override
+    public Pair<RapportImport, List<EquipementVirtuel>> importEquipementsVirtuels(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEquipementVirtuel) {
+        List<EquipementVirtuel> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvEquipementVirtuel.getOriginalFilename());
+        rapportImport.setType("equipement_virtuel");
+
+        try (Reader reader = new InputStreamReader(csvEquipementVirtuel.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setAllowMissingColumnNames(true)
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord ->
+            {
+                boolean isRecordOK = isFieldIsMappedAtLeastOnce(csvRecord, LABEL_NOM_EQUIPEMENT_VIRTUEL, LABEL_NOM_VM)
+                        && Arrays.stream(EQUIPEMENT_VIRTUEL_HEADER).allMatch(csvRecord::isMapped);
+                if (!isRecordOK) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvEquipementVirtuel.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else {
+                    EquipementVirtuel equipementVirtuel = EquipementVirtuel.builder()
+                            .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE)
+                            .nomLot(nomLot)
+                            .dateLot(dateLot)
+                            .nomOrganisation(nomOrganisation)
+                            .nomEquipementVirtuel(CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_VIRTUEL, LABEL_NOM_VM))
+                            .nomEquipementPhysique(CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE))
+                            .nomSourceDonneeEquipementPhysique(CSVHelper.safeString(csvRecord, "nomSourceDonneeEquipementPhysique"))
+                            .vCPU(CSVHelper.safeInteger(csvRecord, "vCPU"))
+                            .cluster(CSVHelper.safeString(csvRecord, "cluster"))
+                            .consoElecAnnuelle(CSVHelper.safeDouble(csvRecord, "consoElecAnnuelle"))
+                            .typeEqv(CSVHelper.safeString(csvRecord, "typeEqv"))
+                            .capaciteStockage(CSVHelper.safeDouble(csvRecord, "capaciteStockage"))
+                            .cleRepartition(CSVHelper.safeDouble(csvRecord, "cleRepartition"))
+                            .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                            .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                            .build();
+
+                    domainModels.add(equipementVirtuel);
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour des équipements virtuels introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des équipements virtuels n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour des équipements virtuels", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des équipements virtuels n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+
+        return Pair.of(rapportImport, domainModels);
+
+    }
+
+    @Override
+    public Pair<RapportImport, List<Application>> importApplications(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvApplication) {
+        List<Application> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvApplication.getOriginalFilename());
+        rapportImport.setType("application");
+
+        try (Reader reader = new InputStreamReader(csvApplication.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setAllowMissingColumnNames(true)
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord ->
+            {
+                boolean isRecordOK = isFieldIsMappedAtLeastOnce(csvRecord, LABEL_NOM_EQUIPEMENT_VIRTUEL, LABEL_NOM_VM)
+                        && Arrays.stream(APPLICATION_HEADER).allMatch(csvRecord::isMapped);
+                if (!isRecordOK) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvApplication.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else {
+                    Application application = Application.builder()
+                            .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE)
+                            .nomLot(nomLot)
+                            .dateLot(dateLot)
+                            .nomOrganisation(nomOrganisation)
+                            .nomApplication(CSVHelper.safeString(csvRecord, "nomApplication"))
+                            .typeEnvironnement(CSVHelper.safeString(csvRecord, "typeEnvironnement"))
+                            .nomEquipementVirtuel(CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_VIRTUEL, LABEL_NOM_VM))
+                            .nomSourceDonneeEquipementVirtuel(CSVHelper.safeString(csvRecord, "nomSourceDonneeEquipementVirtuel"))
+                            .domaine(CSVHelper.safeString(csvRecord, "domaine"))
+                            .sousDomaine(CSVHelper.safeString(csvRecord, "sousDomaine"))
+                            .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                            .nomEquipementPhysique(CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE))
+                            .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                            .build();
+
+                    domainModels.add(application);
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour des applications introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des Applications n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour des Applications", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des Applications n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+
+        return Pair.of(rapportImport, domainModels);
+    }
+
+    @Override
+    public Pair<RapportImport, List<Messagerie>> importMessageries(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie) {
+        List<Messagerie> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvMessagerie.getOriginalFilename());
+        rapportImport.setType("messagerie");
+
+        try (Reader reader = new InputStreamReader(csvMessagerie.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setAllowMissingColumnNames(true)
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord ->
+            {
+                if (!Arrays.stream(MESSAGERIE_HEADER).allMatch(csvRecord::isMapped)) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvMessagerie.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else {
+                    domainModels.add(
+                            Messagerie.builder()
+                                    .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE)
+                                    .nomLot(nomLot)
+                                    .dateLot(dateLot)
+                                    .nomOrganisation(nomOrganisation)
+                                    .nombreMailEmis(CSVHelper.safeInteger(csvRecord, "nombreMailEmis"))
+                                    .nombreMailEmisXDestinataires(CSVHelper.safeInteger(csvRecord, "nombreMailEmisXDestinataires"))
+                                    .volumeTotalMailEmis(CSVHelper.safeInteger(csvRecord, "volumeTotalMailEmis"))
+                                    .moisAnnee(CSVHelper.safeInteger(csvRecord, "MoisAnnee"))
+                                    .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                                    .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                                    .build()
+                    );
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour de la messagerie introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV de la messagerie n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour de la messagerie", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV de la messagerie n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+
+        return Pair.of(rapportImport, domainModels);
+    }
+
+    @Override
+    public Pair<RapportImport, List<Entite>> importEntite(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvEntite) {
+        List<Entite> domainModels = new ArrayList<>();
+        RapportImport rapportImport = new RapportImport();
+        rapportImport.setFichier(csvEntite.getOriginalFilename());
+        rapportImport.setType("entite");
+
+        try (Reader reader = new InputStreamReader(csvEntite.getInputStream())) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setAllowMissingColumnNames(true)
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord ->
+            {
+                if (!Arrays.stream(ENTITE_HEADER).allMatch(csvRecord::isMapped)) {
+                    rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvEntite.getOriginalFilename(), csvRecord.getRecordNumber() + 1));
+                } else {
+                    domainModels.add(
+                            Entite.builder()
+                                    .nomLot(nomLot)
+                                    .dateLot(dateLot)
+                                    .nomOrganisation(nomOrganisation)
+                                    .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE))
+                                    .responsableEntite(CSVHelper.safeString(csvRecord, "responsableEntite"))
+                                    .responsableNumeriqueDurable(CSVHelper.safeString(csvRecord, "responsableNumeriqueDurable"))
+                                    .nbCollaborateurs(CSVHelper.safeInteger(csvRecord, "nbCollaborateurs"))
+                                    .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE))
+                                    .build()
+                    );
+                }
+            });
+
+        } catch (FileNotFoundException e) {
+            LOGGER.error("Erreur CSV pour des entités introuvable", e);
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des entités n'est pas trouvable."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        } catch (Exception e) {
+            LOGGER.error("Erreur durant la lecture d'un CSV pour les entités", e);
+
+            return Pair.of(RapportImport.builder()
+                            .erreurs(Collections.singletonList("Le fichier CSV des entités n'est pas lisible par le système."))
+                            .build()
+                    , Collections.emptyList()
+            );
+        }
+
+        rapportImport.setNbrLignesImportees(domainModels.size());
+
+        return Pair.of(rapportImport, domainModels);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0f73260c61dab67adab68286452b6b65abf9af3
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java
@@ -0,0 +1,52 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportDemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.SoumissionCalculSyncPort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutTraitement;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters.CalculsRestClient;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DataCenterRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.MessagerieRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.CalculRestMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class SoumissionCalculSyncPortImpl implements SoumissionCalculSyncPort {
+
+    EquipementPhysiqueRepository equipementPhysiqueRepository;
+    MessagerieRepository messagerieRepository;
+
+    DataCenterRepository dataCenterRepository;
+    CalculsRestClient calculsRestClient;
+
+    CalculRestMapper calculRestMapper;
+
+    @Override
+    public RapportDemandeCalcul soumissionCalcul(DemandeCalcul demandeCalcul) {
+        validate(demandeCalcul);
+
+        // find equipements physiques à partir de nomLot et nomOrganisation
+        List<Long> equipementPhysiqueIds = equipementPhysiqueRepository.getIdsByNomLotAndStatutTraitement(demandeCalcul.getNomLot(), StatutTraitement.EN_ATTENTE.getValue());
+        List<Long> messagerieEntityIds = messagerieRepository.getIdsByNomLotAndStatutTraitement(demandeCalcul.getNomLot(), StatutTraitement.EN_ATTENTE.getValue());
+
+        // map to Rest
+        var reponseCalculRest = calculsRestClient.postSyncCalcul(
+                equipementPhysiqueIds,
+                messagerieEntityIds
+        );
+
+        var rapport = calculRestMapper.toRest(reponseCalculRest);
+        rapport.setNomLot(demandeCalcul.getNomLot());
+        rapport.setDateLot(demandeCalcul.getDateLot());
+        rapport.setNomOrganisation(demandeCalcul.getNomOrganisation());
+        return rapport;
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6832764f3900b454f45278a346a71f2a5ba7cc95
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java
@@ -0,0 +1,61 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.NotFoundException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Volume;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.StatutPourCalculPort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper.Constants;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jdbc.VolumeJdbc;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.VolumeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+
+@Service
+@Slf4j
+public class StatutPourCalculPortImpl implements StatutPourCalculPort {
+
+    @Autowired
+    private VolumeJdbc volumeJdbc;
+
+    @Autowired
+    private VolumeMapper volumeMapper;
+
+    @Cacheable("statutDesCalculs")
+    @Override
+    public StatutCalculRest statutDesCalculs(String nomLot, String nomOrganisation) {
+
+        var volumeEqPh = volumeJdbc.getVolumeBy(nomLot, nomOrganisation, Constants.TABLE_EQUIPEMENT_PHYSIQUE);
+        var volumeMessagerie = volumeJdbc.getVolumeBy(nomLot, nomOrganisation, Constants.TABLE_MESSAGERIE);
+        return statutCalculs(volumeEqPh, volumeMessagerie);
+    }
+
+    /**
+     * Statut des calculs en cours pour des volumes recuperes de la bdd
+     *
+     * @param volumeEqPh       volume des equipements physiques
+     * @param volumeMessagerie volume de la messagerie
+     * @return le StatutCalculRest
+     */
+    public StatutCalculRest statutCalculs(Volume volumeEqPh, Volume volumeMessagerie) {
+        var totalTraite = volumeEqPh.nbTraite() + volumeMessagerie.nbTraite();
+        var totalEnCours = volumeEqPh.nbEnCours() + volumeMessagerie.nbEnCours();
+
+        if (totalTraite + totalEnCours == 0) {
+            throw new NotFoundException();
+        }
+
+        var etat = totalTraite * 100 / (totalTraite + totalEnCours);
+        var statut = StatutCalculRest.StatutEnum.EN_COURS;
+        if (etat == 100) statut = StatutCalculRest.StatutEnum.TERMINE;
+
+        var result = new StatutCalculRest();
+        result.setStatut(statut);
+        result.setEtat(etat + "%");
+        result.setEquipementPhysique(volumeMapper.toRest(volumeEqPh));
+        result.setMessagerie(volumeMapper.toRest(volumeMessagerie));
+        return result;
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/CalculsServicePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/CalculsServicePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e0a9714a0a63ff48f638b630620e8719788e0f2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/CalculsServicePort.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.output;
+
+import java.util.List;
+
+public interface CalculsServicePort {
+    void postSyncCalcul(List<Long> equipementPhysiqueIds, List<Long> messagerieIds);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/EntreePersistencePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/EntreePersistencePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..2429a96f319eaa22b8f5b845426a3e257b2967f1
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/EntreePersistencePort.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.output;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.AbstractEntree;
+
+import java.util.List;
+import java.util.Set;
+
+public interface EntreePersistencePort<T extends AbstractEntree> {
+    void save(T entree);
+
+    void saveAll(List<T> entrees);
+
+    default int updateStatutInList(String statut, String nomLot, String nomOrganisation, Set<String> noms) {
+        return 0;
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..7fc8e1aa6862219b38c93a4915600b5b247f1f54
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.output;
+
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.*;
+
+import java.util.List;
+
+public interface ReferentielServicePort {
+    boolean hasMixElec(String pays);
+
+    List<TypeEquipementDTO> getAllTypesEquipement();
+
+    CorrespondanceRefEquipementDTO getCorrespondance(String modele);
+
+    ImpactEquipementDTO getImpactEquipement(String refEquipement, String critere, String etape);
+
+    List<EtapeDTO> getAllEtapes();
+
+    List<CritereDTO> getAllCriteres();
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/SaveDonneesEntreePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/SaveDonneesEntreePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..7624aba2dfc8fe8d2933064f1978c0a19d4639f8
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/SaveDonneesEntreePort.java
@@ -0,0 +1,14 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.ports.output;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DonneesEntree;
+
+public interface SaveDonneesEntreePort {
+
+    /**
+     * Sauvegarde de toutes les données d'entrées
+     *
+     * @param donneesEntree {@link DonneesEntree} données à traiter
+     */
+    void save(DonneesEntree donneesEntree);
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1da6ce1ab509d8143dc84f5bd172c9bd805ffed
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java
@@ -0,0 +1,36 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.RestException;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtMessagerieApi;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model.ReponseCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model.SyncCalculRest;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class CalculsRestClient {
+
+    private CalculsEquipementPhysiqueEtMessagerieApi calculsEquipementPhysiqueEtMessagerieApi;
+
+    public ReponseCalculRest postSyncCalcul(List<Long> equipementPhysiqueIds, List<Long> messagerieIds) {
+        try {
+
+            var syncCalculRest = new SyncCalculRest();
+            syncCalculRest.setEquipementPhysiqueIds(equipementPhysiqueIds);
+            syncCalculRest.setMessagerieIds(messagerieIds);
+
+            return calculsEquipementPhysiqueEtMessagerieApi.syncCalculByIds(syncCalculRest).block();
+
+        } catch (WebClientResponseException e) {
+            throw new RestException(e);
+        }
+
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..b101173d9df087ab528b0bed0f0ee5be549a3d12
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java
@@ -0,0 +1,86 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.RestException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.client.InterneNumEcoEvalApi;
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.*;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ReferentielRestClient implements ReferentielServicePort {
+
+    private InterneNumEcoEvalApi interneNumEcoEvalApi;
+
+    @Cacheable("hasMixElec")
+    @Override
+    public boolean hasMixElec(String pays) {
+
+        boolean result = false;
+        try {
+            var res = interneNumEcoEvalApi.getMixElectriqueParPaysWithHttpInfo(pays).block();
+            if (res == null || res.getBody() == null) return result;
+            return !res.getBody().isEmpty();
+        } catch (Exception e) {
+            log.error("Une erreur est survenue lors de l'appel au référentiel mix electrique", e);
+        }
+        return result;
+    }
+
+    @Override
+    public List<TypeEquipementDTO> getAllTypesEquipement() {
+        var result = interneNumEcoEvalApi.getAllTypeEquipementWithHttpInfo().block();
+        return result.getBody();
+    }
+
+    @Cacheable("CorrespondanceRefEquipement")
+    @Override
+    public CorrespondanceRefEquipementDTO getCorrespondance(String modele) {
+        try {
+            return interneNumEcoEvalApi.getCorrespondanceRefEquipement(modele).block();
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
+                return null;
+            }
+            throw new RestException(e);
+        }
+    }
+
+    @Cacheable("ImpactEquipement")
+    @Override
+    public ImpactEquipementDTO getImpactEquipement(String refEquipement, String critere, String etape) {
+
+        try {
+            var res = interneNumEcoEvalApi.getImpactEquipement(refEquipement, critere, etape).block();
+            if (res != null) {
+                return res;
+            }
+        } catch (WebClientResponseException e) {
+            if (e.getStatusCode() != HttpStatus.NOT_FOUND) {
+                log.error("Une erreur est survenue lors de l'appel au référentiel impactequipement", e);
+                return null;
+            }
+        }
+        return null;
+    }
+
+    @Cacheable("Etapes")
+    @Override
+    public List<EtapeDTO> getAllEtapes() {
+        return interneNumEcoEvalApi.getAllEtapesWithHttpInfo().block().getBody();
+    }
+
+    @Cacheable("Criteres")
+    @Override
+    public List<CritereDTO> getAllCriteres() {
+        return interneNumEcoEvalApi.getAllCriteresWithHttpInfo().block().getBody();
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3c4ffc90bd6c9cc9c5e73b7d029a49df1c84b14
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.cache;
+
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SchedulerEvictCache {
+
+    @CacheEvict(value = "statutDesCalculs", allEntries = true)
+    @Scheduled(fixedRateString = "${caching.spring.statutDesCalculs}")
+    public void emptyCacheStatutDesCalculs() {
+    }
+
+    @CacheEvict(value = {
+            "hasMixElec",
+            "Etapes",
+            "Criteres",
+            "CorrespondanceRefEquipement",
+            "ImpactEquipement"
+    }, allEntries = true)
+    @Scheduled(fixedRateString = "${caching.spring.referentiels}")
+    public void emptyCacheReferentiel() {
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/ApplicationPortConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/ApplicationPortConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecc79a180445b56b58d736660969c1c9bae6c806
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/ApplicationPortConfig.java
@@ -0,0 +1,26 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.ImportDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl.ImportDonneesEntreePortImpl;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@AllArgsConstructor
+@ComponentScan(basePackages = "org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters")
+public class ApplicationPortConfig {
+
+    private ReferentielServicePort referentielServicePort;
+
+    private ErrorManagementService errorManagementService;
+    private MessageProperties messageProperties;
+
+    @Bean
+    public ImportDonneesEntreePort importDonneesEntreePort() {
+        return new ImportDonneesEntreePortImpl(referentielServicePort, errorManagementService, messageProperties.getMessages());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..608aefe087afa6b01d150aed4877dbfee666df83
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java
@@ -0,0 +1,50 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.client.InterneNumEcoEvalApi;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtMessagerieApi;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.invoker.ApiClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Configuration
+@Slf4j
+public class CommonIntegrationConfig {
+
+    @Value("${numecoeval.calculs.server.url}")
+    String calculUrl;
+
+    @Value("${numecoeval.referentiel.server.url}")
+    String referentielUrl;
+
+    @Bean
+    public CalculsEquipementPhysiqueEtMessagerieApi clientAPISyncCalculs() {
+        CalculsEquipementPhysiqueEtMessagerieApi calculsApi = new CalculsEquipementPhysiqueEtMessagerieApi();
+        var apiClient = new ApiClient(WebClient.builder()
+                .baseUrl(calculUrl)
+                .build());
+        apiClient.setBasePath(calculUrl);
+        calculsApi.setApiClient(apiClient);
+
+        log.info("Création du client d'API Sync Calcul sur l'URL {}", calculUrl);
+
+        return calculsApi;
+    }
+
+    @Bean
+    public InterneNumEcoEvalApi clientAPIReferentiel() {
+        var interneNumEcoEvalApi = new InterneNumEcoEvalApi();
+        var apiClient = new org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.invoker.ApiClient(WebClient.builder()
+                .baseUrl(referentielUrl)
+                .build());
+        apiClient.setBasePath(referentielUrl);
+        interneNumEcoEvalApi.setApiClient(apiClient);
+
+        log.info("Création du client d'API Referentiel sur l'URL {}", referentielUrl);
+
+        return interneNumEcoEvalApi;
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/GeneralConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/GeneralConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f6f4c05088bdd63ef61658caec4807aa0f9daa7
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/GeneralConfig.java
@@ -0,0 +1,32 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableCaching
+public class GeneralConfig {
+
+    @Bean
+    public ObjectMapper getObjectMapper() {
+        ObjectMapper objectMapper = new ObjectMapper()
+                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+                .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
+                .disable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)
+                .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+                .disable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
+                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+                ;
+
+        // Nécessaire pour lire les objets LocalDate/LocalDateTime
+        objectMapper.registerModule(new JavaTimeModule());
+
+        return objectMapper;
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/MessageProperties.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/MessageProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b155075ddec16d50ac936ab41858b4f18393588
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/MessageProperties.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+
+@Component
+@EnableConfigurationProperties
+@ConfigurationProperties
+@Getter
+@Setter
+public class MessageProperties {
+
+    private HashMap<String, String> messages;
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/OpenApiConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/OpenApiConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..5620670cd79c2703a9c1ac0723e21d279a0b6214
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/OpenApiConfig.java
@@ -0,0 +1,47 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class OpenApiConfig {
+
+    private static final String[] IMPORT_PATHS = {
+            "/entrees/json",
+            "/entrees/csv"
+    };
+    private static final String[] CALCUL_PATHS = {
+            "/entrees/calculs/*"
+    };
+
+    @Bean
+    public GroupedOpenApi importGroupApi() {
+        return GroupedOpenApi.builder()
+                .group("Imports")
+                .displayName("NumEcoEval Imports")
+                .pathsToMatch(IMPORT_PATHS)
+                .build();
+    }
+
+    @Bean
+    public GroupedOpenApi calculsGroupApi() {
+        return GroupedOpenApi.builder()
+                .group("Calculs")
+                .displayName("NumEcoEval Calculs")
+                .pathsToMatch(CALCUL_PATHS)
+                .build();
+    }
+
+    @Bean
+    public GroupedOpenApi allGroupApi() {
+        return GroupedOpenApi.builder()
+                .group("All")
+                .displayName("NumEcoEval Toutes les APIs")
+                .pathsToMatch(ArrayUtils.addAll(IMPORT_PATHS, CALCUL_PATHS))
+                .build();
+    }
+
+}
+
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/security/SecurityConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/security/SecurityConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d89f6dba6ceba8038080a1e17e4fd28a5c77dbb
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/security/SecurityConfig.java
@@ -0,0 +1,63 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.security;
+
+import org.springframework.beans.factory.annotation.Value;
+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.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+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;
+
+/**
+ * Configuration Spring Security
+ */
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+    @Value("${numecoeval.urls.allowed:}")
+    private String[] urlsAllowed;
+
+    /**
+     * Configuration pour les endpoints avec une session DNC.
+     */
+    @Bean
+    SecurityFilterChain globalFilterChain(HttpSecurity http) throws Exception {
+        http
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+                .and()
+                .cors()
+                .and()
+                .authorizeHttpRequests(authz -> authz
+                        // Healthcheck Actuator
+                        .requestMatchers("/health").permitAll()
+                        // application
+                        .requestMatchers("/entrees/**").permitAll()
+                        // Springdoc-openapi
+                        .requestMatchers("/v3/api-docs/**").permitAll()
+                        .requestMatchers("/swagger-ui/**").permitAll()
+                        .requestMatchers("/swagger-ui.html").permitAll()
+                        .requestMatchers("/openapi.yaml").permitAll()
+                )
+                .csrf().disable()
+                .formLogin().disable()
+        ;
+        return http.build();
+    }
+
+    @Bean
+    CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration configuration = new CorsConfiguration();
+        configuration.setAllowedOrigins(Arrays.asList(urlsAllowed));
+        configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTION"));
+        configuration.setAllowCredentials(true);
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", configuration);
+        return source;
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/CalculController.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/CalculController.java
new file mode 100644
index 0000000000000000000000000000000000000000..9727613edf8d5d5f6917e951b15272f2b2aa5adc
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/CalculController.java
@@ -0,0 +1,59 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.SoumissionCalculPort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.SoumissionCalculSyncPort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.StatutPourCalculPort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.DemandeCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.ModeRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.RapportDemandeCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.server.CalculsApi;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.CalculRestMapper;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@AllArgsConstructor
+@Slf4j
+public class CalculController implements CalculsApi {
+
+    CalculRestMapper calculRestMapper;
+
+    SoumissionCalculPort soumissionCalculPort;
+
+    SoumissionCalculSyncPort soumissionCalculSyncPort;
+    StatutPourCalculPort statutPourCalculPort;
+
+    @Override
+    public ResponseEntity<StatutCalculRest> statutPourCalcul(String nomLot, String nomOrganisation) {
+        var statut = statutPourCalculPort.statutDesCalculs(nomLot, nomOrganisation);
+        log.info("Statut global des calculs, nomOrganisation: {}, nomLot: {}. Avancement: {}", nomOrganisation, nomLot, statut.getEtat());
+        return ResponseEntity.ok(statut);
+    }
+
+    @Override
+    public ResponseEntity<RapportDemandeCalculRest> soumissionPourCalcul(DemandeCalculRest demandeCalculRest, ModeRest mode) {
+        log.info("Soumission de calcul pour nom_lot: {}, mode: {}", demandeCalculRest.getNomLot(), mode);
+        var demandeCalcul = calculRestMapper.toDomain(demandeCalculRest);
+
+        var soumission = ModeRest.ASYNC == mode ?
+                soumissionCalculPort.soumissionCalcul(demandeCalcul) :
+                soumissionCalculSyncPort.soumissionCalcul(demandeCalcul);
+
+        return ResponseEntity.ok(calculRestMapper.toRest(soumission));
+    }
+
+    @Override
+    public ResponseEntity<RapportDemandeCalculRest> rejeuCalcul(DemandeCalculRest demandeCalculRest) {
+        log.info("Rejeu de calcul, nom_lot: {}", demandeCalculRest.getNomLot());
+        var demandeCalcul = calculRestMapper.toDomain(demandeCalculRest);
+
+        var soumission = soumissionCalculPort.rejeuCalcul(demandeCalcul);
+
+        var responseBody = calculRestMapper.toRest(soumission);
+
+        return ResponseEntity.ok(responseBody);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f89236569276bdcbd539dbce4b1b15e183824c8e
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java
@@ -0,0 +1,172 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;
+
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.ResultatImport;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.ImportDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.SaveDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.DonneesEntreeRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.RapportImportRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.server.ImportsApi;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper.CSVHelper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.DonneesEntreeRestMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementPostSaveService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+
+@RestController
+@AllArgsConstructor
+@SuppressWarnings("java:S107")
+// Obligatoire à cause de la gestion des fichiers différents au niveau contrat d'interface
+public class ImportCSVController implements ImportsApi {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ImportCSVController.class);
+
+    DonneesEntreeRestMapper donneesEntreeMapper;
+
+    ImportDonneesEntreePort importDonneesEntreePort;
+
+    SaveDonneesEntreePort saveDonneesEntreePort;
+
+    ErrorManagementPostSaveService errorManagementPostSaveService;
+
+    @Override
+    public ResponseEntity<List<RapportImportRest>> importCSV(String nomLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite, String dateLot, String nomOrganisation) {
+        return importInterneCSV(nomLot, dateLot, nomOrganisation, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite);
+    }
+
+    public ResponseEntity<List<RapportImportRest>> importInterneCSV(String nomLot, String dateLot, String nomOrganisation, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) {
+        return ResponseEntity.ok(
+                importDonneesFromCSV(
+                        nomLot, dateLot, nomOrganisation,
+                        csvDataCenter,
+                        csvEquipementPhysique,
+                        csvEquipementVirtuel,
+                        csvApplication,
+                        csvMessagerie,
+                        csvEntite
+                )
+        );
+    }
+
+    @Override
+    public ResponseEntity<List<RapportImportRest>> importJson(DonneesEntreeRest donneesEntreeRest) {
+        throw new ResponseStatusException(
+                HttpStatus.NOT_IMPLEMENTED,
+                "Cette méthode d'import n'a pas encore été implémenté."
+        );
+    }
+
+    public List<RapportImportRest> importDonneesFromCSV(
+            String nomLot, String dateLot, String nomOrganisation,
+            MultipartFile csvDataCenter,
+            MultipartFile csvEquipementPhysique,
+            MultipartFile csvEquipementVirtuel,
+            MultipartFile csvApplication,
+            MultipartFile csvMessagerie,
+            MultipartFile csvEntite) throws ValidationException {
+        LOGGER.info("Reception de fichiers pour imports de données d'entrées : Nom de Lot : {}, Date de lot : {}, Nom Organisation : {}", nomLot, dateLot, nomOrganisation);
+
+        validateRequestParametersForImportCSV(nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite);
+
+        return importAllCsv(csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite, dateLot, nomOrganisation, nomLot);
+    }
+
+    /**
+     * Validation des entrées lors d'un import d'un ou plusieurs CSV.
+     *
+     * @param nomLot                Nom de lot
+     * @param dateLot               date du lot
+     * @param csvDataCenter         Fichier CSV des data centers
+     * @param csvEquipementPhysique Fichier CSV des équipements physiques
+     * @param csvEquipementVirtuel  Fichier CSV des équipements virtuels
+     * @param csvApplication        Fichier CSV des applications
+     * @param csvMessagerie         Fichier CSV de la messagerie
+     * @param csvEntite             Fichier CSV des entités
+     * @throws ResponseStatusException avec le statut 400 lorsque les entrées ne sont pas cohérentes.
+     */
+    private void validateRequestParametersForImportCSV(String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) {
+        if (CSVHelper.fileIsNullOrEmpty(csvDataCenter)
+                && CSVHelper.fileIsNullOrEmpty(csvEquipementPhysique)
+                && CSVHelper.fileIsNullOrEmpty(csvEquipementVirtuel)
+                && CSVHelper.fileIsNullOrEmpty(csvApplication)
+                && CSVHelper.fileIsNullOrEmpty(csvMessagerie)
+                && CSVHelper.fileIsNullOrEmpty(csvEntite)
+        ) {
+            LOGGER.error("Import: Erreur contrôle : Tous les fichiers ne peuvent être vides en même temps");
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Tous les fichiers ne peuvent être vides en même temps");
+        }
+
+        if (StringUtils.isBlank(nomLot)) {
+            LOGGER.error("Import: Erreur contrôle : Le nom du Lot ne peut être pas vide");
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le nom du Lot ne peut être pas vide");
+        }
+
+        if (dateLot != null && !"".equals(dateLot)) {
+            try {
+                LocalDate.parse(dateLot);
+            } catch (DateTimeParseException e) {
+                LOGGER.error("Import: Erreur contrôle : La date du lot doit avoir le format yyyy-MM-dd");
+                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "La date du lot doit avoir le format yyyy-MM-dd");
+            }
+        }
+
+    }
+
+    /**
+     * Importe tous les fichiers CSV en paramètre.
+     *
+     * @param csvDataCenter         Fichier CSV des data centers
+     * @param csvEquipementPhysique Fichier CSV des équipements physiques
+     * @param csvEquipementVirtuel  Fichier CSV des équipements virtuels
+     * @param csvApplication        Fichier CSV des applications
+     * @param csvMessagerie         Fichier CSV de la messagerie
+     * @param csvEntite             Fichier CSV des entités
+     * @param dateLot               Date du lot associée aux fichiers
+     * @param nomOrganisation       Nom de l'organisation
+     * @param nomLot                Nom du lot
+     * @return {@link List} des {@link RapportImportRest} correspondant à l'import
+     * @throws ValidationException en cas d'absence de donner à pousser dans le système.
+     */
+    private List<RapportImportRest> importAllCsv(MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite, String dateLot, String nomOrganisation, String nomLot) throws ValidationException {
+        // Lecture & conversion
+        var resultatImport = importDonneesEntreePort.importCsv(csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite, dateLot, nomOrganisation, nomLot);
+
+        saveDonneesEntreePort.save(resultatImport.getDonneesEntree());
+
+        // verifications apres sauvegarde en bdd
+        updateResultatImport(resultatImport, "equipement_physique", errorManagementPostSaveService.checkEquipementPhysiques(nomLot));
+        updateResultatImport(resultatImport, "equipement_virtuel", errorManagementPostSaveService.checkEquipementVirtuels(nomLot));
+        updateResultatImport(resultatImport, "application", errorManagementPostSaveService.checkApplications(nomLot));
+
+        return resultatImport.getRapports().stream()
+                .map(donneesEntreeMapper::toRestDTO)
+                .toList();
+    }
+
+    /**
+     * Mets a jour l'objet ResultatImport en y ajoutant la liste d'erreurs si non vide
+     *
+     * @param resultatImport l'objet resultatImport
+     * @param type           le type d'element
+     * @param erreurs        la liste d'erreur
+     */
+    private void updateResultatImport(ResultatImport resultatImport, String type, List<String> erreurs) {
+        if (erreurs.isEmpty()) return;
+        resultatImport.getRapports().stream()
+                .filter(res -> type.equals(res.getType()))
+                .findFirst()
+                .ifPresent(o -> o.getErreurs().addAll(erreurs));
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandler.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..034c34c771f063fea94f9136b6edff9662bc93b1
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandler.java
@@ -0,0 +1,80 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.NotFoundException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.RestException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.ErreurRest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import java.time.OffsetDateTime;
+
+@ControllerAdvice
+public class RestExceptionHandler extends ResponseEntityExceptionHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestExceptionHandler.class);
+
+    @ExceptionHandler(value = {ValidationException.class})
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public ResponseEntity<ErreurRest> handleValidationException(ValidationException ex, WebRequest request) {
+        LOG.error("Exception de validation survenue lors de la requête {}, Exception : {}", request.getContextPath(), ex.getErreur());
+        return new ResponseEntity<>(
+                ErreurRest.builder()
+                        .code("400")
+                        .message(ex.getErreur())
+                        .timestamp(OffsetDateTime.now())
+                        .status(400)
+                        .build(),
+                HttpStatus.BAD_REQUEST);
+    }
+
+    @ExceptionHandler(value = {NotFoundException.class})
+    @ResponseStatus(HttpStatus.NOT_FOUND)
+    public ResponseEntity<ErreurRest> handleNotFoundException(NotFoundException ex, WebRequest request) {
+        return new ResponseEntity<>(
+                ErreurRest.builder()
+                        .code("404")
+                        .message(ex.getMessage())
+                        .timestamp(OffsetDateTime.now())
+                        .status(404)
+                        .build(),
+                HttpStatus.NOT_FOUND);
+    }
+
+    @ExceptionHandler(value = {RuntimeException.class, RestException.class})
+    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
+    public ResponseEntity<ErreurRest> runtimeException(Exception ex, WebRequest request) {
+        LOG.error("RuntimeException lors d'un traitement sur l'URI {} : {}", request.getContextPath(), ex.getMessage());
+        LOG.debug("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return new ResponseEntity<>(
+                ErreurRest.builder()
+                        .code("500")
+                        .message("Erreur interne de traitement lors du traitement de la requête")
+                        .timestamp(OffsetDateTime.now())
+                        .status(500)
+                        .build(),
+                HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+
+    @ExceptionHandler(value = {Exception.class})
+    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
+    public ResponseEntity<ErreurRest> exception(Exception ex, WebRequest request) {
+        LOG.error("Exception lors d'un traitement sur l'URI {} : {}", request.getContextPath(), ex.getMessage());
+        LOG.debug("Exception lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return new ResponseEntity<>(
+                ErreurRest.builder()
+                        .code("500")
+                        .message("Erreur interne de traitement lors du traitement de la requête")
+                        .timestamp(OffsetDateTime.now())
+                        .status(500)
+                        .build(),
+                HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/handler/RestClientResponseErrorHandler.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/handler/RestClientResponseErrorHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..44925c4d28ed2624278dd84a44d1caa6bcf54eb0
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/handler/RestClientResponseErrorHandler.java
@@ -0,0 +1,40 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.handler;
+
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ReferentielRuntimeException;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.ResponseErrorHandler;
+
+import java.io.IOException;
+
+public class RestClientResponseErrorHandler implements ResponseErrorHandler {
+
+    private String errorType;
+    private String errorMessage;
+
+    public RestClientResponseErrorHandler(String errorType, String errorMessage) {
+        this.errorType = errorType;
+        this.errorMessage = errorMessage;
+    }
+
+
+    @Override
+    public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
+        return (httpResponse.getStatusCode().is4xxClientError() ||
+                httpResponse.getStatusCode().is5xxServerError());
+    }
+
+
+    @Override
+    public void handleError(ClientHttpResponse httpResponse) throws IOException {
+        if (httpResponse.getStatusCode().is5xxServerError()) {
+            //Handle SERVER_ERROR
+                throw new ReferentielRuntimeException("ErrCalcTech","erreur serveur : "+httpResponse.getStatusText());
+
+        }
+        else if (httpResponse.getStatusCode().is4xxClientError()) {
+            //Handle CLIENT_ERROR
+                throw new ReferentielRuntimeException(errorType,errorMessage);
+        }
+
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/CSVHelper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/CSVHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..976b68b24c0f0a10c0465b79f0aeda32363dcd78
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/CSVHelper.java
@@ -0,0 +1,75 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper;
+
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDate;
+
+public class CSVHelper {
+
+    private CSVHelper() {
+    }
+
+    /**
+     * Renvoie la valeur de la colonne {@param mainName} dans le {@param csvRecord}.
+     * Si le {@param mainName} n'est pas mappé dans le {@link CSVRecord}, la liste des noms alternatifs est utilisée.
+     * Si aucune colonne n'est mappée ou que la liste alternative est vide, la valeur {@code null} est renvoyée.
+     * @param csvRecord La ligne de CSV à traiter
+     * @param mainName Le nom de la colonne souhaitée en 1er
+     * @param alternativeNames Les noms de colonnes alternatifs à utiliser, peut être vide
+     * @return La valeur de la 1er colonne correctement mappée sur la ligne de CSV, {@code null} en absence de mapping ou de contenue
+     */
+    public static String safeString(CSVRecord csvRecord, String mainName, String... alternativeNames) {
+        if(csvRecord.isMapped(mainName)) {
+            return StringUtils.defaultIfBlank(StringUtils.trim(csvRecord.get(mainName)), null);
+        }
+
+        for (String alternativeName : alternativeNames) {
+            if(csvRecord.isMapped(alternativeName)) {
+                return StringUtils.trim(csvRecord.get(alternativeName));
+            }
+        }
+        return null;
+    }
+
+    public static LocalDate safeParseLocalDate(CSVRecord csvRecord, String field) {
+        if(!csvRecord.isMapped(field)) {
+            return null;
+        }
+        if(StringUtils.isEmpty(StringUtils.trim(csvRecord.get(field)))) {
+            return null;
+        }
+        return LocalDate.parse(StringUtils.trim(csvRecord.get(field)));
+    }
+
+    public static Double safeDouble(CSVRecord csvRecord, String field) {
+        if(!csvRecord.isMapped(field)) {
+            return null;
+        }
+        if(!NumberUtils.isCreatable(StringUtils.trim(csvRecord.get(field)))) {
+            return null;
+        }
+        return NumberUtils.toDouble(StringUtils.trim(csvRecord.get(field)));
+    }
+
+    public static Integer safeInteger(CSVRecord csvRecord, String field) {
+        if(!csvRecord.isMapped(field)) {
+            return null;
+        }
+        if(!NumberUtils.isCreatable(StringUtils.trim(csvRecord.get(field)))) {
+            return null;
+        }
+        return NumberUtils.toInt(StringUtils.trim(csvRecord.get(field)));
+    }
+
+    /**
+     * Vérifie si le fichier en paramètre est {@code null} ou vide ({@see MultipartFile#isEmpty()}).
+     * @param fichierATester fichier à tester
+     * @return {@code true} si le fichier est vide ou null sinon {@code false}
+     */
+    public static boolean fileIsNullOrEmpty(MultipartFile fichierATester) {
+        return fichierATester == null || fichierATester.isEmpty();
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c448a70cffe1c8ae0f8feab903321da54a96f50
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper;
+
+public class Constants {
+
+    public static final String TABLE_DONNEES_ENTREES = "en_donnees_entrees";
+    public static final String TABLE_DATA_CENTER = "en_data_center";
+    public static final String TABLE_EQUIPEMENT_PHYSIQUE = "en_equipement_physique";
+    public static final String TABLE_EQUIPEMENT_VIRTUEL = "en_equipement_virtuel";
+    public static final String TABLE_APPLICATION = "en_application";
+    public static final String TABLE_MESSAGERIE = "en_messagerie";
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e6095f9aad73f3e02cbd678d8e2b77fee9fc7d2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jdbc;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportDemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.SoumissionCalculPort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutTraitement;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper.Constants.*;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class SoumissionCalculPortJdbcImpl implements SoumissionCalculPort {
+
+    private static final String STATUT_TRAITEMENT_A_INGERER = StatutTraitement.A_INGERER.getValue();
+
+    private static final String STATUT_TRAITEMENT_EN_ATTENTE = StatutTraitement.EN_ATTENTE.getValue();
+
+    JdbcTemplate jdbcTemplate;
+
+    @Transactional
+    @Override
+    public RapportDemandeCalcul soumissionCalcul(DemandeCalcul demandeCalcul) {
+        validate(demandeCalcul);
+
+        var rapport = new RapportDemandeCalcul();
+        rapport.setNomLot(demandeCalcul.getNomLot());
+        rapport.setDateLot(demandeCalcul.getDateLot());
+        rapport.setNomOrganisation(demandeCalcul.getNomOrganisation());
+        jdbcTemplate.update(getUpdateStatementForTable(TABLE_DONNEES_ENTREES), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE);
+        rapport.setNbrDataCenter(jdbcTemplate.update(getUpdateStatementForTable(TABLE_DATA_CENTER), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE));
+        rapport.setNbrEquipementPhysique(jdbcTemplate.update(getUpdateStatementForTable(TABLE_EQUIPEMENT_PHYSIQUE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE));
+        rapport.setNbrMessagerie(jdbcTemplate.update(getUpdateStatementForTable(TABLE_MESSAGERIE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE));
+        return rapport;
+    }
+
+    @Override
+    public RapportDemandeCalcul rejeuCalcul(DemandeCalcul demandeCalcul) {
+        validate(demandeCalcul);
+
+        var rapport = new RapportDemandeCalcul();
+        rapport.setNomLot(demandeCalcul.getNomLot());
+        rapport.setDateLot(demandeCalcul.getDateLot());
+        rapport.setNomOrganisation(demandeCalcul.getNomOrganisation());
+
+        jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_DONNEES_ENTREES), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot());
+        rapport.setNbrDataCenter(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_DATA_CENTER), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot()));
+        rapport.setNbrEquipementPhysique(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_EQUIPEMENT_PHYSIQUE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot()));
+        rapport.setNbrMessagerie(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_MESSAGERIE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot()));
+        return rapport;
+    }
+
+    private String getUpdateStatementForTable(String table) {
+        return "UPDATE " + table + " SET date_update = NOW(), statut_traitement = ? " +
+                "WHERE nom_lot = ? and statut_traitement = ?";
+    }
+
+    private String getUpdateForRejeuStatementForTable(String table) {
+        return "UPDATE " + table + " SET date_update = NOW(), statut_traitement = ? " +
+                "WHERE nom_lot = ?";
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/VolumeJdbc.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/VolumeJdbc.java
new file mode 100644
index 0000000000000000000000000000000000000000..11275a136df28dc6194e4786a28236ec2c9efae8
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/VolumeJdbc.java
@@ -0,0 +1,75 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jdbc;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.RestException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Volume;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutTraitement;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.sql.Array;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+@Slf4j
+@Service
+public class VolumeJdbc {
+
+    @Autowired
+    private DataSource dataSource;
+
+    private static final String SQL_QUERY_VOLUME = """
+            SELECT count(*) as count from %s
+            WHERE nom_lot = ? AND nom_organisation = ? AND statut_traitement = ANY (?)
+            """;
+
+    /**
+     * @param nomLot          nom lot
+     * @param nomOrganisation nom organisation
+     * @param table           entree table
+     * @return le volume enCours, traite
+     */
+    public Volume getVolumeBy(String nomLot, String nomOrganisation, String table) {
+        long countTermine = 0;
+        long countEnCours = 0;
+
+        try (Connection conn = dataSource.getConnection()) {
+
+            try (PreparedStatement statement = conn.prepareStatement(String.format(SQL_QUERY_VOLUME, table))) {
+
+                Array statuts = conn.createArrayOf("varchar", new String[]{
+                        StatutTraitement.A_INGERER.getValue(),
+                        StatutTraitement.EN_ATTENTE.getValue(),
+                        StatutTraitement.INGERE.getValue()
+                });
+
+                statement.setString(1, nomLot);
+                statement.setString(2, nomOrganisation);
+                statement.setArray(3, statuts);
+
+                var resultSet = statement.executeQuery();
+                while (resultSet.next()) {
+                    countEnCours = resultSet.getLong("count");
+                }
+
+                statuts = conn.createArrayOf("varchar", new String[]{
+                        StatutTraitement.TRAITE.getValue(),
+                        StatutTraitement.EN_ERREUR.getValue()
+                });
+
+                statement.setArray(3, statuts);
+                resultSet = statement.executeQuery();
+                while (resultSet.next()) {
+                    countTermine = resultSet.getLong("count");
+                }
+            }
+        } catch (SQLException e) {
+            log.error("Cannot get volume of table {}", table);
+            throw new RestException(e);
+        }
+
+        return new Volume(countEnCours, countTermine);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..93c80e910419d34fd95e90ca1fe2a4a50ec5fd6c
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapter.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Application;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.ApplicationRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class ApplicationJpaAdapter implements EntreePersistencePort<Application> {
+    private ApplicationRepository repository;
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(Application entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<Application> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListApplication(entrees));
+    }
+}
\ No newline at end of file
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a9e6aed4452cdac180b87a5b5a188131b3c2fa6
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapter.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DataCenterRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class DataCenterJpaAdapter implements EntreePersistencePort<DataCenter> {
+
+    DataCenterRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(DataCenter entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<DataCenter> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListDataCenter(entrees));
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..f97b0c05b48d38333c3966b694606e6936aff1a5
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapter.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DonneesEntree;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DonneesEntreesRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class DonneesEntreesJpaAdapter implements EntreePersistencePort<DonneesEntree> {
+
+    DonneesEntreesRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(DonneesEntree entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<DonneesEntree> entrees) {
+        CollectionUtils.emptyIfNull(entrees).forEach(this::save);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c49757ae5abe88870ff0bfc92bfb3faa155385b4
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapter.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Entite;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EntiteRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class EntiteJpaAdapter implements EntreePersistencePort<Entite> {
+
+    EntiteRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(Entite entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<Entite> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListEntite(entrees));
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7256a142131ea20d00e0e21b0947aee708392ae
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapter.java
@@ -0,0 +1,34 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Set;
+
+@Service
+@AllArgsConstructor
+public class EquipementPhysiqueJpaAdapter implements EntreePersistencePort<EquipementPhysique> {
+
+    EquipementPhysiqueRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(EquipementPhysique entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<EquipementPhysique> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListEquipementPhysique(entrees));
+    }
+
+    public int updateStatutInList(String statut, String nomLot, String nomOrganisation, Set<String> nomsEquipementsPhysiques) {
+        return repository.updateEquipementPhysiqueStatutTraitement(statut, nomLot, nomOrganisation, nomsEquipementsPhysiques);
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..99989e1353dc9d832671eee12148b34c29fe64c4
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapter.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementVirtuel;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementVirtuelRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class EquipementVirtuelJpaAdapter implements EntreePersistencePort<EquipementVirtuel> {
+
+    EquipementVirtuelRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(EquipementVirtuel entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<EquipementVirtuel> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListEquipementVirtuel(entrees) );
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1edae9959e38f16319fcf8a6780fbf78c325d09
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapter.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Messagerie;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.MessagerieRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class MessagerieJpaAdapter implements EntreePersistencePort<Messagerie> {
+
+    MessagerieRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper;
+
+    @Override
+    public void save(Messagerie entree) {
+        repository.save(entreeEntityMapper.toEntity(entree));
+    }
+
+    @Override
+    public void saveAll(List<Messagerie> entrees) {
+        repository.saveAll(entreeEntityMapper.toEntityListMessagerie(entrees));
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..446463b9cb0f21ee842a65315f622338b97d2b9a
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java
@@ -0,0 +1,145 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.time.StopWatch;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.*;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.SaveDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutTraitement;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Slf4j
+@AllArgsConstructor
+@Service
+public class SaveDonneesEntreeAdapter implements SaveDonneesEntreePort {
+
+    private EntreePersistencePort<DonneesEntree> donneesEntreesEntreePersistencePort;
+    private EntreePersistencePort<DataCenter> dataCenterEntreePersistencePort;
+    private EntreePersistencePort<EquipementPhysique> equipementPhysiqueEntreePersistencePort;
+    private EntreePersistencePort<EquipementVirtuel> equipementVirtuelEntreePersistencePort;
+    private EntreePersistencePort<Application> applicationEntreePersistencePort;
+    private EntreePersistencePort<Messagerie> messagerieEntreePersistencePort;
+    private EntreePersistencePort<Entite> entiteEntreePersistencePort;
+
+    @Override
+    @CacheEvict(cacheNames = "correspondanceRefEquipement", allEntries = true)
+    public void save(DonneesEntree donneesEntree) {
+
+        if (donneesEntree == null) {
+            log.warn("Données null reçue");
+            return;
+        }
+
+        log.info("Données reçues  : Nom Lot : {}, Date de lot : {} - Nom Organisation : {}",
+                donneesEntree.getNomLot(), donneesEntree.getDateLot(), donneesEntree.getNomOrganisation()
+        );
+
+
+        Set<String> equipementsPhysiquesImpactes = new HashSet<>();
+        Set<String> csvEquipementPhysiques = new HashSet<>();
+
+        StopWatch globalStopWatch = StopWatch.createStarted();
+
+        StopWatch stopWatch = StopWatch.createStarted();
+        donneesEntreesEntreePersistencePort.save(donneesEntree);
+        stopWatch.stop();
+        log.info("Fin du traitement de l'objet DonneesEntree reçue en {} secondes", stopWatch.getTime(TimeUnit.SECONDS));
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getDataCenters())) {
+            stopWatch = StopWatch.createStarted();
+            dataCenterEntreePersistencePort.saveAll(donneesEntree.getDataCenters());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets DataCenter reçus en {} secondes",
+                    donneesEntree.getDataCenters().size(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+        }
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getEquipementsPhysiques())) {
+            stopWatch = StopWatch.createStarted();
+            equipementPhysiqueEntreePersistencePort.saveAll(donneesEntree.getEquipementsPhysiques());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets EquipementPhysique reçus en {} secondes",
+                    donneesEntree.getEquipementsPhysiques().size(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+            csvEquipementPhysiques = donneesEntree.getEquipementsPhysiques().stream()
+                    .map(EquipementPhysique::getNomEquipementPhysique)
+                    .collect(Collectors.toSet());
+        }
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getEquipementsVirtuels())) {
+            stopWatch = StopWatch.createStarted();
+            equipementVirtuelEntreePersistencePort.saveAll(donneesEntree.getEquipementsVirtuels());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets EquipementVirtuel reçus en {} secondes",
+                    donneesEntree.getEquipementsVirtuels().size(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+
+            equipementsPhysiquesImpactes.addAll(donneesEntree.getEquipementsVirtuels().stream()
+                    .map(EquipementVirtuel::getNomEquipementPhysique)
+                    .collect(Collectors.toSet()));
+        }
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getApplications())) {
+            stopWatch = StopWatch.createStarted();
+            applicationEntreePersistencePort.saveAll(donneesEntree.getApplications());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets Applications reçus en {} secondes",
+                    donneesEntree.getApplications().size(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+
+            equipementsPhysiquesImpactes.addAll(donneesEntree.getApplications().stream()
+                    .map(Application::getNomEquipementPhysique)
+                    .collect(Collectors.toSet()));
+        }
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getMessageries())) {
+            stopWatch = StopWatch.createStarted();
+            messagerieEntreePersistencePort.saveAll(donneesEntree.getMessageries());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets Messagerie reçus en {} secondes",
+                    donneesEntree.getMessageries().size(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+        }
+
+        if (!CollectionUtils.isEmpty(donneesEntree.getEntites())) {
+            stopWatch = StopWatch.createStarted();
+            entiteEntreePersistencePort.saveAll(donneesEntree.getEntites());
+            stopWatch.stop();
+            log.info("Fin du traitement des {} objets Entites reçus en {} secondes",
+                    donneesEntree.getEntites(),
+                    stopWatch.getTime(TimeUnit.SECONDS)
+            );
+        }
+
+
+        equipementsPhysiquesImpactes.removeAll(csvEquipementPhysiques);
+
+        if (!equipementsPhysiquesImpactes.isEmpty()) {
+            // mise a jour du statut_traitement à EN_ATTENTE
+            int nbUpdated = equipementPhysiqueEntreePersistencePort.updateStatutInList(StatutTraitement.EN_ATTENTE.getValue(), donneesEntree.getNomLot(), donneesEntree.getNomOrganisation(), equipementsPhysiquesImpactes);
+            log.info("Traitement en mode delta: Nom de Lot : {} - Date de lot : {} - Nom Organisation : {}. Nombre d'équipements physiques à rejouer : {}, réellement rejoués: {}",
+                    donneesEntree.getNomLot(), donneesEntree.getDateLot(), donneesEntree.getNomOrganisation(),
+                    equipementsPhysiquesImpactes.size(), nbUpdated);
+        }
+
+        globalStopWatch.stop();
+        log.info("Fin du traitement des données reçues : Nom de Lot : {} - Date de lot : {} - Nom Organisation : {}, en {} secondes",
+                donneesEntree.getNomLot(), donneesEntree.getDateLot(), donneesEntree.getNomOrganisation(),
+                globalStopWatch.getTime(TimeUnit.SECONDS)
+        );
+
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/AbstractEntreeEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/AbstractEntreeEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..56f47c673d8d02811722dd05e33740d816c12cd2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/AbstractEntreeEntity.java
@@ -0,0 +1,53 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.MappedSuperclass;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.UpdateTimestamp;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@SuperBuilder
+@MappedSuperclass
+public abstract class AbstractEntreeEntity {
+
+    @CreationTimestamp
+    protected LocalDateTime dateCreation;
+
+    @UpdateTimestamp
+    protected LocalDateTime dateUpdate;
+
+    /**
+     * Nom de l'organisation liée aux données - Metadata
+     */
+    protected String nomOrganisation;
+
+    /**
+     * Nom de la source de données - Metadata
+     */
+    protected String nomSourceDonnee;
+
+    /**
+     * Nom du lot de données
+     */
+    protected String nomLot;
+
+    /**
+     * La date du lot permet d’agréger les données provenant de différentes sources et d'en faire un suivi temporel
+     */
+    protected LocalDate dateLot;
+
+    /**
+     * Statut du traitement de la donnée dans NumEcoEval
+     */
+    protected String statutTraitement;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/ApplicationEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/ApplicationEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..687361b3c041c3da7f590e3d99599084f0d47dd2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/ApplicationEntity.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+/**
+ * Entité représentant une application dans les données d'entrées.
+ */
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode
+@Table(name = "EN_APPLICATION")
+@Entity
+public class ApplicationEntity extends AbstractEntreeEntity{
+   @Id
+   @GeneratedValue(generator = "SEQ_EN_APPLICATION", strategy = GenerationType.SEQUENCE)
+   @SequenceGenerator(name = "SEQ_EN_APPLICATION", sequenceName="SEQ_EN_APPLICATION",allocationSize=1000)
+   @Column(nullable = false)
+   private Long id;
+
+   /**
+    * Nom de l'application
+    */
+   private String nomApplication;
+
+   /**
+    * Type d'environnement de l'instance de l'application
+    */
+   private String typeEnvironnement;
+
+   /**
+    * Référence de l'équipement virtuel rattaché
+    */
+   private String nomEquipementVirtuel;
+
+   /**
+    * Référence de l'équipement physique rattaché
+    */
+   private String nomEquipementPhysique;
+
+   /**
+    * Nom de la source de données pour l'équipement physique rattaché
+    */
+   private String nomSourceDonneeEquipementVirtuel;
+
+   /**
+    * Domaine ou catégorie principale de l'application
+    */
+   private String domaine;
+
+   /**
+    * Domaine ou catégorie secondaire de l'application
+    */
+   private String sousDomaine;
+
+   /**
+    * Nom de l'entité rattachée à l'application
+    */
+   private String nomEntite;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DataCenterEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DataCenterEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f9a6f4b8c6d4d2bbe6420bcad1de36d24fe5d84
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DataCenterEntity.java
@@ -0,0 +1,38 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_DATA_CENTER")
+@Entity
+public class DataCenterEntity extends AbstractEntreeEntity {
+
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_DATA_CENTER", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_DATA_CENTER", sequenceName="SEQ_EN_DATA_CENTER",allocationSize=1000)
+    @Column(nullable = false)
+    protected Long id;
+
+    private String nomCourtDatacenter;
+    private String nomLongDatacenter;
+    private Double pue;
+    private String localisation;
+    private String nomEntite;
+
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DonneesEntreesEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DonneesEntreesEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..277304f7f6a6c0f1059c6b3399745c544b8371d2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/DonneesEntreesEntity.java
@@ -0,0 +1,58 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+/**
+ * Entité représentant un message global d'arrivée de Données d'entrées.
+ */
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_DONNEES_ENTREES")
+@Entity
+public class DonneesEntreesEntity extends AbstractEntreeEntity {
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_DONNEES_ENTREES", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_DONNEES_ENTREES", sequenceName = "SEQ_EN_DONNEES_ENTREES", allocationSize = 1000)
+    @Column(nullable = false)
+    protected Long id;
+
+    /**
+     * Nombre de Data Centers rattachés à ce message de données d'entrées
+     */
+    private Long nbrDataCenter;
+
+    /**
+     * Nombre d'équipments physiques rattachés à ce message de données d'entrées
+     */
+    private Long nbrEquipementsPhysiques;
+
+    /**
+     * Nombre d'équipements virtuels rattachés à ce message de données d'entrées
+     */
+    private Long nbrEquipementsVirtuels;
+
+    /**
+     * Nombre d'applications rattachés à ce message de données d'entrées
+     */
+    private Long nbrApplications;
+
+    /**
+     * Nombre d'éléments de messageries rattachés à ce message de données d'entrées
+     */
+    private Long nbrMessageries;
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EntiteEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EntiteEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc0b05ac741f339bda300a86fafa32ea8d46693c
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EntiteEntity.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_ENTITE")
+@Entity
+public class EntiteEntity extends AbstractEntreeEntity
+{
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_ENTITE", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_ENTITE", sequenceName="SEQ_EN_ENTITE",allocationSize=1000)
+    @Column(nullable = false)
+    private Long id;
+
+    private String nomEntite;
+    private Integer nbCollaborateurs;
+    private String responsableEntite;
+    private String responsableNumeriqueDurable;
+
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementPhysiqueEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementPhysiqueEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..75cd3f41f5ae926f32741753975805881da072f4
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementPhysiqueEntity.java
@@ -0,0 +1,52 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_EQUIPEMENT_PHYSIQUE")
+@Entity
+public class EquipementPhysiqueEntity extends AbstractEntreeEntity {
+
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_EQUIPEMENT_PHYSIQUE", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_EQUIPEMENT_PHYSIQUE", sequenceName = "SEQ_EN_EQUIPEMENT_PHYSIQUE", allocationSize = 1000)
+    @Column(nullable = false)
+    private Long id;
+
+    private String nomEquipementPhysique;
+    private String type;
+    private String modele;
+    private String statut;
+
+    @Column(name = "pays_utilisation")
+    private String paysDUtilisation;
+    private String utilisateur;
+    private LocalDate dateAchat;
+    private LocalDate dateRetrait;
+    private String nbCoeur;
+    private String nomCourtDatacenter;
+    private Double nbJourUtiliseAn;
+    private Float goTelecharge;
+    private Double consoElecAnnuelle;
+    private boolean serveur;
+    private Double dureeVieDefaut;
+    // référence d'équipement par défaut, propre au traitement
+    private String refEquipementParDefaut;
+    // référence d'équipement retenu via Correspondance dans le référentiel, propre au traitement
+    String refEquipementRetenu;
+    private String nomEntite;
+    private Double quantite;
+    private String modeUtilisation;
+    private Double tauxUtilisation;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementVirtuelEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementVirtuelEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fb7ec065b1e355e278a0af92e21aebfa1a01991
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/EquipementVirtuelEntity.java
@@ -0,0 +1,33 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_EQUIPEMENT_VIRTUEL")
+@Entity
+public class EquipementVirtuelEntity extends AbstractEntreeEntity {
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_EQUIPEMENT_VIRTUEL", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_EQUIPEMENT_VIRTUEL", sequenceName = "SEQ_EN_EQUIPEMENT_VIRTUEL", allocationSize = 1000)
+    @Column(nullable = false)
+    private Long id;
+    private String nomEquipementVirtuel;
+    private String nomEquipementPhysique;
+    private String nomSourceDonneeEquipementPhysique;
+    private Integer vCPU;
+    private String cluster;
+    private String nomEntite;
+    private Double consoElecAnnuelle;
+    private String typeEqv;
+    private Double capaciteStockage;
+    private Double cleRepartition;
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/MessagerieEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/MessagerieEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..8682ad72767732c386063e067c63c77f253aef20
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/MessagerieEntity.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.SequenceGenerator;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.SuperBuilder;
+
+@Getter
+@Setter
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "EN_MESSAGERIE")
+@Entity
+public class MessagerieEntity extends AbstractEntreeEntity
+{
+    @Id
+    @GeneratedValue(generator = "SEQ_EN_MESSAGERIE", strategy = GenerationType.SEQUENCE)
+    @SequenceGenerator(name = "SEQ_EN_MESSAGERIE", sequenceName="SEQ_EN_MESSAGERIE",allocationSize=1000)
+    @Column(nullable = false)
+    private Long id;
+    private Integer volumeTotalMailEmis;
+    private Integer nombreMailEmis;
+    private Integer nombreMailEmisXDestinataires;
+    private Integer moisAnnee;
+    private String nomEntite;
+
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/ApplicationRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/ApplicationRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..e56779c112eb1fe292ad873c8a8e2644f5c19afc
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/ApplicationRepository.java
@@ -0,0 +1,31 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.ApplicationEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ApplicationRepository extends JpaRepository<ApplicationEntity, Long> {
+    @Query(value = """
+            SELECT nom_application  FROM en_application ea
+            LEFT join en_equipement_physique eep ON ea.nom_equipement_physique  = eep.nom_equipement_physique
+            WHERE ea.nom_lot = ?1
+            AND (ea.nom_equipement_physique is null
+            OR eep.nom_equipement_physique is null)
+            ORDER BY nom_application
+            """, nativeQuery = true)
+    List<String> getApplicationSansEquipementPhysique(String nomLot);
+
+    @Query(value = """
+            SELECT nom_application  FROM en_application ea
+            LEFT join en_equipement_virtuel eev ON ea.nom_equipement_virtuel = eev.nom_equipement_virtuel
+            WHERE ea.nom_lot = ?1
+            AND (ea.nom_equipement_virtuel is null
+            OR eev.nom_equipement_virtuel is null)
+            ORDER BY nom_application
+            """, nativeQuery = true)
+    List<String> getApplicationSansEquipementVirtuel(String nomLot);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DataCenterRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DataCenterRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..a761918045b32e08ea0789bd32970d3b8950dd8e
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DataCenterRepository.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DataCenterEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface DataCenterRepository extends JpaRepository<DataCenterEntity, Long> {
+
+    long countByNomLot(String nomLot);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DonneesEntreesRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DonneesEntreesRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e08aeec5893cd6b4fe86fa8c14f8e18e23060ee
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/DonneesEntreesRepository.java
@@ -0,0 +1,10 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DonneesEntreesEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface DonneesEntreesRepository extends JpaRepository<DonneesEntreesEntity,Long>
+{
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EntiteRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EntiteRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..25a62cf4089cd910f46a61c33303181f21b71340
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EntiteRepository.java
@@ -0,0 +1,10 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EntiteEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface EntiteRepository extends JpaRepository<EntiteEntity,Long>
+{
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementPhysiqueRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementPhysiqueRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3d870be9d54624c3c463bdb1f5579ca28811cd7
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementPhysiqueRepository.java
@@ -0,0 +1,49 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementPhysiqueEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Set;
+
+@Repository
+public interface EquipementPhysiqueRepository extends JpaRepository<EquipementPhysiqueEntity, Long> {
+
+    @Transactional
+    @Modifying
+    @Query("""
+              UPDATE EquipementPhysiqueEntity eqp
+              SET eqp.statutTraitement = :statut
+              WHERE eqp.nomLot = :nomLot
+              AND eqp.nomOrganisation = :nomOrganisation
+              AND eqp.nomEquipementPhysique IN :noms
+            """)
+    int updateEquipementPhysiqueStatutTraitement(
+            @Param("statut") String statut,
+            @Param("nomLot") String nomLot,
+            @Param("nomOrganisation") String nomOrganisation,
+            @Param("noms") Set<String> noms
+    );
+
+    @Query("select id from #{#entityName} where nomLot = ?1 and statutTraitement = ?2")
+    List<Long> getIdsByNomLotAndStatutTraitement(String nomLot, String statutTraitement);
+
+    @Query(value = """
+            WITH datacenters AS (
+                SELECT nom_court_datacenter FROM en_data_center WHERE nom_lot = ?1
+            )
+            SELECT nom_equipement_physique FROM en_equipement_physique eep
+            WHERE serveur = true
+            AND nom_lot = ?1
+            AND (nom_court_datacenter is null OR
+            nom_court_datacenter NOT IN (SELECT nom_court_datacenter FROM datacenters))
+            ORDER BY nom_equipement_physique
+            """, nativeQuery = true)
+    List<String> getEquipementPhysiqueSansDatacenter(String nomLot);
+
+}
\ No newline at end of file
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementVirtuelRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementVirtuelRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..20fbe3a82f385ca38570047c6146fbab29043047
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/EquipementVirtuelRepository.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementVirtuelEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface EquipementVirtuelRepository extends JpaRepository<EquipementVirtuelEntity, Long> {
+
+    @Query(value = """
+            SELECT nom_equipement_virtuel FROM en_equipement_virtuel eev
+            LEFT join en_equipement_physique eep ON eev.nom_equipement_physique  = eep.nom_equipement_physique
+            WHERE eev.nom_lot = ?1
+            AND (eev.nom_equipement_physique is null
+            OR eep.nom_equipement_physique is null)
+            ORDER BY nom_equipement_virtuel
+            """, nativeQuery = true)
+    List<String> getEquipementVirtuelSansEquipementPhysique(String nomLot);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/MessagerieRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/MessagerieRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..f48d59d2c5dc0501173aaff9363f97a66080b247
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/MessagerieRepository.java
@@ -0,0 +1,14 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository;
+
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.MessagerieEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface MessagerieRepository extends JpaRepository<MessagerieEntity, Long> {
+    @Query("select id from #{#entityName} where nomLot = ?1 and statutTraitement = ?2")
+    List<Long> getIdsByNomLotAndStatutTraitement(String nomLot, String statutTraitement);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/CalculRestMapper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/CalculRestMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ccfe00781433d1d1dae54c83248608b4009f9e2
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/CalculRestMapper.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportDemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.DemandeCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.RapportDemandeCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model.ReponseCalculRest;
+
+@Mapper(componentModel = "spring")
+public interface CalculRestMapper {
+
+    DemandeCalcul toDomain(DemandeCalculRest restDTO);
+
+    RapportDemandeCalculRest toRest(RapportDemandeCalcul domain);
+
+    RapportDemandeCalcul toRest(ReponseCalculRest reponseCalculRest);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/DonneesEntreeRestMapper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/DonneesEntreeRestMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..07d8cf9c96ede3f4a270e4dbb02c2e04a56d5484
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/DonneesEntreeRestMapper.java
@@ -0,0 +1,12 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.RapportImport;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.RapportImportRest;
+
+@Mapper(componentModel = "spring")
+public interface DonneesEntreeRestMapper {
+
+    RapportImportRest toRestDTO(RapportImport rapportImport);
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e2ee607e9fa0f40b02071060eb5d63337c880c9
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java
@@ -0,0 +1,53 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Application;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DonneesEntree;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Entite;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementVirtuel;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Messagerie;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.ApplicationEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DataCenterEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DonneesEntreesEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EntiteEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementPhysiqueEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementVirtuelEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.MessagerieEntity;
+
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface EntreeEntityMapper {
+
+    DonneesEntreesEntity toEntity(DonneesEntree domain);
+    DataCenterEntity toEntity(DataCenter domain);
+    EquipementPhysiqueEntity toEntity(EquipementPhysique domain);
+    @Mapping(target = "vCPU", source = "VCPU")
+    EquipementVirtuelEntity toEntity(EquipementVirtuel domain);
+    ApplicationEntity toEntity(Application domain);
+    MessagerieEntity toEntity(Messagerie domain);
+    EntiteEntity toEntity(Entite domain);
+    List<DataCenterEntity> toEntityListDataCenter(List<DataCenter> domains);
+    List<EquipementPhysiqueEntity> toEntityListEquipementPhysique(List<EquipementPhysique> domains);
+    List<EquipementVirtuelEntity> toEntityListEquipementVirtuel(List<EquipementVirtuel> domains);
+    List<ApplicationEntity> toEntityListApplication(List<Application> domains);
+    List<MessagerieEntity> toEntityListMessagerie(List<Messagerie> domains);
+    List<EntiteEntity> toEntityListEntite(List<Entite> domains);
+
+    DonneesEntree toDomain(DonneesEntreesEntity entity);
+    DataCenter toDomain(DataCenterEntity entity);
+    EquipementPhysique toDomain(EquipementPhysiqueEntity entity);
+    EquipementVirtuel toDomain(EquipementVirtuelEntity entity);
+    Application toDomain(ApplicationEntity entity);
+    Messagerie toDomain(MessagerieEntity entity);
+    Entite toDomain(Entite entity);
+    List<DataCenter> toDomainListDataCenter(List<DataCenterEntity> entities);
+    List<EquipementPhysique> toDomainListEquipementPhysique(List<EquipementPhysiqueEntity> entities);
+    List<EquipementVirtuel> toDomainListEquipementVirtuel(List<EquipementVirtuelEntity> entities);
+    List<Application> toDomainListApplication(List<ApplicationEntity> entities);
+    List<Messagerie> toDomainListMessagerie(List<MessagerieEntity> entities);
+    List<Entite> toDomainListEntite(List<EntiteEntity> entities);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/VolumeMapper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/VolumeMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..99854023db55a7d82e70c8057678c6ac41c7bb3f
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/VolumeMapper.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Volume;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.VolumeRest;
+
+@Mapper(componentModel = "spring")
+public interface VolumeMapper {
+
+    VolumeRest toRest(Volume volume);
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java
new file mode 100644
index 0000000000000000000000000000000000000000..e10fe962bdff06ffae7153267dd9202b9faa20c7
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java
@@ -0,0 +1,54 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.service;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.MessageProperties;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.ApplicationRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementVirtuelRepository;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class ErrorManagementPostSaveService {
+
+    final MessageProperties messageProperties;
+
+    final EquipementPhysiqueRepository equipementPhysiqueRepository;
+    final EquipementVirtuelRepository equipementVirtuelRepository;
+    final ApplicationRepository applicationRepository;
+
+    public List<String> checkEquipementPhysiques(String nomLot) {
+        // CA 3.2
+        return equipementPhysiqueRepository.getEquipementPhysiqueSansDatacenter(nomLot).stream()
+                .map(equipementPhysique -> messageProperties.getMessages().get("EQUIPEMENT_DATACENTER_INCONNU").formatted(equipementPhysique))
+                .toList();
+    }
+
+    public List<String> checkEquipementVirtuels(String nomLot) {
+        // CA 3.3
+        return equipementVirtuelRepository.getEquipementVirtuelSansEquipementPhysique(nomLot).stream()
+                .map(equipementVirtuel -> messageProperties.getMessages().get("EQUIPEMENT_VIRTUEL_INCONNU").formatted(equipementVirtuel))
+                .toList();
+    }
+
+    public List<String> checkApplications(String nomLot) {
+        var result = new ArrayList<String>();
+
+        // CA 3.4.1
+        result.addAll(applicationRepository.getApplicationSansEquipementPhysique(nomLot).stream()
+                .map(equipementVirtuel -> messageProperties.getMessages().get("APPLICATION_AVEC_EQUIPEMENT_PHYSIQUE_INCONNU").formatted(equipementVirtuel))
+                .toList());
+
+        // CA 3.4.2
+        result.addAll(applicationRepository.getApplicationSansEquipementPhysique(nomLot).stream()
+                .map(equipementVirtuel -> messageProperties.getMessages().get("APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU").formatted(equipementVirtuel))
+                .toList());
+        
+        return result;
+    }
+
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java
new file mode 100644
index 0000000000000000000000000000000000000000..952379b7acbcdeaf9a01a8488019dd731bf7dd52
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java
@@ -0,0 +1,114 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.service;
+
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.MessageProperties;
+import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.CorrespondanceRefEquipementDTO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Service
+@AllArgsConstructor
+public class ErrorManagementService {
+
+    final MessageProperties messageProperties;
+
+    final ReferentielServicePort referentielServicePort;
+
+    @Value("#{'${constraints.mode-utilisation}'.split(',')}")
+    private List<String> modeUtilisationList;
+
+    /**
+     * Vérifie si la localisation du datacenter existe dans la table ref_MixElec.pays
+     *
+     * @param dataCenter le datacenter
+     * @return la liste d'erreur
+     */
+    public List<String> checkDataCenter(DataCenter dataCenter) {
+        var result = new ArrayList<String>();
+
+        // CA 1.3
+        if (!referentielServicePort.hasMixElec(dataCenter.getLocalisation())) {
+            result.add(messageProperties.getMessages().get("DATACENTER_MIX_ELEC_LOCALISATION_INCONNUE").formatted(dataCenter.getLocalisation(), dataCenter.getNomLongDatacenter()));
+        }
+
+        return result;
+    }
+
+    /**
+     * Vérifie un equipement physique
+     *
+     * @param equipementPhysique     l'equipement physique
+     * @param refEquipementParDefaut la reference d'equipement par default
+     * @return la paire (erreurs, avertissements)
+     */
+    public Pair<List<String>, List<String>> checkEquipementPhysique(EquipementPhysique equipementPhysique, String refEquipementParDefaut) {
+        var erreurs = new ArrayList<String>();
+
+        // CA 1.2
+        // L'ajout d'un équipement physique dont le pays d'utilisation n'existe pas dans la table ref_MixElec.pays sort l'erreur suivante dans le rapport de contrôle
+        if (StringUtils.isNotBlank(equipementPhysique.getPaysDUtilisation()) &&
+                !referentielServicePort.hasMixElec(equipementPhysique.getPaysDUtilisation())) {
+
+            erreurs.add(messageProperties.getMessages().get("EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE").formatted(equipementPhysique.getPaysDUtilisation(), equipementPhysique.getNomEquipementPhysique()));
+        }
+
+        String refEquipement = refEquipementParDefaut;
+
+        // CA 1.5
+        // L'ajout d'un équipement physique dont le type d'équipement ne possède pas de refEquipementParDefaut et dont le Modele n'est pas présent dans la table des ref_CorrespondanceRefEqP sort l'erreur suivante dans le rapport de contrôle
+        if (StringUtils.isBlank(refEquipementParDefaut)) {
+            CorrespondanceRefEquipementDTO refCorrespondance = referentielServicePort.getCorrespondance(equipementPhysique.getModele());
+            if (refCorrespondance == null) {
+                erreurs.add(messageProperties.getMessages().get("EQUIPEMENT_CORRESPONDANCE_INCONNUE").formatted(equipementPhysique.getNomEquipementPhysique(), equipementPhysique.getType()));
+            } else {
+                refEquipement = refCorrespondance.getRefEquipementCible();
+            }
+        }
+
+        // CA 2.1
+        // L'ajout d'un équipement physique dont la référence d'impact (déterminée à partir de la table de correspondance ou à partir de la table type équipement) est nulle sort un warning
+        var avertissements = new ArrayList<String>();
+
+        var etapes = referentielServicePort.getAllEtapes();
+        var criteres = referentielServicePort.getAllCriteres();
+        for (var critere : criteres) {
+            for (var etape : etapes) {
+                var impact = referentielServicePort.getImpactEquipement(refEquipement, critere.getNomCritere(), etape.getCode());
+                if (impact == null) {
+                    avertissements.add(messageProperties.getMessages().get("EQUIPEMENT_IMPACT_INCONNU").formatted(refEquipement, etape.getCode(), critere.getNomCritere()));
+                }
+            }
+        }
+
+        // CA 3.1
+        // L'ajout d'un équipement dont le date de retrait (equipementPhysique.DateRetrait) précède la date d'achat (equipementPhysique.DateAchat)
+        if (equipementPhysique.getDateAchat() != null && equipementPhysique.getDateRetrait() != null &&
+                equipementPhysique.getDateAchat().isBefore(equipementPhysique.getDateRetrait())) {
+
+            erreurs.add(messageProperties.getMessages().get("EQUIPEMENT_DATE_INCOHERENTE").formatted(equipementPhysique.getNomEquipementPhysique()));
+        }
+        //CA 4.1
+        //L'ajout d'un équipement dont le mode d'utilisation est autre que COPE, BYOD ou null
+        if (equipementPhysique.getModeUtilisation() != null && !modeUtilisationList.contains(equipementPhysique.getModeUtilisation())) {
+            avertissements.add(messageProperties.getMessages().get("EQUIPEMENT_MODE_UTILISATION_INCONNU").formatted(equipementPhysique.getModeUtilisation()));
+        }
+        //CA 5.1
+        //L'ajout d'un équipement dont le taux d'utilisation n'est pas compris entre 0 et 1
+        Double taux = equipementPhysique.getTauxUtilisation();
+        if (taux != null && (taux < 0 || taux > 1)) {
+            avertissements.add(messageProperties.getMessages().get("EQUIPEMENT_TAUX_UTILISATION_INVALIDE").formatted(taux));
+        }
+
+        return Pair.of(erreurs, avertissements);
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/main/resources/application.yaml b/services/api-expositiondonneesentrees/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c41b811a2864a5167ae0c7222e2dd8da0d123463
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/resources/application.yaml
@@ -0,0 +1,92 @@
+# Application
+numecoeval:
+  urls:
+    allowed: "http://localhost"
+  referentiel:
+    server:
+      url: "http://localhost:18080"
+  calculs:
+    server:
+      url: "http://localhost:18085"
+
+# Serveur Web
+server:
+  port: 18081
+  shutdown: graceful
+  tomcat:
+    mbeanregistry:
+      enabled: true
+
+# Actuator
+management:
+  server:
+    port: 18081
+  security:
+    user:
+      name: "actuator"
+      password: "NotReally@GoodPasswordForActuator"
+      roles: ACTUATOR_ADMIN
+  endpoints:
+    web:
+      base-path: /
+      exposure:
+        include: health,prometheus,httptrace,info,metrics,mappings
+
+#CONFIGURATION BASES
+spring:
+  sql:
+    init:
+      mode: always
+  # Base de données
+  datasource:
+    generate-unique-name: true
+    url: "jdbc:postgresql://localhost:5432/postgres?reWriteBatchedInserts=true"
+    username: postgres
+    password: postgres
+    driver-class-name: org.postgresql.Driver
+    tomcat:
+      test-on-borrow: false
+      jmx-enabled: false
+      max-active: 100
+  jpa:
+    #   POSTGRES
+    generate-ddl: true
+    database-platform: org.hibernate.dialect.PostgreSQLDialect
+    hibernate:
+      ddl-auto: none
+    show-sql: false
+    properties:
+      hibernate:
+        order_inserts: true
+        jdbc:
+          batch_size: 1000
+        generate_statistics: false
+    open-in-view: true
+  # Taille des uploads et des requêtes
+  servlet:
+    multipart:
+      max-request-size: "200MB"
+      max-file-size: "50MB"
+
+caching:
+  spring:
+    statutDesCalculs: "PT10S"
+    referentiels: "PT10M"
+
+messages:
+  LIGNE_INCONSISTENTE: "Fichier %s : La ligne n°%d n'est pas consistente avec les headers du fichier"
+  LIGNE_INCORRECTE: "Fichier %s : La ligne n°%d est incorrecte pour l'objet %s requise"
+  TYPE_EQUIPEMENT_INCONNU: "Le type d'équipement %s correspondant à l'équipement %s n'existe pas dans la table des références ref_TypeEquipement"
+  EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE: "Le pays %s correspondant à l'équipement physique %s n'existe pas dans la table des mix électriques ref_MixElec.pays"
+  DATACENTER_MIX_ELEC_LOCALISATION_INCONNUE: "La localisation %s du centre de données %s n'existe pas dans la table des mix électriques ref_MixElec.pays"
+  EQUIPEMENT_CORRESPONDANCE_INCONNUE: "L'équipement %s de type %s ne possède pas de référence d'équipement par défaut dans la table ref_typeEquipement et pas de correspondance dans la table ref_CorrespondanceRefEqP"
+  EQUIPEMENT_IMPACT_INCONNU: "L'impact de l'équipement de référence %s pour l'étape %s et le critère %s ne pourra pas être calculé en raison de l'absence de facteur d'impact sur l'équipement"
+  EQUIPEMENT_DATE_INCOHERENTE: "L'âge de l'équipement %s ne peut être calculé car sa date de retrait précède sa date d'achat"
+  EQUIPEMENT_MODE_UTILISATION_INCONNU: "Le mode d'utilisation renseigné '%s' est inconnu du référentiel"
+  EQUIPEMENT_TAUX_UTILISATION_INVALIDE: "Le taux d'utilisation renseigné '%s' n'est pas valide, il doit être compris entre 0 et 1, le taux par défaut sera appliqué."
+  EQUIPEMENT_DATACENTER_INCONNU: "L'équipement %s n'est lié à aucun datacenter"
+  EQUIPEMENT_VIRTUEL_INCONNU: "L'équipement virtuel %s n'est supporté par aucun équipement physique"
+  APPLICATION_AVEC_EQUIPEMENT_PHYSIQUE_INCONNU: "L'application %s n'est supporté par aucun équipement physique"
+  APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU: "L'application %s n'est supporté par aucun équipement virtuel"
+constraints:
+  mode-utilisation: "BYOD,COPE"
diff --git a/services/api-expositiondonneesentrees/src/main/resources/logback.xml b/services/api-expositiondonneesentrees/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fea456675435e3becdd6dc6d1085241a04b5a126
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/resources/logback.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-expositiondonneesentrees/src/main/resources/schema.sql b/services/api-expositiondonneesentrees/src/main/resources/schema.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a6b627e6429f87542aede23ed4b0521fd2c032aa
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/resources/schema.sql
@@ -0,0 +1,176 @@
+CREATE TABLE IF NOT EXISTS en_donnees_entrees
+(
+    id                        int8         NOT NULL,
+    date_update               timestamp    NULL,
+    date_creation             timestamp    NULL,
+    date_lot                  date         NULL,
+    nom_organisation          varchar(255) NULL,
+    nom_lot                   varchar(255) NULL,
+    nbr_applications          int8         NULL,
+    nbr_data_center           int8         NULL,
+    nbr_equipements_physiques int8         NULL,
+    nbr_equipements_virtuels  int8         NULL,
+    nbr_messageries           int8         NULL,
+    CONSTRAINT en_donnees_entrees_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_data_center
+(
+    id                   int8         NOT NULL,
+    date_creation        timestamp    NULL,
+    date_update          timestamp    NULL,
+    date_lot             date         NULL,
+    nom_lot              varchar(255) NULL,
+    nom_organisation     varchar(255) NULL,
+    nom_source_donnee    varchar(255) NULL,
+    localisation         varchar(255) NULL,
+    nom_court_datacenter varchar(255) NULL,
+    nom_entite           varchar(255) NULL,
+    nom_long_datacenter  varchar(255) NULL,
+    pue                  float8       NULL,
+    CONSTRAINT en_data_center_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_equipement_physique
+(
+    id                        int8         NOT NULL,
+    date_creation             timestamp    NULL,
+    date_update               timestamp    NULL,
+    date_lot                  date         NULL,
+    nom_lot                   varchar(255) NULL,
+    nom_organisation          varchar(255) NULL,
+    nom_source_donnee         varchar(255) NULL,
+    conso_elec_annuelle       float8       NULL,
+    date_achat                date         NULL,
+    date_retrait              date         NULL,
+    duree_vie_defaut          float8       NULL,
+    go_telecharge             float4       NULL,
+    modele                    varchar(255) NULL,
+    nb_coeur                  varchar(255) NULL,
+    nb_jour_utilise_an        float8       NULL,
+    nom_court_datacenter      varchar(255) NULL,
+    nom_entite                varchar(255) NULL,
+    nom_equipement_physique   varchar(255) NULL,
+    pays_utilisation          varchar(255) NULL,
+    quantite                  float8       NULL,
+    serveur                   bool         NOT NULL,
+    statut                    varchar(255) NULL,
+    "type"                    varchar(255) NULL,
+    utilisateur               varchar(255) NULL,
+    mode_utilisation          varchar(255) NULL,
+    taux_utilisation          float8       NULL,
+    CONSTRAINT en_equipement_physique_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_equipement_virtuel
+(
+    id                      int8         NOT NULL,
+    date_creation           timestamp    NULL,
+    date_lot                date         NULL,
+    nom_lot                 varchar(255) NULL,
+    nom_organisation        varchar(255) NULL,
+    nom_source_donnee       varchar(255) NULL,
+    "cluster"               varchar(255) NULL,
+    nom_entite              varchar(255) NULL,
+    nom_equipement_physique varchar(255) NULL,
+    nom_equipement_virtuel  varchar(255) NULL,
+    vcpu                    int4         NULL,
+    CONSTRAINT en_equipement_virtuel_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_application
+(
+    id                      int8         NOT NULL,
+    date_creation           timestamp    NULL,
+    date_lot                date         NULL,
+    nom_lot                 varchar(255) NULL,
+    nom_organisation        varchar(255) NULL,
+    nom_source_donnee       varchar(255) NULL,
+    domaine                 varchar(255) NULL,
+    nom_application         varchar(255) NULL,
+    nom_entite              varchar(255) NULL,
+    nom_equipement_virtuel  varchar(255) NULL,
+    nom_equipement_physique varchar(255) NULL,
+    sous_domaine            varchar(255) NULL,
+    type_environnement      varchar(255) NULL,
+    CONSTRAINT en_application_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_messagerie
+(
+    id                             int8         NOT NULL,
+    date_creation                  timestamp    NULL,
+    date_update                    timestamp    NULL,
+    date_lot                       date         NULL,
+    nom_lot                        varchar(255) NULL,
+    nom_organisation               varchar(255) NULL,
+    nom_source_donnee              varchar(255) NULL,
+    mois_annee                     int4         NULL,
+    nom_entite                     varchar(255) NULL,
+    nombre_mail_emis               int4         NULL,
+    nombre_mail_emisxdestinataires int4         NULL,
+    volume_total_mail_emis         int4         NULL,
+    CONSTRAINT en_messagerie_pkey PRIMARY KEY (id)
+);
+
+CREATE TABLE IF NOT EXISTS en_entite
+(
+    id                                  int8         NOT NULL,
+    date_creation                       timestamp    NULL,
+    date_update                         timestamp    NULL,
+    date_lot                            date         NULL,
+    nom_lot                             varchar(255) NULL,
+    nom_organisation                    varchar(255) NULL,
+    nom_source_donnee                   varchar(255) NULL,
+    nom_entite                          varchar(255) NULL,
+    nb_collaborateurs                   int4         NULL,
+    responsable_entite                  varchar(255) NULL,
+    responsable_numerique_durable       varchar(255) NULL,
+    CONSTRAINT en_entite_pkey PRIMARY KEY (id)
+);
+
+CREATE SEQUENCE IF NOT EXISTS seq_en_entite INCREMENT BY 1000;
+
+ALTER TABLE IF EXISTS en_donnees_entrees ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_data_center ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_application ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+ALTER TABLE IF EXISTS en_messagerie ADD COLUMN IF NOT EXISTS statut_traitement varchar(255);
+
+ALTER TABLE IF EXISTS en_donnees_entrees ADD COLUMN IF NOT EXISTS date_update timestamp;
+ALTER TABLE IF EXISTS en_data_center ADD COLUMN IF NOT EXISTS date_update timestamp;
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS date_update timestamp;
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS date_update timestamp;
+ALTER TABLE IF EXISTS en_application ADD COLUMN IF NOT EXISTS date_update timestamp;
+ALTER TABLE IF EXISTS en_messagerie ADD COLUMN IF NOT EXISTS date_update timestamp;
+
+-- Taiga#937 - Impacts - La source de l'équipement virtuel peut être différente de celle de l'équipement physique
+ALTER TABLE IF EXISTS en_equipement_virtuel
+    ADD COLUMN IF NOT EXISTS nom_source_donnee_equipement_physique varchar(255);
+
+-- Taiga#937 - Impacts - La source de l'instance d'application peut être différente de celle de l'équipement virtuel
+ALTER TABLE IF EXISTS en_application
+    ADD COLUMN IF NOT EXISTS nom_source_donnee_equipement_virtuel varchar(255);
+
+-- Taiga#457 - Impacts - Ajout des colonnes conso_elec_annuelle, type_eqv, capacite_stockage et cle_repartition
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS conso_elec_annuelle float8;
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS type_eqv varchar(255);
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS capacite_stockage float8;
+ALTER TABLE IF EXISTS en_equipement_virtuel ADD COLUMN IF NOT EXISTS cle_repartition float8;
+-- Taiga#457 - Impacts - Ajout de la colonne pour la capacité totale de stockage
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS stockage_total_virtuel float8;
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS mode_utilisation varchar(255);
+ALTER TABLE IF EXISTS en_equipement_physique ADD COLUMN IF NOT EXISTS taux_utilisation float8;
+
+-- Creation indexes
+-- Accelere la recuperation des donnees depuis EquipementPhysiqueIntegrationConfig.java
+CREATE INDEX IF NOT EXISTS idx_en_equipement_physique_statut_traitement ON en_equipement_physique (statut_traitement);
+-- Accelere le count du volume des calculs - api-expositiondonneesentrees
+CREATE INDEX IF NOT EXISTS idx_en_equipement_physique_nom_lot ON en_equipement_physique (nom_lot);
+
+-- Indexes pour api-event-calculs
+-- Accelere la recuperation des equipements virtuels d'un equipement physique
+CREATE INDEX IF NOT EXISTS idx_en_equipement_virtuel_nom_equipement_physique ON en_equipement_virtuel (nom_equipement_physique);
+-- Accelere la recuperation des applications d'un equipement virtuel
+CREATE INDEX IF NOT EXISTS idx_en_application_nom_equipement_physique_et_virtuel ON en_application (nom_equipement_physique, nom_equipement_virtuel);
diff --git a/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml b/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9cd38d0d6829013d3d9ef083404f41e5f8c46e93
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml
@@ -0,0 +1,575 @@
+openapi: 3.0.1
+info:
+  title: NumEcoEval - API données d'entrées
+  version: v0
+  license:
+    name: Apache 2.0
+  description: |
+    API permettant l'import de données dans le système NumEcoEval. \
+    L'import de données seul ne permet pas d'importer et impose de soumettre la demande de calcul après l'import des données.
+tags:
+  - name: Imports
+    description: Endpoints liés à l'import de données dans NumEcoEval
+  - name: Calculs
+    description: Endpoints liés au déclenchement de calcul dans NumEcoEval
+paths:
+  /entrees/calculs/statut:
+    get:
+      summary: Endpoint de récupération du statut des calculs.
+      description: |
+        Endpoint de récupération du statut des calculs.
+      tags:
+        - Calculs
+      operationId: statutPourCalcul
+      parameters:
+        - in: query
+          name: nomLot
+          schema:
+            type: string
+          required: true
+          description: Nom lot
+        - in: query
+          name: nomOrganisation
+          schema:
+            type: string
+          required: true
+          description: Nom Organisation
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Contenu de la soumission incorrecte
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Rapport d'import des données d'entrées
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/StatutCalculRest"
+  /entrees/calculs/soumission:
+    post:
+      summary: Endpoint de soumission de données d'entrées pour lancer les calculs dans NumEcoEval.
+      description: |
+        Endpoint de soumission de données d'entrées pour lancer les calculs dans NumEcoEval.
+      tags:
+        - Calculs
+      operationId: soumissionPourCalcul
+      parameters:
+        - in: query
+          name: mode
+          schema:
+            $ref: "#/components/schemas/ModeRest"
+          required: false
+          description: Mode de traitement, SYNC ou ASYNC
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Contenu de la soumission incorrecte
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Rapport d'import des données d'entrées
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/RapportDemandeCalculRest"
+  /entrees/calculs/rejeu:
+    post:
+      summary: Endpoint de rejeu des calculs à partir des données d'entrées pour relancer les calculs dans NumEcoEval.
+      description: |
+        Endpoint de rejeu des calculs à partir des données d'entrées pour relancer les calculs dans NumEcoEval.
+      tags:
+        - Calculs
+      operationId: rejeuCalcul
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Contenu de la soumission incorrecte
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Rapport d'import des données d'entrées
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/RapportDemandeCalculRest"
+  /entrees/json:
+    post:
+      tags:
+        - Imports
+      summary: Soumission de données d'entrées au format CSV pour calcul d'indicateurs
+      description: |
+        Endpoint de soumission des données d'entrées au format JSON pour le calcul d'indicateurs. \
+        La taille totale de tout le contenu JSON ne doit pas dépasser 10 Mo.
+      operationId: importJson
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DonneesEntreeRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Contenu de la soumission incorrecte
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Rapport d'import des données d'entrées
+          content:
+            'application/json':
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/RapportImportRest"
+  /entrees/csv:
+    post:
+      tags:
+        - Imports
+      summary: Soumission de données d'entrées au format CSV pour calcul d'indicateurs
+      description: |
+        Endpoint de soumission des données d'entrées au format CSV pour le calcul d'indicateurs. \
+        La taille totale de tous les fichiers ne doit pas dépasser 10 Mo. \
+        Le séparateur des fichiers CSV est le point-virgule (;). \
+        Le Header du CSV des data centers est : nomCourtDatacenter;nomLongDatacenter;pue;localisation;nomSourceDonnee \
+        Le Header du CSV des équipements physiques est : modele;quantite;nomEquipementPhysique;type;statut;paysDUtilisation;utilisateur;dateAchat;dateRetrait;nbCoeur;nomCourtDatacenter;goTelecharge;modeUtilisation;tauxUtilisation;nbJourUtiliseAn;consoElecAnnuelle;nomSourceDonnee \
+        Le Header du CSV des équipements virtuels est : nomEquipementVirtuel;nomEquipementPhysique;vCPU;cluster;nomSourceDonnee;nomSourceEquipementPhysique;consoElecAnnuelle;typeEqv;capaciteStockage;cleRepartition \
+        Le Header du CSV des application est : nomApplication;typeEnvironnement;nomEquipementVirtuel;nomEquipementPhysique;domaine;sousDomaine;nomSourceDonnee;typeEqv;nomSourceEquipementVirtuel;capaciteStockage;cleRepartition \
+        Le Header du CSV de la messagerie est : nombreMailEmis;nombreMailEmisXDestinataires;volumeTotalMailEmis;MoisAnnee;nomSourceDonnee \
+        Le Header du CSV des entités est : nomEntite;nbCollaborateurs;responsableEntite;responsableNumeriqueResponsable;nomSourceDonnee
+
+      operationId: importCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              type: object
+              required:
+                - nomLot
+              properties:
+                csvDataCenter:
+                  type: string
+                  format: binary
+                csvEquipementPhysique:
+                  type: string
+                  format: binary
+                csvEquipementVirtuel:
+                  type: string
+                  format: binary
+                csvApplication:
+                  type: string
+                  format: binary
+                csvMessagerie:
+                  type: string
+                  format: binary
+                csvEntite:
+                  type: string
+                  format: binary
+                dateLot:
+                  type: string
+                nomOrganisation:
+                  type: string
+                nomLot:
+                  type: string
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Contenu de la soumission incorrecte
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Rapport d'import des données d'entrées
+          content:
+            'application/json':
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/RapportImportRest"
+components:
+  schemas:
+    StatutTraitement:
+      description: Statut de traitement des données d'entrées dans NumEcoEval
+      type: string
+      enum:
+        - EN_ATTENTE
+        - A_INGERER
+        - INGERE
+        - TRAITE
+        - A_REJOUER
+        - EN_ERREUR
+    DemandeCalculRest:
+      description: Objet à soumettre pour une demande de calcul
+      required:
+        - nomLot
+      properties:
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+    ModeRest:
+      type: string
+      enum:
+        - ASYNC
+        - SYNC
+      default: ASYNC
+    StatutCalculRest:
+      description: Statut des calculs.
+      properties:
+        statut:
+          description: "Statut global des calculs"
+          type: string
+          enum:
+            - TERMINE
+            - EN_COURS
+        etat:
+          description: "Etat des calculs"
+          type: string
+        equipementPhysique:
+          description: "Bloc equipement physique"
+          $ref: '#/components/schemas/VolumeRest'
+        messagerie:
+          description: "Bloc messagerie"
+          $ref: '#/components/schemas/VolumeRest'
+    VolumeRest:
+      description: Volume
+      type: object
+      properties:
+        nbEnCours:
+          type: integer
+        nbTraite:
+          type: integer
+    RapportDemandeCalculRest:
+      description: Rapport de la demande de calcul.
+      properties:
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+        nbrDataCenter:
+          description: Nombre de Data Center concernés
+          type: integer
+        nbrEquipementPhysique:
+          description: Nombre d'équipements physiques concernés
+          type: integer
+        nbrEquipementVirtuel:
+          description: Nombre d'équipements physiques concernés
+          type: integer
+        nbrApplication:
+          description: Nombre d'application concernées
+          type: integer
+        nbrMessagerie:
+          description: Nombre d'éléments de messagerie concernés
+          type: integer
+    ErreurRest:
+      description: Objet standard pour les réponses en cas d'erreur d'API
+      type: object
+      properties:
+        code:
+          description: Code de l'erreur
+          type: string
+        message:
+          description: Message de l'erreur
+          type: string
+        status:
+          description: Code Statut HTTP de la réponse
+          type: integer
+        timestamp:
+          description: Date & Heure de l'erreur
+          type: string
+          format: date-time
+    RapportImportRest:
+      description: Rapport d'import pour un fichier
+      type: object
+      properties:
+        fichier:
+          description: Fichier concerné par le rapport
+          type: string
+        erreurs:
+          description: Erreurs du fichier
+          type: array
+          items:
+            type: string
+        avertissements:
+          description: Avertissements du fichier
+          type: array
+          items:
+            type: string
+        nbrLignesImportees:
+          description: Nombre de lignes importées
+          type: integer
+    DonneesEntreeRest:
+      description: Données d'entres de NumEcoEval
+      type: object
+      required:
+        - dateLot
+        - nomOrganisation
+      properties:
+        nomOrganisation:
+          description: Nom de l'organisation rattachée au données
+          type: string
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+        dateLot:
+          description: Date de lot rattachée au données
+          type: string
+        dataCenters:
+          type: array
+          items:
+            $ref: "#/components/schemas/DataCenterRest"
+        equipementsPhysiques:
+          type: array
+          items:
+            $ref: "#/components/schemas/EquipementPhysiqueRest"
+        messageries:
+          type: array
+          items:
+            $ref: "#/components/schemas/MessagerieRest"
+        entites:
+          type: array
+          items:
+            $ref: "#/components/schemas/EntiteRest"
+    DataCenterRest:
+      description: Représentation d'un DataCenter dans NumEcoEval
+      properties:
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nomLongDatacenter:
+          description: ""
+          type: string
+        pue:
+          description: ""
+          type: number
+        localisation:
+          description: ""
+          type: string
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+    EquipementPhysiqueRest:
+      description: Représentation d'un équipement physique dans NumEcoEval
+      properties:
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        modele:
+          description: ""
+          type: string
+        type:
+          description: ""
+          type: string
+        statut:
+          description: ""
+          type: string
+        paysDUtilisation:
+          description: ""
+          type: string
+        utilisateur:
+          description: ""
+          type: string
+        dateAchat:
+          description: ""
+          type: string
+          format: date
+        dateRetrait:
+          description: ""
+          type: string
+          format: date
+        nbCoeur:
+          description: ""
+          type: string
+        modeUtilisation:
+          description: ""
+          type: string
+        tauxUtilisation:
+          description: ""
+          type: number
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nbJourUtiliseAn:
+          description: ""
+          type: number
+        goTelecharge:
+          description: ""
+          type: number
+        quantite:
+          description: ""
+          type: number
+        serveur:
+          description: ""
+          type: boolean
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        equipementsVirtuels:
+          description: ""
+          items:
+            $ref: "#/components/schemas/EquipementVirtuelRest"
+    EquipementVirtuelRest:
+      description: Représentation d'un équipement virtuel dans NumEcoEval
+      properties:
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        vCPU:
+          description: ""
+          type: integer
+        cluster:
+          description: ""
+          type: string
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        nomSourceDonneeEquipementPhysique:
+          description: "Nom de la source de la donnée pour l'équipement physique"
+          type: string
+        applications:
+          description: ""
+          type: array
+          items:
+            $ref: "#/components/schemas/ApplicationRest"
+        typeEqv:
+          description: |
+            Le type d'équipement virtuel contient "calcul", "stockage" ou null.
+            Peut être omis entièrement si ce n'est pas applicable.
+          type: string
+        capaciteStockage:
+          description: |
+            Capacité de stockage de l'équipement virtuel en To.
+          type: number
+          format: double
+        cleRepartition:
+          description: |
+            La clé de repartition est exprimée comme une fraction.
+          type: number
+          format: double
+        consoElecAnnuelle:
+          description: |
+            Consommation électrique annuelle de l'équipement virtuel.
+          type: number
+          format: double
+    ApplicationRest:
+      description: Représentation d'une application dans NumEcoEval
+      properties:
+        nomApplication:
+          description: ""
+          type: string
+        typeEnvironnement:
+          description: ""
+          type: string
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        domaine:
+          description: ""
+          type: string
+        sousDomaine:
+          description: ""
+          type: string
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        nomSourceDonneeEquipementVirtuel:
+          description: "Nom de la source de la donnée pour l'équipement virtuel"
+          type: string
+    MessagerieRest:
+      description: Représentation d'éléments de messagerie dans NumEcoEval
+      properties:
+        nombreMailEmis:
+          description: ""
+          type: integer
+        nombreMailEmisXDestinataires:
+          description: ""
+          type: integer
+        volumeTotalMailEmis:
+          description: ""
+          type: integer
+        moisAnnee:
+          description: "Mois et Année rattachés au données, format MMAAAA"
+          type: integer
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+    EntiteRest:
+      description: Représentation d'une entité dans NumEcoEval
+      properties:
+        nomEntite:
+          description: "Nom de l'entité"
+          type: string
+        nbCollaborateurs:
+          description: "Nombre de collaborateur de l'entité"
+          type: integer
+        responsableEntite:
+          description: "Nom du responsable de l'entité"
+          type: string
+        responsableNumeriqueDurable:
+          description: "Nom du responsable du numérique durable dans l'entité"
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
\ No newline at end of file
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bdb213e5c574fc002de9fc6f57da89459227be6
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java
@@ -0,0 +1,160 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.port.input;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.*;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl.ImportDonneesEntreePortImpl;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementService;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ImportDonneesEntreePortImplTest {
+    @Mock
+    MultipartFile fileToRead;
+
+    @Mock
+    ReferentielServicePort referentielServicePort;
+
+    Map<String, String> errorMessages = Map.of();
+
+    ImportDonneesEntreePortImpl importDonneesEntreePort;
+    ErrorManagementService errorManagementService;
+
+    @BeforeEach
+    public void init() {
+        MockitoAnnotations.openMocks(this);
+        importDonneesEntreePort = new ImportDonneesEntreePortImpl(referentielServicePort, errorManagementService, errorMessages);
+    }
+
+    @Test
+    void importDataCenter_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        Pair<RapportImport, List<DataCenter>> resultImport = importDonneesEntreePort.importDataCenter(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des DataCenter n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importDataCenter_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        Pair<RapportImport, List<DataCenter>> resultImport = importDonneesEntreePort.importDataCenter(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des DataCenters n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEquipementsPhysiques_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        Pair<RapportImport, List<EquipementPhysique>> resultImport = importDonneesEntreePort.importEquipementsPhysiques(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des équipements physiques n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEquipementsPhysiques_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        Pair<RapportImport, List<EquipementPhysique>> resultImport = importDonneesEntreePort.importEquipementsPhysiques(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des équipements physiques n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEquipementsVirtuels_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        Pair<RapportImport, List<EquipementVirtuel>> resultImport = importDonneesEntreePort.importEquipementsVirtuels(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des équipements virtuels n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEquipementsVirtuels_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        Pair<RapportImport, List<EquipementVirtuel>> resultImport = importDonneesEntreePort.importEquipementsVirtuels(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des équipements virtuels n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importApplications_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        Pair<RapportImport, List<Application>> resultImport = importDonneesEntreePort.importApplications(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des Applications n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importApplications_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        Pair<RapportImport, List<Application>> resultImport = importDonneesEntreePort.importApplications(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des Applications n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importMessageries_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        Pair<RapportImport, List<Messagerie>> resultImport = importDonneesEntreePort.importMessageries(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV de la messagerie n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importMessageries_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        Pair<RapportImport, List<Messagerie>> resultImport = importDonneesEntreePort.importMessageries(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV de la messagerie n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEntite_onIOException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test"));
+
+        var resultImport = importDonneesEntreePort.importEntite(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des entités n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0));
+    }
+
+    @Test
+    void importEntite_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException {
+        Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test"));
+
+        var resultImport = importDonneesEntreePort.importEntite(null, null, null, fileToRead);
+
+        assertTrue(resultImport.getValue().isEmpty());
+        assertEquals("Le fichier CSV des entités n'est pas trouvable.", resultImport.getKey().getErreurs().get(0));
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/SoumissionCalculPortImplTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/SoumissionCalculPortImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3df6461c7df9ea070a921ecd234ee09276bc90ce
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/SoumissionCalculPortImplTest.java
@@ -0,0 +1,86 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.port.input;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DemandeCalcul;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.SoumissionCalculPort;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jdbc.SoumissionCalculPortJdbcImpl;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SoumissionCalculPortImplTest {
+
+    @Mock
+    JdbcTemplate jdbcTemplate;
+
+    SoumissionCalculPort soumissionCalculPort;
+
+    @BeforeEach
+    public void init() {
+        MockitoAnnotations.openMocks(this);
+        soumissionCalculPort = new SoumissionCalculPortJdbcImpl(jdbcTemplate);
+    }
+
+    @Test
+    void whenDemandeIsNull_validateShouldThrowException() {
+        var exception = assertThrows(ValidationException.class, () -> soumissionCalculPort.validate(null));
+        assertEquals("Corps de la demande obligatoire", exception.getErreur());
+    }
+
+    @Test
+    void whenDateLotIsNull_validateShouldThrowException() {
+        var demande = DemandeCalcul.builder()
+                .dateLot(null)
+                .nomOrganisation(null)
+                .nomLot(null)
+                .build();
+        var exception = assertThrows(ValidationException.class, () -> soumissionCalculPort.validate(demande));
+        assertEquals("Nom de lot obligatoire", exception.getErreur());
+    }
+
+    @Test
+    void whenDemandeIsValid_soumissionShouldBeOK() {
+        var demande = DemandeCalcul.builder()
+                .nomLot("TEST|2023-01-01")
+                .build();
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_donnees_entrees"), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(1);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_data_center"), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(2);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_equipement_physique"), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(5);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_messagerie"), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(20);
+
+        var resultat = soumissionCalculPort.soumissionCalcul(demande);
+
+        assertNotNull(resultat);
+        assertEquals(2, resultat.getNbrDataCenter());
+        assertEquals(5, resultat.getNbrEquipementPhysique());
+        assertNull(resultat.getNbrEquipementVirtuel());
+        assertNull(resultat.getNbrApplication());
+        assertEquals(20, resultat.getNbrMessagerie());
+    }
+
+    @Test
+    void whenDemandeIsValid_rejeuShouldBeOK() {
+        var demande = DemandeCalcul.builder()
+                .nomLot("TEST|2023-01-01")
+                .build();
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_donnees_entrees"), Mockito.anyString(), Mockito.anyString())).thenReturn(1);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_data_center"), Mockito.anyString(), Mockito.anyString())).thenReturn(2);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_equipement_physique"), Mockito.anyString(), Mockito.anyString())).thenReturn(5);
+        Mockito.when(jdbcTemplate.update(Mockito.contains("en_messagerie"), Mockito.anyString(), Mockito.anyString())).thenReturn(20);
+
+        var resultat = soumissionCalculPort.rejeuCalcul(demande);
+
+        assertNotNull(resultat);
+        assertEquals(2, resultat.getNbrDataCenter());
+        assertEquals(5, resultat.getNbrEquipementPhysique());
+        assertNull(resultat.getNbrEquipementVirtuel());
+        assertNull(resultat.getNbrApplication());
+        assertEquals(20, resultat.getNbrMessagerie());
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5162cec935f1e158d5a0b112e9465a8205e7589
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java
@@ -0,0 +1,106 @@
+package org.mte.numecoeval.expositiondonneesentrees.domain.port.input;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mapstruct.factory.Mappers;
+import org.mockito.InjectMocks;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.NotFoundException;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Volume;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.impl.StatutPourCalculPortImpl;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.StatutCalculRest;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.VolumeMapper;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.SerializationFeature;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@ExtendWith(MockitoExtension.class)
+class StatutPourCalculPortImplTest {
+
+    @InjectMocks
+    StatutPourCalculPortImpl statutPourCalculPort;
+
+    private static final ObjectMapper mapper = new ObjectMapper()
+            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            .configure(SerializationFeature.INDENT_OUTPUT, true);
+
+    @BeforeEach
+    public void setup() {
+        VolumeMapper volumeMapper = Mappers.getMapper(VolumeMapper.class); // Initialization of the mapper
+        ReflectionTestUtils.setField(statutPourCalculPort, "volumeMapper", volumeMapper);
+    }
+
+    @Test
+    void testStatutDesCalculs_Nominal() throws IOException {
+
+        /* INPUT VOLUME MOCKED */
+        var volumeEqPhysique = new Volume(10L, 100L);
+        var volumeMessagerie = new Volume(50L, 5000L);
+
+        /* EXECUTE : params does not matter in the test */
+        var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeMessagerie);
+
+        var expected = mapper.readValue("""
+                {
+                     "statut" : "EN_COURS",
+                     "etat" : "98%",
+                     "equipementPhysique" : {
+                       "nbEnCours" : 10,
+                       "nbTraite" : 100
+                     },
+                     "messagerie" : {
+                       "nbEnCours" : 50,
+                       "nbTraite" : 5000
+                     }
+                   }
+                """, StatutCalculRest.class);
+
+        /* ASSERT */
+        assertEquals(mapper.writeValueAsString(expected), mapper.writeValueAsString(actual));
+
+    }
+
+    @Test
+    void testStatutDesCalculs_Termine() throws IOException {
+
+        /* INPUT VOLUME MOCKED */
+        var volumeEqPhysique = new Volume(0L, 100L);
+        var volumeMessagerie = new Volume(0L, 5000L);
+
+        /* EXECUTE : params does not matter in the test */
+        var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeMessagerie);
+
+        var expected = mapper.readValue("""
+                {
+                   "statut" : "TERMINE",
+                   "etat" : "100%",
+                   "equipementPhysique" : {
+                     "nbEnCours" : 0,
+                     "nbTraite" : 100
+                   },
+                   "messagerie" : {
+                     "nbEnCours" : 0,
+                     "nbTraite" : 5000
+                   }
+                 }
+                """, StatutCalculRest.class);
+
+        /* ASSERT */
+        assertEquals(mapper.writeValueAsString(expected), mapper.writeValueAsString(actual));
+
+    }
+
+    @Test
+    void testStatutDesCalculs_NotFound() {
+        var volume0 = new Volume(0L, 0L);
+        assertThrows(NotFoundException.class, () -> statutPourCalculPort.statutCalculs(volume0, volume0));
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8ca5bc9d0df40d9a919021536b090502444c096
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java
@@ -0,0 +1,115 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.expositiondonneesentrees.domain.ports.input.ImportDonneesEntreePort;
+import org.mte.numecoeval.expositiondonneesentrees.generated.api.model.DonneesEntreeRest;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter.SaveDonneesEntreeAdapter;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.DonneesEntreeRestMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.DonneesEntreeRestMapperImpl;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementPostSaveService;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ImportCSVControllerTest {
+
+    @InjectMocks
+    private ImportCSVController importCSVController;
+
+    @Mock
+    ImportDonneesEntreePort importDonneesEntreePort;
+
+    @Mock
+    SaveDonneesEntreeAdapter saveDonneesEntreeAdapter;
+
+    DonneesEntreeRestMapper donneesEntreeMapper = new DonneesEntreeRestMapperImpl();
+
+    @Mock
+    ErrorManagementPostSaveService errorManagementPostSaveService;
+
+    @BeforeEach
+    public void init() {
+        MockitoAnnotations.openMocks(this);
+        importCSVController = new ImportCSVController(donneesEntreeMapper, importDonneesEntreePort, saveDonneesEntreeAdapter, errorManagementPostSaveService);
+    }
+
+    @Test
+    void importJson_shouldThrowExceptionWithNotImplemented() {
+        var donneesTests = Instancio.of(DonneesEntreeRest.class).create();
+        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importJson(donneesTests));
+
+        assertEquals(HttpStatus.NOT_IMPLEMENTED, exception.getStatusCode());
+        assertEquals("Cette méthode d'import n'a pas encore été implémenté.", exception.getReason());
+    }
+
+    @Test
+    void importCSV_onNullFiles_shouldThrowResponseStatusExceptionWithBadRequest() {
+        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", null, null, null, null, null, null));
+
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason());
+    }
+
+    @Test
+    void importCSV_onEmptyFiles_shouldThrowResponseStatusExceptionWithBadRequest() {
+        MockMultipartFile csvDataCenters = new MockMultipartFile("csvDataCenterVide.csv", new byte[]{});
+        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementsVide.csv", new byte[]{});
+        MockMultipartFile csvEquipementsVirtuels = new MockMultipartFile("csvEquipementVirtuelVide.csv", new byte[]{});
+        MockMultipartFile csvApplications = new MockMultipartFile("csvApplicationVide.csv", new byte[]{});
+        MockMultipartFile csvMessagerie = new MockMultipartFile("csvMessagerieVide.csv", new byte[]{});
+        MockMultipartFile csvEntite = new MockMultipartFile("csvEntiteVide.csv", new byte[]{});
+
+        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));
+
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason());
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    void importCSV_whenNomLotIsNullOrBlank_shouldThrowResponseStatusExceptionWithBadRequest(String nomLot) throws IOException {
+        MockMultipartFile csvDataCenters = null;
+        InputStream fileEquipement = new FileInputStream(ResourceUtils.getFile("target/test-classes/equipementPhysique.csv"));
+        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement);
+        MockMultipartFile csvEquipementsVirtuels = null;
+        MockMultipartFile csvApplications = null;
+        MockMultipartFile csvMessagerie = null;
+        MockMultipartFile csvEntite = null;
+
+        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV(nomLot, "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));
+
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("Le nom du Lot ne peut être pas vide", exception.getReason());
+    }
+
+    @Test
+    void importCSV_whenDateLotBadFormat_shouldThrowResponseStatusExceptionWithBadRequest() throws IOException {
+        MockMultipartFile csvDataCenters = null;
+        InputStream fileEquipement = new FileInputStream(ResourceUtils.getFile("target/test-classes/equipementPhysique.csv"));
+        MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement);
+        MockMultipartFile csvEquipementsVirtuels = null;
+        MockMultipartFile csvApplications = null;
+        MockMultipartFile csvMessagerie = null;
+        MockMultipartFile csvEntite = null;
+
+        var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("test", "20230101", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite));
+
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("La date du lot doit avoir le format yyyy-MM-dd", exception.getReason());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandlerTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..331c5ac551944890d179cfbff9d32f5c51e6c65f
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/RestExceptionHandlerTest.java
@@ -0,0 +1,64 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.controller;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException;
+import org.springframework.web.context.request.WebRequest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.when;
+
+class RestExceptionHandlerTest {
+
+    RestExceptionHandler restExceptionHandler = new RestExceptionHandler();
+
+    @Mock
+    WebRequest webRequest;
+
+    @BeforeEach
+    public void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void onException_shouldReturnGenericMessage() {
+        Exception erreur = new Exception();
+        when(webRequest.getContextPath()).thenReturn("/test");
+
+        var response = restExceptionHandler.exception(erreur, webRequest);
+        assertNotNull(response.getBody(), "Le corps de la réponse en erreur ne peut être null");
+        assertEquals("500", response.getBody().getCode());
+        assertEquals(500, response.getBody().getStatus());
+        assertEquals("Erreur interne de traitement lors du traitement de la requête", response.getBody().getMessage());
+    }
+
+
+    @Test
+    void onRuntimeException_shouldReturnGenericMessage() {
+        var erreur = new NullPointerException("test");
+        when(webRequest.getContextPath()).thenReturn("/test");
+
+        var response = restExceptionHandler.runtimeException(erreur, webRequest);
+        assertNotNull(response.getBody(), "Le corps de la réponse en erreur ne peut être null");
+        assertEquals("500", response.getBody().getCode());
+        assertEquals(500, response.getBody().getStatus());
+        assertEquals("Erreur interne de traitement lors du traitement de la requête", response.getBody().getMessage());
+    }
+
+
+    @Test
+    void onValidationException_shouldReturnGenericMessage() {
+        var erreur = new ValidationException("Erreur lors de la validation des paramètres");
+        when(webRequest.getContextPath()).thenReturn("/test");
+
+        var response = restExceptionHandler.handleValidationException(erreur, webRequest);
+        assertNotNull(response.getBody(), "Le corps de la réponse en erreur ne peut être null");
+        assertEquals("400", response.getBody().getCode());
+        assertEquals(400, response.getBody().getStatus());
+        assertEquals(erreur.getErreur(), response.getBody().getMessage());
+    }
+
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eeeb03839d552600697cac701e6507c02aeb252
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/ApplicationJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Application;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.ApplicationEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.ApplicationRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class ApplicationJpaAdapterTest {
+    @InjectMocks
+    private ApplicationJpaAdapter jpaAdapter;
+
+    @Mock
+    ApplicationRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new ApplicationJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        Application domain = Instancio.of(Application.class).create();
+        ArgumentCaptor<ApplicationEntity> valueCapture = ArgumentCaptor.forClass(ApplicationEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        Application domain1 = Instancio.of(Application.class).create();
+        Application domain2 = Instancio.of(Application.class).create();
+        ArgumentCaptor<List<ApplicationEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<Application> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2a6853a28f0df9a0473e184b63a7e58d1335f08
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DataCenterJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DataCenterEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DataCenterRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class DataCenterJpaAdapterTest {
+    @InjectMocks
+    private DataCenterJpaAdapter jpaAdapter;
+
+    @Mock
+    DataCenterRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new DataCenterJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        DataCenter domain = Instancio.of(DataCenter.class).create();
+        ArgumentCaptor<DataCenterEntity> valueCapture = ArgumentCaptor.forClass(DataCenterEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        DataCenter domain1 = Instancio.of(DataCenter.class).create();
+        DataCenter domain2 = Instancio.of(DataCenter.class).create();
+        ArgumentCaptor<List<DataCenterEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<DataCenter> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b20b58191c521f7d56c2daabf03713e76a94f3b
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/DonneesEntreesJpaAdapterTest.java
@@ -0,0 +1,63 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.DonneesEntree;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DonneesEntreesEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DonneesEntreesRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class DonneesEntreesJpaAdapterTest {
+    @InjectMocks
+    private DonneesEntreesJpaAdapter jpaAdapter;
+
+    @Mock
+    DonneesEntreesRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new DonneesEntreesJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        DonneesEntree domain = Instancio.of(DonneesEntree.class).create();
+        ArgumentCaptor<DonneesEntreesEntity> valueCapture = ArgumentCaptor.forClass(DonneesEntreesEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveForEachObject() {
+        DonneesEntree domain1 = Instancio.of(DonneesEntree.class).create();
+        DonneesEntree domain2 = Instancio.of(DonneesEntree.class).create();
+        List<DonneesEntree> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(entrees.size())).save(Mockito.any());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..14592ff8de9e55a99f50e0817f70053356c74ebf
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EntiteJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Entite;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EntiteEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EntiteRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class EntiteJpaAdapterTest {
+    @InjectMocks
+    private EntiteJpaAdapter jpaAdapter;
+
+    @Mock
+    EntiteRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new EntiteJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        Entite domain = Instancio.of(Entite.class).create();
+        ArgumentCaptor<EntiteEntity> valueCapture = ArgumentCaptor.forClass(EntiteEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        Entite domain1 = Instancio.of(Entite.class).create();
+        Entite domain2 = Instancio.of(Entite.class).create();
+        ArgumentCaptor<List<EntiteEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<Entite> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..66b5e07ba992a29d9f9d9c7b255c5d4875efbc68
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementPhysiqueJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementPhysiqueEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class EquipementPhysiqueJpaAdapterTest {
+    @InjectMocks
+    private EquipementPhysiqueJpaAdapter jpaAdapter;
+
+    @Mock
+    EquipementPhysiqueRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new EquipementPhysiqueJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        EquipementPhysique domain = Instancio.of(EquipementPhysique.class).create();
+        ArgumentCaptor<EquipementPhysiqueEntity> valueCapture = ArgumentCaptor.forClass(EquipementPhysiqueEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        EquipementPhysique domain1 = Instancio.of(EquipementPhysique.class).create();
+        EquipementPhysique domain2 = Instancio.of(EquipementPhysique.class).create();
+        ArgumentCaptor<List<EquipementPhysiqueEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<EquipementPhysique> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f12f31312b1360304d68b8689e7f2ede5912d0e
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/EquipementVirtuelJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementVirtuel;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementVirtuelEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementVirtuelRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class EquipementVirtuelJpaAdapterTest {
+    @InjectMocks
+    private EquipementVirtuelJpaAdapter jpaAdapter;
+
+    @Mock
+    EquipementVirtuelRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new EquipementVirtuelJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        EquipementVirtuel domain = Instancio.of(EquipementVirtuel.class).create();
+        ArgumentCaptor<EquipementVirtuelEntity> valueCapture = ArgumentCaptor.forClass(EquipementVirtuelEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        EquipementVirtuel domain1 = Instancio.of(EquipementVirtuel.class).create();
+        EquipementVirtuel domain2 = Instancio.of(EquipementVirtuel.class).create();
+        ArgumentCaptor<List<EquipementVirtuelEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<EquipementVirtuel> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bed6a8f0c3c023237d07176072197491592baec
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/MessagerieJpaAdapterTest.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter;
+
+import org.instancio.Instancio;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.expositiondonneesentrees.domain.model.Messagerie;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.MessagerieEntity;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.MessagerieRepository;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper;
+import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.times;
+
+@ExtendWith(MockitoExtension.class)
+class MessagerieJpaAdapterTest {
+    @InjectMocks
+    private MessagerieJpaAdapter jpaAdapter;
+
+    @Mock
+    MessagerieRepository repository;
+
+    EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl();
+
+    @BeforeEach
+    void setup(){
+        jpaAdapter = new MessagerieJpaAdapter(repository, entreeEntityMapper);
+    }
+
+    @Test
+    void saveShouldConvertAndCallSave() {
+        Messagerie domain = Instancio.of(Messagerie.class).create();
+        ArgumentCaptor<MessagerieEntity> valueCapture = ArgumentCaptor.forClass(MessagerieEntity.class);
+
+        jpaAdapter.save(domain);
+
+        Mockito.verify(repository, times(1)).save(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+    }
+
+    @Test
+    void saveAllShouldConvertAndCallSaveAll() {
+        Messagerie domain1 = Instancio.of(Messagerie.class).create();
+        Messagerie domain2 = Instancio.of(Messagerie.class).create();
+        ArgumentCaptor<List<MessagerieEntity>> valueCapture = ArgumentCaptor.forClass(List.class);
+        List<Messagerie> entrees = Arrays.asList(
+                domain1,
+                domain2
+        );
+
+        jpaAdapter.saveAll(entrees);
+
+        Mockito.verify(repository, times(1)).saveAll(valueCapture.capture());
+        assertNotNull(valueCapture.getValue());
+        assertEquals(2, valueCapture.getValue().size());
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/test/DataTableUtils.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/test/DataTableUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..f33acb898a2f72198764094017b0be0c698f94fc
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/test/DataTableUtils.java
@@ -0,0 +1,58 @@
+package org.mte.numecoeval.expositiondonneesentrees.test;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDate;
+import java.util.Map;
+
+/**
+ * Classe utilitaire pour les DataTable et la récupération de champ dans des types particuliers à partir de String.
+ */
+public class DataTableUtils {
+
+    public static String safeString(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return null;
+        }
+        return rowDatatable.get(key);
+    }
+
+    public static LocalDate safeLocalDate(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return null;
+        }
+        return LocalDate.parse(rowDatatable.get(key));
+    }
+
+    public static Double safeDouble(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return null;
+        }
+        return Double.parseDouble(rowDatatable.get(key));
+    }
+
+    public static Float safeFloat(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return null;
+        }
+        return Float.parseFloat(rowDatatable.get(key));
+    }
+
+    public static Integer safeInteger(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return null;
+        }
+        return Integer.parseInt(rowDatatable.get(key));
+    }
+
+    public static Boolean safeBoolean(Map<String, String> rowDatatable, String key) {
+        if(StringUtils.isBlank(rowDatatable.get(key))) {
+            return false;
+        }
+        return Boolean.parseBoolean(rowDatatable.get(key));
+    }
+
+    private DataTableUtils() {
+        // Private constructor
+    }
+}
diff --git a/services/api-expositiondonneesentrees/src/test/resources/application-test.yaml b/services/api-expositiondonneesentrees/src/test/resources/application-test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d44397117df1ff8f32e028e9df94184db4ec38ba
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/resources/application-test.yaml
@@ -0,0 +1,36 @@
+# Application
+numecoeval:
+  referentiel:
+    server:
+      url: "http://localhost:19090"
+
+# Serveur Web
+server:
+  port: 18080
+  tomcat:
+    mbeanregistry:
+      enabled: true
+
+# Actuator
+management:
+  server:
+    port: 18080
+  security:
+    user:
+      name: "test"
+      password: "test"
+      roles: ACTUATOR_ADMIN
+
+#CONFIGURATION BASES
+zonky:
+  test:
+    database:
+      postgres:
+        server:
+          properties:
+            max_connections: 100
+      provider: zonky
+
+spring:
+  jpa:
+    show-sql: true
diff --git a/services/api-expositiondonneesentrees/src/test/resources/equipementPhysique.csv b/services/api-expositiondonneesentrees/src/test/resources/equipementPhysique.csv
new file mode 100644
index 0000000000000000000000000000000000000000..dec2cbe1fa34fe8d08aa4031b70da63b6399cc3f
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/resources/equipementPhysique.csv
@@ -0,0 +1,2 @@
+test
+test
diff --git a/services/api-expositiondonneesentrees/src/test/resources/logback-test.xml b/services/api-expositiondonneesentrees/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000000000000000000000000000000000..276e8663b6ec7e552b8f0fca2c216be40286fadc
--- /dev/null
+++ b/services/api-expositiondonneesentrees/src/test/resources/logback-test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+    <property name="FILE_LOG_PATTERN"
+              value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="FILE_LOG_CHARSET" value="${FILE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+    <!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+    <root level="INFO">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-referentiel/.gitignore b/services/api-referentiel/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..20c8d182d7c273a6d0db62fbf6f998ffb1357150
--- /dev/null
+++ b/services/api-referentiel/.gitignore
@@ -0,0 +1,32 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/api-referentiel/README.md b/services/api-referentiel/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..880578971d3e3660f7400eeb4100afcfd7a2b08f
--- /dev/null
+++ b/services/api-referentiel/README.md
@@ -0,0 +1,4 @@
+# api-referentiel
+
+Application API Référentiel portant le chargement et l'exposition des différents référentiels utilisés par les calculs
+
diff --git a/services/api-referentiel/dependency_check_suppressions.xml b/services/api-referentiel/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15f53bbc9ca0caa969e8cf94333045ac34dbd899
--- /dev/null
+++ b/services/api-referentiel/dependency_check_suppressions.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-security-crypto-5.7.3.jar
+   La librairie Spring Security est en version 5.7.3.
+   Cette CVE est marquée uniquement jusqu'à la version 5.2.4 (exclus)
+   https://nvd.nist.gov/vuln/detail/CVE-2020-5408
+   ]]></notes>
+        <cve>CVE-2020-5408</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: spring-web-5.3.22.jar
+   Dans notre contexte, nous ne recevons pas de code Java de l'extérieur et n'effectuons pas de dé-sérialisation de code Java
+   Côté Spring, le point est déjà remonté comme un faux-positif : https://github.com/spring-projects/spring-framework/issues/24434#issuecomment-744519525
+   ]]></notes>
+        <cve>CVE-2016-1000027</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   file name: snakeyaml-1.33.jar
+   Faux-positif : la version de Snakeyaml est la 1.33, la CVE existe uniquement sur les versions < 1.32
+   https://nvd.nist.gov/vuln/detail/CVE-2022-38752
+   ]]></notes>
+        <cve>CVE-2022-38752</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif sur toutes les librairies utils: https://github.com/jeremylong/DependencyCheck/issues/5213
+   Concerne : software.amazon.awssdk:utils qui n'est pas utilisé
+   ]]></notes>
+        <cve>CVE-2021-4277</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-positif : matchent à tort sur tous les commons : https://github.com/jeremylong/DependencyCheck/issues/5132
+   ]]></notes>
+        <cve>CVE-2021-37533</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+    et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-1471</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-3064</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+   et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2021-4235</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Concerne hutool-json et json-java qui ne sont pas utilisés.
+   Le faux-positif se trouve sur json-path, jackson-core, accessors-smart et json-smart.
+   cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2022-45688</cve>
+    </suppress>
+
+
+    <suppress>
+        <notes><![CDATA[
+   Faux-Positif : Conformément au lien, nous ne sommes pas dans un des cas de vulnérabilité.
+   cf. cf. https://github.com/jeremylong/DependencyCheck/issues/5502
+   ]]></notes>
+        <cve>CVE-2023-20862</cve>
+    </suppress>
+</suppressions>
diff --git a/services/api-referentiel/pom.xml b/services/api-referentiel/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..183894cc3afebfffbc9e3808f83f3e9a838f338d
--- /dev/null
+++ b/services/api-referentiel/pom.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <artifactId>api-referentiel</artifactId>
+    <version>1.2.3-SNAPSHOT</version>
+    <name>api-referentiel</name>
+    <description>API Referentiel - Lecture, chargement et exposition par API</description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <properties>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.mte.numecoeval</groupId>
+            <artifactId>common</artifactId>
+        </dependency>
+
+        <!-- open api docs provisoire -->
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-common</artifactId>
+        </dependency>
+
+        <!-- Security -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- Mapping -->
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+        </dependency>
+        <!-- Monitoring -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- JPA -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+
+        <!-- Nécessaire avec Spring Boot 3 pour Hibernate -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- REST -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-rest</artifactId>
+        </dependency>
+
+
+        <!-- Utilitaire -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+        </dependency>
+
+        <!-- Driver pour base de données -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- TU/TI -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-suite</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Base de données de tests -->
+        <dependency>
+            <groupId>org.hsqldb</groupId>
+            <artifactId>hsqldb</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests fonctionnels -->
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-junit-platform-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests d'API REST -->
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/ReferentielApplication.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/ReferentielApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e1f87988312723722f91a452e23a5d1ca463c7f
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/ReferentielApplication.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.referentiel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ReferentielApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ReferentielApplication.class, args);
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/data/ResultatImport.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/data/ResultatImport.java
new file mode 100644
index 0000000000000000000000000000000000000000..56a091d44f3ce11a99e10b7d20bb8b5c411cc316
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/data/ResultatImport.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.referentiel.domain.data;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class ResultatImport<T> {
+
+    List<String> erreurs = new ArrayList<>();
+
+    long nbrLignesImportees = 0;
+
+    List<T> objects;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/NotFoundException.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/NotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae14c1abbbe9e12201e983be23cee933e4e24638
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/NotFoundException.java
@@ -0,0 +1,8 @@
+package org.mte.numecoeval.referentiel.domain.exception;
+
+public class NotFoundException extends RuntimeException {
+
+    public NotFoundException(String message) {
+        super(message);
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielException.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielException.java
new file mode 100644
index 0000000000000000000000000000000000000000..18c1c92574fa5b261cf2e6e0eef655e17224be01
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielException.java
@@ -0,0 +1,8 @@
+package org.mte.numecoeval.referentiel.domain.exception;
+
+public class ReferentielException extends Exception {
+
+    public ReferentielException(String message) {
+        super(message);
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielRuntimeException.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..79e8ed19018bfb4630f7ee083d0981260db165c9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/exception/ReferentielRuntimeException.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.referentiel.domain.exception;
+
+public class ReferentielRuntimeException extends RuntimeException {
+    public ReferentielRuntimeException(String message) {
+        super(message);
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/AbstractReferentiel.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/AbstractReferentiel.java
new file mode 100644
index 0000000000000000000000000000000000000000..e28b6a86644254f7c6162ba850c75c6cd0687b56
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/AbstractReferentiel.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import java.io.Serializable;
+
+public interface AbstractReferentiel extends Serializable {
+    // Actuellement l'interface n'a pas de comportement par défaut ni de champ partagé
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/CorrespondanceRefEquipement.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/CorrespondanceRefEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bfc53c16e198d2a6125d0fadc6355b126177fdc
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/CorrespondanceRefEquipement.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.FieldDefaults;
+
+@Builder
+@Data
+@FieldDefaults(level = AccessLevel.PRIVATE)
+public class CorrespondanceRefEquipement implements AbstractReferentiel {
+
+    String modeleEquipementSource;
+    String refEquipementCible;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Critere.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Critere.java
new file mode 100644
index 0000000000000000000000000000000000000000..05fb3cd2fbf4fdea854238d52ba3ffdefd4cc902
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Critere.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class Critere implements AbstractReferentiel {
+    String nomCritere;
+    String unite;
+    String description;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Etape.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Etape.java
new file mode 100644
index 0000000000000000000000000000000000000000..301f82e78dce2448cac00de1575f5cd9219aa9a9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Etape.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class Etape implements AbstractReferentiel {
+    String code;
+    String libelle;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c55577c9ee2320a50ceed50ed7ffac765ad3c15
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class Hypothese implements AbstractReferentiel {
+    String code;
+    String valeur;
+    String source;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactEquipement.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..df20f22fb876e8f2e1f86f502237c835a1de16a9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactEquipement.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class ImpactEquipement implements AbstractReferentiel {
+
+    String refEquipement;
+    String etape;
+    String critere;
+    String source;
+    String type;
+    Double valeur;
+    Double consoElecMoyenne;
+    String description;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactMessagerie.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..1da3e59cb9af56a2856a6c6140dc119ca6cba8e5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactMessagerie.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class ImpactMessagerie implements AbstractReferentiel {
+
+    String critere;
+    Double constanteCoefficientDirecteur;
+    Double constanteOrdonneeOrigine;
+    String source;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactReseau.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactReseau.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3a6672a045a16754019f290124da8d2fe1dec40
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/ImpactReseau.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImpactReseau implements AbstractReferentiel {
+
+    String refReseau;
+    String etape;
+    String critere;
+    String source;
+    Double valeur;
+    Double consoElecMoyenne;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/MixElectrique.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/MixElectrique.java
new file mode 100644
index 0000000000000000000000000000000000000000..498d50382d5a472130a3e7d6d701a7daba16961e
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/MixElectrique.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class MixElectrique implements AbstractReferentiel {
+
+    String pays;
+    String raccourcisAnglais;
+    String critere;
+    Double valeur;
+    String source;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeEquipement.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..e32a429c4475c24bc8792888a06d1d4d70bdf6a8
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeEquipement.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.referentiel.domain.model;
+
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.FieldDefaults;
+
+@Builder
+@Data
+@FieldDefaults(level = AccessLevel.PRIVATE)
+public class TypeEquipement implements AbstractReferentiel {
+
+    String type;
+    boolean serveur;
+    String commentaire;
+    Double dureeVieDefaut;
+    String source;
+    // Référence de l'équipement par défaut, permet des correspondances en cas d'absence de correspondance direct.
+    String refEquipementParDefaut;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/CritereId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/CritereId.java
new file mode 100644
index 0000000000000000000000000000000000000000..692a5fb789069faf465b10c4ea1af4fc3c4a5d18
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/CritereId.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class CritereId implements Serializable {
+
+    String nomCritere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/EtapeId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/EtapeId.java
new file mode 100644
index 0000000000000000000000000000000000000000..b795f786b81bf7287d5d8e1c4042c2328a95b760
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/EtapeId.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class EtapeId implements Serializable {
+
+    String code;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/HypotheseId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/HypotheseId.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c95cf398a6365094e0f287b44eea53d66c93885
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/HypotheseId.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@AllArgsConstructor
+public class HypotheseId implements Serializable {
+
+    String code;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactEquipementId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactEquipementId.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bb9cb754096ea8323c6b137e7a394c5c5435058
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactEquipementId.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class ImpactEquipementId implements Serializable {
+    String refEquipement;
+    String etape;
+    String critere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactReseauId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactReseauId.java
new file mode 100644
index 0000000000000000000000000000000000000000..22a3511d4f40f47e8fcca45b1999a608968e44e9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/ImpactReseauId.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImpactReseauId implements Serializable {
+
+    String refReseau;
+    String etape;
+    String critere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/MixElectriqueId.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/MixElectriqueId.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0f006f9fc0da2ac7dd871785cdd6afcf48edf71
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/id/MixElectriqueId.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.referentiel.domain.model.id;
+
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+public class MixElectriqueId implements Serializable {
+
+    String pays;
+    String critere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/ImportCSVReferentielPort.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/ImportCSVReferentielPort.java
new file mode 100644
index 0000000000000000000000000000000000000000..85affa82b959e335c2a5d376c08435e676a98fad
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/ImportCSVReferentielPort.java
@@ -0,0 +1,70 @@
+package org.mte.numecoeval.referentiel.domain.ports.input;
+
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+
+import java.io.InputStream;
+import java.util.Arrays;
+
+public interface ImportCSVReferentielPort<T> {
+
+    String CSV_SEPARATOR = ";";
+
+    String MESSAGE_AVERTISSEMENT_LIGNE_INCONSISTENTE = "Fichier %s : La ligne n°%d n'est pas consistente avec les headers du fichier";
+
+    String MESSAGE_LIGNE_INVALIDE = "La ligne n°%d est invalide : %s";
+
+    void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException;
+
+    default void checkAllHeadersAreMapped(CSVRecord csvRecord, String[] headers)  throws ReferentielException{
+        if(!Arrays.stream(headers).allMatch(csvRecord::isMapped)) {
+            throw new ReferentielException(MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber()+1, "Entêtes incohérentes"));
+        }
+    }
+
+    default void checkFieldIsMappedInCSVRecord(CSVRecord csvRecord, String field)  throws ReferentielException{
+        if(!csvRecord.isMapped(field)) {
+            throw new ReferentielException(MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber()+1, "La colonne "+field+" doit être présente"));
+        }
+    }
+
+    default void checkFieldIsMappedAndNotBlankInCSVRecord(CSVRecord csvRecord, String field)  throws ReferentielException{
+        checkFieldIsMappedInCSVRecord(csvRecord, field);
+        if(StringUtils.isBlank(csvRecord.get(field))) {
+            throw new ReferentielException(MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber()+1, "La colonne "+field+" ne peut être vide"));
+        }
+    }
+
+    ResultatImport<T> importCSV(InputStream csvInputStream);
+    default Double getDoubleValueFromRecord(CSVRecord csvRecord, String field, Double defaultValue) {
+        if(!NumberUtils.isCreatable(StringUtils.trim(csvRecord.get(field)))) {
+            return defaultValue;
+        }
+        return NumberUtils.toDouble(csvRecord.get(field));
+    }
+
+    /**
+     * Renvoie la valeur de la colonne {@param mainName} dans le {@param csvRecord}.
+     * Si le {@param mainName} n'est pas mappé dans le {@link CSVRecord}, la liste des noms alternatifs est utilisée.
+     * Si aucune colonne n'est mappée ou que la liste alternative est vide, la valeur {@code null} est renvoyée.
+     * @param csvRecord La ligne de CSV à traiter
+     * @param mainName Le nom de la colonne souhaitée en 1er
+     * @param alternativeNames Les noms de colonnes alternatifs à utiliser, peut être vide
+     * @return La valeur de la 1er colonne correctement mappée sur la ligne de CSV, {@code null} en absence de mapping
+     */
+    default String getStringValueFromRecord(CSVRecord csvRecord, String mainName, String... alternativeNames) {
+        if(csvRecord.isMapped(mainName)) {
+            return StringUtils.trim(csvRecord.get(mainName));
+        }
+
+        for (String alternativeName : alternativeNames) {
+            if(csvRecord.isMapped(alternativeName)) {
+                return StringUtils.trim(csvRecord.get(alternativeName));
+            }
+        }
+        return null;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCorrespondanceRefEquipementPortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCorrespondanceRefEquipementPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae62e8d4b997e1e2801e5ac5a4e8ec634552960a
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCorrespondanceRefEquipementPortImpl.java
@@ -0,0 +1,75 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportCorrespondanceRefEquipementPortImpl implements ImportCSVReferentielPort<CorrespondanceRefEquipementDTO> {
+    public static final String MODELE_EQUIPEMENT_SOURCE = "modeleEquipementSource";
+    public static final String REF_EQUIPEMENT_CIBLE = "refEquipementCible";
+    private static final String[] HEADERS = new String[]{MODELE_EQUIPEMENT_SOURCE, REF_EQUIPEMENT_CIBLE};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, MODELE_EQUIPEMENT_SOURCE);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, REF_EQUIPEMENT_CIBLE);
+    }
+
+    @Override
+    public ResultatImport<CorrespondanceRefEquipementDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<CorrespondanceRefEquipementDTO> resultatImport = new ResultatImport<>();
+        List<CorrespondanceRefEquipementDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(CorrespondanceRefEquipementDTO.builder()
+                            .modeleEquipementSource(csvRecord.get(MODELE_EQUIPEMENT_SOURCE).trim())
+                            .refEquipementCible(csvRecord.get(REF_EQUIPEMENT_CIBLE).trim())
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCriterePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCriterePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c622f8b4061d00f3d050e04b4d12fe58eef99944
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportCriterePortImpl.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportCriterePortImpl implements ImportCSVReferentielPort<CritereDTO> {
+    private static final String HEADER_NOM_CRITERE = "nomCritere";
+    private static final String[] HEADERS = new String[]{HEADER_NOM_CRITERE, "description", "unite"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_NOM_CRITERE);
+    }
+
+    @Override
+    public ResultatImport<CritereDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<CritereDTO> resultatImport = new ResultatImport<>();
+        List<CritereDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(CritereDTO.builder()
+                            .nomCritere(csvRecord.get(HEADER_NOM_CRITERE).trim())
+                            .description(csvRecord.get("description"))
+                            .unite(csvRecord.get("unite"))
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportEtapePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportEtapePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6358dcd6c7da0170cf6163cf17baa6accc46f8d3
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportEtapePortImpl.java
@@ -0,0 +1,73 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportEtapePortImpl implements ImportCSVReferentielPort<EtapeDTO> {
+    private static final String[] HEADERS = new String[]{"code", "libelle"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    @Override
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, "code");
+    }
+
+    @Override
+    public ResultatImport<EtapeDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<EtapeDTO> resultatImport = new ResultatImport<>();
+        List<EtapeDTO> etapeDTOS = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    etapeDTOS.add(EtapeDTO.builder()
+                            .code(csvRecord.get("code").trim())
+                            .libelle(csvRecord.get("libelle").trim())
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(etapeDTOS);
+        resultatImport.setNbrLignesImportees(etapeDTOS.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a14c212bf109b37daa8441740e7cf7c1e9d937e8
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java
@@ -0,0 +1,75 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportHypothesePortImpl implements ImportCSVReferentielPort<HypotheseDTO> {
+    private static final String HEADER_VALEUR = "valeur";
+    private static final String[] HEADERS = new String[]{"cle", HEADER_VALEUR, "source"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, "cle");
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_VALEUR);
+    }
+
+    @Override
+    public ResultatImport<HypotheseDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<HypotheseDTO> resultatImport = new ResultatImport<>();
+        List<HypotheseDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(HypotheseDTO.builder()
+                            .valeur(csvRecord.get(HEADER_VALEUR).trim())
+                            .code(csvRecord.get("cle").trim())
+                            .source(csvRecord.get("source").trim())
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactEquipementPortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactEquipementPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b44f79be20345381ea4ba647af6822da072331c
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactEquipementPortImpl.java
@@ -0,0 +1,90 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportImpactEquipementPortImpl implements ImportCSVReferentielPort<ImpactEquipementDTO> {
+    private static final String HEADER_REF_EQUIPEMENT = "refEquipement";
+    private static final String HEADER_ETAPEACV = "etapeacv";
+    private static final String HEADER_CRITERE = "critere";
+    private static final String HEADER_CONSO_ELEC_MOYENNE = "consoElecMoyenne";
+    private static final String HEADER_VALEUR = "valeur";
+    private static final String[] HEADERS = new String[]{
+            HEADER_REF_EQUIPEMENT, HEADER_ETAPEACV, HEADER_CRITERE,
+            HEADER_CONSO_ELEC_MOYENNE, HEADER_VALEUR, "source", "type"
+    };
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_REF_EQUIPEMENT);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_ETAPEACV);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_CRITERE);
+        checkFieldIsMappedInCSVRecord(csvRecord, HEADER_CONSO_ELEC_MOYENNE);
+        checkFieldIsMappedInCSVRecord(csvRecord, HEADER_VALEUR);
+    }
+
+    @Override
+    public ResultatImport<ImpactEquipementDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<ImpactEquipementDTO> resultatImport = new ResultatImport<>();
+        List<ImpactEquipementDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(ImpactEquipementDTO.builder()
+                            .refEquipement(csvRecord.get(HEADER_REF_EQUIPEMENT).trim())
+                            .etape(csvRecord.get(HEADER_ETAPEACV).trim())
+                            .critere(csvRecord.get(HEADER_CRITERE).trim())
+                            .consoElecMoyenne(getDoubleValueFromRecord(csvRecord, HEADER_CONSO_ELEC_MOYENNE, null))
+                            .valeur(getDoubleValueFromRecord(csvRecord, HEADER_VALEUR, null))
+                            .source(getStringValueFromRecord(csvRecord, "source"))
+                            .type(getStringValueFromRecord(csvRecord,"type"))
+                            .description(getStringValueFromRecord(csvRecord,"description"))
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactMessageriePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactMessageriePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..53d24fc02fb58c0174fce02eb76ecc51a05d76f2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactMessageriePortImpl.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportImpactMessageriePortImpl implements ImportCSVReferentielPort<ImpactMessagerieDTO> {
+    private static final String HEADER_CRITERE = "critere";
+    private static final String[] HEADERS = new String[]{HEADER_CRITERE,"constanteCoefficientDirecteur","constanteOrdonneeOrigine","source"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_CRITERE);
+    }
+
+    @Override
+    public ResultatImport<ImpactMessagerieDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<ImpactMessagerieDTO> resultatImport = new ResultatImport<>();
+        List<ImpactMessagerieDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(ImpactMessagerieDTO.builder()
+                                    .critere(csvRecord.get(HEADER_CRITERE).trim())
+                                    .constanteCoefficientDirecteur(getDoubleValueFromRecord(csvRecord,"constanteCoefficientDirecteur", null))
+                                    .constanteOrdonneeOrigine(getDoubleValueFromRecord(csvRecord,"constanteOrdonneeOrigine", null))
+                                    .source(csvRecord.get("source").trim())
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+        return resultatImport;
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactReseauPortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactReseauPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4d6e0d79b333553839064ba030d8e62ade3ace7
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportImpactReseauPortImpl.java
@@ -0,0 +1,87 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportImpactReseauPortImpl implements ImportCSVReferentielPort<ImpactReseauDTO> {
+    private static final String HEADER_REF_RESEAU = "refReseau";
+    private static final String HEADER_ETAPE_ACV = "etapeACV";
+    private static final String HEADER_CRITERE = "critere";
+    private static final String HEADER_VALEUR = "valeur";
+    private static final String HEADER_CONSO_ELEC_MOYENNE = "consoElecMoyenne";
+    private static final String[] HEADERS = new String[]{
+            HEADER_REF_RESEAU, HEADER_ETAPE_ACV, HEADER_CRITERE, HEADER_VALEUR,
+            HEADER_CONSO_ELEC_MOYENNE, "source"
+    };
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_REF_RESEAU);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_ETAPE_ACV);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_CRITERE);
+        checkFieldIsMappedInCSVRecord(csvRecord, HEADER_CONSO_ELEC_MOYENNE);
+        checkFieldIsMappedInCSVRecord(csvRecord, HEADER_VALEUR);
+    }
+
+    @Override
+    public ResultatImport<ImpactReseauDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<ImpactReseauDTO> resultatImport = new ResultatImport<>();
+        List<ImpactReseauDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(ImpactReseauDTO.builder()
+                            .critere(csvRecord.get(HEADER_CRITERE).trim())
+                            .refReseau(csvRecord.get(HEADER_REF_RESEAU).trim())
+                            .consoElecMoyenne(getDoubleValueFromRecord(csvRecord, HEADER_CONSO_ELEC_MOYENNE, null))
+                            .valeur(getDoubleValueFromRecord(csvRecord, HEADER_VALEUR, null))
+                            .source(csvRecord.get("source").trim())
+                            .etapeACV(csvRecord.get(HEADER_ETAPE_ACV).trim())
+                            .build());
+                } catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber() + 1, e.getMessage());
+                    resultatImport.getErreurs().add(e.getMessage());
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportMixElectriquePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportMixElectriquePortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..78978f4d3ab4f6ccb856084c060a5c594827f8aa
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportMixElectriquePortImpl.java
@@ -0,0 +1,80 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportMixElectriquePortImpl implements ImportCSVReferentielPort<MixElectriqueDTO> {
+    private static final String HEADER_PAYS = "pays";
+    private static final String HEADER_RACCOURCIS_ANGLAIS = "raccourcisAnglais";
+    private static final String HEADER_CRITERE = "critere";
+    private static final String[] HEADERS = new String[]{HEADER_PAYS, HEADER_RACCOURCIS_ANGLAIS, HEADER_CRITERE, "valeur", "source"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_PAYS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_RACCOURCIS_ANGLAIS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_CRITERE);
+    }
+
+    @Override
+    public ResultatImport<MixElectriqueDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<MixElectriqueDTO> resultatImport = new ResultatImport<>();
+        List<MixElectriqueDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setAllowMissingColumnNames(true)
+                    .setTrim(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(MixElectriqueDTO.builder()
+                            .pays(csvRecord.get(HEADER_PAYS).trim())
+                            .raccourcisAnglais(csvRecord.get(HEADER_RACCOURCIS_ANGLAIS).trim())
+                            .critere(csvRecord.get(HEADER_CRITERE).trim())
+                            .valeur(getDoubleValueFromRecord(csvRecord,"valeur",null))
+                            .source(csvRecord.get("source"))
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+
+        return resultatImport;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeEquipementPortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeEquipementPortImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..493c25350102b2382263ff483f89d338fbfde11b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeEquipementPortImpl.java
@@ -0,0 +1,77 @@
+package org.mte.numecoeval.referentiel.domain.ports.input.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang3.BooleanUtils;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class ImportTypeEquipementPortImpl implements ImportCSVReferentielPort<TypeEquipementDTO> {
+    private static final String HEADER_TYPE = "type";
+    private static final String[] HEADERS = new String[]{HEADER_TYPE,"serveur","commentaire","dureeVieDefaut","source","refEquipementParDefaut"};
+
+    public static String[] getHeaders() {
+        return HEADERS;
+    }
+
+    public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+        checkAllHeadersAreMapped(csvRecord, HEADERS);
+        checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_TYPE);
+    }
+
+    @Override
+    public ResultatImport<TypeEquipementDTO> importCSV(InputStream csvInputStream) {
+        ResultatImport<TypeEquipementDTO> resultatImport = new ResultatImport<>();
+        List<TypeEquipementDTO> dtos = new ArrayList<>();
+
+        try (Reader reader = new InputStreamReader(csvInputStream)) {
+            Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder()
+                    .setHeader()
+                    .setDelimiter(CSV_SEPARATOR)
+                    .setTrim(true)
+                    .setAllowMissingColumnNames(true)
+                    .setSkipHeaderRecord(true)
+                    .build().parse(reader);
+            records.forEach(csvRecord -> {
+                try {
+                    checkCSVRecord(csvRecord);
+                    dtos.add(TypeEquipementDTO.builder()
+                                    .type(csvRecord.get(HEADER_TYPE).trim())
+                                    .serveur(BooleanUtils.toBoolean(csvRecord.get("serveur").trim()))
+                                    .commentaire(csvRecord.get("commentaire").trim())
+                                    .dureeVieDefaut(getDoubleValueFromRecord(csvRecord,"dureeVieDefaut",null))
+                                    .source(csvRecord.get("source").trim())
+                                    .refEquipementParDefaut(getStringValueFromRecord(csvRecord, "refEquipementParDefaut"))
+                            .build());
+                }
+                catch (Exception e) {
+                    log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage());
+                    resultatImport.getErreurs().add( e.getMessage() );
+                }
+            });
+
+        } catch (Exception e) {
+            log.error("Erreur de traitement du fichier", e);
+
+            resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu."));
+            resultatImport.setNbrLignesImportees(0);
+            resultatImport.setObjects(null);
+            return resultatImport;
+        }
+        resultatImport.setObjects(dtos);
+        resultatImport.setNbrLignesImportees(dtos.size());
+        return resultatImport;
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..45902d67798ffa4ee4be54103b372cb02248913c
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielCsvExportService.java
@@ -0,0 +1,111 @@
+package org.mte.numecoeval.referentiel.domain.ports.output;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+@Slf4j
+public abstract class ReferentielCsvExportService<T> {
+    static final String DELIMITER = ";";
+
+    final Class<T> typeParameterClass;
+
+    protected ReferentielCsvExportService(Class<T> typeParameterClass) {
+        this.typeParameterClass = typeParameterClass;
+    }
+
+    /**
+     * Headers du fichier CSV.
+     * @return Tableau des headers du fichier CSV généré.
+     */
+    protected abstract String[] getHeaders();
+
+    /**
+     * Ecriture d'une ligne dans le fichier CSV.
+     * @param csvPrinter {@link CSVPrinter} à utiliser
+     * @param objectToWrite objet à traiter
+     * @throws IOException levée en cas d'erreur de la ligne viw le {@link CSVPrinter}
+     */
+    protected abstract void printRecord(CSVPrinter csvPrinter, T objectToWrite) throws IOException;
+
+    /**
+     * Renvoie la liste des objets à traiter pour le CSV.
+     * @return Liste des objets à traiter, peut être {@code null}
+     */
+    protected abstract List<T> getObjectsToWrite();
+
+    /**
+     * Méthode appelé pour identifier un objet à traiter dans les logs d'erreur spécifique.
+     * @param object objet à traiter, ne peut être {@code null}
+     * @return {@link String} perettant d'identifier l'objet
+     */
+    protected abstract String getObjectId(T object);
+
+    /**
+     * Renvoie la chaine de caractères correctement formatté pour un {@link Double}
+     * @param doubleValue valeur à traiter
+     * @return {@link String} du représentant le double au bon format
+     */
+    protected String formatDouble(Double doubleValue) {
+        if(Objects.isNull(doubleValue)) {
+            return StringUtils.EMPTY;
+        }
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+        return df.format(doubleValue);
+    }
+
+    /**
+     * Log d'une erreur sur l'écriture d'une ligne du fichier CSV.
+     * @param objectToWrite objet à traiter
+     * @param exception {@link Exception} levée lors de l'erreur sur l'écriture de la ligne
+     */
+    public void logRecordError(T objectToWrite, Exception exception) {
+        var logMessage = "Erreur d'écriture d'une ligne d'objet "+ typeParameterClass.getName();
+        if(Objects.nonNull(objectToWrite)) {
+            logMessage = "Erreur d'écriture d'une ligne d'objet %s : %s".formatted(typeParameterClass.getName(), getObjectId(objectToWrite));
+        }
+        log.error(logMessage, exception);
+    }
+
+    /**
+     * Logs d'une erreur en cas de problème à l'écriture via {@link Writer}
+     * @param exception {@link Exception} levée lors de l'erreur sur l'écriture dans le Writer
+     */
+    public void logWriterError(Exception exception) {
+        log.error("Erreur d'écriture du fichier CSV des objets {}", typeParameterClass.getName(), exception);
+    }
+
+    /**
+     * Ecriture du fichier CSV via {@link Writer}.
+     * @see #printRecord(CSVPrinter, Object)
+     * @see #logRecordError(Object, Exception)
+     * @see #logWriterError(Exception)
+     * @param writer {@link Writer} à utiliser
+     */
+    public void writeToCsv(Writer writer) {
+        List<T> objects = getObjectsToWrite();
+        CSVFormat csvFormat = CSVFormat.Builder.create().setHeader(getHeaders()).setDelimiter(DELIMITER).build();
+        try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) {
+            CollectionUtils.emptyIfNull(objects).forEach(objectToWrite -> {
+                try {
+                    printRecord(csvPrinter, objectToWrite);
+                } catch (Exception e) {
+                    logRecordError(objectToWrite, e);
+                }
+            });
+        } catch (Exception e) {
+            logWriterError(e);
+        }
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ea16327109dcd0edaa87801de08a740f88876b9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java
@@ -0,0 +1,49 @@
+package org.mte.numecoeval.referentiel.domain.ports.output;
+
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.AbstractReferentiel;
+
+import java.util.Collection;
+import java.util.List;
+
+
+public interface ReferentielPersistencePort<T extends AbstractReferentiel, P extends Object> {
+
+    /**
+     * Sauvegarde et mise à jour
+     *
+     * @param referentiel
+     * @return
+     */
+    T save(T referentiel) throws ReferentielException;
+
+    /**
+     * Ajout en masse d'une liste
+     *
+     * @param referentiel
+     * @throws ReferentielException
+     */
+    void saveAll(Collection<T> referentiel) throws ReferentielException;
+
+    /**
+     * Recherche par id
+     *
+     * @param id
+     * @return
+     */
+    T get(P id) throws ReferentielException;
+
+    /**
+     * purge entity
+     */
+    void purge();
+
+    /**
+     * liste des elements d'une table
+     *
+     * @return
+     */
+    List<T> getAll();
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CorrespondanceRefEquipemenetCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CorrespondanceRefEquipemenetCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..c580f5be87c792a88ebbb3d344addcb07d73b29b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CorrespondanceRefEquipemenetCsvExportService.java
@@ -0,0 +1,43 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportHypothesePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CorrespondanceRefEquipementRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class CorrespondanceRefEquipemenetCsvExportService extends ReferentielCsvExportService<CorrespondanceRefEquipementEntity> {
+
+    private final CorrespondanceRefEquipementRepository repository;
+
+    public CorrespondanceRefEquipemenetCsvExportService(CorrespondanceRefEquipementRepository repository) {
+        super(CorrespondanceRefEquipementEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportHypothesePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<CorrespondanceRefEquipementEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(CorrespondanceRefEquipementEntity object) {
+        return object.getModeleEquipementSource();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, CorrespondanceRefEquipementEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getModeleEquipementSource(),objectToWrite.getRefEquipementCible());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..0836535d25ccc84f5f3b455ba4f53fe5272423be
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportService.java
@@ -0,0 +1,43 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CritereRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class CritereCsvExportService extends ReferentielCsvExportService<CritereEntity> {
+
+    private final CritereRepository repository;
+
+    public CritereCsvExportService(CritereRepository repository) {
+        super(CritereEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportCriterePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<CritereEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(CritereEntity object) {
+        return object.getNomCritere();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, CritereEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getNomCritere(),objectToWrite.getDescription(),objectToWrite.getUnite());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6bfabf1d44c4ef5bba94339be80c4142c483523
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportService.java
@@ -0,0 +1,41 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportEtapePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.EtapeRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class EtapeCsvExportService extends ReferentielCsvExportService<EtapeEntity> {
+    private final EtapeRepository repository;
+
+    public EtapeCsvExportService(EtapeRepository repository) {
+        super(EtapeEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportEtapePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<EtapeEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(EtapeEntity object) {
+        return object.getCode();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, EtapeEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getCode(),objectToWrite.getLibelle());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..684802434814496fe3fb183ca27a8dd6f785e7af
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java
@@ -0,0 +1,43 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportHypothesePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.HypotheseRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class HypotheseCsvExportService extends ReferentielCsvExportService<HypotheseEntity> {
+
+    private final HypotheseRepository repository;
+
+    public HypotheseCsvExportService(HypotheseRepository repository) {
+        super(HypotheseEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportHypothesePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<HypotheseEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(HypotheseEntity object) {
+        return object.getCode();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, HypotheseEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getCode(),objectToWrite.getValeur(),objectToWrite.getSource());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea7030a8826430df874d89cee1a7238807abc449
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportService.java
@@ -0,0 +1,47 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactEquipementPortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactEquipementRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class ImpactEquipementCsvExportService extends ReferentielCsvExportService<ImpactEquipementEntity> {
+
+    private final ImpactEquipementRepository repository;
+
+    public ImpactEquipementCsvExportService(ImpactEquipementRepository repository) {
+        super(ImpactEquipementEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportImpactEquipementPortImpl.getHeaders();
+    }
+
+    @Override
+    public List<ImpactEquipementEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(ImpactEquipementEntity object) {
+        return String.join("-", object.getRefEquipement(),object.getEtape(),object.getCritere());
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, ImpactEquipementEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getRefEquipement(),
+                objectToWrite.getEtape(),objectToWrite.getCritere(),
+                formatDouble(objectToWrite.getConsoElecMoyenne()),formatDouble(objectToWrite.getValeur()),
+                objectToWrite.getSource(), objectToWrite.getType()
+                );
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c0ab188c2f3153c662803adc149ecd78395f14c
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportService.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactMessageriePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactMessagerieRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class ImpactMessagerieCsvExportService extends ReferentielCsvExportService<ImpactMessagerieEntity> {
+
+    private final ImpactMessagerieRepository repository;
+
+    public ImpactMessagerieCsvExportService(ImpactMessagerieRepository repository) {
+        super(ImpactMessagerieEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportImpactMessageriePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<ImpactMessagerieEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(ImpactMessagerieEntity object) {
+        return object.getCritere();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, ImpactMessagerieEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(
+                objectToWrite.getCritere(),
+                formatDouble(objectToWrite.getConstanteCoefficientDirecteur()),
+                formatDouble(objectToWrite.getConstanteOrdonneeOrigine()),
+                objectToWrite.getSource()
+                );
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcc0937fd4249cfc0b7cffa82b42e4defcc0a295
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportService.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactReseauPortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactReseauRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class ImpactReseauCsvExportService extends ReferentielCsvExportService<ImpactReseauEntity> {
+
+    private final ImpactReseauRepository repository;
+
+    public ImpactReseauCsvExportService(ImpactReseauRepository repository) {
+        super(ImpactReseauEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportImpactReseauPortImpl.getHeaders();
+    }
+
+    @Override
+    public List<ImpactReseauEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(ImpactReseauEntity object) {
+        return String.join("-", object.getRefReseau(),object.getEtape(),object.getCritere());
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, ImpactReseauEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getRefReseau(),
+                objectToWrite.getEtape(),objectToWrite.getCritere(),
+                formatDouble(objectToWrite.getValeur()),
+                formatDouble(objectToWrite.getConsoElecMoyenne()),
+                objectToWrite.getSource()
+                );
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/MixElectriqueCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/MixElectriqueCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..af99d634c27a8717191ecd89a031d430ea8d426d
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/MixElectriqueCsvExportService.java
@@ -0,0 +1,49 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportMixElectriquePortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.MixElectriqueRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class MixElectriqueCsvExportService extends ReferentielCsvExportService<MixElectriqueEntity> {
+
+    private final MixElectriqueRepository repository;
+
+    public MixElectriqueCsvExportService(MixElectriqueRepository repository) {
+        super(MixElectriqueEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportMixElectriquePortImpl.getHeaders();
+    }
+
+    @Override
+    public List<MixElectriqueEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(MixElectriqueEntity object) {
+        return String.join("-", object.getPays(), object.getCritere());
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, MixElectriqueEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(
+                objectToWrite.getPays(),
+                objectToWrite.getRaccourcisAnglais(),
+                objectToWrite.getCritere(),
+                formatDouble(objectToWrite.getValeur()),
+                objectToWrite.getSource()
+                );
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..adee3de7ce6a40528edc120eac8b4420da7c6b52
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java
@@ -0,0 +1,47 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+
+@Service
+public class TypeEquipementCsvExportService extends ReferentielCsvExportService<TypeEquipementEntity> {
+
+    private final TypeEquipementRepository repository;
+
+    public TypeEquipementCsvExportService(TypeEquipementRepository repository) {
+        super(TypeEquipementEntity.class);
+        this.repository = repository;
+    }
+
+    @Override
+    public String[] getHeaders() {
+        return ImportTypeEquipementPortImpl.getHeaders();
+    }
+
+    @Override
+    public List<TypeEquipementEntity> getObjectsToWrite() {
+        return repository.findAll();
+    }
+
+    @Override
+    protected String getObjectId(TypeEquipementEntity object) {
+        return object.getType();
+    }
+
+    @Override
+    public void printRecord(CSVPrinter csvPrinter, TypeEquipementEntity objectToWrite) throws IOException {
+        csvPrinter.printRecord(objectToWrite.getType(),
+                objectToWrite.isServeur(),
+                objectToWrite.getCommentaire(),
+                formatDouble(objectToWrite.getDureeVieDefaut()),
+                objectToWrite.getSource(), objectToWrite.getRefEquipementParDefaut());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/ReferentielConfig.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/ReferentielConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..b5f32c702f2d478694a9bc8324e9cc134e081e39
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/ReferentielConfig.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.referentiel.infrastructure.configuration;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@Configuration
+@EnableWebMvc
+public class ReferentielConfig {
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfig.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd928e3953f3a2f67d8169b5d7f99977586c95b7
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfig.java
@@ -0,0 +1,105 @@
+package org.mte.numecoeval.referentiel.infrastructure.configuration.openapi;
+
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ReferentielOpenApiConfig {
+
+    @Bean
+    public OpenAPI configOpenAPI() {
+        return new OpenAPI()
+                .info(new Info().title("API des référentiels de NumEcoEval")
+                        .description("""
+                                Endpoints permettant de manipuler les référentiels de NumEcoEval.
+                                Les endpoints CRUD sont générés via Spring DataRest.
+                                                                
+                                Les endpoints d'export CSV permettent d'exporter l'intégralité d'un référentiel
+                                sous forme de fichier CSV ré-importable via les endpoints d'imports.
+                                                                
+                                Les endpoints d'import fonctionnent en annule & remplace et supprimeront l'intégralité
+                                du référentiel et utiliseront le contenu du CSV pour peupler le référentiel.
+                                                                
+                                Les endpoints internes sont utilisés par les différents modules de NumEcoEval.
+                                """)
+                        .version("v0.0.1")
+                        .license(new License()
+                                .name("Apache 2.0")
+                                .url("https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/api-referentiel/-/blob/main/LICENSE.txt")
+                        )
+                )
+                .externalDocs(new ExternalDocumentation()
+                        .description("NumEcoEval Documentation")
+                        .url("https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/docs"));
+    }
+
+    @Bean
+    public GroupedOpenApi springDataRestOpenApiGroup() {
+        String[] paths = {
+                "/CorrespondanceRefEquipement/**",
+                "/Critere/**",
+                "/Etape/**",
+                "/Hypothèses/**",
+                "/ImpactEquipement/**",
+                "/ImpactMessagerie/**",
+                "/ImpactReseau/**",
+                "/MixElectrique/**",
+                "/TypeEquipement/**",
+                "/profile/**",
+                "/version"
+        };
+        return GroupedOpenApi.builder()
+                .group("spring-data-rest")
+                .displayName("Spring Data Rest - Auto-Générés")
+                .pathsToMatch(paths)
+                .build();
+    }
+
+    @Bean
+    public GroupedOpenApi numEcoEvalGlobalOpenApiGroup() {
+        String[] paths = {
+                "/referentiel/**",
+                "/version"
+        };
+        return GroupedOpenApi.builder()
+                .group("NumEcoEval-Global")
+                .displayName("NumEcoEval Global")
+                .pathsToMatch(paths)
+                .build();
+    }
+
+    @Bean
+    public GroupedOpenApi numEcoEvalOpenApiGroup() {
+        String[] paths = {
+                "/referentiel/*",
+                "/referentiel/mixelecs/{pays}",
+                "/referentiel/typesEquipement/{type}",
+                "/referentiel/impactsMessagerie/{critere}",
+        };
+        return GroupedOpenApi.builder()
+                .group("NumEcoEval")
+                .displayName("NumEcoEval Internes")
+                .pathsToMatch(paths)
+                .pathsToExclude("/referentiel/*/csv")
+                .build();
+    }
+
+    @Bean
+    public GroupedOpenApi numEcoEvalAdministrationOpenApiGroup() {
+        String[] paths = {
+                "/referentiel/*/csv"
+        };
+        return GroupedOpenApi.builder()
+                .group("NumEcoEval-administration")
+                .displayName("Administration NumEcoEval")
+                .pathsToMatch(paths)
+                .build();
+    }
+
+}
+
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfig.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..48d35c8bbe67aaf7c1182c0e29e326b7fd542f48
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfig.java
@@ -0,0 +1,56 @@
+package org.mte.numecoeval.referentiel.infrastructure.configuration.security;
+
+import org.springframework.beans.factory.annotation.Value;
+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.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+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;
+
+/**
+ * Configuration Spring Security
+ */
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+    @Value("${numecoeval.urls.allowed:}")
+    private String[] urlsAllowed;
+
+    /**
+     * Configuration pour les endpoints avec une session DNC.
+     */
+    @Bean
+    SecurityFilterChain globalFilterChain(HttpSecurity http) throws Exception {
+        http
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+                .and()
+                .cors()
+                .and()
+                .authorizeHttpRequests(authz -> authz
+                        .requestMatchers("/health").permitAll()
+                        .requestMatchers("/**").permitAll()
+                )
+                .csrf().disable()
+                .formLogin().disable()
+        ;
+        return http.build();
+    }
+
+    @Bean
+    CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration configuration = new CorsConfiguration();
+        configuration.setAllowedOrigins(Arrays.asList(urlsAllowed));
+        configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTION"));
+        configuration.setAllowCredentials(true);
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", configuration);
+        return source;
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..f57cd54eff759fa682146d885396b2bc09e70168
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java
@@ -0,0 +1,66 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CorrespondanceRefEquipementRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersistencePort<CorrespondanceRefEquipement,String> {
+
+    CorrespondanceRefEquipementMapper mapper;
+    CorrespondanceRefEquipementRepository repository;
+
+    @Override
+    public CorrespondanceRefEquipement save(CorrespondanceRefEquipement referentiel) throws ReferentielException {
+        var entityToSave = mapper.toEntity(referentiel);
+        if(entityToSave != null) {
+            var entitySaved = repository.save(entityToSave);
+            return mapper.toDomain(entitySaved);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<CorrespondanceRefEquipement> referentiels) throws ReferentielException {
+        repository.saveAll(ListUtils.emptyIfNull(referentiels
+                .stream()
+                .map(typeEquipement -> mapper.toEntity(typeEquipement))
+                .toList()));
+    }
+
+    @Override
+    public CorrespondanceRefEquipement get(String id) throws ReferentielException {
+        if(id != null) {
+            var entityOpt=  repository.findById(id);
+            return entityOpt
+                    .map(entity -> mapper.toDomain(entity))
+                    .orElseThrow(() -> new ReferentielException("Correspondance au RefEquipement "+ id +" non trouvé"));
+        }
+        throw new ReferentielException("Correspondance au RefEquipement (id null) non trouvé");
+    }
+
+    @Override
+    public void purge() {
+        repository.deleteAll();
+    }
+
+    @Override
+    public List<CorrespondanceRefEquipement> getAll() {
+
+        return ListUtils.emptyIfNull(repository.findAll())
+                .stream()
+                .map(typeEquipementEntity -> mapper.toDomain(typeEquipementEntity))
+                .toList();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CritereJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CritereJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e92b9a7ae3b10c60a3c724aee25c91ad9198dd81
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CritereJpaAdapter.java
@@ -0,0 +1,59 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.domain.model.id.CritereId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CritereRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CritereMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class CritereJpaAdapter implements ReferentielPersistencePort<Critere, CritereId> {
+
+    CritereRepository critereRepository;
+
+    // Pour les purges des données filles
+    ImpactEquipementJpaAdapter impactEquipementJpaAdapter;
+    ImpactReseauJpaAdapter impactReseauJpaAdapter;
+    MixElectriqueJpaAdapter mixElectriqueJpaAdapter;
+
+    ImpactMessagerieJpaAdapter impactMessagerieJpaAdapter;
+
+    CritereMapper critereMapper;
+
+
+    @Override
+    public Critere save(Critere referentiel) throws ReferentielException {
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<Critere> referentiel) throws ReferentielException {
+        critereRepository.saveAll(critereMapper.toEntities(referentiel));
+    }
+
+    @Override
+    public Critere get(CritereId id) throws ReferentielException {
+        return null;
+    }
+
+    @Override
+    public void purge() {
+        // Purge des données parentes
+        critereRepository.deleteAll();
+    }
+
+    @Override
+    public List<Critere> getAll() {
+        return critereMapper.toDomains(critereRepository.findAll());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..f41082688aca9e14fffef4141d7132667ac5e51d
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java
@@ -0,0 +1,55 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.domain.model.id.EtapeId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.EtapeRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.EtapeMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class EtapeJpaAdapter implements ReferentielPersistencePort<Etape, EtapeId> {
+    EtapeRepository etapeRepository;
+
+    EtapeMapper etapeMapper;
+
+    // Pour les purges des données filles
+    ImpactReseauJpaAdapter impactReseauJpaAdapter;
+    ImpactEquipementJpaAdapter impactEquipementJpaAdapter;
+
+
+    @Override
+    public Etape save(Etape referentiel) throws ReferentielException {
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<Etape> referentiel) throws ReferentielException {
+        etapeRepository.saveAll(etapeMapper.toEntities(referentiel));
+    }
+
+    @Override
+    public Etape get(EtapeId id) throws ReferentielException {
+        return null;
+    }
+
+    @Override
+    public void purge() {
+        // Purge des données parentes
+        etapeRepository.deleteAll();
+    }
+
+    @Override
+    public List<Etape> getAll() {
+        return etapeMapper.toDomains(etapeRepository.findAll());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec82b030e9eb5fea4709fbcdf3cc9ace87cc64dd
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java
@@ -0,0 +1,60 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.HypotheseRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class HypotheseJpaAdapter implements ReferentielPersistencePort<Hypothese, HypotheseId> {
+    HypotheseRepository hypotheseRepository;
+
+    HypotheseMapper hypotheseMapper;
+
+
+    @Override
+    public Hypothese save(Hypothese referentiel) throws ReferentielException {
+        var entityToSave = hypotheseMapper.toEntity(referentiel);
+        if(entityToSave != null) {
+            var entitySaved = hypotheseRepository.save(entityToSave);
+            return hypotheseMapper.toDomain(entitySaved);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<Hypothese> referentiel) throws ReferentielException {
+        hypotheseRepository.saveAll(hypotheseMapper.toEntities(referentiel));
+    }
+
+    @Override
+    public Hypothese get(HypotheseId id) throws ReferentielException {
+        Optional<HypotheseEntity> hypotheseOpt = hypotheseRepository.findById(hypotheseMapper.toEntityId(id));
+        HypotheseEntity hypotheseEntity = hypotheseOpt.orElseThrow(() -> new ReferentielException("Hypothèse non trouvé"));
+        return hypotheseMapper.toDomain(hypotheseEntity);
+    }
+
+    @Override
+    public void purge() {
+        hypotheseRepository.deleteAll();
+    }
+
+    @Override
+    public List<Hypothese> getAll() {
+        return hypotheseMapper.fromEntities(hypotheseRepository.findAll());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactEquipementJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactEquipementJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..59da314f3d6ca1edd1a0cbb9f3bd4f532d0c869b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactEquipementJpaAdapter.java
@@ -0,0 +1,69 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactEquipementIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactEquipementRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ImpactEquipementJpaAdapter implements ReferentielPersistencePort<ImpactEquipement, ImpactEquipementId> {
+
+    private ImpactEquipementRepository repository;
+
+    private ImpactEquipementMapper mapper;
+
+
+    @Override
+    public ImpactEquipement save(ImpactEquipement referentiel) throws ReferentielException {
+        var entityToSave = mapper.toEntity(referentiel);
+        if(entityToSave != null) {
+            var entitySaved = repository.save(entityToSave);
+            return mapper.toDomain(entitySaved);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<ImpactEquipement> referentiel) throws ReferentielException {
+        purge();
+        repository.saveAll(mapper.toEntities(referentiel));
+    }
+
+    @Override
+    public ImpactEquipement get(ImpactEquipementId id) throws ReferentielException {
+        if(id != null) {
+            ImpactEquipementIdEntity ieIdEntity = mapper.toEntityId(id);
+            Optional<ImpactEquipementEntity> optionalEntity = repository.findById(ieIdEntity);
+            return mapper.toDomain(
+                    optionalEntity
+                            .orElseThrow(() -> new ReferentielException("Impact Equipement non trouvé"))
+            );
+        }
+        throw new ReferentielException("Impact Equipement non trouvé");
+    }
+
+    @Override
+    public void purge() {
+        repository.deleteAll();
+    }
+
+    @Override
+    public List<ImpactEquipement> getAll() {
+        return ListUtils.emptyIfNull(mapper.toDomains(repository.findAll()));
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..585544e835c4e9608192d2ce99bb80cb90548d47
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java
@@ -0,0 +1,57 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CritereRepository;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactMessagerieRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ImpactMessagerieJpaAdapter implements ReferentielPersistencePort<ImpactMessagerie,String> {
+
+    ImpactMessagerieMapper impactMessagerieMapper;
+    ImpactMessagerieRepository impactMessagerieRepository;
+    CritereRepository critereRepository;
+
+    @Override
+    public ImpactMessagerie save(ImpactMessagerie referentiel) throws ReferentielException {
+        var entity = impactMessagerieRepository.save(impactMessagerieMapper.toEntity(referentiel));
+        return impactMessagerieMapper.toDomain(entity);
+    }
+
+    @Override
+    public void saveAll(Collection<ImpactMessagerie> domains) throws ReferentielException {
+        impactMessagerieRepository.saveAll(impactMessagerieMapper.toEntities(domains));
+    }
+
+    @Override
+    public ImpactMessagerie get(String critere) throws ReferentielException {
+        if(critere != null) {
+            var entityOpt=  impactMessagerieRepository.findById(critere);
+            return entityOpt
+                    .map(impactMessagerieEntity -> impactMessagerieMapper.toDomain(impactMessagerieEntity))
+                    .orElseThrow(() -> new ReferentielException("ImpactMessagerie non trouvé"));
+        }
+        throw new ReferentielException("ImpactMessagerie non trouvé");
+    }
+
+    @Override
+    public void purge() {
+        impactMessagerieRepository.deleteAll();
+    }
+
+    @Override
+    public List<ImpactMessagerie> getAll() {
+        return impactMessagerieMapper.toDomains(ListUtils.emptyIfNull(impactMessagerieRepository.findAll()));
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactReseauJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactReseauJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7019303191b263e84c41b2da9a373e1e15953d5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactReseauJpaAdapter.java
@@ -0,0 +1,62 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactReseauRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactReseauMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ImpactReseauJpaAdapter implements ReferentielPersistencePort<ImpactReseau, ImpactReseauId> {
+    ImpactReseauRepository reseauRepository;
+
+    ImpactReseauMapper reseauMapper;
+
+    @Override
+    public ImpactReseau save(ImpactReseau facteurImpact) throws ReferentielException {
+        ImpactReseauEntity impactReseauEntity = reseauMapper.toEntity(facteurImpact);
+        ImpactReseauEntity save = reseauRepository.save(impactReseauEntity);
+        return reseauMapper.toDomain(save);
+    }
+
+    @Override
+    public void saveAll(Collection<ImpactReseau> facteursImpacts) throws ReferentielException {
+        List<ImpactReseauEntity> impactReseauEntities = reseauMapper.toEntity(facteursImpacts);
+        reseauRepository.saveAll(impactReseauEntities);
+    }
+
+
+    @Override
+    public ImpactReseau get(ImpactReseauId id) throws ReferentielException {
+        ImpactReseauIdEntity reseauId = reseauMapper.toEntityId(id);
+        Optional<ImpactReseauEntity> reseauEntityOptional = reseauRepository.findById(reseauId);
+        return reseauMapper.toDomain(
+                reseauEntityOptional.orElseThrow(() -> new ReferentielException("Impact Réseau non trouvé"))
+        );
+    }
+
+    @Override
+    public void purge() {
+        reseauRepository.deleteAll();
+    }
+
+    @Override
+    public List<ImpactReseau> getAll() {
+        return ListUtils.emptyIfNull(reseauMapper.toDomains(reseauRepository.findAll()));
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..48337d782a49867ae8186f98355c4f31e61b08e3
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java
@@ -0,0 +1,69 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.MixElectriqueIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.MixElectriqueRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class MixElectriqueJpaAdapter implements ReferentielPersistencePort<MixElectrique, MixElectriqueId> {
+    MixElectriqueRepository mixElectriqueRepository;
+    MixElectriqueMapper mixElectriqueMapper;
+
+
+    @Override
+    public MixElectrique save(MixElectrique referentiel) throws ReferentielException {
+        var entityToSave = mixElectriqueMapper.toEntity(referentiel);
+        if (entityToSave != null) {
+            var entitySaved = mixElectriqueRepository.save(entityToSave);
+            return mixElectriqueMapper.toDomain(entitySaved);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<MixElectrique> mixElecs) throws ReferentielException {
+        List<MixElectriqueEntity> mixElecsEntities = mixElectriqueMapper.toEntities(mixElecs);
+        mixElectriqueRepository.saveAll(mixElecsEntities);
+    }
+
+
+    @Override
+    public MixElectrique get(MixElectriqueId id) throws ReferentielException {
+        if (id != null) {
+            MixElectriqueIdEntity meIdEntity = mixElectriqueMapper.toEntityId(id);
+            Optional<MixElectriqueEntity> reseauEntityOptional = mixElectriqueRepository.findById(meIdEntity);
+            return mixElectriqueMapper.toDomain(
+                    reseauEntityOptional
+                            .orElseThrow(() -> new ReferentielException("Mix Electrique non trouvé pour l'id " + id))
+            );
+        }
+        throw new ReferentielException("Mix Electrique non trouvé pour l'id null");
+    }
+
+    @Override
+    public void purge() {
+        mixElectriqueRepository.deleteAll();
+    }
+
+    @Override
+    public List<MixElectrique> getAll() {
+        return ListUtils.emptyIfNull(mixElectriqueMapper.toDomains(mixElectriqueRepository.findAll()));
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0c2e7d9d1136f0bf5f91361a5426c81fcfa7f8b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java
@@ -0,0 +1,60 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class TypeEquipementJpaAdapter implements ReferentielPersistencePort<TypeEquipement,String> {
+
+    TypeEquipementMapper typeEquipementMapper;
+    TypeEquipementRepository typeEquipementRepository;
+
+    @Override
+    public TypeEquipement save(TypeEquipement referentiel) throws ReferentielException {
+        typeEquipementRepository.save(typeEquipementMapper.toEntity(referentiel));
+        return null;
+    }
+
+    @Override
+    public void saveAll(Collection<TypeEquipement> referentiels) throws ReferentielException {
+        typeEquipementRepository.saveAll(ListUtils.emptyIfNull(referentiels
+                .stream()
+                .map(typeEquipement -> typeEquipementMapper.toEntity(typeEquipement))
+                .toList()));
+    }
+
+    @Override
+    public TypeEquipement get(String id) throws ReferentielException {
+        var entityOpt=  typeEquipementRepository.findById(id);
+        if(entityOpt.isPresent()){
+            return typeEquipementMapper.toDomaine(entityOpt.get());
+        }
+        return null;
+    }
+
+    @Override
+    public void purge() {
+        typeEquipementRepository.deleteAll();
+    }
+
+    @Override
+    public List<TypeEquipement> getAll() {
+
+        return ListUtils.emptyIfNull(typeEquipementRepository.findAll())
+                .stream()
+                .map(typeEquipementEntity -> typeEquipementMapper.toDomaine(typeEquipementEntity))
+                .toList();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/AbstractReferentielEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/AbstractReferentielEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..933be59b8ff94121b754d344a8458ddb5b46d1eb
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/AbstractReferentielEntity.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import java.io.Serializable;
+
+public interface AbstractReferentielEntity extends Serializable {
+    // Actuellement l'interface n'a pas de comportement par défaut ni de champ partagé
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CorrespondanceRefEquipementEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CorrespondanceRefEquipementEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1c533dcfff0a24497c35f1c679f48974dfda8ba
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CorrespondanceRefEquipementEntity.java
@@ -0,0 +1,49 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@Entity
+@Table(name = "REF_CORRESPONDANCE_REF_EQP")
+public class CorrespondanceRefEquipementEntity implements AbstractReferentielEntity {
+    @Id
+    String modeleEquipementSource;
+
+    String refEquipementCible;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CorrespondanceRefEquipementEntity that = (CorrespondanceRefEquipementEntity) o;
+
+        return new EqualsBuilder()
+                .append(modeleEquipementSource, that.modeleEquipementSource)
+                .append(refEquipementCible, that.refEquipementCible)
+                .isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37)
+                .append(modeleEquipementSource)
+                .append(refEquipementCible)
+                .toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CritereEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CritereEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a8b37991eb246b4cd54bba6001d9bec15ade67b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/CritereEntity.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.CritereIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Entity
+@IdClass(CritereIdEntity.class)
+@Table(name = "REF_CRITERE")
+public class CritereEntity implements AbstractReferentielEntity {
+    @Id
+    String nomCritere;
+    String unite;
+    String description;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CritereEntity that = (CritereEntity) o;
+
+        return new EqualsBuilder().append(nomCritere, that.nomCritere).append(unite, that.unite).append(description, that.description).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(nomCritere).append(unite).append(description).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/EtapeEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/EtapeEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..e24f78e5666a15804c0ef96172248adee1aa136d
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/EtapeEntity.java
@@ -0,0 +1,45 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.EtapeIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@Entity
+@IdClass(EtapeIdEntity.class)
+@Table(name = "REF_ETAPEACV")
+public class EtapeEntity implements AbstractReferentielEntity {
+    @Id
+    String code;
+    String libelle;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EtapeEntity that = (EtapeEntity) o;
+
+        return new EqualsBuilder().append(code, that.code).append(libelle, that.libelle).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(code).append(libelle).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab8fc01d6afe8d1ac715682ffe993053c9d076ac
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.HypotheseIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+@Entity
+@IdClass(HypotheseIdEntity.class)
+@Table(name = "REF_HYPOTHESE")
+public class HypotheseEntity implements AbstractReferentielEntity {
+    @Id
+    String code;
+    String valeur;
+    String source;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        HypotheseEntity that = (HypotheseEntity) o;
+
+        return new EqualsBuilder().append(code, that.code).append(valeur, that.valeur).append(source, that.source).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(code).append(valeur).append(source).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactEquipementEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactEquipementEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f90d6a89b57c90304e76927270b36641ecd78f5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactEquipementEntity.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactEquipementIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Entity
+@IdClass(ImpactEquipementIdEntity.class)
+@Table(name = "REF_IMPACTEQUIPEMENT")
+public class ImpactEquipementEntity implements AbstractReferentielEntity {
+    @Id
+    @Column(name = "REFEQUIPEMENT")
+    String refEquipement;
+    @Id
+    @Column(name = "ETAPEACV")
+    String etape;
+    @Id
+    @Column(name = "NOMCRITERE")
+    String critere;
+    String source;
+    String type;
+    Double valeur;
+    Double consoElecMoyenne;
+
+    String description;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ImpactEquipementEntity that = (ImpactEquipementEntity) o;
+
+        return new EqualsBuilder()
+                .append(refEquipement, that.refEquipement)
+                .append(etape, that.etape)
+                .append(critere, that.critere)
+                .append(source, that.source)
+                .append(type, that.type)
+                .append(valeur, that.valeur)
+                .append(consoElecMoyenne, that.consoElecMoyenne)
+                .append(description, that.description)
+                .isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37)
+                .append(refEquipement)
+                .append(etape)
+                .append(critere)
+                .append(source)
+                .append(type)
+                .append(valeur)
+                .append(consoElecMoyenne)
+                .append(description)
+                .toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactMessagerieEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactMessagerieEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..d461f0656ce0c247893eae09f18863f853387575
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactMessagerieEntity.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Entity
+@Table(name = "REF_IMPACT_MESSAGERIE")
+public class ImpactMessagerieEntity implements AbstractReferentielEntity {
+
+    @Id
+    @Column(name = "NOM_CRITERE")
+    String critere;
+
+    Double constanteCoefficientDirecteur;
+    Double constanteOrdonneeOrigine;
+    String source;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ImpactMessagerieEntity that = (ImpactMessagerieEntity) o;
+
+        return new EqualsBuilder().append(critere, that.critere).append(constanteCoefficientDirecteur, that.constanteCoefficientDirecteur).append(constanteOrdonneeOrigine, that.constanteOrdonneeOrigine).append(source, that.source).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(critere).append(constanteCoefficientDirecteur).append(constanteOrdonneeOrigine).append(source).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactReseauEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactReseauEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b202ed39cad4a4285abbb64638108c3c858a8ff
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/ImpactReseauEntity.java
@@ -0,0 +1,54 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Entity
+@IdClass(ImpactReseauIdEntity.class)
+@Table(name = "REF_IMPACTRESEAU")
+public class ImpactReseauEntity implements AbstractReferentielEntity {
+    @Id
+    @Column(name = "REFRESEAU", nullable = false)
+    String refReseau;
+    @Id
+    @Column(name = "ETAPEACV", nullable = false)
+    String etape;
+    @Id
+    @Column(name = "NOMCRITERE", nullable = false)
+    String critere;
+    String source;
+    Double valeur;
+    @Column(name = "CONSOELECMOYENNE")
+    Double consoElecMoyenne;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ImpactReseauEntity that = (ImpactReseauEntity) o;
+
+        return new EqualsBuilder().append(refReseau, that.refReseau).append(etape, that.etape).append(critere, that.critere).append(source, that.source).append(valeur, that.valeur).append(consoElecMoyenne, that.consoElecMoyenne).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(refReseau).append(etape).append(critere).append(source).append(valeur).append(consoElecMoyenne).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/MixElectriqueEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/MixElectriqueEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..c42caef280ddd7e9d58ba18f0fd6e1ffa2d2a2fd
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/MixElectriqueEntity.java
@@ -0,0 +1,51 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.IdClass;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.MixElectriqueIdEntity;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Entity
+@IdClass(MixElectriqueIdEntity.class)
+@Table(name = "REF_MIXELEC")
+public class MixElectriqueEntity implements AbstractReferentielEntity {
+
+    @Id
+    String pays;
+    @Id
+    @Column(name = "NOMCRITERE")
+    String critere;
+    @Column(name = "RACCOURCISANGLAIS")
+    String raccourcisAnglais;
+    String source;
+    Double valeur;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        MixElectriqueEntity that = (MixElectriqueEntity) o;
+
+        return new EqualsBuilder().append(pays, that.pays).append(critere, that.critere).append(raccourcisAnglais, that.raccourcisAnglais).append(source, that.source).append(valeur, that.valeur).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(pays).append(critere).append(raccourcisAnglais).append(source).append(valeur).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeEquipementEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeEquipementEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..dced599b8bfd87384cf40e5e1d750bb03e598406
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeEquipementEntity.java
@@ -0,0 +1,47 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Builder
+@Getter
+@Setter
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity(name = "REF_TYPE_EQUIPEMENT")
+public class TypeEquipementEntity implements AbstractReferentielEntity {
+    @Id
+    String type;
+    boolean serveur;
+    String commentaire;
+    Double dureeVieDefaut;
+    String source;
+
+    // Référence de l'équipement par défaut, permet des correspondances en cas d'absence de correspondance direct.
+    String refEquipementParDefaut;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TypeEquipementEntity that = (TypeEquipementEntity) o;
+
+        return new EqualsBuilder().append(serveur, that.serveur).append(type, that.type).append(commentaire, that.commentaire).append(dureeVieDefaut, that.dureeVieDefaut).append(source, that.source).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(type).append(serveur).append(commentaire).append(dureeVieDefaut).append(source).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/AbstractReferentieIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/AbstractReferentieIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ba9d175aa56f96779e0705aa0cce77e789cdbf4
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/AbstractReferentieIdEntity.java
@@ -0,0 +1,7 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import java.io.Serializable;
+
+public interface AbstractReferentieIdEntity extends Serializable {
+    // Actuellement l'interface n'a pas de comportement par défaut ni de champ partagé
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/CritereIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/CritereIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c1083cbdee65cd67167a04f834e03d02b5eac1f
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/CritereIdEntity.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class CritereIdEntity implements AbstractReferentieIdEntity {
+    String nomCritere;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CritereIdEntity that = (CritereIdEntity) o;
+
+        return new EqualsBuilder().append(nomCritere, that.nomCritere).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(nomCritere).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/EtapeIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/EtapeIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6560bd37b4467d66dd6684e82d0fe9c44bd8bc9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/EtapeIdEntity.java
@@ -0,0 +1,36 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class EtapeIdEntity implements AbstractReferentieIdEntity {
+    String code;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EtapeIdEntity that = (EtapeIdEntity) o;
+
+        return new EqualsBuilder().append(code, that.code).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(code).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/HypotheseIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/HypotheseIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ee5948e6af68a28393798d280af37209ada53f5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/HypotheseIdEntity.java
@@ -0,0 +1,36 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class HypotheseIdEntity implements AbstractReferentieIdEntity {
+
+    String code;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        HypotheseIdEntity that = (HypotheseIdEntity) o;
+
+        return new EqualsBuilder().append(code, that.code).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(code).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactEquipementIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactEquipementIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cec43b73242229117ab002d08a442c84e92273e
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactEquipementIdEntity.java
@@ -0,0 +1,38 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+
+public class ImpactEquipementIdEntity implements AbstractReferentieIdEntity {
+    String refEquipement;
+    String etape;
+    String critere;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ImpactEquipementIdEntity that = (ImpactEquipementIdEntity) o;
+
+        return new EqualsBuilder().append(refEquipement, that.refEquipement).append(etape, that.etape).append(critere, that.critere).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(refEquipement).append(etape).append(critere).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactReseauIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactReseauIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..e43e72515a5253f3dc2dab50e0785109390202ea
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/ImpactReseauIdEntity.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class ImpactReseauIdEntity implements AbstractReferentieIdEntity {
+    String refReseau;
+    String etape;
+    String critere;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ImpactReseauIdEntity that = (ImpactReseauIdEntity) o;
+
+        return new EqualsBuilder().append(refReseau, that.refReseau).append(etape, that.etape).append(critere, that.critere).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(refReseau).append(etape).append(critere).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/MixElectriqueIdEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/MixElectriqueIdEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..feae6b5e6dd3e93cb85ec49839a86fd86ee09442
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/id/MixElectriqueIdEntity.java
@@ -0,0 +1,38 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+
+public class MixElectriqueIdEntity implements AbstractReferentieIdEntity {
+
+    String pays;
+    String critere;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        MixElectriqueIdEntity that = (MixElectriqueIdEntity) o;
+
+        return new EqualsBuilder().append(pays, that.pays).append(critere, that.critere).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).append(pays).append(critere).toHashCode();
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CorrespondanceRefEquipementRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CorrespondanceRefEquipementRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..119bd61c0d87e04fb3b99026e2728b9b1773aceb
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CorrespondanceRefEquipementRepository.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "CorrespondanceRefEquipement" , itemResourceRel = "CorrespondancesRefEquipement")
+@Tag(name = "CorrespondanceRefEquipement")
+public interface CorrespondanceRefEquipementRepository extends JpaRepository<CorrespondanceRefEquipementEntity,String> {
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CritereRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CritereRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c75dc90952d76f2ca49edf297bc86730c8e45c9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/CritereRepository.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.CritereIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.Description;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(
+        path = "Critere",
+        collectionResourceDescription = @Description("""
+                Endpoints CRUD généré par Spring Data REST pour la récupération de plusieurs critères d'impact écologique.
+                """),
+        itemResourceDescription = @Description("""
+                Endpoints CRUD généré par Spring Data REST pour la récupération d'un critère d'impact écologique.
+                """)
+)
+@Tag(name = "Critères - CRUD/Spring Data REST")
+public interface CritereRepository extends JpaRepository<CritereEntity, CritereIdEntity> {
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/EtapeRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/EtapeRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..0027d7c15867d7fa9ae779014cbea01683847a86
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/EtapeRepository.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.EtapeIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "Etape" , itemResourceRel = "Etapes")
+@Tag(name = "Etapes - CRUD/Spring Data REST")
+public interface EtapeRepository extends JpaRepository<EtapeEntity, EtapeIdEntity> {
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/HypotheseRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/HypotheseRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..250786e94bbf543078b4ef032859080f867e4bf4
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/HypotheseRepository.java
@@ -0,0 +1,17 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.HypotheseIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+import java.util.Optional;
+
+
+@RepositoryRestResource(path = "Hypothèses" , itemResourceRel = "Hypothèses")
+@Tag(name = "Hypothèse - CRUD/Spring Data REST")
+public interface HypotheseRepository extends JpaRepository<HypotheseEntity, HypotheseIdEntity> {
+
+    Optional<HypotheseEntity> findById(HypotheseIdEntity id);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactEquipementRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactEquipementRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..af84c79ce5ea6c97a8382882298a9a6c1ce1ac44
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactEquipementRepository.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactEquipementIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "ImpactEquipement" , itemResourceRel = "ImpactEquipements")
+@Tag(name = "ImpactEquipement - CRUD/Spring Data REST")
+public interface ImpactEquipementRepository extends JpaRepository<ImpactEquipementEntity, ImpactEquipementIdEntity> {
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactMessagerieRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactMessagerieRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecb9a4e88e142ee88b2b6c5afb2c32e8530e83d2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactMessagerieRepository.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "ImpactMessagerie" , itemResourceRel = "ImpactMessageries")
+@Tag(name = "ImpactMessagerie - CRUD/Spring Data REST")
+public interface ImpactMessagerieRepository extends JpaRepository<ImpactMessagerieEntity, String> {
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactReseauRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactReseauRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..f37f3c3a1c46539f5af638dcc465603104d6e56b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/ImpactReseauRepository.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "ImpactReseau" , itemResourceRel = "ImpactReseaux")
+@Tag(name = "ImpactReseau - CRUD/Spring Data REST")
+public interface ImpactReseauRepository extends JpaRepository<ImpactReseauEntity, ImpactReseauIdEntity> {
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/MixElectriqueRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/MixElectriqueRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..448a8b3b3d58aef07ab855e05bba64785f142311
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/MixElectriqueRepository.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.MixElectriqueIdEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "MixElectrique" , itemResourceRel = "MixElectriques")
+@Tag(name = "MixElectrique - CRUD/Spring Data REST")
+public interface MixElectriqueRepository extends JpaRepository<MixElectriqueEntity, MixElectriqueIdEntity> {
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeEquipementRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeEquipementRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..c924a861d9b2ee3c0419de07a61ad416d37d6e72
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeEquipementRepository.java
@@ -0,0 +1,11 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa.repository;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.rest.core.annotation.RepositoryRestResource;
+
+@RepositoryRestResource(path = "TypeEquipement" , itemResourceRel = "TypesEquipements")
+@Tag(name = "TypeEquipement - CRUD/Spring Data REST")
+public interface TypeEquipementRepository extends JpaRepository<TypeEquipementEntity,String> {
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CorrespondanceRefEquipementMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CorrespondanceRefEquipementMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..6501c7b5d37e791f964b28a4246179f14094d6da
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CorrespondanceRefEquipementMapper.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface CorrespondanceRefEquipementMapper {
+
+    CorrespondanceRefEquipement toDomain(CorrespondanceRefEquipementEntity entity);
+
+    CorrespondanceRefEquipement toDomain(CorrespondanceRefEquipementDTO dto);
+
+    CorrespondanceRefEquipementEntity toEntity(CorrespondanceRefEquipement domain);
+
+    List<CorrespondanceRefEquipementEntity> toEntities(Collection<CorrespondanceRefEquipement> domains);
+
+    CorrespondanceRefEquipementDTO toDto(CorrespondanceRefEquipement domain);
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CritereMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CritereMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..b898dcdfa050cb91e38e3aa5210a41403b75ffb1
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/CritereMapper.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface CritereMapper {
+    List<Critere> toDomainsFromDTO(List<CritereDTO> criteresDTO);
+
+    List<CritereEntity> toEntities(Collection<Critere> referentiel);
+
+    List<CritereDTO> toDTO(List<Critere> all);
+
+    List<Critere> toDomains(List<CritereEntity> all);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/EtapeMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/EtapeMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a46e49054a09432b1fceacc90617f7162d4f31a
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/EtapeMapper.java
@@ -0,0 +1,22 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface EtapeMapper {
+    List<Etape> toDomain(List<EtapeDTO> etapesDTO);
+
+    List<Etape> toDomains(List<EtapeEntity> etapesEntities);
+
+    EtapeEntity toEntity(Etape referentiel);
+
+    List<EtapeEntity> toEntities(Collection<Etape> referentiel);
+
+    List<EtapeDTO> toDTO(List<Etape> etapes);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/HypotheseMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/HypotheseMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..958173206925637856b3b5f21df2406249b7d6de
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/HypotheseMapper.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.HypotheseIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.HypotheseIdDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface HypotheseMapper {
+
+    HypotheseEntity toEntity(Hypothese referentiel);
+
+    List<HypotheseEntity> toEntities(Collection<Hypothese> referentiel);
+
+    List<Hypothese> fromEntities(List<HypotheseEntity> all);
+
+
+    Collection<Hypothese> toDomains(List<HypotheseDTO> hypotheses);
+
+    List<HypotheseDTO> toDtos(List<Hypothese> all);
+
+
+    HypotheseId toDomain(HypotheseIdDTO hypotheseIdDTO);
+
+    HypotheseDTO toDTO(Hypothese hypothese);
+
+
+    HypotheseIdEntity toEntityId(HypotheseId id);
+
+    Hypothese toDomain(HypotheseEntity hypothese);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactEquipementMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactEquipementMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..d129f74be694fcf660c67443f85f2d7fe4020448
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactEquipementMapper.java
@@ -0,0 +1,33 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactEquipementIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactEquipementIdDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface ImpactEquipementMapper {
+    ImpactEquipementId toDomainId(ImpactEquipementIdDTO id);
+
+    ImpactEquipementEntity toEntity(ImpactEquipement referentiel);
+
+    List<ImpactEquipementEntity> toEntities(Collection<ImpactEquipement> referentiel);
+
+    ImpactEquipementIdEntity toEntityId(ImpactEquipementId id);
+
+    ImpactEquipement toDomain(ImpactEquipementEntity entity);
+
+    List<ImpactEquipement> toDomains(List<ImpactEquipementEntity> entities);
+
+    ImpactEquipement toDomain(ImpactEquipementDTO dto);
+
+    List<ImpactEquipement> toDomainsFromDTO(List<ImpactEquipementDTO> iesDTO);
+
+    ImpactEquipementDTO toDTO(ImpactEquipement impactEquipement);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactMessagerieMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactMessagerieMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f30310e73615a5a4f049084b5bbc7f28653d09ef
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactMessagerieMapper.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface ImpactMessagerieMapper {
+
+    ImpactMessagerieEntity toEntity(ImpactMessagerie impactMessagerie);
+    List<ImpactMessagerieEntity> toEntities(Collection<ImpactMessagerie> impactMessageries);
+
+    ImpactMessagerie toDomain(ImpactMessagerieEntity impactMessagerieEntity);
+    ImpactMessagerie toDomain(ImpactMessagerieDTO dto);
+    List<ImpactMessagerie> toDomains(List<ImpactMessagerieEntity> entities);
+    List<ImpactMessagerie> toDomainsFromDTO(List<ImpactMessagerieDTO> dtos);
+
+    List<ImpactMessagerieDTO> toDTOs(List<ImpactMessagerie> impactMessageries);
+    ImpactMessagerieDTO toDTO(ImpactMessagerie impactMessagerie);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactReseauMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactReseauMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..3411ffc6babc1b1e406f6a9ad144b15c47ccafc2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/ImpactReseauMapper.java
@@ -0,0 +1,39 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactReseauIdDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+
+public interface ImpactReseauMapper {
+
+    ImpactReseauEntity toEntity(ImpactReseau impactReseau);
+
+    @Mapping(source = "etape", target = "etapeACV")
+    ImpactReseauDTO toDTO(ImpactReseau impactReseau);
+
+    ImpactReseauIdEntity toEntityId(ImpactReseauId reseauId);
+
+    ImpactReseau toDomain(ImpactReseauEntity reseauEntity);
+
+    @Mapping(source = "etapeACV", target = "etape")
+    ImpactReseau toDomain(ImpactReseauDTO impactReseauDTO);
+
+    @Mapping(source = "etapeACV", target = "etape")
+    ImpactReseauId toDomainId(ImpactReseauIdDTO idImpactReseauDTO);
+
+    List<ImpactReseauEntity> toEntity(Collection<ImpactReseau> facteursImpacts);
+
+    List<ImpactReseau> toDomains(List<ImpactReseauEntity> entities);
+
+    List<ImpactReseau> toDomainsFromDTO(List<ImpactReseauDTO> dtos);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/MixElectriqueMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/MixElectriqueMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c204d9f4306df29c599cbb2e0f14531f64383951
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/MixElectriqueMapper.java
@@ -0,0 +1,32 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.MixElectriqueIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.MixElectriqueIdDTO;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface MixElectriqueMapper {
+
+    MixElectriqueId toDomainId(MixElectriqueIdDTO id);
+
+    MixElectriqueEntity toEntity(MixElectrique mixElecs);
+
+    List<MixElectriqueEntity> toEntities(Collection<MixElectrique> mixElecs);
+
+    MixElectriqueIdEntity toEntityId(MixElectriqueId id);
+
+    MixElectrique toDomain(MixElectriqueEntity mixElec);
+
+    List<MixElectrique> toDomains(List<MixElectriqueEntity> mixElec);
+
+    List<MixElectrique> toDomainsFromDTO(List<MixElectriqueDTO> mixElecs);
+
+    MixElectriqueDTO toDTO(MixElectrique mixElectrique);
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..aef63367511cdd0991bc65ce28de9f84b2100c66
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.referentiel.infrastructure.mapper;
+
+import org.mapstruct.Mapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper(componentModel = "spring")
+public interface TypeEquipementMapper {
+
+    TypeEquipement toDomaine(TypeEquipementEntity typeEquipementEntity);
+    TypeEquipement toDomaine(TypeEquipementDTO typeEquipementDTO);
+
+    TypeEquipementEntity toEntity(TypeEquipement typeEquipement);
+    List<TypeEquipementEntity> toEntities(Collection<TypeEquipement> typeEquipements);
+
+    TypeEquipementDTO toDto(TypeEquipement typeEquipement);
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/BaseExportReferentiel.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/BaseExportReferentiel.java
new file mode 100644
index 0000000000000000000000000000000000000000..118bcbfcfe9e1603d1bbfd4c4b59a5b18c6c83f2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/BaseExportReferentiel.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller;
+
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public interface BaseExportReferentiel<T> {
+
+    default void exportCSV(HttpServletResponse servletResponse, ReferentielCsvExportService<T> csvExportService, String baseFilename) throws IOException {
+        servletResponse.setStatus(200);
+        servletResponse.setContentType("text/csv");
+        servletResponse.setCharacterEncoding("UTF-8");
+        servletResponse.addHeader("Content-Disposition","attachment; filename="+baseFilename+"-"+
+                DateTimeFormatter.ofPattern("yyyy-MM-dd_hhmmss").format(LocalDateTime.now()) +".csv");
+        csvExportService.writeToCsv(servletResponse.getWriter());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielAdministrationCorrespondanceRefEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielAdministrationCorrespondanceRefEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..6db611f89300265941ea66305831157ae02ff9c0
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielAdministrationCorrespondanceRefEquipementRestApi.java
@@ -0,0 +1,43 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.correspondance;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationCorrespondanceRefEquipementRestApi {
+
+    @Operation(
+            summary = "Alimentation du référentiel des correspondances de RefEquipement par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importCorrespondanceRefEquipementCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/correspondanceRefEquipement/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les correspondances de RefEquipement sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportCorrespondanceRefEquipementCSV"
+    )
+    @GetMapping("/referentiel/correspondanceRefEquipement/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..2255fe5ddf85a6b58a7f7df6f5bee2190a05e0ad
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApi.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.correspondance;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+public interface ReferentielCorrespondanceRefEquipementRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération d'une correspondance de refEquipement à partir d'un modèle d'équipement.",
+            description = """
+                    Endpoint interne utilisé dans l'import de données d'entrées dans NumEcoEval
+                    pour déterminer la référence d'équipement à utiliser dans les référentiels'.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getCorrespondanceRefEquipement"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Correspondance trouvée",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = CorrespondanceRefEquipementDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Correspondance non trouvée", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/correspondanceRefEquipement", produces = MediaType.APPLICATION_JSON_VALUE)
+    CorrespondanceRefEquipementDTO get(@RequestParam(name = "modele") final String modele);
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a552e5286e1988887457bbff3aa2adf74434b7d4
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImpl.java
@@ -0,0 +1,55 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.correspondance;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCorrespondanceRefEquipementPortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.CorrespondanceRefEquipemenetCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.CorrespondanceRefEquipementFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielCorrespondanceRefEquipementRestApiImpl implements BaseExportReferentiel<CorrespondanceRefEquipementEntity>, ReferentielCorrespondanceRefEquipementRestApi, ReferentielAdministrationCorrespondanceRefEquipementRestApi {
+    private CorrespondanceRefEquipementFacade referentielFacade;
+
+    private CorrespondanceRefEquipemenetCsvExportService csvExportService;
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportCorrespondanceRefEquipementPortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @SneakyThrows
+    @Override
+    public CorrespondanceRefEquipementDTO get(String modele) {
+        return referentielFacade.get(modele);
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "correspondancesRefEquipement");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielAdministrationCritereRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielAdministrationCritereRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e1b8382851c0f928fd8e40b584cd41401a46b12
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielAdministrationCritereRestApi.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationCritereRestApi {
+
+    @Operation(
+            summary = "Alimentation des Criteres par csv  (annule et remplace).",
+            description = "Alimentation des Criteres par csv  (annule et remplace).",
+            tags = {"Import Référentiels"},
+            operationId = "importCriteresCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/criteres/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les criteres sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportCriteresCSV"
+    )
+    @GetMapping("/referentiel/criteres/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1c5ab8e5f545db51c656c434af61419ff2e6d6c
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApi.java
@@ -0,0 +1,36 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+
+import java.util.List;
+
+public interface ReferentielCritereRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération de tous les critères d'impacts écologiques",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getAllCriteres"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "impact reseau trouvé",
+                    content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = CritereDTO.class)))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Reseau  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/criteres", produces = MediaType.APPLICATION_JSON_VALUE)
+    List<CritereDTO> getAll();
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..72fe0a6c3523cc3b8485e207f3b12d9069c6ace9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImpl.java
@@ -0,0 +1,56 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.CritereCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.CritereFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielCritereRestApiImpl implements BaseExportReferentiel<CritereEntity>, ReferentielCritereRestApi, ReferentielAdministrationCritereRestApi {
+    private CritereFacade referentielFacade;
+    private CritereCsvExportService csvExportService;
+
+
+    @Override
+    public List<CritereDTO> getAll() {
+        return referentielFacade.getAll();
+    }
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportCriterePortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "criteres");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielAdministrationEtapeRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielAdministrationEtapeRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd10619b03f95ae99e9e3f3aebf152a8ce0f86f2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielAdministrationEtapeRestApi.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationEtapeRestApi {
+
+    @Operation(
+            summary = "Alimentation Etape ACV par csv : annule et remplace.",
+            description = "Alimentation Etape ACV par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importEtapesCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/etapes/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+    @Operation(
+            summary = "Exporter les etapes sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportEtapesCSV"
+    )
+    @GetMapping("/referentiel/etapes/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..8fc7bcd7fc8713186b8c0fc22b0c2445d47e9cc9
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApi.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+
+import java.util.List;
+
+public interface ReferentielEtapeRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération de toutes les étapes ACV",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Renvoie l'intégralité des étapes du cycle de vie (étapes ACV) des équipements.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getAllEtapes"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "etape acv non trouvé",
+                    content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = EtapeDTO.class)))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Reseau  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/etapes", produces = MediaType.APPLICATION_JSON_VALUE)
+    List<EtapeDTO> getAll();
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2335d8f0adfd64674da570a30a8685409ac51760
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImpl.java
@@ -0,0 +1,56 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportEtapePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.EtapeCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.EtapeFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielEtapeRestApiImpl implements BaseExportReferentiel<EtapeEntity>,ReferentielEtapeRestApi, ReferentielAdministrationEtapeRestApi {
+    private EtapeFacade referentielFacade;
+    private EtapeCsvExportService csvExportService;
+
+
+
+    @Override
+    public List<EtapeDTO> getAll() {
+        return referentielFacade.getAll();
+    }
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportEtapePortImpl().importCSV(fichier.getInputStream());
+
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "etapes");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/exception/ReferentelExceptionHandler.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/exception/ReferentelExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..245a9e7a06fca28d47c4553af5fea549acb55e44
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/exception/ReferentelExceptionHandler.java
@@ -0,0 +1,79 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.exception;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.NotFoundException;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielRuntimeException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.context.request.WebRequest;
+
+import java.time.LocalDateTime;
+
+import static org.springframework.http.HttpStatus.*;
+
+@Slf4j
+@RestControllerAdvice
+public class ReferentelExceptionHandler {
+
+    /**
+     * writer error message
+     *
+     * @param ex     excepetion
+     * @param status le statut http
+     * @return l'objet erreur
+     */
+    private static ErrorResponseDTO writeErrorResponse(Exception ex, HttpStatus status) {
+        return ErrorResponseDTO.builder()
+                .status(status)
+                .code(status.value())
+                .timestamp(LocalDateTime.now())
+                .message(ex.getLocalizedMessage()).build();
+    }
+
+    @ExceptionHandler(value = {NotFoundException.class})
+    public ErrorResponseDTO notFoundException(Exception ex, WebRequest request) {
+        return writeErrorResponse(ex, NOT_FOUND);
+    }
+
+    @ExceptionHandler(value = {ReferentielException.class})
+    @ResponseStatus(value = NOT_FOUND)
+    public ErrorResponseDTO referentielException(Exception ex, WebRequest request) {
+        return writeErrorResponse(ex, NOT_FOUND);
+    }
+
+    @ExceptionHandler(value = {ReferentielRuntimeException.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErrorResponseDTO referentielPersistenceException(Exception ex, WebRequest request) {
+        return writeErrorResponse(ex, INTERNAL_SERVER_ERROR);
+    }
+
+    @ExceptionHandler(value = {DataIntegrityViolationException.class})
+    @ResponseStatus(BAD_REQUEST)
+    public ErrorResponseDTO dataIntegrityViolationException(DataIntegrityViolationException ex, WebRequest request) {
+        log.debug("DataIntegrityViolationException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return writeErrorResponse(new Exception("Erreur d'intégrité lors de la persistence des données."), BAD_REQUEST);
+    }
+
+    @ExceptionHandler(value = {RuntimeException.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErrorResponseDTO runtimeException(Exception ex, WebRequest request) {
+        log.error("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        log.debug("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
+    }
+
+    @ExceptionHandler(value = {Exception.class})
+    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
+    public ErrorResponseDTO exception(Exception ex, WebRequest request) {
+        log.error("Exception lors d'un traitement sur l'URI {} : {}", request.getContextPath(), ex.getMessage());
+        log.debug("Exception lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
+        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
+    }
+
+}
+
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielAdministrationHypotheseRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielAdministrationHypotheseRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..34bb5683957fed156254b3be6d7428acd6d60750
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielAdministrationHypotheseRestApi.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationHypotheseRestApi {
+
+    @Operation(
+            summary = "Alimentation des Hypothèses par csv : annule et remplace.",
+            description = "Alimentation des Hypothèses par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importHypothesesCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/hypotheses/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les hypothèses sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportHypothesesCSV"
+    )
+    @GetMapping("/referentiel/hypotheses/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc18fd8279a0d09ffbdb003ff424a4d93cc7e656
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApi.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+public interface ReferentielHypotheseRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération d'une hypothèse par son code",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Renvoie une hypothèse en fonction de sa clé.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getHypothese"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Hypothèse trouvé",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = HypotheseDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Hypothèse non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/hypothese", produces = MediaType.APPLICATION_JSON_VALUE)
+    HypotheseDTO get(@RequestParam @Schema(description = "Clé de l'hypothèse") final String cle);
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a021fb0e659763d0b860bca97010d2dbe842532
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImpl.java
@@ -0,0 +1,58 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportHypothesePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.HypotheseCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.HypotheseIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.HypotheseFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielHypotheseRestApiImpl implements BaseExportReferentiel<HypotheseEntity>, ReferentielAdministrationHypotheseRestApi, ReferentielHypotheseRestApi {
+    private HypotheseFacade referentielFacade;
+
+    private HypotheseCsvExportService csvExportService;
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportHypothesePortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @SneakyThrows
+    @Override
+    public HypotheseDTO get(String cle) {
+        HypotheseIdDTO hypotheseIdDTO = new HypotheseIdDTO();
+        hypotheseIdDTO.setCode(cle);
+        return referentielFacade.get(hypotheseIdDTO);
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "hypotheses");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielAdministrationImpactEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielAdministrationImpactEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..acef1066978903d2f13a5cae4c82703efecdb1c5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielAdministrationImpactEquipementRestApi.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactequipement;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationImpactEquipementRestApi {
+
+    @Operation(
+            summary = "Alimentation du référentiel ImpactEquipement par csv : annule et remplace.",
+            description = "Alimentation du référentiel ImpactEquipement par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importImpactEquipementCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/impactequipements/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les impacts d'équipements sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportImpactEquipementCSV"
+    )
+    @GetMapping("/referentiel/impactequipements/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f642a9ba2b34e981f5a86e9475c2ae8bbf08e07
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApi.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactequipement;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+public interface ReferentielImpactEquipementRestApi {
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération d'un Impact Equipement",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Récupération d'un impact équipement en fonction de 3 paramètres:
+                    <ul>
+                        <li>La référence d'équipement: refEquipement</li>
+                        <li>Le critère d'impact: critere</li>
+                        <li>L'étape ACV: etapeACV</li>
+                    </ul>
+                    .
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getImpactEquipement")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "impact equipement trouvé",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ImpactEquipementDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Equipement  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/impactequipements", produces = MediaType.APPLICATION_JSON_VALUE)
+    ImpactEquipementDTO get(
+            @RequestParam
+            @Schema(description = "Référence de l'équipement recherché") final String refEquipement,
+            @RequestParam
+            @Schema(description = "Nom du critère d'impact écologique") final String critere,
+            @RequestParam
+            @Schema(description = "Code de l'étape ACV") final String etapeacv
+    );
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..27e9300d43b819aaebaa41c385fc7c589feaedfb
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImpl.java
@@ -0,0 +1,66 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactequipement;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactEquipementPortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactEquipementCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactEquipementIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactEquipementFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielImpactEquipementRestApiImpl implements BaseExportReferentiel<ImpactEquipementEntity>, ReferentielImpactEquipementRestApi, ReferentielAdministrationImpactEquipementRestApi {
+    private ImpactEquipementFacade referentielFacade;
+
+    private ImpactEquipementCsvExportService csvExportService;
+
+    @SneakyThrows
+    @Override
+    public ImpactEquipementDTO get(String refEquipement, String critere, String etapeacv) {
+
+        ImpactEquipementIdDTO id = ImpactEquipementIdDTO.builder()
+                .refEquipement(StringUtils.trim(refEquipement))
+                .critere(critere)
+                .etape(etapeacv)
+                .build();
+        
+        return referentielFacade.get(id);
+    }
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportImpactEquipementPortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "impactEquipement");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..df45d62727162bdabfc1445629c6651be9c1d200
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApi.java
@@ -0,0 +1,61 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import java.util.List;
+
+public interface ReferentielImpactMessagerieRestApi {
+
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération d'un impact de messagerie",
+            description = """
+                    Endpoint interne utilisé dans l'enrichissement des données pour un calcul dans le module api-enrichissement de NumEcoEval.
+                    Renvoie un élément du référentiel des impacts de messagerie.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getImpactMessagerie"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = " Référentiel Impact Messagerie",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = ImpactMessagerieDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = " Référentiel Impact Messagerie  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/impactsMessagerie/{critere}", produces = MediaType.APPLICATION_JSON_VALUE)
+    ImpactMessagerieDTO getImpactMessagerie(@PathVariable
+                                                  @Schema(description = "Critère recherché") String critere);
+
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération des impacts de messagerie",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Renvoie l'intégralité des impacts de messagerie.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getAllImpactMessagerie"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = " Référentiel Impact Messagerie",
+                    content = {@Content(mediaType = "application/json",
+                            array = @ArraySchema(schema = @Schema(implementation = ImpactMessagerieDTO.class)))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = " Référentiel Impact Messagerie  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/impactsMessagerie", produces = MediaType.APPLICATION_JSON_VALUE)
+    List<ImpactMessagerieDTO> getAllImpactMessagerie();
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ee0ff2e88abe876e3f4767edd89b2f7ba3b674d
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImpl.java
@@ -0,0 +1,59 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactMessageriePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactMessagerieCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactMessagerieFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielImpactMessagerieRestApiImpl implements BaseExportReferentiel<ImpactMessagerieEntity>, ReferentielInterneImpactMessagerieRestApi, ReferentielImpactMessagerieRestApi {
+
+    private ImpactMessagerieFacade impactMessagerieFacade;
+
+    private ImpactMessagerieCsvExportService csvExportService;
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportImpactMessageriePortImpl().importCSV(fichier.getInputStream());
+        impactMessagerieFacade.purgeAndAddAll(rapportImport.getObjects());
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @Override
+    public ImpactMessagerieDTO getImpactMessagerie(String critere) {
+        return impactMessagerieFacade.getImpactMessagerieForCritere(critere);
+    }
+
+    @Override
+    public List<ImpactMessagerieDTO> getAllImpactMessagerie() {
+        return impactMessagerieFacade.getAllImpactMessagerie();
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "impactMessagerie");
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielInterneImpactMessagerieRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielInterneImpactMessagerieRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..6272030fe67c6092388e18322cf6d56395a36cd0
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielInterneImpactMessagerieRestApi.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielInterneImpactMessagerieRestApi {
+
+    @Operation(
+            summary = "Alimentation du référentiel Impact Messagerie par csv : annule et remplace.",
+            description = "Alimentation du référentiel Impact Messagerie par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importImpactMessagerieCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/impactMessagerie/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les impacts de messagerie sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportImpactMessagerieCSV"
+    )
+    @GetMapping("/referentiel/impactMessagerie/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielAdministrationImpactReseauRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielAdministrationImpactReseauRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d2340e1940a3734b7e83ad7fd6fb9d399638659
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielAdministrationImpactReseauRestApi.java
@@ -0,0 +1,79 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationImpactReseauRestApi {
+
+    @Operation(
+            summary = "Exposition ressource ajout d' un Impact Reseau",
+            tags = {"Administration détaillée"},
+            hidden = true,
+            description = "Exposition ressource ajout d' un Impact Reseau"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "impact reseau trouvé",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ImpactReseauDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Réseau non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/impactreseaux", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    ResponseEntity<ImpactReseauDTO> add(@RequestBody final ImpactReseauDTO impactReseauDTO) throws ReferentielException;
+
+    @Operation(
+            summary = "Exposition ressource update Impact Reseau  ",
+            tags = {"Administration détaillée"},hidden = true
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Modication d'un impact reseau : les champs refReseau, critere & etapeACV ne peuvent pas être modifié",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ImpactReseauDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Réseau non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PutMapping(path = "/referentiel/impactreseaux", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    ResponseEntity<ImpactReseauDTO> update(@RequestBody final ImpactReseauDTO impactReseauDTO) throws ReferentielException;
+
+
+    @Operation(
+            summary = "Alimentation du référentiel ImpactReseau par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importImpactReseauxCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/impactreseaux/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les impacts réseaux sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportImpactReseauxCSV"
+    )
+    @GetMapping("/referentiel/impactreseaux/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f65700204f4caffba28e3415d97eca3d549ebe5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApi.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+public interface ReferentielImpactReseauRestApi {
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération d'un Impact Réseau",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Récupération d'un impact écologique vis à vis de l'usage du réseau en fonction de 3 paramètres:
+                    <ul>
+                        <li>La référence d'impact réseau: refReseau</li>
+                        <li>Le critère d'impact: critere</li>
+                        <li>L'étape ACV: etapeACV</li>
+                    </ul>
+                    .
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getImpactReseau")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "impact reseau trouvé",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ImpactReseauDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Impact Reseau  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/impactreseaux", produces = MediaType.APPLICATION_JSON_VALUE)
+    ImpactReseauDTO get(
+            @RequestParam
+            @Schema(description = "Référence de réseau recherché") final String refReseau,
+            @RequestParam
+            @Schema(description = "Nom du critère d'impact écologique") final String critere,
+            @RequestParam
+            @Schema(description = "Code de l'étape ACV") final String etapeacv
+    );
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..bdd40ff1b8de1cd5ff3f4420b3a8f16b6fd65b94
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImpl.java
@@ -0,0 +1,93 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactReseauPortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactReseauCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactReseauIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactReseauFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielImpactReseauRestApiImpl implements BaseExportReferentiel<ImpactReseauEntity>, ReferentielImpactReseauRestApi, ReferentielAdministrationImpactReseauRestApi {
+    private ImpactReseauFacade referentielFacade;
+
+    private ImpactReseauCsvExportService csvExportService;
+
+
+    @SneakyThrows
+    @Override
+    public ImpactReseauDTO get(String refReseau, String critere, String etapeacv) {
+        ImpactReseauIdDTO idImpactReseauDTO = ImpactReseauIdDTO.builder()
+                .critere(critere)
+                .etapeACV(etapeacv)
+                .refReseau(refReseau).build();
+        return referentielFacade.get(idImpactReseauDTO);
+    }
+
+
+    @Override
+    public ResponseEntity<ImpactReseauDTO> add(ImpactReseauDTO impactReseauDTO) throws ReferentielException {
+        if (Objects.isNull(impactReseauDTO)) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le corps de la requête ne peut être null");
+        }
+        if (StringUtils.isBlank(impactReseauDTO.getSource())) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "La source est obligatoire");
+        }
+        return ResponseEntity.ok().body(referentielFacade.addOrUpdate(impactReseauDTO));
+    }
+
+    @Override
+    @PutMapping(path = "/referentiel/impactreseaux", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<ImpactReseauDTO> update(ImpactReseauDTO impactReseauDTO) throws ReferentielException {
+        if (Objects.isNull(impactReseauDTO)) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le corps de la requête ne peut être null");
+        }
+        if (StringUtils.isBlank(impactReseauDTO.getSource())) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "La source est obligatoire");
+        }
+        return ResponseEntity.ok().body(referentielFacade.addOrUpdate(impactReseauDTO));
+    }
+
+    @Override
+    @PostMapping(path = "/referentiel/impactreseaux/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportImpactReseauPortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "impactReseaux");
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielAdministrationMixElectriqueRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielAdministrationMixElectriqueRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..a983084502654e264d83e7d8500d1be18bfe1952
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielAdministrationMixElectriqueRestApi.java
@@ -0,0 +1,45 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.mixelectrique;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationMixElectriqueRestApi {
+
+
+    @Operation(
+            summary = "Alimentation du référentiel ImpactEquipement par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importImpactEquipementCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/mixelecs/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les impacts des mix électrique sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportImpactEquipementCSV"
+    )
+    @GetMapping("/referentiel/mixelecs/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElecRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElecRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..770a4e6031689a219f81b3de2f923e3f440ef60d
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElecRestApiImpl.java
@@ -0,0 +1,75 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.mixelectrique;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportMixElectriquePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.MixElectriqueCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.MixElectriqueIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.MixElectriqueFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielMixElecRestApiImpl implements BaseExportReferentiel<MixElectriqueEntity>, ReferentielMixElectriqueRestApi, ReferentielAdministrationMixElectriqueRestApi {
+    private MixElectriqueFacade referentielFacade;
+
+    private MixElectriqueCsvExportService csvExportService;
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportMixElectriquePortImpl().importCSV(fichier.getInputStream());
+        referentielFacade.purgeAndAddAll(rapportImport.getObjects());
+
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @SneakyThrows
+    @Override
+    public List<MixElectriqueDTO> get(String pays) {
+
+        if ("_all".equals(pays)) {
+            return referentielFacade.getAll();
+        } else {
+            return referentielFacade.getByPays(pays);
+        }
+
+    }
+
+    @SneakyThrows
+    @Override
+    public MixElectriqueDTO get(String pays, String critere) {
+        MixElectriqueIdDTO id = MixElectriqueIdDTO.builder()
+                .pays(pays)
+                .critere(critere)
+                .build();
+        
+        return referentielFacade.get(id);
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "mixElec");
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..d29e7e28226f980ac30bfd80f0b30d1701a8aad6
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApi.java
@@ -0,0 +1,70 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.mixelectrique;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+public interface ReferentielMixElectriqueRestApi {
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération d'un Mix électrique",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Récupération d'un mix électrique en fonction de paramètres:
+                    <ul>
+                        <li>Le pays de l'équipement: pays</li>
+                        <li>Le critère d'impact: critere</li>
+                    </ul>
+                    .
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getMixElectrique")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "mix Electrique trouvé",
+                    content = {@Content(mediaType = "application/json", schema = @Schema(implementation = MixElectriqueDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "mix Electrique  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/mixelecs", produces = MediaType.APPLICATION_JSON_VALUE)
+    MixElectriqueDTO get(
+            @RequestParam
+            @Schema(description = "Pays recherché") final String pays,
+            @RequestParam
+            @Schema(description = "Nom du critère d'impact écologique") final String critere
+    );
+
+    @Operation(summary = "Endpoint interne à NumEcoEval - Récupération de Mix électriques par pays",
+            description = """
+                    Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+                    Récupération de mix électriques en fonction de paramètres:
+                    <ul>
+                        <li>Le pays de l'équipement: pays</li>
+                    </ul>
+                    Cas spécifique avec pays = _all pour retourner tous les Mix electriques.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getMixElectriqueParPays")
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "mix Electrique trouvé",
+                    content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = MixElectriqueDTO.class)))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "mix Electrique  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/mixelecs/{pays}", produces = MediaType.APPLICATION_JSON_VALUE)
+    List<MixElectriqueDTO> get(
+            @PathVariable
+            @Schema(description = "Pays recherché") final String pays
+    );
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielAdministrationTypeEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielAdministrationTypeEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0daa761c15e81958f01a687bc00dc81025c33f5
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielAdministrationTypeEquipementRestApi.java
@@ -0,0 +1,43 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.servlet.http.HttpServletResponse;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface ReferentielAdministrationTypeEquipementRestApi {
+
+    @Operation(
+            summary = "Alimentation du référentiel Type Equipement par csv : annule et remplace.",
+            tags = {"Import Référentiels"},
+            operationId = "importTypeEquipementCSV"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @PostMapping(path = "/referentiel/typeEquipement/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException;
+
+
+    @Operation(
+            summary = "Exporter les impacts des types d'équipements sous format csv",
+            tags = {"Export Référentiels"},
+            operationId = "exportTypeEquipementCSV"
+    )
+    @GetMapping("/referentiel/typeEquipement/csv")
+    void exportCSV(HttpServletResponse servletResponse) throws IOException;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bbc6c19f09fd10c1ab0b7b9ce4fa82bcc99a171
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApi.java
@@ -0,0 +1,63 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import java.util.List;
+
+public interface ReferentielTypeEquipementRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération de tous les types d'équipement",
+            description = """
+                    Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval.
+                    Renvoie l'intégralité des types d'équipements utilisables par NumEcoEval.
+                    
+                    Les types d'équipement servent notamment à alimenter la durée de vie par défaut des équipements
+                    reçues.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getAllTypeEquipement"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Types Equipement",
+                    content = {@Content(mediaType = "application/json",
+                            array = @ArraySchema(schema = @Schema(implementation = TypeEquipementDTO.class)))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Types Equipement  non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/typesEquipement", produces = MediaType.APPLICATION_JSON_VALUE)
+    List<TypeEquipementDTO> getTypesEquipement();
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération d'un type d'équipement via son type",
+            description = """
+                    V2 - Endpoint interne utilisé à l'enrichissement données pour un équipement physique.
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getTypeEquipement"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Types Equipement",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = TypeEquipementDTO.class))}),
+            @ApiResponse(responseCode = "400", description = "Invalid request",
+                    content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))}),
+            @ApiResponse(responseCode = "404", description = "Types Equipement non trouvé", content = {@Content(mediaType = "application/json",
+                    schema = @Schema(implementation = ErrorResponseDTO.class))})})
+    @GetMapping(path = "/referentiel/typesEquipement/{type}", produces = MediaType.APPLICATION_JSON_VALUE)
+    TypeEquipementDTO getTypeEquipement(@PathVariable @Schema(description = "type recherché") String type) throws ReferentielException;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..13b16bec0eb738adf4b449529f099b8222ad21e1
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java
@@ -0,0 +1,60 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement;
+
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeEquipementCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeEquipementFacade;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@Slf4j
+@AllArgsConstructor
+public class ReferentielTypeEquipementRestApiImpl implements BaseExportReferentiel<TypeEquipementEntity>, ReferentielTypeEquipementRestApi, ReferentielAdministrationTypeEquipementRestApi {
+
+   private TypeEquipementFacade typeEquipementFacade;
+
+   private TypeEquipementCsvExportService csvExportService;
+
+    @Override
+    public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException {
+        if (fichier == null || fichier.isEmpty()) {
+            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide");
+        }
+        var rapportImport = new ImportTypeEquipementPortImpl().importCSV(fichier.getInputStream());
+        typeEquipementFacade.purgeAndAddAll(rapportImport.getObjects());
+        return new RapportImportDTO(
+                fichier.getOriginalFilename(),
+                rapportImport.getErreurs(),
+                rapportImport.getNbrLignesImportees()
+        );
+    }
+
+    @Override
+    public TypeEquipementDTO getTypeEquipement(String type) throws ReferentielException {
+        return typeEquipementFacade.getTypeEquipementForType(type);
+    }
+
+    @Override
+    public List<TypeEquipementDTO> getTypesEquipement() {
+        return typeEquipementFacade.getAllTypesEquipement();
+    }
+
+    @Override
+    public void exportCSV(HttpServletResponse servletResponse) throws IOException {
+        exportCSV(servletResponse, csvExportService, "typeEquipement");
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..68f3d076662a1c6deb0672846a072b1d379d2b65
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApi.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.version;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.VersionDTO;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+
+public interface VersionRestApi {
+
+    @Operation(
+            summary = "Endpoint interne à NumEcoEval - Récupération de la version courante",
+            description = """
+                    Endpoint interne utilisé pour connaître la version installée
+                    """,
+            tags = "Interne NumEcoEval",
+            operationId = "getVersion"
+    )
+    @ApiResponses(value = {
+            @ApiResponse(responseCode = "200", description = "Version",
+                    content = {@Content(mediaType = "application/json",
+                            schema = @Schema(implementation = VersionDTO.class))})
+    })
+    @GetMapping(path = "/version", produces = MediaType.APPLICATION_JSON_VALUE)
+    VersionDTO getVersion();
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApiImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d1539469e152f0385166fbb3c89e6fce468355e
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/version/VersionRestApiImpl.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.version;
+
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.VersionDTO;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class VersionRestApiImpl implements VersionRestApi {
+
+    @Value("${version}")
+    private String version;
+
+    @Override
+    public VersionDTO getVersion() {
+        return new VersionDTO(version);
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CorrespondanceRefEquipementDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CorrespondanceRefEquipementDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..3101e193f460916398a2c628269d6253bdafbd85
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CorrespondanceRefEquipementDTO.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Référentiel de correspondance entre un modèle d'équipement physique et une référence d'équipement dans les référentiels."
+)
+public class CorrespondanceRefEquipementDTO implements Serializable {
+    @Schema(
+            description = "Modèle de l'équipement, clé du référentiel"
+    )
+    String modeleEquipementSource;
+    @Schema(
+            description = "Référence d'équipement correspondant au modèle de l'équipement"
+    )
+    String refEquipementCible;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CritereDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CritereDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..e955fdd23529edef26710827998892c755d5d17b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/CritereDTO.java
@@ -0,0 +1,33 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Référentiel de critère d'impact écologique"
+)
+public class CritereDTO implements Serializable {
+    @Schema(
+            description = "Nom du critère d'impact écologique, clé du référentiel"
+    )
+    String nomCritere;
+    @Schema(
+            description = "Unité du critère d'impact écologique"
+    )
+    String unite;
+    @Schema(
+            description = "Description du critère d'impact écologique"
+    )
+    String description;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ErrorResponseDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ErrorResponseDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7ab387791a67273dd9d4cee22bb54356026e7da
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ErrorResponseDTO.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+import org.springframework.http.HttpStatus;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Schema(
+        description = "Objet standard pour les réponses en cas d'erreur d'API"
+)
+public class ErrorResponseDTO implements Serializable {
+    @Schema(
+            description = "Code de l'erreur"
+    )
+    int code;
+    @Schema(
+            description = "Message de l'erreur"
+    )
+    String message;
+    @Schema(
+            description = "Statut HTTP de la réponse"
+    )
+    HttpStatus status;
+    @Schema(
+            description = "Date & Heure de l'erreur"
+    )
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss")
+    LocalDateTime timestamp;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/EtapeDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/EtapeDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf027f173b17931e60f9ef3f82eae516231064b8
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/EtapeDTO.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@EqualsAndHashCode
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Builder
+@Schema(
+        description = "Référentiel d'étape dans le cycle de vie d'un équipement (Etape ACV)"
+)
+public class EtapeDTO implements Serializable {
+    @Schema(
+            description = "Code de l'étape. Ne contient que des majuscules, clé du référentiel",
+            pattern = "[A-Z]+"
+    )
+    String code;
+    @Schema(
+            description = "Libellé de l'étape"
+    )
+    String libelle;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfb8931abfbb6657c620b5409683029929e8b8e2
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java
@@ -0,0 +1,33 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Référentiel des hypothèses utilisées pour les calculs"
+)
+public class HypotheseDTO implements Serializable {
+    @Schema(
+            description = "Code de l'hypothèse, clé du référentiel"
+    )
+    String code;
+    @Schema(
+            description = "Valeur de l'hypothèse"
+    )
+    String valeur;
+    @Schema(
+            description = "Source de l'hypothèse"
+    )
+    String source;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactEquipementDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactEquipementDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..18c0d47148847a01c2cda2ba70a063fb72ba2f5c
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactEquipementDTO.java
@@ -0,0 +1,52 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Schema(
+        description = "Référentiel de l'impact écologique d'un équipement physique dans les référentiels. La clé est composé des champs refEquipement, etape et critere."
+)
+public class ImpactEquipementDTO implements Serializable {
+    @Schema(
+            description = "Référence de l'équipement physique, fait partie de la clé dans le référentiel"
+    )
+    String refEquipement;
+    @Schema(
+            description = "Étape ACV concernée, fait partie de la clé dans le référentiel"
+    )
+    String etape;
+    @Schema(
+            description = "Critère d'impact écologique concerné, fait partie de la clé dans le référentiel"
+    )
+    String critere;
+    @Schema(
+            description = "Source de l'impact écologique pour cette équipement physique"
+    )
+    String source;
+    @Schema(
+            description = "Type de l'équipement physique concerné"
+    )
+    String type;
+    @Schema(
+            description = "Valeur de l'impact écologique"
+    )
+    Double valeur;
+    @Schema(
+            description = "Consommation électrique moyenne"
+    )
+    Double consoElecMoyenne;
+    @Schema(
+            description = "Description de l'entrée dans le référentiel"
+    )
+    String description;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactMessagerieDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactMessagerieDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..2964d2a7c9a2ce9adbc0a914928f754741ab1418
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactMessagerieDTO.java
@@ -0,0 +1,38 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Référentiel de l'impact écologique d'une messagerie. La clé est le champ critere. Chaque entrée représente les composants d'une fonction affine (Ax+b)."
+)
+public class ImpactMessagerieDTO implements Serializable {
+    @Schema(
+            description = "Coefficient directeur de la fonction affine"
+    )
+    Double constanteCoefficientDirecteur;
+    @Schema(
+            description = "Constante de la fonction affine"
+    )
+    Double constanteOrdonneeOrigine;
+    @Schema(
+            description = "Critère de l'impact écologique d'une messagerie, clé du référentiel"
+    )
+    String critere;
+    @Schema(
+            description = "Source de l'impact écologique d'une messagerie"
+    )
+    String source;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactReseauDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactReseauDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6ea17bb8dd2a8db2d8102b7c964f9d6d0381577
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/ImpactReseauDTO.java
@@ -0,0 +1,58 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Schema(
+        description = "Référentiel de l'impact écologique d'un équipement physique vis à vis de l'usage du réseau dans les référentiels. La clé est composé des champs refReseau, etapeACV et critere."
+)
+public class ImpactReseauDTO implements Serializable {
+    @Schema(
+            description = "Référence de l'usage du réseau, fait partie de la clé du référentiel"
+    )
+    @JsonProperty("refReseau")
+    String refReseau;
+    @Schema(
+            description = "Étape ACV concerné pour l'usage du réseau, fait partie de la clé du référentiel"
+    )
+    @JsonProperty("etapeACV")
+    String etapeACV;
+    @Schema(
+            description = "Critère d'impact écologique concerné pour l'usage du réseau, fait partie de la clé du référentiel"
+    )
+    @JsonProperty("critere")
+    String critere;
+    @Schema(
+            description = "Unité de l'impact écologique concerné pour l'usage du réseau. Champ Déprécié",
+            deprecated = true
+    )
+    @JsonProperty("unite")
+    String unite;
+    @Schema(
+            description = "Source de l'impact écologique"
+    )
+    @JsonProperty("source")
+    String source;
+    @Schema(
+            description = "Valeur de l'impact écologique"
+    )
+    @JsonProperty("valeur")
+    Double valeur;
+    @Schema(
+            description = "Consommation électrique moyenne de l'impact écologique"
+    )
+    @JsonProperty("consoElecMoyenne")
+    Double consoElecMoyenne;
+}
\ No newline at end of file
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/MixElectriqueDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/MixElectriqueDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e12ab0169ef55c3296241e8d8fb8c4e230ccfa7
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/MixElectriqueDTO.java
@@ -0,0 +1,41 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Schema(
+        description = "Référentiel des mix électrique couvrant l'usage de l'électricité vis à vis du pays d'utilisation de l'équipement. La clé du référentiel est composé des champs pays et critere."
+)
+public class MixElectriqueDTO implements Serializable {
+
+    @Schema(
+            description = "Pays concerné, fait partie de la clé du référentiel"
+    )
+    String pays;
+    @Schema(
+            description = "Code du pays concerné en anglais"
+    )
+    String raccourcisAnglais;
+    @Schema(
+            description = "Critère d'impact écologique concerné, fait partie de la clé du référentiel"
+    )
+    String critere;
+    @Schema(
+            description = "Valeur du référentiel"
+    )
+    Double valeur;
+    @Schema(
+            description = "Source de la valeur du référentiel"
+    )
+    String source;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/RapportImportDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/RapportImportDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..129a03b2a73da21a8e4fd482f208682f25baf189
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/RapportImportDTO.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class RapportImportDTO {
+
+    String fichier;
+
+    List<String> erreurs = new ArrayList<>();
+
+    long nbrLignesImportees = 0;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeEquipementDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeEquipementDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac9e33dbb9da55a9b1e4bce5fe8d1b1dd609146b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeEquipementDTO.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Référentiel des types d'équipements physiques utilisables dans le système. La clé du référentiel est le champ type."
+)
+public class TypeEquipementDTO implements Serializable {
+    @Schema(
+            description = "Type de l'équipment physique, clé du référentiel"
+    )
+    String type;
+    @Schema(
+            description = "Flag indiquant si l'équipement physique est un serveur"
+    )
+    boolean serveur;
+    @Schema(
+            description = "Commentaire de l'entrée dans le référentiel"
+    )
+    String commentaire;
+    @Schema(
+            description = "Durée de vie par défaut de ce type d'équipement physique"
+    )
+    Double dureeVieDefaut;
+    @Schema(
+            description = "Source de l'information du référentiel"
+    )
+    String source;
+    @Schema(
+            description = "Référence de l'équipement par défaut, permet des correspondances en cas d'absence de correspondance direct"
+    )
+    String refEquipementParDefaut;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/VersionDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/VersionDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..69168dbf4ea5d4ce75eb89d8297d2fcf8fd4a22b
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/VersionDTO.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+@Builder
+@Schema(
+        description = "Version applicative"
+)
+public class VersionDTO implements Serializable {
+    @Schema(
+            description = "La version"
+    )
+    String version;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/CritereIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/CritereIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e9e53d130735363e63514b2247694570018d944
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/CritereIdDTO.java
@@ -0,0 +1,26 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class CritereIdDTO implements Serializable {
+
+    String nomCritere;
+
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/EtapeIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/EtapeIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef396485d1973017697450b1f645a50ac8065e5a
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/EtapeIdDTO.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class EtapeIdDTO implements Serializable {
+
+    String code;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/HypotheseIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/HypotheseIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec20ee6b92a09a3a0b62c43fd8f791c74fab8997
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/HypotheseIdDTO.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@EqualsAndHashCode
+@Accessors(chain = true)
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@NoArgsConstructor
+public class HypotheseIdDTO implements Serializable {
+    String code;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactEquipementIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactEquipementIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..7800d19e960b8147d5ec2612d5ba7b702f0dc9c7
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactEquipementIdDTO.java
@@ -0,0 +1,26 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class ImpactEquipementIdDTO implements Serializable {
+    String refEquipement;
+    String etape;
+    String critere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactReseauIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactReseauIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fc29e59a8706121c9139374a46a3f2633ce9abf
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/ImpactReseauIdDTO.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class ImpactReseauIdDTO implements Serializable {
+    @JsonProperty("refReseau")
+    String refReseau;
+    @JsonProperty("etapeACV")
+    String etapeACV;
+    @JsonProperty("critere")
+    String critere;
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/MixElectriqueIdDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/MixElectriqueIdDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..de5aad79af6eda10a27021c962ea401596bcf188
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/id/MixElectriqueIdDTO.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.experimental.FieldDefaults;
+
+import java.io.Serializable;
+
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@EqualsAndHashCode
+public class MixElectriqueIdDTO implements Serializable {
+    String pays;
+    String critere;
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..007e5271f781e3704438f65cb4c82018d1351edf
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacade.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class CorrespondanceRefEquipementFacade {
+    private ReferentielPersistencePort<CorrespondanceRefEquipement, String> persistencePort;
+    private CorrespondanceRefEquipementMapper mapper;
+
+    public CorrespondanceRefEquipementDTO get(String modeleEquipementSource) throws ReferentielException {
+        var correspondanceRefEquipement = persistencePort.get(modeleEquipementSource);
+        if (correspondanceRefEquipement != null) {
+            return mapper.toDto(correspondanceRefEquipement);
+        }
+        return null;
+    }
+
+    public List<CorrespondanceRefEquipementDTO> getAll() {
+        List<CorrespondanceRefEquipement> domains = persistencePort.getAll();
+        return CollectionUtils.emptyIfNull(domains).stream().map(domain -> mapper.toDto(domain)).toList();
+    }
+
+    public void purgeAndAddAll(List<CorrespondanceRefEquipementDTO> correspondances) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(CollectionUtils.emptyIfNull(correspondances).stream()
+                .map(dto -> mapper.toDomain(dto))
+                .toList());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..fafbfa46e85103ce32a747a5b1b7e2b9b0c11399
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacade.java
@@ -0,0 +1,42 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.domain.model.id.CritereId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CritereMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class CritereFacade {
+
+    private ReferentielPersistencePort<Critere, CritereId> persistencePort;
+
+    private CritereMapper mapper;
+
+    /**
+     * creation liste etapes
+     *
+     * @param criteresDTO
+     */
+    public void purgeAndAddAll(List<CritereDTO> criteresDTO) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomainsFromDTO(criteresDTO));
+    }
+
+    /**
+     * Recuperation de la liste des hypotheses
+     *
+     * @return
+     */
+    public List<CritereDTO> getAll() {
+        return mapper.toDTO(persistencePort.getAll());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5f03d23c3cd7fc0bcf3d341f1b357c8df3988b4
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacade.java
@@ -0,0 +1,41 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.domain.model.id.EtapeId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.EtapeMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class EtapeFacade {
+
+    private ReferentielPersistencePort<Etape, EtapeId> persistencePort;
+
+    private EtapeMapper mapper;
+
+
+    /**
+     * Ajout en masse des etapes
+     *
+     * @param etapesDTO
+     */
+    public void purgeAndAddAll(List<EtapeDTO> etapesDTO) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomain(etapesDTO));
+    }
+
+    /**
+     * @return
+     */
+    public List<EtapeDTO> getAll() {
+        return mapper.toDTO(persistencePort.getAll());
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..ceeb6491fcf33d705b8147b34bcfa732a15e7cd1
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacade.java
@@ -0,0 +1,50 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.HypotheseIdDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class HypotheseFacade {
+
+    private ReferentielPersistencePort<Hypothese, HypotheseId> persistencePort;
+
+
+    private HypotheseMapper mapper;
+
+    /**
+     * Ajout des hypotheses depuis un fichier csv
+     *
+     * @param hypotheses
+     */
+    public void purgeAndAddAll(List<HypotheseDTO> hypotheses) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomains(hypotheses));
+    }
+
+    /**
+     * Recuperation de la liste des hypotheses
+     *
+     * @return
+     */
+    public List<HypotheseDTO> getAll() {
+        return mapper.toDtos(persistencePort.getAll());
+    }
+
+
+    public HypotheseDTO get(HypotheseIdDTO hypotheseIdDTO) throws ReferentielException {
+        Hypothese hypothese = persistencePort.get(mapper.toDomain(hypotheseIdDTO));
+        return mapper.toDTO(hypothese);
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..e94e380f5e12dda9b6e4e5974a360a7a88365896
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacade.java
@@ -0,0 +1,37 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactEquipementIdDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ImpactEquipementFacade {
+
+    private ReferentielPersistencePort<ImpactEquipement, ImpactEquipementId> persistencePort;
+
+
+    private ImpactEquipementMapper mapper;
+
+
+    public ImpactEquipementDTO get(ImpactEquipementIdDTO id) throws ReferentielException {
+        ImpactEquipementId equipementId = mapper.toDomainId(id);
+        ImpactEquipement impactEquipement = persistencePort.get(equipementId);
+        return mapper.toDTO(impactEquipement);
+    }
+
+    public void purgeAndAddAll(List<ImpactEquipementDTO> iesDTO) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomainsFromDTO(iesDTO));
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ab3067a0d41f523876eeb4dbc34a560a70287e7
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacade.java
@@ -0,0 +1,46 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.ListUtils;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielRuntimeException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+public class ImpactMessagerieFacade {
+    private ReferentielPersistencePort<ImpactMessagerie, String> persistencePort;
+    private ImpactMessagerieMapper mapper;
+
+    public ImpactMessagerieFacade(ReferentielPersistencePort<ImpactMessagerie, String> persistencePort, ImpactMessagerieMapper mapper) {
+        this.persistencePort = persistencePort;
+        this.mapper = mapper;
+    }
+
+    public ImpactMessagerieDTO getImpactMessagerieForCritere(String critere) {
+        try {
+            var impactMessagerie = persistencePort.get(critere);
+            return mapper.toDTO(impactMessagerie);
+        } catch (Exception e) {
+            log.error("Erreur lors de l'accès à l'impact Messagerie : Critère : {} : {}", critere, e.getMessage());
+            throw new ReferentielRuntimeException(e.getMessage());
+        }
+    }
+
+    public List<ImpactMessagerieDTO> getAllImpactMessagerie() {
+        List<ImpactMessagerie> domains = persistencePort.getAll();
+        return ListUtils.emptyIfNull(mapper.toDTOs(domains));
+    }
+
+    public void purgeAndAddAll(List<ImpactMessagerieDTO> dtos) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomainsFromDTO(dtos));
+    }
+
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c28678300113accb73d0496a54373c35ab8de8f
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacade.java
@@ -0,0 +1,40 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactReseauMapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactReseauIdDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class ImpactReseauFacade {
+
+    private ReferentielPersistencePort<ImpactReseau, ImpactReseauId> persistencePort;
+
+    private ImpactReseauMapper mapper;
+
+    public ImpactReseauDTO get(ImpactReseauIdDTO idImpactReseauDTO) throws ReferentielException {
+        ImpactReseau impactReseau = persistencePort.get(mapper.toDomainId(idImpactReseauDTO));
+        return mapper.toDTO(impactReseau);
+    }
+
+    public ImpactReseauDTO addOrUpdate(ImpactReseauDTO impactReseauDTO) throws ReferentielException {
+        ImpactReseau save = persistencePort.save(mapper.toDomain(impactReseauDTO));
+        return mapper.toDTO(save);
+    }
+
+    public void purgeAndAddAll(List<ImpactReseauDTO> impactesReseaux) throws ReferentielException {
+        persistencePort.purge();
+        List<ImpactReseau> impactReseauList = mapper.toDomainsFromDTO(impactesReseaux);
+        persistencePort.saveAll(impactReseauList);
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..921e025335cece357de5adc67058a149df140a53
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacade.java
@@ -0,0 +1,48 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapper;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.MixElectriqueIdDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+public class MixElectriqueFacade {
+
+    private ReferentielPersistencePort<MixElectrique, MixElectriqueId> persistencePort;
+
+    private MixElectriqueMapper mapper;
+
+    public MixElectriqueDTO get(MixElectriqueIdDTO id) throws ReferentielException {
+        MixElectriqueId electriqueId = mapper.toDomainId(id);
+        MixElectrique mixElectrique = persistencePort.get(electriqueId);
+        return mapper.toDTO(mixElectrique);
+    }
+
+    public List<MixElectriqueDTO> getAll() {
+        return persistencePort.getAll().stream()
+                .map(mix -> mapper.toDTO(mix))
+                .toList();
+    }
+
+    public List<MixElectriqueDTO> getByPays(String pays) {
+        return persistencePort.getAll().stream()
+                .filter(mix -> pays.equals(mix.getPays()) || pays.equals(mix.getRaccourcisAnglais()))
+                .map(mix -> mapper.toDTO(mix))
+                .toList();
+    }
+
+    public void purgeAndAddAll(List<MixElectriqueDTO> mixElecs) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(mapper.toDomainsFromDTO(mixElecs));
+    }
+}
diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeEquipementFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeEquipementFacade.java
new file mode 100644
index 0000000000000000000000000000000000000000..927baa144103e9fc1c599dad50db0ec76c63d0aa
--- /dev/null
+++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeEquipementFacade.java
@@ -0,0 +1,45 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@Slf4j
+public class TypeEquipementFacade {
+    private ReferentielPersistencePort<TypeEquipement, String> persistencePort;
+    private TypeEquipementMapper mapper;
+
+    public TypeEquipementFacade(ReferentielPersistencePort<TypeEquipement, String> persistencePort, TypeEquipementMapper mapper) {
+        this.persistencePort = persistencePort;
+        this.mapper = mapper;
+    }
+
+    public TypeEquipementDTO getTypeEquipementForType(String type) throws ReferentielException {
+        var typeEquipement = persistencePort.get(type);
+        if (typeEquipement != null) {
+            return mapper.toDto(typeEquipement);
+        }
+        return null;
+    }
+
+    public List<TypeEquipementDTO> getAllTypesEquipement() {
+        List<TypeEquipement> typeEquipements = persistencePort.getAll();
+        return CollectionUtils.emptyIfNull(typeEquipements).stream().map(typeEquipement -> mapper.toDto(typeEquipement)).toList();
+    }
+
+    public void purgeAndAddAll(List<TypeEquipementDTO> types) throws ReferentielException {
+        persistencePort.purge();
+        persistencePort.saveAll(CollectionUtils.emptyIfNull(types).stream()
+                .map(typeEquipementDTO -> mapper.toDomaine(typeEquipementDTO))
+                .toList());
+    }
+
+}
diff --git a/services/api-referentiel/src/main/resources/application.yaml b/services/api-referentiel/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef3b2fa58dfb17ab251ca3b7d1c1a4d988ab10fc
--- /dev/null
+++ b/services/api-referentiel/src/main/resources/application.yaml
@@ -0,0 +1,67 @@
+# Replaced by CI/CD
+version: "1.0.0"
+
+# Application
+numecoeval:
+  urls:
+    allowed: "http://localhost"
+
+#CONFIGURATION BASES
+spring:
+  sql:
+    init:
+      mode: always
+  # Base de données
+  datasource:
+    generate-unique-name: true
+    url: "jdbc:postgresql://localhost:5432/postgres"
+    username: postgres
+    password: postgres
+    driver-class-name: org.postgresql.Driver
+    tomcat:
+      test-on-borrow: false
+      jmx-enabled: false
+      max-active: 100
+  jpa:
+    #   POSTGRES
+    generate-ddl: true
+    database-platform: org.hibernate.dialect.PostgreSQLDialect
+    hibernate:
+      ddl-auto: none
+    show-sql: false
+    properties:
+      hibernate:
+        order_inserts: true
+        jdbc:
+          batch_size: 1000
+        generate_statistics: false
+    open-in-view: true
+
+  # Taille des uploads et des requêtes
+  servlet:
+    multipart:
+      max-request-size: "12MB"
+      max-file-size: "10MB"
+
+# Serveur Web
+server:
+  port: 18080
+  shutdown: graceful
+  tomcat:
+    mbeanregistry:
+      enabled: true
+
+# Actuator
+management:
+  server:
+    port: 18080
+  security:
+    user:
+      name: "test"
+      password: "test"
+      roles: ACTUATOR_ADMIN
+  endpoints:
+    web:
+      base-path: /
+      exposure:
+        include: health,prometheus,httptrace,info,metrics,mappings
\ No newline at end of file
diff --git a/services/api-referentiel/src/main/resources/logback.xml b/services/api-referentiel/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7f5ba8183b2e7b4900a70dd8f6d2d0d9e00d09c6
--- /dev/null
+++ b/services/api-referentiel/src/main/resources/logback.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+<!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+
+    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+<!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <root level="${APP_LOGGING_LEVEL:-INFO}">
+        <appender-ref ref="CONSOLE" />
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-referentiel/src/main/resources/schema.sql b/services/api-referentiel/src/main/resources/schema.sql
new file mode 100644
index 0000000000000000000000000000000000000000..e394926020efd12d149a435ee516dd18317c341a
--- /dev/null
+++ b/services/api-referentiel/src/main/resources/schema.sql
@@ -0,0 +1,91 @@
+CREATE TABLE IF NOT EXISTS ref_etapeacv
+(
+    code    varchar(255) NOT NULL,
+    libelle varchar(255) NULL,
+    CONSTRAINT ref_etapeacv_pkey PRIMARY KEY (code)
+);
+
+CREATE TABLE IF NOT EXISTS ref_critere
+(
+    nom_critere varchar(255) NOT NULL,
+    description varchar(255) NULL,
+    unite       varchar(255) NULL,
+    CONSTRAINT ref_critere_pkey PRIMARY KEY (nom_critere)
+);
+
+CREATE TABLE IF NOT EXISTS ref_hypothese
+(
+    code     varchar(255) NOT NULL,
+    "source" varchar(255) NULL,
+    valeur   varchar(255) NULL,
+    CONSTRAINT ref_hypothese_pkey PRIMARY KEY (code)
+);
+
+CREATE TABLE IF NOT EXISTS ref_type_equipement
+(
+    "type"                    varchar(255) NOT NULL,
+    commentaire               varchar(255) NULL,
+    duree_vie_defaut          float8       NULL,
+    serveur                   bool         NOT NULL,
+    "source"                  varchar(255) NULL,
+    ref_equipement_par_defaut varchar(255) NULL,
+    CONSTRAINT ref_type_equipement_pkey PRIMARY KEY (type)
+);
+
+CREATE TABLE IF NOT EXISTS ref_impact_messagerie
+(
+    constante_coefficient_directeur float8       NULL,
+    constante_ordonnee_origine      float8       NULL,
+    "source"                        varchar(255) NULL,
+    nom_critere                     varchar(255) NOT NULL,
+    CONSTRAINT ref_impact_messagerie_pkey PRIMARY KEY (nom_critere)
+);
+
+CREATE TABLE IF NOT EXISTS ref_correspondance_ref_eqp
+(
+    modele_equipement_source varchar(255) NOT NULL,
+    ref_equipement_cible     varchar(255) NULL,
+    CONSTRAINT ref_correspondance_ref_eqp_pkey PRIMARY KEY (modele_equipement_source)
+);
+
+CREATE TABLE IF NOT EXISTS ref_impactequipement
+(
+    refequipement      varchar(255) NOT NULL,
+    conso_elec_moyenne float8       NULL,
+    "source"           varchar(255) NULL,
+    "type"             varchar(255) NULL,
+    valeur             float8       NULL,
+    etapeacv           varchar(255) NOT NULL,
+    nomcritere         varchar(255) NOT NULL,
+    description        varchar(255) NULL,
+    CONSTRAINT ref_impactequipement_pkey PRIMARY KEY (nomcritere, etapeacv, refequipement)
+);
+
+CREATE TABLE IF NOT EXISTS ref_impactreseau
+(
+    refreseau        varchar(255) NOT NULL,
+    consoelecmoyenne float8       NULL,
+    "source"         varchar(255) NULL,
+    valeur           float8       NULL,
+    etapeacv         varchar(255) NOT NULL,
+    nomcritere       varchar(255) NOT NULL,
+    CONSTRAINT ref_impactreseau_pkey PRIMARY KEY (nomcritere, etapeacv, refreseau)
+);
+
+CREATE TABLE IF NOT EXISTS ref_mixelec
+(
+    pays              varchar(255) NOT NULL,
+    raccourcisanglais varchar(255) NULL,
+    "source"          varchar(255) NULL,
+    valeur            float8       NULL,
+    nomcritere        varchar(255) NOT NULL,
+    CONSTRAINT ref_mixelec_pkey PRIMARY KEY (nomcritere, pays)
+);
+
+-- suppression des contraintes de clés étrangères
+ALTER TABLE ref_impactequipement DROP CONSTRAINT IF EXISTS fk5iuiwnk7rymtob1fku71uuj52;
+ALTER TABLE ref_impactequipement DROP CONSTRAINT IF EXISTS fksfjum8kagn7q6vsv5uqn6kimx;
+ALTER TABLE ref_impactreseau DROP CONSTRAINT IF EXISTS fk31ykp7xtj41win3ptqlr3us9s;
+ALTER TABLE ref_impactreseau DROP CONSTRAINT IF EXISTS fkb8tkreu8c8s8pqqnft6vr4pnf;
+ALTER TABLE ref_mixelec DROP CONSTRAINT IF EXISTS fkdncd4m2je6fbno7pkn850u1fs;
+ALTER TABLE ref_impact_messagerie DROP CONSTRAINT IF EXISTS fkohnlpwfp0ebk7dswmfbe5l3k0;
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/CucumberIntegrationTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/CucumberIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a41ee15a04dc4a606e70369bceab12796980cf9
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/CucumberIntegrationTest.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.referentiel;
+
+import io.cucumber.spring.CucumberContextConfiguration;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.suite.api.ConfigurationParameter;
+import org.junit.platform.suite.api.IncludeEngines;
+import org.junit.platform.suite.api.SelectClasspathResource;
+import org.junit.platform.suite.api.Suite;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
+import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;
+
+@CucumberContextConfiguration
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+@ActiveProfiles(profiles = {"test"})
+@Suite
+@IncludeEngines("cucumber")
+@SelectClasspathResource("org/mte/numecoeval/referentiel")
+@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty,html:target/cucumber-reports.html")
+@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "org.mte.numecoeval.referentiel")
+class CucumberIntegrationTest {
+
+    @Test
+    void loadCucumber() {
+        Assertions.assertNotNull(CucumberIntegrationTest.class);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/ReferentielApplicationTests.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/ReferentielApplicationTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d1c0da87d2007f08862bdc4b22e20efa5a97a2f
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/ReferentielApplicationTests.java
@@ -0,0 +1,68 @@
+package org.mte.numecoeval.referentiel;
+
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese.ReferentielHypotheseRestApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.Environment;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.web.bind.annotation.GetMapping;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+@ActiveProfiles(profiles = {"test"})
+class ReferentielApplicationTests {
+
+    @Autowired
+    Environment environment;
+
+    @BeforeEach
+    public void setupRestAssured() {
+        RestAssured.baseURI = "http://localhost";
+        RestAssured.port = Integer.parseInt(Objects.requireNonNull(environment.getProperty("server.port")));
+    }
+    @Test
+    void contextLoads() {
+        Assertions.assertNotNull(ReferentielApplication.class);
+    }
+
+    @Test
+    void getHypothese_whenNoData_shouldReturn404() throws NoSuchMethodException {
+        String requestPath = Arrays.stream(ReferentielHypotheseRestApi.class.getMethod("get", String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        var response = given()
+                .contentType(ContentType.JSON)
+                .param("cle", "NonExistant")
+                .get(requestPath)
+                .thenReturn();
+
+        assertEquals(404, response.getStatusCode());
+        var errorResponseDTO = response.as(ErrorResponseDTO.class);
+        assertEquals(404, errorResponseDTO.getCode());
+        assertEquals("Hypothèse non trouvé", errorResponseDTO.getMessage());
+    }
+
+    @Test
+    void unknownEndpoint_shouldReturn400() throws NoSuchMethodException {
+        var response = given()
+                .contentType(ContentType.JSON)
+                .get("/this/is/not/an/existing/endpoint?true=yes")
+                .thenReturn();
+
+        assertEquals(404, response.getStatusCode());
+        var errorResponseDTO = response.as(LinkedHashMap.class);
+        assertEquals("/this/is/not/an/existing/endpoint", errorResponseDTO.get("path"));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCSVReferentielPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCSVReferentielPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..77fc8f59d79374343b1a1f8171021ae994f6ffbb
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCSVReferentielPortTest.java
@@ -0,0 +1,47 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.apache.commons.csv.CSVRecord;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCorrespondanceRefEquipementPortImpl;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class ImportCSVReferentielPortTest {
+
+    @Mock
+    CSVRecord csvRecord;
+
+    ImportCSVReferentielPort<CorrespondanceRefEquipementDTO> importPortToTest = new ImportCorrespondanceRefEquipementPortImpl();
+
+    @Test
+    void checkFieldIsMappedInCSVRecord_whenFieldIsntMapped_shouldThrowException() {
+        var field = "test";
+        when(csvRecord.getRecordNumber()).thenReturn(0L);
+        when(csvRecord.isMapped(field)).thenReturn(false);
+
+        var exception = assertThrows(ReferentielException.class, () -> importPortToTest.checkFieldIsMappedInCSVRecord(csvRecord, field));
+        assertEquals("La ligne n°1 est invalide : La colonne test doit être présente", exception.getMessage());
+    }
+
+    @Test
+    void getStringValueFromRecord_shouldUseAlternativeNamesIfFieldUnavailable() {
+        var field = "test";
+        var alternativeName = "alternativeField";
+        when(csvRecord.isMapped(field)).thenReturn(false);
+        when(csvRecord.isMapped(alternativeName)).thenReturn(true);
+        String expectedValue = "Value";
+        when(csvRecord.get(alternativeName)).thenReturn(expectedValue);
+
+        var result = importPortToTest.getStringValueFromRecord(csvRecord, field, alternativeName);
+        assertEquals(expectedValue, result);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCorrespondanceRefEquipementPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCorrespondanceRefEquipementPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5579678341e5c552cf31decab306b02b7fc5d99
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCorrespondanceRefEquipementPortTest.java
@@ -0,0 +1,86 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCorrespondanceRefEquipementPortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportCorrespondanceRefEquipementPortTest {
+
+    ImportCSVReferentielPort<CorrespondanceRefEquipementDTO> importPortToTest = new ImportCorrespondanceRefEquipementPortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/correspondanceRefEquipement.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(3, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(3, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele01".equals(etapeDTO.getModeleEquipementSource()) && "refCible01".equals(etapeDTO.getRefEquipementCible())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele02".equals(etapeDTO.getModeleEquipementSource()) && "refCible01".equals(etapeDTO.getRefEquipementCible())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele03".equals(etapeDTO.getModeleEquipementSource()) && "refCible02".equals(etapeDTO.getRefEquipementCible())));
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/correspondanceRefEquipement_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(3, resultatImport.getNbrLignesImportees());
+        assertEquals(2, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne modeleEquipementSource ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°5 est invalide : La colonne refEquipementCible ne peut être vide"::equals));
+        assertEquals(3, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele01".equals(etapeDTO.getModeleEquipementSource()) && "refCible01".equals(etapeDTO.getRefEquipementCible())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele01".equals(etapeDTO.getModeleEquipementSource()) && "refCible01".equals(etapeDTO.getRefEquipementCible())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "modele03".equals(etapeDTO.getModeleEquipementSource()) && "refCible02".equals(etapeDTO.getRefEquipementCible())));
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCriterePortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCriterePortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c003cb2ba95dab833630051ae7cd5261707be54
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportCriterePortTest.java
@@ -0,0 +1,128 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.mockito.Mockito.*;
+
+class ImportCriterePortTest {
+
+    ImportCSVReferentielPort<CritereDTO> importPortToTest = new ImportCriterePortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/critere.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        Assertions.assertEquals(5, resultatImport.getNbrLignesImportees());
+        Assertions.assertEquals(0, resultatImport.getErreurs().size());
+        Assertions.assertEquals(5, resultatImport.getObjects().size());
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "kg CO_{2} eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Émissions de particules fines".equals(dto.getNomCritere())
+                        && "Émissions de particules fines".equals(dto.getDescription())
+                        && "Diseaseincidence".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Radiations ionisantes".equals(dto.getNomCritere())
+                        && "Description de Tests".equals(dto.getDescription())
+                        && "kBq U-235 eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Acidification".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "mol H^{+} eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Épuisement des ressources naturelles (minérales et métaux)".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "kg Sb eq".equals(dto.getUnite()))
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/critere_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        Assertions.assertEquals(5, resultatImport.getNbrLignesImportees());
+        Assertions.assertEquals(1, resultatImport.getErreurs().size());
+        Assertions.assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne nomCritere ne peut être vide"::equals));
+        Assertions.assertEquals(5, resultatImport.getObjects().size());
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "kg CO_{2} eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Émissions de particules fines".equals(dto.getNomCritere())
+                        && "Émissions de particules fines".equals(dto.getDescription())
+                        && "Diseaseincidence".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Radiations ionisantes".equals(dto.getNomCritere())
+                        && "Description de Tests".equals(dto.getDescription())
+                        && "kBq U-235 eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Acidification".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "mol H^{+} eq".equals(dto.getUnite()))
+        );
+        Assertions.assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Épuisement des ressources naturelles (minérales et métaux)".equals(dto.getNomCritere())
+                        && "".equals(dto.getDescription())
+                        && "kg Sb eq".equals(dto.getUnite()))
+        );
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
+        Assertions.assertEquals(1, resultatImport.getErreurs().size());
+        Assertions.assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
+        Assertions.assertEquals(1, resultatImport.getErreurs().size());
+        Assertions.assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        Assertions.assertEquals(0, resultatImport.getNbrLignesImportees());
+        Assertions.assertEquals(1, resultatImport.getErreurs().size());
+        Assertions.assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportEtapePortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportEtapePortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7a63cb2194fb96e9f19c87ddac2713449a366b5
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportEtapePortTest.java
@@ -0,0 +1,86 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportEtapePortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportEtapePortTest {
+
+    ImportCSVReferentielPort<EtapeDTO> importPortToTest = new ImportEtapePortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/etapeACV.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "UTILISATION".equals(etapeDTO.getCode()) && "Utilisation".equals(etapeDTO.getLibelle())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "FABRICATION".equals(etapeDTO.getCode()) && "Fabrication".equals(etapeDTO.getLibelle())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "DISTRIBUTION".equals(etapeDTO.getCode()) && "Distribution".equals(etapeDTO.getLibelle())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "FIN_DE_VIE".equals(etapeDTO.getCode()) && "Fin de vie".equals(etapeDTO.getLibelle())));
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/etapeACV_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(3, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne code ne peut être vide"::equals));
+        assertEquals(3, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "FABRICATION".equals(etapeDTO.getCode()) && "Fabrication".equals(etapeDTO.getLibelle())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "DISTRIBUTION".equals(etapeDTO.getCode()) && "Distribution".equals(etapeDTO.getLibelle())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(etapeDTO -> "FIN_DE_VIE".equals(etapeDTO.getCode()) && "Fin de vie".equals(etapeDTO.getLibelle())));
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportHypothesePortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportHypothesePortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..aba280bcc8301480942af84247390b9b63eb0d4b
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportHypothesePortTest.java
@@ -0,0 +1,84 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportHypothesePortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportHypothesePortTest {
+
+    ImportCSVReferentielPort<HypotheseDTO> importPortToTest = new ImportHypothesePortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/hypothese.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(2, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(2, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto -> "PUEPardDfault".equals(dto.getCode()) && "1.6".equals(dto.getValeur()) && "expertise IJO".equals(dto.getSource())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto -> "DureeVieServeurParDefaut".equals(dto.getCode()) && "3".equals(dto.getValeur()) && "US 46".equals(dto.getSource())));
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/hypothese_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(2, resultatImport.getNbrLignesImportees());
+        assertEquals(2, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°3 est invalide : La colonne cle ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne valeur ne peut être vide"::equals));
+        assertEquals(2, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto -> "PUEPardDfault".equals(dto.getCode()) && "1.6".equals(dto.getValeur()) && "expertise IJO".equals(dto.getSource())));
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto -> "DureeVieServeurParDefaut".equals(dto.getCode()) && "3".equals(dto.getValeur()) && "US 46".equals(dto.getSource())));
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactEquipementPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactEquipementPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5def8e6cf34027cb405bca2c4f22d5f894ac10ea
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactEquipementPortTest.java
@@ -0,0 +1,170 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactEquipementPortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Objects;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportImpactEquipementPortTest {
+
+    ImportCSVReferentielPort<ImpactEquipementDTO> importPortToTest = new ImportImpactEquipementPortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactEquipement.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "FABRICATION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(149.0).equals(dto.getValeur())
+                        && Double.valueOf(30.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && Objects.isNull(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "DISTRIBUTION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(11.0082325332).equals(dto.getValeur())
+                        && Double.valueOf(29.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && Objects.isNull(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "UTILISATION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.9485359999999998).equals(dto.getValeur())
+                        && Double.valueOf(28.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && Objects.isNull(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "FIN_DE_VIE".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.46).equals(dto.getValeur())
+                        && Double.valueOf(1.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && Objects.isNull(dto.getDescription())
+                )
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactEquipement_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(3, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne refEquipement ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°5 est invalide : La colonne etapeacv ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°6 est invalide : La colonne critere ne peut être vide"::equals));
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "FABRICATION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(149.0).equals(dto.getValeur())
+                        && Double.valueOf(30.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && "description Ordinateur Portable 1".equals(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "DISTRIBUTION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(11.0082325332).equals(dto.getValeur())
+                        && Double.valueOf(29.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && "description Ordinateur Portable 2".equals(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "UTILISATION".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.9485359999999998).equals(dto.getValeur())
+                        && Double.valueOf(28.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && "description Ordinateur Portable 3".equals(dto.getDescription())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Ordinateur portable 14.5 8 Go RAM 564 Go SSD".equals(dto.getRefEquipement())
+                        && "FIN_DE_VIE".equals(dto.getEtape())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.46).equals(dto.getValeur())
+                        && Double.valueOf(1.1).equals(dto.getConsoElecMoyenne())
+                        && "Ref_Base_donnee_reference_20220728.xlsx".equals(dto.getSource())
+                        && "Ordinateur Portable".equals(dto.getType())
+                        && "description Ordinateur Portable 4".equals(dto.getDescription())
+                )
+        );
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactMessageriePortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactMessageriePortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..acd3d077128da98ac1ef01f7809c702b2d21c3dc
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactMessageriePortTest.java
@@ -0,0 +1,114 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactMessageriePortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportImpactMessageriePortTest {
+
+    ImportCSVReferentielPort<ImpactMessagerieDTO> importPortToTest = new ImportImpactMessageriePortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactMessagerie.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(5, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(5, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(0.5).equals(dto.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(0).equals(dto.getConstanteOrdonneeOrigine())
+                        && "Tests".equals(dto.getSource())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Émissions de particules fines".equals(dto.getCritere())
+                        && Double.valueOf(1.000111).equals(dto.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(1.451).equals(dto.getConstanteOrdonneeOrigine())
+                        && "Tests".equals(dto.getSource())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Radiations ionisantes".equals(dto.getCritere())
+                        && Double.valueOf(0.00005).equals(dto.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(0.02315412).equals(dto.getConstanteOrdonneeOrigine())
+                        && "Tests".equals(dto.getSource())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Acidification".equals(dto.getCritere())
+                        && Double.valueOf(1.224586).equals(dto.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(0.042).equals(dto.getConstanteOrdonneeOrigine())
+                        && "Tests".equals(dto.getSource())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Épuisement des ressources naturelles (minérales et métaux)".equals(dto.getCritere())
+                        && Double.valueOf(2.020).equals(dto.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(0.678).equals(dto.getConstanteOrdonneeOrigine())
+                        && "Tests".equals(dto.getSource())
+                )
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactMessagerie_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(2, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°3 est invalide : La colonne critere ne peut être vide"::equals));
+        assertEquals(2, resultatImport.getObjects().size());
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactReseauPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactReseauPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8607e23d72143f8023183d040a95b0be5fc562db
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportImpactReseauPortTest.java
@@ -0,0 +1,148 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactReseauPortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.springframework.util.ResourceUtils;
+
+import java.io.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportImpactReseauPortTest {
+
+    ImportCSVReferentielPort<ImpactReseauDTO> importPortToTest = new ImportImpactReseauPortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactreseau.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "DISTRIBUTION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.428).equals(dto.getValeur())
+                        && Double.valueOf(0.0020).equals(dto.getConsoElecMoyenne())
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "FABRICATION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(518.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "FIN_DE_VIE".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(64.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "UTILISATION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(76.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/impactreseau_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(3, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne refReseau ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°5 est invalide : La colonne etapeACV ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°6 est invalide : La colonne critere ne peut être vide"::equals));
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "DISTRIBUTION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(1.428).equals(dto.getValeur())
+                        && Double.valueOf(0.0020).equals(dto.getConsoElecMoyenne())
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "FABRICATION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(518.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "FIN_DE_VIE".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(64.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "impactReseauMobileMoyen".equals(dto.getRefReseau())
+                        && "UTILISATION".equals(dto.getEtapeACV())
+                        && "Changement climatique".equals(dto.getCritere())
+                        && Double.valueOf(76.28).equals(dto.getValeur())
+                        && StringUtils.isEmpty(dto.getUnite())
+                        && dto.getConsoElecMoyenne() == null
+                        && "RefTest V1.00".equals(dto.getSource()))
+        );
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportMixElectriquePortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportMixElectriquePortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f0e312607bdec2699245d37703534b480a22433
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportMixElectriquePortTest.java
@@ -0,0 +1,141 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportMixElectriquePortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportMixElectriquePortTest {
+
+    ImportCSVReferentielPort<MixElectriqueDTO> importPortToTest = new ImportMixElectriquePortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/mixElectrique.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(4, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "France".equals(dto.getPays())
+                        && "FR".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(149).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "Brésil".equals(dto.getPays())
+                        && "BR".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(11.0082325332).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "Angleterre".equals(dto.getPays())
+                        && "EN".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(1.9485359999999998).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "USA".equals(dto.getPays())
+                        && "US".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(1.46).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/mixElectrique_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(4, resultatImport.getNbrLignesImportees());
+        assertEquals(3, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°4 est invalide : La colonne pays ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°5 est invalide : La colonne raccourcisAnglais ne peut être vide"::equals));
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°6 est invalide : La colonne critere ne peut être vide"::equals));
+        assertEquals(4, resultatImport.getObjects().size());
+        resultatImport.getObjects().forEach(
+                mixElectriqueDTO -> System.out.printf("%s ; %s ; %s ; %s%n", mixElectriqueDTO.getCritere(), mixElectriqueDTO.getPays(), mixElectriqueDTO.getRaccourcisAnglais(), mixElectriqueDTO.getValeur())
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "France".equals(dto.getPays())
+                        && "FR".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(149).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "Brésil".equals(dto.getPays())
+                        && "BR".equals(dto.getRaccourcisAnglais())
+                        //&& Double.valueOf(11.0082325332).equals(dto.getValeur())
+                        //&& "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "Angleterre".equals(dto.getPays())
+                        && "EN".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(1.9485359999999998).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(dto ->
+                "Changement climatique".equals(dto.getCritere())
+                        && "USA".equals(dto.getPays())
+                        && "US".equals(dto.getRaccourcisAnglais())
+                        && Double.valueOf(1.46).equals(dto.getValeur())
+                        && "Ref_Base_donnee_reference_20480728.xlsx".equals(dto.getSource()))
+        );
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeEquipementPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeEquipementPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a1ff3df0ba982fe10f1d65f85b240962ddddd65
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeEquipementPortTest.java
@@ -0,0 +1,115 @@
+package org.mte.numecoeval.referentiel.domain.port.input;
+
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl;
+import org.springframework.util.ResourceUtils;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+
+class ImportTypeEquipementPortTest {
+
+    ImportCSVReferentielPort<TypeEquipementDTO> importPortToTest = new ImportTypeEquipementPortImpl();
+
+    @Test
+    void importCSV_shouldImportAllDatas() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/typeEquipement.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(2, resultatImport.getNbrLignesImportees());
+        assertEquals(0, resultatImport.getErreurs().size());
+        assertEquals(2, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(typeEquipementDTO ->
+                "Serveur".equals(typeEquipementDTO.getType())
+                        && typeEquipementDTO.isServeur()
+                        && Double.valueOf(6.0).equals(typeEquipementDTO.getDureeVieDefaut())
+                        && "Exemple de serveur basique".equals(typeEquipementDTO.getSource())
+                        && "Test simple".equals(typeEquipementDTO.getCommentaire())
+                        && "serveur_par_defaut".equals(typeEquipementDTO.getRefEquipementParDefaut())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(typeEquipementDTO ->
+                "Laptop".equals(typeEquipementDTO.getType())
+                        && !typeEquipementDTO.isServeur()
+                        && Double.valueOf(5.0).equals(typeEquipementDTO.getDureeVieDefaut())
+                        && "ADEME, durée de vie des EEE, UF utiliser une ordinateur, écran non cathodique et LCD, https://vu.fr/bOQZ".equals(typeEquipementDTO.getSource())
+                        && "Test simple".equals(typeEquipementDTO.getCommentaire())
+                        && "laptop_par_defaut".equals(typeEquipementDTO.getRefEquipementParDefaut())
+                )
+        );
+    }
+
+    @Test
+    void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/typeEquipement_errorInMiddle.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(2, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°3 est invalide : La colonne type ne peut être vide"::equals));
+        assertEquals(2, resultatImport.getObjects().size());
+        assertTrue(resultatImport.getObjects().stream().anyMatch(typeEquipementDTO ->
+                        "Serveur".equals(typeEquipementDTO.getType())
+                                && typeEquipementDTO.isServeur()
+                                && Double.valueOf(6.0).equals(typeEquipementDTO.getDureeVieDefaut())
+                                && "Exemple de serveur basique".equals(typeEquipementDTO.getSource())
+                                && "Test simple".equals(typeEquipementDTO.getCommentaire())
+                                && "serveur_par_defaut".equals(typeEquipementDTO.getRefEquipementParDefaut())
+                )
+        );
+        assertTrue(resultatImport.getObjects().stream().anyMatch(typeEquipementDTO ->
+                        "Laptop".equals(typeEquipementDTO.getType())
+                                && !typeEquipementDTO.isServeur()
+                                && Double.valueOf(5.0).equals(typeEquipementDTO.getDureeVieDefaut())
+                                && "ADEME, durée de vie des EEE, UF utiliser une ordinateur, écran non cathodique et LCD, https://vu.fr/bOQZ".equals(typeEquipementDTO.getSource())
+                                && "Test simple".equals(typeEquipementDTO.getCommentaire())
+                                && "laptop_par_defaut".equals(typeEquipementDTO.getRefEquipementParDefaut())
+                )
+        );
+    }
+
+    @Test
+    void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception {
+        File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv");
+        var resultatImport = importPortToTest.importCSV(new FileInputStream(file));
+
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals));
+    }
+
+    @Test
+    void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doNothing().when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+
+    @Test
+    void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException {
+        DataInputStream dataInputStream = mock(DataInputStream.class);
+        doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close();
+
+        var resultatImport = importPortToTest.importCSV(dataInputStream);
+
+        verify(dataInputStream).close();
+        assertEquals(0, resultatImport.getNbrLignesImportees());
+        assertEquals(1, resultatImport.getErreurs().size());
+        assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0));
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..50a7ff9a5aece407a6adb64023e7f9c5bdb861fb
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java
@@ -0,0 +1,398 @@
+package org.mte.numecoeval.referentiel.factory;
+
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.CritereId;
+import org.mte.numecoeval.referentiel.domain.model.id.EtapeId;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.CritereIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.EtapeIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.HypotheseIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.MixElectriqueIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.CritereIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.EtapeIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.HypotheseIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactEquipementIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactReseauIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.MixElectriqueIdDTO;
+
+public class TestDataFactory {
+
+    public static final String DEFAULT_ETAPE = "UTILISATION";
+
+    public static final String DEFAULT_CRITERE = "Changement Climatique";
+    public static final String DEFAULT_UNITE = "kg CO² eq";
+
+    public static class CritereFactory {
+        public static CritereDTO dto(String nomCritere, String unite, String description) {
+            return new CritereDTO(nomCritere, unite, description);
+        }
+
+        public static Critere domain(String nomCritere, String description, String unite) {
+            return new Critere()
+                    .setNomCritere(nomCritere)
+                    .setDescription(description)
+                    .setUnite(unite);
+        }
+
+        public static CritereEntity entity(String nomCritere, String description, String unite) {
+            return new CritereEntity()
+                    .setNomCritere(nomCritere)
+                    .setDescription(description)
+                    .setUnite(unite);
+        }
+
+        public static CritereIdDTO idDTO(String nomCritere) {
+            return new CritereIdDTO(nomCritere);
+        }
+
+        public static CritereId idDomain(String nomCritere) {
+            return new CritereId()
+                    .setNomCritere(nomCritere);
+        }
+
+        public static CritereIdEntity idEntity(String nomCritere) {
+            return new CritereIdEntity()
+                    .setNomCritere(nomCritere);
+        }
+    }
+
+    public static class EtapeFactory {
+
+        public static EtapeDTO dto(String code, String libelle) {
+            return new EtapeDTO(code, libelle);
+        }
+
+        public static Etape domain(String code, String libelle) {
+            return new Etape()
+                    .setCode(code)
+                    .setLibelle(libelle);
+        }
+
+        public static EtapeEntity entity(String code, String libelle) {
+            return new EtapeEntity()
+                    .setCode(code)
+                    .setLibelle(libelle);
+        }
+
+        public static EtapeIdDTO idDTO(String code) {
+            return new EtapeIdDTO(code);
+        }
+
+        public static EtapeId idDomain(String code) {
+            return new EtapeId()
+                    .setCode(code);
+        }
+
+        public static EtapeIdEntity idEntity(String code) {
+            return new EtapeIdEntity()
+                    .setCode(code);
+        }
+    }
+
+    public static class HypotheseFactory {
+        public static HypotheseDTO dto(String code, String valeur, String source) {
+            return new HypotheseDTO(code, valeur, source);
+        }
+
+        public static Hypothese domain(String code, String valeur, String source) {
+            return new Hypothese()
+                    .setCode(code)
+                    .setValeur(valeur)
+                    .setSource(source);
+        }
+
+        public static HypotheseEntity entity(String code, String valeur, String source) {
+            return new HypotheseEntity()
+                    .setCode(code)
+                    .setValeur(valeur)
+                    .setSource(source);
+        }
+
+        public static HypotheseIdDTO idDTO(String code) {
+            return new HypotheseIdDTO()
+                    .setCode(code);
+        }
+
+        public static HypotheseId idDomain(String code) {
+            return new HypotheseId()
+                    .setCode(code);
+        }
+
+        public static HypotheseIdEntity idEntity(String code) {
+            return new HypotheseIdEntity()
+                    .setCode(code);
+        }
+    }
+
+    public static class TypeEquipementFactory {
+        public static TypeEquipementDTO dto(String type, boolean estUnServeur, Double dureeVieDefaut, String commentaire, String source, String refEquipementParDefaut) {
+            return TypeEquipementDTO.builder()
+                    .type(type)
+                    .serveur(estUnServeur)
+                    .dureeVieDefaut(dureeVieDefaut)
+                    .source(source)
+                    .commentaire(commentaire)
+                    .refEquipementParDefaut(refEquipementParDefaut)
+                    .build();
+        }
+
+        public static TypeEquipement domain(String type, boolean estUnServeur, Double dureeVieDefaut, String commentaire, String source, String refEquipementParDefaut) {
+            return TypeEquipement.builder()
+                    .type(type)
+                    .serveur(estUnServeur)
+                    .dureeVieDefaut(dureeVieDefaut)
+                    .source(source)
+                    .commentaire(commentaire)
+                    .refEquipementParDefaut(refEquipementParDefaut)
+                    .build();
+        }
+
+        public static TypeEquipementEntity entity(String type, boolean estUnServeur, Double dureeVieDefaut, String commentaire, String source, String refEquipementParDefaut) {
+            return new TypeEquipementEntity(type,estUnServeur,commentaire,dureeVieDefaut,source, refEquipementParDefaut);
+        }
+    }
+
+    public static class MixElectriqueFactory {
+
+        public static MixElectriqueDTO dto(CritereDTO critere, String pays, String raccourcisAnglais, Double valeur, String source) {
+            return new MixElectriqueDTO(
+                    pays,
+                    raccourcisAnglais,
+                    critere.getNomCritere(),
+                    valeur,
+                    source
+            );
+        }
+
+        public static MixElectrique domain(Critere critere, String pays, String raccourcisAnglais, Double valeur, String source) {
+            return new MixElectrique()
+                    .setCritere(critere.getNomCritere())
+                    .setPays(pays)
+                    .setRaccourcisAnglais(raccourcisAnglais)
+                    .setValeur(valeur)
+                    .setSource(source);
+        }
+
+        public static MixElectriqueEntity entity(CritereEntity critere, String pays, String raccourcisAnglais, Double valeur, String source) {
+            return new MixElectriqueEntity()
+                    .setCritere(critere.getNomCritere())
+                    .setPays(pays)
+                    .setRaccourcisAnglais(raccourcisAnglais)
+                    .setValeur(valeur)
+                    .setSource(source);
+        }
+
+        public static MixElectriqueIdDTO idDTO(CritereIdDTO critereId, String pays) {
+            return MixElectriqueIdDTO
+                    .builder()
+                    .critere(critereId.getNomCritere())
+                    .pays(pays)
+                    .build();
+        }
+
+        public static MixElectriqueId idDomain(CritereId critereId, String pays) {
+            return new MixElectriqueId()
+                    .setCritere(critereId.getNomCritere())
+                    .setPays(pays);
+        }
+
+        public static MixElectriqueIdEntity idEntity(CritereIdEntity critereId, String pays) {
+            return new MixElectriqueIdEntity()
+                    .setCritere(critereId.getNomCritere())
+                    .setPays(pays);
+        }
+    }
+
+    public static class ImpactEquipementFactory {
+
+        public static ImpactEquipementDTO dto(String etape, String critere, String refEquipement, String source, String type, Double valeur, Double consoElecMoyenne, String description) {
+            return new ImpactEquipementDTO(
+                    refEquipement,
+                    etape,
+                    critere,
+                    source,
+                    type,
+                    valeur,
+                    consoElecMoyenne,
+                    description
+            );
+        }
+
+        public static ImpactEquipement domain(Etape etape, Critere critere, String refEquipement, String source, String type, Double valeur, Double consoElecMoyenne) {
+            return new ImpactEquipement()
+                    .setEtape(etape.getCode())
+                    .setCritere(critere.getNomCritere())
+                    .setRefEquipement(refEquipement)
+                    .setSource(source)
+                    .setType(type)
+                    .setValeur(valeur)
+                    .setConsoElecMoyenne(consoElecMoyenne);
+        }
+
+        public static ImpactEquipementEntity entity(EtapeEntity etape, CritereEntity critere, String refEquipement, String source, String type, Double valeur, Double consoElecMoyenne) {
+            return new ImpactEquipementEntity()
+                    .setEtape(etape.getCode())
+                    .setCritere(critere.getNomCritere())
+                    .setRefEquipement(refEquipement)
+                    .setSource(source)
+                    .setType(type)
+                    .setValeur(valeur)
+                    .setConsoElecMoyenne(consoElecMoyenne);
+        }
+
+        public static ImpactEquipementIdDTO idDTO(String etapeIdDTO, String critereId, String refEquipement) {
+            return ImpactEquipementIdDTO
+                    .builder()
+                    .etape(etapeIdDTO)
+                    .critere(critereId)
+                    .refEquipement(refEquipement)
+                    .build();
+        }
+
+        public static ImpactEquipementId idDomain(String etapeId, String critereId, String refEquipement) {
+            return new ImpactEquipementId()
+                    .setEtape(etapeId)
+                    .setCritere(critereId)
+                    .setRefEquipement(refEquipement);
+        }
+
+    }
+
+    public static class ImpactReseauFactory {
+
+        public static ImpactReseauDTO dto(EtapeDTO etape, CritereDTO critere, String refReseau, String source, Double valeur, Double consoElecMoyenne) {
+            return new ImpactReseauDTO(
+                    refReseau,
+                    etape.getCode(),
+                    critere.getNomCritere(),
+                    null,
+                    source,
+                    valeur,
+                    consoElecMoyenne
+            );
+        }
+
+        public static ImpactReseau domain(Etape etape, Critere critere, String refReseau, String source, Double valeur, Double consoElecMoyenne) {
+            return new ImpactReseau()
+                    .setEtape(etape.getCode())
+                    .setCritere(critere.getNomCritere())
+                    .setRefReseau(refReseau)
+                    .setSource(source)
+                    .setValeur(valeur)
+                    .setConsoElecMoyenne(consoElecMoyenne);
+        }
+
+        public static ImpactReseauEntity entity(EtapeEntity etape, CritereEntity critere, String refReseau, String source, Double valeur, Double consoElecMoyenne) {
+            return new ImpactReseauEntity()
+                    .setEtape(etape.getCode())
+                    .setCritere(critere.getNomCritere())
+                    .setRefReseau(refReseau)
+                    .setSource(source)
+                    .setValeur(valeur)
+                    .setConsoElecMoyenne(consoElecMoyenne);
+        }
+
+        public static ImpactReseauIdDTO idDTO(EtapeIdDTO etapeIdDTO, CritereIdDTO critereId, String refReseau) {
+            return ImpactReseauIdDTO
+                    .builder()
+                    .etapeACV(etapeIdDTO.getCode())
+                    .critere(critereId.getNomCritere())
+                    .refReseau(refReseau)
+                    .build();
+        }
+
+        public static ImpactReseauId idDomain(EtapeId etapeId, CritereId critereId, String refReseau) {
+            return new ImpactReseauId()
+                    .setEtape(etapeId.getCode())
+                    .setCritere(critereId.getNomCritere())
+                    .setRefReseau(refReseau);
+        }
+
+        public static ImpactReseauIdEntity idEntity(EtapeIdEntity etapeIdEntity, CritereIdEntity critereId, String refReseau) {
+            return new ImpactReseauIdEntity()
+                    .setEtape(etapeIdEntity.getCode())
+                    .setCritere(critereId.getNomCritere())
+                    .setRefReseau(refReseau);
+        }
+    }
+
+    public static class ImpactMessagerieFactory {
+
+        public static ImpactMessagerieDTO dto(CritereDTO critere, Double constanteCoefficientDirecteur, Double constanteOrdonneeOrigine, String source) {
+            return ImpactMessagerieDTO.builder()
+                    .critere(critere.getNomCritere())
+                    .source(source)
+                    .constanteCoefficientDirecteur(constanteCoefficientDirecteur)
+                    .constanteOrdonneeOrigine(constanteOrdonneeOrigine)
+                    .build();
+        }
+
+        public static ImpactMessagerie domain(Critere critere, Double constanteCoefficientDirecteur, Double constanteOrdonneeOrigine, String source) {
+            return new ImpactMessagerie()
+                    .setCritere(critere.getNomCritere())
+                    .setSource(source)
+                    .setConstanteCoefficientDirecteur(constanteCoefficientDirecteur)
+                    .setConstanteOrdonneeOrigine(constanteOrdonneeOrigine);
+        }
+
+        public static ImpactMessagerieEntity entity(CritereEntity critere, Double constanteCoefficientDirecteur, Double constanteOrdonneeOrigine, String source) {
+            return new ImpactMessagerieEntity()
+                    .setCritere(critere.getNomCritere())
+                    .setSource(source)
+                    .setConstanteCoefficientDirecteur(constanteCoefficientDirecteur)
+                    .setConstanteOrdonneeOrigine(constanteOrdonneeOrigine);
+        }
+    }
+
+    public static class CorrespondanceRefEquipementFactory {
+        public static CorrespondanceRefEquipementDTO dto(String modeleSource, String refEquipementCible) {
+            return CorrespondanceRefEquipementDTO.builder()
+                    .modeleEquipementSource(modeleSource)
+                    .refEquipementCible(refEquipementCible)
+                    .build();
+        }
+
+        public static CorrespondanceRefEquipement domain(String modeleSource, String refEquipementCible) {
+            return CorrespondanceRefEquipement.builder()
+                    .modeleEquipementSource(modeleSource)
+                    .refEquipementCible(refEquipementCible)
+                    .build();
+        }
+
+        public static CorrespondanceRefEquipementEntity entity(String modeleSource, String refEquipementCible) {
+            return new CorrespondanceRefEquipementEntity()
+                    .setModeleEquipementSource(modeleSource)
+                    .setRefEquipementCible(refEquipementCible);
+        }
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2523f23e5260907fd19c3b14681d585f167b12a7
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/CritereCsvExportServiceTest.java
@@ -0,0 +1,100 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CritereRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class CritereCsvExportServiceTest {
+
+    @InjectMocks
+    CritereCsvExportService exportService;
+
+    @Mock
+    CritereRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportCriterePortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "","kg CO_{2} eq"),
+                TestDataFactory.CritereFactory.entity("Acidification", "","mol H^{+} eq")
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.CritereFactory.entity("Changement climatique", "","kg CO_{2} eq");
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(entity.getNomCritere(), entity.getDescription(), entity.getUnite());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord(){
+        var entity = TestDataFactory.CritereFactory.entity("Changement climatique", "","kg CO_{2} eq");
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord(){
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile(){
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "Test","kg CO_{2} eq")
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "nomCritere;description;unite\r\nChangement climatique;Test;kg CO_{2} eq\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bde0c0e3b4feb8d77b3101fb78aad431a4eb18e
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/EtapeCsvExportServiceTest.java
@@ -0,0 +1,100 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportEtapePortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.EtapeRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class EtapeCsvExportServiceTest {
+
+    @InjectMocks
+    EtapeCsvExportService exportService;
+
+    @Mock
+    EtapeRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportEtapePortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.EtapeFactory.entity("UTILISATION","Utilisation"),
+                TestDataFactory.EtapeFactory.entity("FIN_DE_VIE","Fin de vie")
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.EtapeFactory.entity("UTILISATION","Utilisation");
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(entity.getCode(), entity.getLibelle());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord(){
+        var entity = TestDataFactory.EtapeFactory.entity("UTILISATION","Utilisation");
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord(){
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile(){
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.EtapeFactory.entity("UTILISATION","Utilisation")
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "code;libelle\r\nUTILISATION;Utilisation\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..349805af1058ff0598b4d95fa389445a1240f5bc
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java
@@ -0,0 +1,100 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportHypothesePortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.HypotheseRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class HypotheseCsvExportServiceTest {
+
+    @InjectMocks
+    HypotheseCsvExportService exportService;
+
+    @Mock
+    HypotheseRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportHypothesePortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source"),
+                TestDataFactory.HypotheseFactory.entity("clé2", "1.0","Source")
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source");
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(entity.getCode(), entity.getValeur(), entity.getSource());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord(){
+        var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source");
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord(){
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile(){
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source")
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "cle;valeur;source\r\nclé;0.0;Source\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d33419aa6bb26209f5742ca3fff7308405217e63
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactEquipementCsvExportServiceTest.java
@@ -0,0 +1,128 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactEquipementPortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactEquipementRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class ImpactEquipementCsvExportServiceTest {
+
+    @InjectMocks
+    ImpactEquipementCsvExportService exportService;
+
+    @Mock
+    ImpactEquipementRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportImpactEquipementPortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.ImpactEquipementFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", "Ecran", 0.1, 0.2
+                ),
+                TestDataFactory.ImpactEquipementFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("DISTRIBUTION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", "Ecran", 0.01, 0.002
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.ImpactEquipementFactory.entity(
+                TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                "Ref-Ecran", "RefTest", "Ecran", 0.1, 0.2
+        );
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(entity.getRefEquipement(),
+                entity.getEtape(), entity.getCritere(),
+                df.format(entity.getConsoElecMoyenne()), df.format(entity.getValeur()),
+                entity.getSource(), entity.getType());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord() {
+        var entity = TestDataFactory.ImpactEquipementFactory.entity(
+                TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                "Ref-Ecran", "RefTest", "Ecran", 0.1, 0.2
+        );
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord() {
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile() {
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.ImpactEquipementFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", "Ecran", 0.1, 0.2
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "refEquipement;etapeacv;critere;consoElecMoyenne;valeur;source;type\r\nRef-Ecran;UTILISATION;Changement climatique;0.2;0.1;RefTest;Ecran\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..843d2d3db84b8a578ca48dcb6c98994b6c9e0158
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMessagerieCsvExportServiceTest.java
@@ -0,0 +1,124 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactMessageriePortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactMessagerieRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class ImpactMessagerieCsvExportServiceTest {
+
+    @InjectMocks
+    ImpactMessagerieCsvExportService exportService;
+
+    @Mock
+    ImpactMessagerieRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportImpactMessageriePortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.ImpactMessagerieFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                        0.2, 0.0005, "Test"
+                ),
+                TestDataFactory.ImpactMessagerieFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Acidification", "",""),
+                        0.2, 0.0005, "Test"
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.ImpactMessagerieFactory.entity(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                0.2, 0.0005, "Test"
+        );
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(
+                entity.getCritere(),
+                df.format(entity.getConstanteCoefficientDirecteur()),
+                df.format(entity.getConstanteOrdonneeOrigine()),
+                entity.getSource());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord(){
+        var entity = TestDataFactory.ImpactMessagerieFactory.entity(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                0.2, 0.0005, "Test"
+        );
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord(){
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile(){
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.ImpactMessagerieFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                        0.2, 0.0005, "Test"
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "critere;constanteCoefficientDirecteur;constanteOrdonneeOrigine;source\r\nChangement climatique;0.2;0.0005;Test\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..212d0da355dff7bd6e2170283ff1f577d1fdb344
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java
@@ -0,0 +1,126 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportMixElectriquePortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.MixElectriqueRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class ImpactMixElectriqueCsvExportServiceTest {
+
+    @InjectMocks
+    MixElectriqueCsvExportService exportService;
+
+    @Mock
+    MixElectriqueRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        Assertions.assertEquals(ImportMixElectriquePortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.MixElectriqueFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                        "France", "FR",0.2, "Test"
+                ),
+                TestDataFactory.MixElectriqueFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Acidification", "",""),
+                        "Angleterre", "EN",0.1, "Test"
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.MixElectriqueFactory.entity(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                "France", "FR",0.2, "Test"
+        );
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(
+                entity.getPays(),
+                entity.getRaccourcisAnglais(),
+                entity.getCritere(),
+                df.format(entity.getValeur()),
+                entity.getSource());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord(){
+        var entity = TestDataFactory.MixElectriqueFactory.entity(
+                TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                "France", "FR",0.2, "Test"
+        );
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord(){
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile(){
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.MixElectriqueFactory.entity(
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "",""),
+                        "France", "FR",0.2, "Test"
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "pays;raccourcisAnglais;critere;valeur;source\r\nFrance;FR;Changement climatique;0.2;Test\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3eeee78506deeadd1d44ddebfa08218cb08d4cdd
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactReseauCsvExportServiceTest.java
@@ -0,0 +1,128 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportImpactReseauPortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactReseauRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class ImpactReseauCsvExportServiceTest {
+
+    @InjectMocks
+    ImpactReseauCsvExportService exportService;
+
+    @Mock
+    ImpactReseauRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        assertEquals(ImportImpactReseauPortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.ImpactReseauFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", 0.1, 0.2
+                ),
+                TestDataFactory.ImpactReseauFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("DISTRIBUTION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", 0.01, 0.002
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.ImpactReseauFactory.entity(
+                TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                "Ref-Ecran", "RefTest", 0.1, 0.2
+        );
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(entity.getRefReseau(),
+                entity.getEtape(), entity.getCritere(),
+                df.format(entity.getValeur()), df.format(entity.getConsoElecMoyenne()),
+                entity.getSource());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord() {
+        var entity = TestDataFactory.ImpactReseauFactory.entity(
+                TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                "Ref-Ecran", "RefTest", 0.1, 0.2
+        );
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord() {
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile() {
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.ImpactReseauFactory.entity(
+                        TestDataFactory.EtapeFactory.entity("UTILISATION", ""),
+                        TestDataFactory.CritereFactory.entity("Changement climatique", "", ""),
+                        "Ref-Ecran", "RefTest", 0.1, 0.2
+                )
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "refReseau;etapeACV;critere;valeur;consoElecMoyenne;source\r\nRef-Ecran;UTILISATION;Changement climatique;0.1;0.2;RefTest\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ReferentielCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ReferentielCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6ac4cf82e932640268f8c2eac6ab39553bf5ba4
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ReferentielCsvExportServiceTest.java
@@ -0,0 +1,158 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import lombok.Getter;
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ReferentielCsvExportServiceTest {
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void writeToCsvShouldLogGenericFileError() {
+        // given
+        var list = new ArrayList<EtapeEntity>();
+        list.add(TestDataFactory.EtapeFactory.entity("UTILISATION", "Utilisation"));
+        list.add(null);
+        var exportService = new TestReferentielCsvExportService(new String[]{"code"}, list);
+        var faultyWriter = new Writer() {
+            @Override
+            public void write(char[] cbuf, int off, int len) throws IOException {
+                // Do nothing
+            }
+
+            @Override
+            public void flush() throws IOException {
+                // Do nothing
+            }
+
+            @Override
+            public void close() throws IOException {
+                throw new IOException("Exception de test");
+            }
+        };
+
+        // When
+        assertDoesNotThrow(() -> exportService.writeToCsv(faultyWriter));
+
+        // Then
+        assertTrue(exportService.isLogFileErrorCalled());
+        assertNotNull(exportService.getLogFileException());
+        assertEquals("Exception de test", exportService.getLogFileException().getMessage());
+    }
+
+    @Test
+    void writeToCsvShouldLogGenericRecordErrorAndProducesCSVWithOnlyHeaders() {
+        // given
+        var list = new ArrayList<EtapeEntity>();
+        list.add(null);
+        var exportService = new TestReferentielCsvExportService(new String[]{"code"}, list);
+        var stringWriter = new StringWriter();
+
+        // When
+        assertDoesNotThrow(() -> exportService.writeToCsv(stringWriter));
+
+        // Then
+        assertTrue(exportService.isLogRecordErrorCalled());
+        assertNotNull(exportService.getLogRecordException());
+        assertEquals(NullPointerException.class, exportService.getLogRecordException().getClass());
+        String result = stringWriter.toString();
+        assertEquals(
+                "code\r\n",
+                result
+        );
+    }
+
+    @Test
+    void writeToCsvGivenEmptyListShouldProducesCSVWithOnlyHeaders() {
+        // given
+        var list = new ArrayList<EtapeEntity>();
+        var exportService = new TestReferentielCsvExportService(new String[]{"code"}, list);
+        var stringWriter = new StringWriter();
+
+        // When
+        assertDoesNotThrow(() -> exportService.writeToCsv(stringWriter));
+
+        // Then
+        assertFalse(exportService.isLogRecordErrorCalled());
+        assertNull(exportService.getLogRecordException());
+        String result = stringWriter.toString();
+        assertEquals(
+                "code\r\n",
+                result
+        );
+    }
+
+    @Getter
+    static
+    class TestReferentielCsvExportService extends ReferentielCsvExportService<EtapeEntity> {
+
+        boolean logRecordErrorCalled = false;
+
+        Exception logRecordException = null;
+
+        boolean logFileErrorCalled = false;
+
+        Exception logFileException = null;
+
+        String[] headers;
+
+        List<EtapeEntity> records;
+
+        public TestReferentielCsvExportService(String[] headers, List<EtapeEntity> records) {
+            super(EtapeEntity.class);
+            this.headers = headers;
+            this.records = records;
+        }
+
+        @Override
+        public String[] getHeaders() {
+            return headers;
+        }
+
+        @Override
+        protected String getObjectId(EtapeEntity object) {
+            return object.getCode();
+        }
+
+        @Override
+        public void printRecord(CSVPrinter csvPrinter, EtapeEntity objectToWrite) throws IOException {
+            csvPrinter.printRecord(objectToWrite.getCode());
+        }
+
+        @Override
+        public List<EtapeEntity> getObjectsToWrite() {
+            return records;
+        }
+
+        @Override
+        public void logRecordError(EtapeEntity objectToWrite, Exception exception) {
+            super.logRecordError(objectToWrite, exception);
+            logRecordErrorCalled = true;
+            logRecordException = exception;
+        }
+
+        @Override
+        public void logWriterError(Exception exception) {
+            super.logWriterError(exception);
+            logFileErrorCalled = true;
+            logFileException = exception;
+        }
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2433525aad876db28bc19c054c014b44f0bd884a
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java
@@ -0,0 +1,122 @@
+package org.mte.numecoeval.referentiel.infrastructure.adapter.export;
+
+import org.apache.commons.csv.CSVPrinter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+class TypeEquipementCsvExportServiceTest {
+
+    @InjectMocks
+    TypeEquipementCsvExportService exportService;
+
+    @Mock
+    TypeEquipementRepository repository;
+
+    @Mock
+    CSVPrinter csvPrinter;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void getHeadersShouldReturnSameHeadersAsImport() {
+        Assertions.assertEquals(ImportTypeEquipementPortImpl.getHeaders(), exportService.getHeaders());
+    }
+
+    @Test
+    void getObjectsToWriteShouldReturnRepositoryFindAll() {
+        var entities = List.of(
+                TestDataFactory.TypeEquipementFactory.entity(
+                        "Serveur", true, 6.0, "", "Test",
+                        "test"),
+                TestDataFactory.TypeEquipementFactory.entity(
+                        "Ecran", false, 4.0, "", "Test",
+                        "test")
+        );
+        when(repository.findAll()).thenReturn(entities);
+
+        assertEquals(entities, exportService.getObjectsToWrite());
+    }
+
+    @Test
+    void printRecordShouldUseEntityAttributes() throws IOException {
+        var entity = TestDataFactory.TypeEquipementFactory.entity(
+                "Serveur", true, 6.0, "", "Test",
+                "test");
+        DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
+        df.setMaximumFractionDigits(340);
+
+        assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity));
+
+        Mockito.verify(csvPrinter, times(1)).printRecord(
+                entity.getType(),
+                entity.isServeur(),
+                entity.getCommentaire(),
+                df.format(entity.getDureeVieDefaut()),
+                entity.getSource(),
+                entity.getRefEquipementParDefaut());
+    }
+
+    @Test
+    void logRecordErrorShouldLogSpecificErrorForRecord() {
+        var entity = TestDataFactory.TypeEquipementFactory.entity(
+                "Serveur", true, 6.0, "", "Test",
+                "test");
+
+        assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForRecord() {
+        assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test")));
+    }
+
+    @Test
+    void logRecordErrorShouldLogGenericErrorForFile() {
+        assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test")));
+    }
+
+    @Test
+    void writeToCsvShouldReturnCSV() {
+        // given
+        var entities = List.of(
+                TestDataFactory.TypeEquipementFactory.entity(
+                        "Serveur", true, 6.0, "Commentaires", "Test",
+                        "test")
+        );
+        when(repository.findAll()).thenReturn(entities);
+        StringWriter stringWriter = new StringWriter();
+
+        // when
+        exportService.writeToCsv(stringWriter);
+
+        // Then
+        String result = stringWriter.toString();
+        assertEquals(
+                "type;serveur;commentaire;dureeVieDefaut;source;refEquipementParDefaut\r\nServeur;true;Commentaires;6;Test;test\r\n",
+                result
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfigTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..62cddecea11c02f271cb30379e07d5ce01bc071e
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/openapi/ReferentielOpenApiConfigTest.java
@@ -0,0 +1,55 @@
+package org.mte.numecoeval.referentiel.infrastructure.configuration.openapi;
+
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.SpecVersion;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class ReferentielOpenApiConfigTest {
+    @Test
+    void testConfigOpenAPI() {
+        OpenAPI actualConfigOpenAPIResult = (new ReferentielOpenApiConfig()).configOpenAPI();
+        assertNull(actualConfigOpenAPIResult.getComponents());
+        assertNull(actualConfigOpenAPIResult.getWebhooks());
+        assertNull(actualConfigOpenAPIResult.getTags());
+        assertEquals(SpecVersion.V30, actualConfigOpenAPIResult.getSpecVersion());
+        assertNull(actualConfigOpenAPIResult.getServers());
+        assertNull(actualConfigOpenAPIResult.getSecurity());
+        assertNull(actualConfigOpenAPIResult.getPaths());
+        assertEquals("3.0.1", actualConfigOpenAPIResult.getOpenapi());
+        assertNull(actualConfigOpenAPIResult.getExtensions());
+        ExternalDocumentation externalDocs = actualConfigOpenAPIResult.getExternalDocs();
+        assertEquals("https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/docs", externalDocs.getUrl());
+        assertNull(externalDocs.getExtensions());
+        assertEquals("NumEcoEval Documentation", externalDocs.getDescription());
+        Info info = actualConfigOpenAPIResult.getInfo();
+        assertEquals("API des référentiels de NumEcoEval", info.getTitle());
+        assertNull(info.getTermsOfService());
+        assertNull(info.getSummary());
+        assertNull(info.getExtensions());
+        assertEquals("v0.0.1", info.getVersion());
+        assertEquals("""
+                                Endpoints permettant de manipuler les référentiels de NumEcoEval.
+                                Les endpoints CRUD sont générés via Spring DataRest.
+                                
+                                Les endpoints d'export CSV permettent d'exporter l'intégralité d'un référentiel
+                                sous forme de fichier CSV ré-importable via les endpoints d'imports.
+                                
+                                Les endpoints d'import fonctionnent en annule & remplace et supprimeront l'intégralité
+                                du référentiel et utiliseront le contenu du CSV pour peupler le référentiel.
+                                
+                                Les endpoints internes sont utilisés par les différents modules de NumEcoEval.
+                                """,
+                info.getDescription());
+        assertNull(info.getContact());
+        License license = info.getLicense();
+        assertEquals("https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/api-referentiel/-/blob/main/LICENSE.txt", license.getUrl());
+        assertEquals("Apache 2.0", license.getName());
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfigTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..03a7d63707b47a5ad001d85a251fde08b924b303
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/configuration/security/SecurityConfigTest.java
@@ -0,0 +1,34 @@
+package org.mte.numecoeval.referentiel.infrastructure.configuration.security;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.annotation.ObjectPostProcessor;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.HashMap;
+
+import static org.mockito.Mockito.mock;
+
+@SpringBootTest
+@ActiveProfiles(profiles = {"test"})
+class SecurityConfigTest {
+    @Autowired
+    private SecurityConfig securityConfig;
+
+    @Test
+    void testGlobalFilterChain() throws Exception {
+        ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
+        AuthenticationProvider provider = mock(AuthenticationProvider.class);
+        AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp);
+        AuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(opp);
+        securityConfig.globalFilterChain(new HttpSecurity(opp, authenticationBuilder, new HashMap<>()));
+        Assertions.assertNotNull(securityConfig);
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/csv/ImportCSVReferentielPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/csv/ImportCSVReferentielPortTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b1993fd422cb9a866b5f30bad4c276012b0c45b
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/csv/ImportCSVReferentielPortTest.java
@@ -0,0 +1,68 @@
+package org.mte.numecoeval.referentiel.infrastructure.csv;
+
+import org.apache.commons.csv.CSVRecord;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort;
+
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class ImportCSVReferentielPortTest {
+
+    CSVRecord csvRecord;
+    ImportCSVReferentielPort csvReferentielPort = new ImportCSVReferentielPort() {
+        @Override
+        public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException {
+            // Nothing to do
+        }
+
+        @Override
+        public ResultatImport importCSV(InputStream csvInputStream) {
+            return new ResultatImport<>();
+        }
+    };
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        csvRecord = mock(CSVRecord.class);
+    }
+
+    @Test
+    void getDoubleValue_shouldReturnRecordValue() {
+        when(csvRecord.get("doubleValue")).thenReturn("1.6");
+
+        Double value = csvReferentielPort.getDoubleValueFromRecord(csvRecord, "doubleValue", null);
+
+        assertEquals(1.6, value);
+    }
+
+    @Test
+    void getDoubleValue_givenUntrimmedValue_shouldReturnRecordValue() {
+        when(csvRecord.get("doubleValue")).thenReturn("            97.58              ");
+
+        Double value = csvReferentielPort.getDoubleValueFromRecord(csvRecord, "doubleValue", null);
+
+        assertEquals(97.58, value);
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    void getDoubleValue_shouldReturnDefaultValue(String nullOrEmptyValue) {
+        when(csvRecord.get("doubleValue")).thenReturn(nullOrEmptyValue);
+
+        Double value = csvReferentielPort.getDoubleValueFromRecord(csvRecord, "doubleValue", 0.0);
+
+        assertEquals(0.0, value);
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CorrespondanceRefEquipementJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CorrespondanceRefEquipementJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d9f08d295565bd6f7fec8f19509d2252292d6f2
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CorrespondanceRefEquipementJpaAdapterTest.java
@@ -0,0 +1,128 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.CorrespondanceRefEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CorrespondanceRefEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CorrespondanceRefEquipementRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CorrespondanceRefEquipementJpaAdapterTest {
+
+    @InjectMocks
+    private CorrespondanceRefEquipementJpaAdapter jpaAdapter;
+
+    @Mock
+    CorrespondanceRefEquipementRepository hypotheseRepository;
+
+    CorrespondanceRefEquipementMapper mapper = new CorrespondanceRefEquipementMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(jpaAdapter, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnDomain() {
+        var expectedEntity = new CorrespondanceRefEquipementEntity()
+                .setModeleEquipementSource("source")
+                .setRefEquipementCible("cible");
+        var wantedId = "source";
+
+        Mockito.when(hypotheseRepository.findById(wantedId)).thenReturn(Optional.of(expectedEntity));
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.get(wantedId) );
+
+        assertEquals(expectedEntity.getModeleEquipementSource(), expectedDomain.getModeleEquipementSource());
+        assertEquals(expectedEntity.getRefEquipementCible(), expectedDomain.getRefEquipementCible());
+    }
+
+    @Test
+    void get_shouldThrowException() {
+        var wantedId = "notExisting";
+
+        Mockito.when(hypotheseRepository.findById(wantedId)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(wantedId) );
+
+        assertEquals("Correspondance au RefEquipement "+ wantedId +" non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void get_withNullValueShouldThrowException() {
+        String wantedId = null;
+
+        Mockito.when(hypotheseRepository.findById(wantedId)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(wantedId) );
+
+        assertEquals("Correspondance au RefEquipement (id null) non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void purge_shouldCallDeleteAll() {
+        jpaAdapter.purge();
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).deleteAll();
+    }
+
+    @Test
+    void getAll_shouldCallfindAll() {
+        jpaAdapter.getAll();
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).findAll();
+    }
+
+    @Test
+    void saveAll_shouldCallsaveAll() {
+        var domainToSave = CorrespondanceRefEquipement.builder()
+                .modeleEquipementSource("source")
+                .refEquipementCible("cible")
+                .build();
+        var entityToSave = mapper.toEntity(domainToSave);
+
+        assertDoesNotThrow(() -> jpaAdapter.saveAll(Collections.singletonList(domainToSave)));
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).saveAll(Collections.singletonList(entityToSave));
+    }
+
+    @Test
+    void save_shouldSaveAndReturnDomain() {
+        var wantedDomain = CorrespondanceRefEquipement.builder()
+                .modeleEquipementSource("source")
+                .refEquipementCible("cible")
+                .build();
+        var expectedEntity = mapper.toEntities(Collections.singletonList(wantedDomain)).get(0);
+
+        Mockito.when(hypotheseRepository.save(expectedEntity)).thenReturn(expectedEntity);
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(wantedDomain) );
+
+        assertEquals(expectedEntity.getModeleEquipementSource(), expectedDomain.getModeleEquipementSource());
+        assertEquals(expectedEntity.getRefEquipementCible(), expectedDomain.getRefEquipementCible());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void save_shouldSaveAndReturnNull(CorrespondanceRefEquipement nullValue) {
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(nullValue) );
+
+        assertNull(expectedDomain);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CritereJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CritereJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..90267150d9e703c2237e40699f1583a8ab3dfa87
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/CritereJpaAdapterTest.java
@@ -0,0 +1,170 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.domain.model.id.CritereId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.CritereJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactMessagerieJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactReseauJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.MixElectriqueJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.CritereEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.CritereRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CritereMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {CritereJpaAdapter.class})
+@ExtendWith(SpringExtension.class)
+class CritereJpaAdapterTest {
+    @Autowired
+    private CritereJpaAdapter critereJpaAdapter;
+
+    @MockBean
+    private CritereMapper critereMapper;
+
+    @MockBean
+    private CritereRepository critereRepository;
+
+    @MockBean
+    private ImpactEquipementJpaAdapter impactEquipementJpaAdapter;
+
+    @MockBean
+    private ImpactReseauJpaAdapter impactReseauJpaAdapter;
+
+    @MockBean
+    private MixElectriqueJpaAdapter mixElectriqueJpaAdapter;
+
+    @MockBean
+    private ImpactMessagerieJpaAdapter impactMessagerieJpaAdapter;
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#save(Critere)}
+     */
+    @Test
+    void testSave() throws ReferentielException {
+        Critere critere = new Critere();
+        critere.setDescription("The characteristics of someone or something");
+        critere.setNomCritere("Nom Critere");
+        critere.setUnite("Unite");
+        assertNull(critereJpaAdapter.save(critere));
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#save(Critere)}
+     */
+    @Test
+    void testSave2() throws ReferentielException {
+        Critere critere = new Critere();
+        critere.setDescription("The characteristics of someone or something");
+        critere.setNomCritere("Nom Critere");
+        critere.setUnite("Unite");
+
+        Critere critere1 = new Critere();
+        critere1.setDescription("The characteristics of someone or something");
+        critere1.setNomCritere("Nom Critere");
+        critere1.setUnite("Unite");
+
+        Critere critere2 = new Critere();
+        critere2.setDescription("The characteristics of someone or something");
+        critere2.setNomCritere("Nom Critere");
+        critere2.setUnite("Unite");
+        Critere critere3 = mock(Critere.class);
+        when(critere3.setDescription((String) any())).thenReturn(critere);
+        when(critere3.setNomCritere((String) any())).thenReturn(critere1);
+        when(critere3.setUnite((String) any())).thenReturn(critere2);
+        critere3.setDescription("The characteristics of someone or something");
+        critere3.setNomCritere("Nom Critere");
+        critere3.setUnite("Unite");
+        assertNull(critereJpaAdapter.save(critere3));
+        verify(critere3).setDescription((String) any());
+        verify(critere3).setNomCritere((String) any());
+        verify(critere3).setUnite((String) any());
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#saveAll(Collection)}
+     */
+    @Test
+    void testSaveAll() throws ReferentielException {
+        when(critereMapper.toEntities((Collection<Critere>) any())).thenReturn(new ArrayList<>());
+        when(critereRepository.saveAll((Iterable<CritereEntity>) any())).thenReturn(new ArrayList<>());
+        critereJpaAdapter.saveAll(new ArrayList<>());
+        verify(critereMapper).toEntities((Collection<Critere>) any());
+        verify(critereRepository).saveAll((Iterable<CritereEntity>) any());
+        assertTrue(critereJpaAdapter.getAll().isEmpty());
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#get(CritereId)}
+     */
+    @Test
+    void testGet() throws ReferentielException {
+        CritereId critereId = new CritereId();
+        critereId.setNomCritere("Nom Critere");
+        assertNull(critereJpaAdapter.get(critereId));
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#get(CritereId)}
+     */
+    @Test
+    void testGet2() throws ReferentielException {
+        CritereId critereId = new CritereId();
+        critereId.setNomCritere("Nom Critere");
+        CritereId critereId1 = mock(CritereId.class);
+        when(critereId1.setNomCritere((String) any())).thenReturn(critereId);
+        critereId1.setNomCritere("Nom Critere");
+        assertNull(critereJpaAdapter.get(critereId1));
+        verify(critereId1).setNomCritere((String) any());
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#purge()}
+     */
+    @Test
+    void testPurge() {
+        doNothing().when(impactReseauJpaAdapter).purge();
+        doNothing().when(impactEquipementJpaAdapter).purge();
+        doNothing().when(mixElectriqueJpaAdapter).purge();
+        doNothing().when(impactMessagerieJpaAdapter).purge();
+        doNothing().when(critereRepository).deleteAll();
+        critereJpaAdapter.purge();
+
+        // Purge des données filles
+        verify(impactReseauJpaAdapter, times(0)).purge();
+        verify(impactEquipementJpaAdapter, times(0)).purge();
+        verify(mixElectriqueJpaAdapter, times(0)).purge();
+        verify(impactMessagerieJpaAdapter, times(0)).purge();
+
+        verify(critereRepository).deleteAll();
+        assertTrue(critereJpaAdapter.getAll().isEmpty());
+    }
+
+    /**
+     * Method under test: {@link CritereJpaAdapter#getAll()}
+     */
+    @Test
+    void testGetAll() {
+        ArrayList<Critere> critereList = new ArrayList<>();
+        when(critereMapper.toDomains((List<CritereEntity>) any())).thenReturn(critereList);
+        when(critereRepository.findAll()).thenReturn(new ArrayList<>());
+        List<Critere> actualAll = critereJpaAdapter.getAll();
+        assertSame(critereList, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(critereMapper).toDomains((List<CritereEntity>) any());
+        verify(critereRepository).findAll();
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/EtapeJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/EtapeJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..42201c320fd809990a90de0e346429e687bcafc1
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/EtapeJpaAdapterTest.java
@@ -0,0 +1,147 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.domain.model.id.EtapeId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.EtapeJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactReseauJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.EtapeEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.EtapeRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.EtapeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {EtapeJpaAdapter.class})
+@ExtendWith(SpringExtension.class)
+class EtapeJpaAdapterTest {
+    @Autowired
+    private EtapeJpaAdapter etapeJpaAdapter;
+
+    @MockBean
+    private EtapeMapper etapeMapper;
+
+    @MockBean
+    private EtapeRepository etapeRepository;
+
+    // Pour les purges des données filles
+    @MockBean
+    ImpactReseauJpaAdapter impactReseauJpaAdapter;
+    @MockBean
+    ImpactEquipementJpaAdapter impactEquipementJpaAdapter;
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#save(Etape)}
+     */
+    @Test
+    void testSave() throws ReferentielException {
+        Etape etape = new Etape();
+        etape.setCode("Code");
+        etape.setLibelle("Libelle");
+        assertNull(etapeJpaAdapter.save(etape));
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#save(Etape)}
+     */
+    @Test
+    void testSave2() throws ReferentielException {
+        Etape etape = new Etape();
+        etape.setCode("Code");
+        etape.setLibelle("Libelle");
+
+        Etape etape1 = new Etape();
+        etape1.setCode("Code");
+        etape1.setLibelle("Libelle");
+        Etape etape2 = mock(Etape.class);
+        when(etape2.setCode((String) any())).thenReturn(etape);
+        when(etape2.setLibelle((String) any())).thenReturn(etape1);
+        etape2.setCode("Code");
+        etape2.setLibelle("Libelle");
+        assertNull(etapeJpaAdapter.save(etape2));
+        verify(etape2).setCode((String) any());
+        verify(etape2).setLibelle((String) any());
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#saveAll(Collection)}
+     */
+    @Test
+    void testSaveAll() throws ReferentielException {
+        when(etapeMapper.toEntities((Collection<Etape>) any())).thenReturn(new ArrayList<>());
+        when(etapeRepository.saveAll((Iterable<EtapeEntity>) any())).thenReturn(new ArrayList<>());
+        etapeJpaAdapter.saveAll(new ArrayList<>());
+        verify(etapeMapper).toEntities((Collection<Etape>) any());
+        verify(etapeRepository).saveAll((Iterable<EtapeEntity>) any());
+        assertTrue(etapeJpaAdapter.getAll().isEmpty());
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#get(EtapeId)}
+     */
+    @Test
+    void testGet() throws ReferentielException {
+        EtapeId etapeId = new EtapeId();
+        etapeId.setCode("Code");
+        assertNull(etapeJpaAdapter.get(etapeId));
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#get(EtapeId)}
+     */
+    @Test
+    void testGet2() throws ReferentielException {
+        EtapeId etapeId = new EtapeId();
+        etapeId.setCode("Code");
+        EtapeId etapeId1 = mock(EtapeId.class);
+        when(etapeId1.setCode((String) any())).thenReturn(etapeId);
+        etapeId1.setCode("Code");
+        assertNull(etapeJpaAdapter.get(etapeId1));
+        verify(etapeId1).setCode((String) any());
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#purge()}
+     */
+    @Test
+    void testPurge() {
+        doNothing().when(impactReseauJpaAdapter).purge();
+        doNothing().when(impactEquipementJpaAdapter).purge();
+        doNothing().when(etapeRepository).deleteAll();
+
+        etapeJpaAdapter.purge();
+
+        // Purge des données filles
+        verify(impactReseauJpaAdapter, times(0)).purge();
+        verify(impactEquipementJpaAdapter, times(0)).purge();
+        verify(etapeRepository).deleteAll();
+        assertTrue(etapeJpaAdapter.getAll().isEmpty());
+    }
+
+    /**
+     * Method under test: {@link EtapeJpaAdapter#getAll()}
+     */
+    @Test
+    void testGetAll() {
+        ArrayList<Etape> etapeList = new ArrayList<>();
+        when(etapeMapper.toDomains((List<EtapeEntity>) any())).thenReturn(etapeList);
+        when(etapeRepository.findAll()).thenReturn(new ArrayList<>());
+        List<Etape> actualAll = etapeJpaAdapter.getAll();
+        assertSame(etapeList, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(etapeMapper).toDomains((List<EtapeEntity>) any());
+        verify(etapeRepository).findAll();
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/HypotheseJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/HypotheseJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c76fc171cfcf23d62a1e3bab54e1df86b7d1bf30
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/HypotheseJpaAdapterTest.java
@@ -0,0 +1,130 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.HypotheseJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.HypotheseEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.HypotheseRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HypotheseJpaAdapterTest {
+
+    @InjectMocks
+    private HypotheseJpaAdapter hypotheseJpaAdapter;
+
+    @Mock
+    HypotheseRepository hypotheseRepository;
+
+    HypotheseMapper hypotheseMapper = new HypotheseMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(hypotheseJpaAdapter, "hypotheseMapper", hypotheseMapper);
+    }
+
+    @Test
+    void get_shouldReturnDomain() {
+        var expectedEntity = new HypotheseEntity()
+                .setCode("code")
+                .setValeur("valeur")
+                .setSource("test");
+        var wantedId = new HypotheseId()
+                .setCode(expectedEntity.getCode());
+        var wantedEntityId = hypotheseMapper.toEntityId(wantedId);
+
+        Mockito.when(hypotheseRepository.findById(wantedEntityId)).thenReturn(Optional.of(expectedEntity));
+
+        var expectedDomain = assertDoesNotThrow( () -> hypotheseJpaAdapter.get(wantedId) );
+
+        Assertions.assertEquals(expectedEntity.getCode(), expectedDomain.getCode());
+        Assertions.assertEquals(expectedEntity.getValeur(), expectedDomain.getValeur());
+        Assertions.assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void get_shouldThrowException() {
+        var expectedEntity = new HypotheseEntity()
+                .setCode("code")
+                .setValeur("valeur")
+                .setSource("test");
+        var wantedId = new HypotheseId()
+                .setCode(expectedEntity.getCode());
+        var wantedEntityId = hypotheseMapper.toEntityId(wantedId);
+
+        Mockito.when(hypotheseRepository.findById(wantedEntityId)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> hypotheseJpaAdapter.get(wantedId) );
+
+        assertEquals("Hypothèse non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void purge_shouldCallDeleteAll() {
+        hypotheseJpaAdapter.purge();
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).deleteAll();
+    }
+
+    @Test
+    void getAll_shouldCallfindAll() {
+        hypotheseJpaAdapter.getAll();
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).findAll();
+    }
+
+    @Test
+    void saveAll_shouldCallsaveAll() {
+        var domainToSave = new Hypothese()
+                .setCode("code")
+                .setValeur("valeur")
+                .setSource("test");
+        var entityToSave = hypotheseMapper.toEntity(domainToSave);
+
+        assertDoesNotThrow(() -> hypotheseJpaAdapter.saveAll(Collections.singletonList(domainToSave)));
+
+        Mockito.verify(hypotheseRepository, Mockito.times(1)).saveAll(Collections.singletonList(entityToSave));
+    }
+
+    @Test
+    void save_shouldSaveAndReturnDomain() {
+        var wantedDomain = new Hypothese()
+                .setCode("code")
+                .setValeur("valeur")
+                .setSource("test");
+        var expectedEntity = hypotheseMapper.toEntities(Collections.singletonList(wantedDomain)).get(0);
+
+        Mockito.when(hypotheseRepository.save(expectedEntity)).thenReturn(expectedEntity);
+
+        var expectedDomain = assertDoesNotThrow( () -> hypotheseJpaAdapter.save(wantedDomain) );
+
+        Assertions.assertEquals(wantedDomain.getCode(), expectedDomain.getCode());
+        Assertions.assertEquals(wantedDomain.getValeur(), expectedDomain.getValeur());
+        Assertions.assertEquals(wantedDomain.getSource(), expectedDomain.getSource());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void save_shouldSaveAndReturnNull(Hypothese nullValue) {
+        var expectedDomain = assertDoesNotThrow( () -> hypotheseJpaAdapter.save(nullValue) );
+
+        assertNull(expectedDomain);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactEquipementJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactEquipementJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5485aa72111439e385475b60e7f8d24846011e3
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactEquipementJpaAdapterTest.java
@@ -0,0 +1,159 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactEquipementEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactEquipementRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ImpactEquipementJpaAdapterTest {
+
+    @InjectMocks
+    private ImpactEquipementJpaAdapter jpaAdapter;
+
+    @Mock
+    ImpactEquipementRepository repository;
+
+    ImpactEquipementMapper mapper = new ImpactEquipementMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(jpaAdapter, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnDomain() {
+        var expectedEntity = new ImpactEquipementEntity()
+                .setEtape("UTILISATION")
+                .setCritere("Changement climatique")
+                .setRefEquipement("Ecran 27 pouces")
+                .setType("Monitor")
+                .setSource("Test")
+                .setConsoElecMoyenne(0.020)
+                .setValeur(0.120);
+
+        var wantedId = new ImpactEquipementId()
+                .setEtape("UTILISATION")
+                .setCritere("Changement climatique")
+                .setRefEquipement(expectedEntity.getRefEquipement());
+        var wantedEntityId = mapper.toEntityId(wantedId);
+        Mockito.when(repository.findById(wantedEntityId)).thenReturn(Optional.of(expectedEntity));
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.get(wantedId) );
+
+        assertNotNull(expectedDomain.getEtape());
+        assertEquals(expectedEntity.getEtape(), expectedDomain.getEtape());
+        assertNotNull(expectedDomain.getCritere());
+        assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        assertEquals(expectedEntity.getRefEquipement(), expectedDomain.getRefEquipement());
+        assertEquals(expectedEntity.getType(), expectedDomain.getType());
+        assertEquals(expectedEntity.getConsoElecMoyenne(), expectedDomain.getConsoElecMoyenne());
+        assertEquals(expectedEntity.getValeur(), expectedDomain.getValeur());
+        assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void get_shouldThrowException() {
+        var wantedId = new ImpactEquipementId()
+                .setEtape("Absent")
+                .setCritere("Inexistant")
+                .setRefEquipement("NonExistant");
+        var wantedEntityId = mapper.toEntityId(wantedId);
+        Mockito.when(repository.findById(wantedEntityId)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(wantedId) );
+
+        assertEquals("Impact Equipement non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void get_whenNull_shouldThrowException() {
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(null) );
+
+        assertEquals("Impact Equipement non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void purge_shouldCallDeleteAll() {
+        jpaAdapter.purge();
+
+        Mockito.verify(repository, Mockito.times(1)).deleteAll();
+    }
+
+    @Test
+    void getAll_shouldCallfindAll() {
+        jpaAdapter.getAll();
+
+        Mockito.verify(repository, Mockito.times(1)).findAll();
+    }
+
+    @Test
+    void saveAll_shouldCallsaveAll() {
+        var domainToSave = new ImpactEquipement()
+                .setEtape("UTILISATION")
+                .setCritere("Changement climatique")
+                .setRefEquipement("Ecran 27 pouces")
+                .setType("Monitor")
+                .setSource("Test")
+                .setConsoElecMoyenne(0.020)
+                .setValeur(0.120);
+        var entityToSave = mapper.toEntity(domainToSave);
+
+        assertDoesNotThrow(() -> jpaAdapter.saveAll(Collections.singletonList(domainToSave)));
+
+        Mockito.verify(repository, Mockito.times(1)).saveAll(Collections.singletonList(entityToSave));
+    }
+
+    @Test
+    void save_shouldSaveAndReturnDomain() {
+        var wantedDomain = new ImpactEquipement()
+                .setEtape("UTILISATION")
+                .setCritere("Changement climatique")
+                .setRefEquipement("Ecran 27 pouces")
+                .setType("Monitor")
+                .setSource("Test")
+                .setConsoElecMoyenne(0.020)
+                .setValeur(0.120);
+        var expectedEntity = mapper.toEntities(Collections.singletonList(wantedDomain)).get(0);
+
+        Mockito.when(repository.save(expectedEntity)).thenReturn(expectedEntity);
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(wantedDomain) );
+
+        assertNotNull(expectedDomain.getEtape());
+        assertEquals(expectedEntity.getEtape(), expectedDomain.getEtape());
+        assertNotNull(expectedDomain.getCritere());
+        assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        assertEquals(expectedEntity.getRefEquipement(), expectedDomain.getRefEquipement());
+        assertEquals(expectedEntity.getType(), expectedDomain.getType());
+        assertEquals(expectedEntity.getConsoElecMoyenne(), expectedDomain.getConsoElecMoyenne());
+        assertEquals(expectedEntity.getValeur(), expectedDomain.getValeur());
+        assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void save_shouldSaveAndReturnNull(ImpactEquipement nullValue) {
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(nullValue) );
+
+        assertNull(expectedDomain);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactMessagerieJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactMessagerieJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f292ec118630b03e1c10fee6f93a9b5a7a6dcdca
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactMessagerieJpaAdapterTest.java
@@ -0,0 +1,149 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactMessagerieJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactMessagerieEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactMessagerieRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ImpactMessagerieJpaAdapterTest {
+
+    @InjectMocks
+    private ImpactMessagerieJpaAdapter jpaAdapter;
+
+    @Mock
+    ImpactMessagerieRepository repository;
+
+    ImpactMessagerieMapper mapper = new ImpactMessagerieMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(jpaAdapter, "impactMessagerieMapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnDomain() {
+        var expectedCritere = "Changement climatique";
+        var expectedEntity = new ImpactMessagerieEntity()
+                .setCritere("Changement climatique")
+                .setSource("Test")
+                .setConstanteCoefficientDirecteur(0.05)
+                .setConstanteOrdonneeOrigine(0.00120);
+
+        Mockito.when(repository.findById(expectedCritere)).thenReturn(Optional.of(expectedEntity));
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.get(expectedCritere) );
+
+        assertNotNull(expectedDomain.getCritere());
+        assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        assertEquals(expectedEntity.getConstanteCoefficientDirecteur(), expectedDomain.getConstanteCoefficientDirecteur());
+        assertEquals(expectedEntity.getConstanteOrdonneeOrigine(), expectedDomain.getConstanteOrdonneeOrigine());
+        assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void get_shouldThrowException() {
+        var expectedCritere = "Changement climatique";
+        Mockito.when(repository.findById(expectedCritere)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(expectedCritere) );
+
+        assertEquals("ImpactMessagerie non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void get_whenNull_shouldThrowException() {
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(null) );
+
+        assertEquals("ImpactMessagerie non trouvé",expectedException.getMessage());
+    }
+
+    @Test
+    void purge_shouldCallDeleteAll() {
+        jpaAdapter.purge();
+
+        Mockito.verify(repository, Mockito.times(1)).deleteAll();
+    }
+
+    @Test
+    void getAll_shouldCallfindAll() {
+        var expectedEntity = new ImpactMessagerieEntity()
+                .setCritere("Changement climatique")
+                .setSource("Test")
+                .setConstanteCoefficientDirecteur(0.05)
+                .setConstanteOrdonneeOrigine(0.00120);
+        Mockito.when(repository.findAll()).thenReturn(Collections.singletonList(expectedEntity));
+
+        var result = jpaAdapter.getAll();
+
+        Mockito.verify(repository, Mockito.times(1)).findAll();
+        assertNotNull(result);
+        assertEquals(1, result.size());
+
+        var expectedDomain = result.get(0);
+        assertNotNull(expectedDomain.getCritere());
+        assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        assertEquals(expectedEntity.getConstanteCoefficientDirecteur(), expectedDomain.getConstanteCoefficientDirecteur());
+        assertEquals(expectedEntity.getConstanteOrdonneeOrigine(), expectedDomain.getConstanteOrdonneeOrigine());
+        assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void saveAll_shouldCallsaveAll() {
+        var domainToSave = new ImpactMessagerie()
+                .setCritere("Changement climatique")
+                .setSource("Test")
+                .setConstanteCoefficientDirecteur(0.05)
+                .setConstanteOrdonneeOrigine(0.00120);
+        var entityToSave = mapper.toEntity(domainToSave);
+
+        assertDoesNotThrow(() -> jpaAdapter.saveAll(Collections.singletonList(domainToSave)));
+
+        Mockito.verify(repository, Mockito.times(1)).saveAll(Collections.singletonList(entityToSave));
+    }
+
+    @Test
+    void save_shouldSaveAndReturnDomain() {
+        var wantedDomain = new ImpactMessagerie()
+                .setCritere("Changement climatique")
+                .setSource("Test")
+                .setConstanteCoefficientDirecteur(0.05)
+                .setConstanteOrdonneeOrigine(0.00120);
+        var expectedEntity = mapper.toEntities(Collections.singletonList(wantedDomain)).get(0);
+
+        Mockito.when(repository.save(expectedEntity)).thenReturn(expectedEntity);
+
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(wantedDomain) );
+
+        assertNotNull(expectedDomain.getCritere());
+        assertEquals(wantedDomain.getCritere(), expectedDomain.getCritere());
+        assertEquals(expectedEntity.getConstanteCoefficientDirecteur(), expectedDomain.getConstanteCoefficientDirecteur());
+        assertEquals(expectedEntity.getConstanteOrdonneeOrigine(), expectedDomain.getConstanteOrdonneeOrigine());
+        assertEquals(wantedDomain.getSource(), expectedDomain.getSource());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void save_shouldSaveAndReturnNull(ImpactMessagerie nullValue) {
+        var expectedDomain = assertDoesNotThrow( () -> jpaAdapter.save(nullValue) );
+
+        assertNull(expectedDomain);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactReseauJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactReseauJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..258f988fa6bd331fd6f263044f03a421398231b1
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/ImpactReseauJpaAdapterTest.java
@@ -0,0 +1,197 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mockito;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactReseauJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.ImpactReseauEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.ImpactReseauIdEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.ImpactReseauRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactReseauMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ImpactReseauJpaAdapter.class})
+@ExtendWith(SpringExtension.class)
+class ImpactReseauJpaAdapterTest {
+    @Autowired
+    private ImpactReseauJpaAdapter impactReseauJpaAdapter;
+
+    @MockBean
+    private ImpactReseauMapper impactReseauMapper;
+
+    @MockBean
+    private ImpactReseauRepository impactReseauRepository;
+
+    /**
+     * Method under test: {@link ImpactReseauJpaAdapter#save(ImpactReseau)}
+     */
+    @Test
+    void testSave() throws ReferentielException {
+        String expectedCritere = "Nom Critere";
+        String expectedEtape = "Code";
+        ImpactReseau impactReseau = new ImpactReseau();
+        impactReseau.setConsoElecMoyenne(10.0d);
+        impactReseau.setCritere(expectedCritere);
+        impactReseau.setEtape(expectedEtape);
+        impactReseau.setRefReseau("Ref Reseau");
+        impactReseau.setSource("Source");
+        impactReseau.setValeur(10.0d);
+
+        ImpactReseauEntity impactReseauEntity = new ImpactReseauEntity();
+        impactReseauEntity.setConsoElecMoyenne(10.0d);
+        impactReseauEntity.setCritere(expectedCritere);
+
+        impactReseauEntity.setEtape(expectedEtape);
+        impactReseauEntity.setRefReseau("Ref Reseau");
+        impactReseauEntity.setSource("Source");
+        impactReseauEntity.setValeur(10.0d);
+        when(impactReseauMapper.toDomain((ImpactReseauEntity) any())).thenReturn(impactReseau);
+        when(impactReseauMapper.toEntity((ImpactReseau) any())).thenReturn(impactReseauEntity);
+
+        ImpactReseauEntity impactReseauEntity1 = new ImpactReseauEntity();
+        impactReseauEntity1.setConsoElecMoyenne(10.0d);
+        impactReseauEntity1.setCritere(expectedCritere);
+        impactReseauEntity1.setEtape(expectedEtape);
+        impactReseauEntity1.setRefReseau("Ref Reseau");
+        impactReseauEntity1.setSource("Source");
+        impactReseauEntity1.setValeur(10.0d);
+        when(impactReseauRepository.save((ImpactReseauEntity) any())).thenReturn(impactReseauEntity1);
+
+        ImpactReseau impactReseau1 = new ImpactReseau();
+        impactReseau1.setConsoElecMoyenne(10.0d);
+        impactReseau1.setCritere(expectedCritere);
+        impactReseau1.setEtape(expectedEtape);
+        impactReseau1.setRefReseau("Ref Reseau");
+        impactReseau1.setSource("Source");
+        impactReseau1.setValeur(10.0d);
+        assertSame(impactReseau, impactReseauJpaAdapter.save(impactReseau1));
+        verify(impactReseauMapper).toDomain((ImpactReseauEntity) any());
+        verify(impactReseauMapper).toEntity((ImpactReseau) any());
+        verify(impactReseauRepository).save((ImpactReseauEntity) any());
+    }
+
+    /**
+     * Method under test: {@link ImpactReseauJpaAdapter#saveAll(Collection)}
+     */
+    @Test
+    void testSaveAll() throws ReferentielException {
+        when(impactReseauMapper.toEntity((Collection<ImpactReseau>) any())).thenReturn(new ArrayList<>());
+        when(impactReseauRepository.saveAll((Iterable<ImpactReseauEntity>) any())).thenReturn(new ArrayList<>());
+        impactReseauJpaAdapter.saveAll(new ArrayList<>());
+        verify(impactReseauMapper).toEntity((Collection<ImpactReseau>) any());
+        verify(impactReseauRepository).saveAll((Iterable<ImpactReseauEntity>) any());
+    }
+
+    /**
+     * Method under test: {@link ImpactReseauJpaAdapter#get(ImpactReseauId)}
+     */
+    @Test
+    void testGet() throws ReferentielException {
+        String expectedCritere = "Nom Critere";
+        String expectedEtape = "Code";
+        ImpactReseauIdEntity impactReseauIdEntity = new ImpactReseauIdEntity();
+        impactReseauIdEntity.setCritere(expectedCritere);
+        impactReseauIdEntity.setEtape(expectedEtape);
+        impactReseauIdEntity.setRefReseau("Ref Reseau");
+
+        ImpactReseau impactReseau = new ImpactReseau();
+        impactReseau.setConsoElecMoyenne(10.0d);
+        impactReseau.setCritere(expectedCritere);
+        impactReseau.setEtape(expectedEtape);
+        impactReseau.setRefReseau("Ref Reseau");
+        impactReseau.setSource("Source");
+        impactReseau.setValeur(10.0d);
+        when(impactReseauMapper.toDomain((ImpactReseauEntity) any())).thenReturn(impactReseau);
+        when(impactReseauMapper.toEntityId((ImpactReseauId) any())).thenReturn(impactReseauIdEntity);
+
+        ImpactReseauEntity impactReseauEntity = new ImpactReseauEntity();
+        impactReseauEntity.setConsoElecMoyenne(10.0d);
+        impactReseauEntity.setCritere(expectedCritere);
+        impactReseauEntity.setEtape(expectedEtape);
+        impactReseauEntity.setRefReseau("Ref Reseau");
+        impactReseauEntity.setSource("Source");
+        impactReseauEntity.setValeur(10.0d);
+        Optional<ImpactReseauEntity> ofResult = Optional.of(impactReseauEntity);
+        when(impactReseauRepository.findById((ImpactReseauIdEntity) any())).thenReturn(ofResult);
+
+        ImpactReseauId impactReseauId = new ImpactReseauId();
+        impactReseauId.setCritere(expectedCritere);
+        impactReseauId.setEtape(expectedEtape);
+        impactReseauId.setRefReseau("Ref Reseau");
+        assertSame(impactReseau, impactReseauJpaAdapter.get(impactReseauId));
+        verify(impactReseauMapper).toDomain((ImpactReseauEntity) any());
+        verify(impactReseauMapper).toEntityId(any());
+        verify(impactReseauRepository).findById(any());
+    }
+
+    /**
+     * Method under test: {@link ImpactReseauJpaAdapter#get(ImpactReseauId)}
+     */
+    @Test
+    void testGet2() throws ReferentielException {
+        String expectedCritere = "Nom Critere";
+        String expectedEtape = "Code";
+        ImpactReseauIdEntity impactReseauIdEntity = new ImpactReseauIdEntity();
+        impactReseauIdEntity.setCritere(expectedCritere);
+        impactReseauIdEntity.setEtape(expectedEtape);
+        impactReseauIdEntity.setRefReseau("Ref Reseau");
+
+        ImpactReseau impactReseau = new ImpactReseau();
+        impactReseau.setConsoElecMoyenne(10.0d);
+        impactReseau.setCritere(expectedCritere);
+        impactReseau.setEtape(expectedEtape);
+        impactReseau.setRefReseau("Ref Reseau");
+        impactReseau.setSource("Source");
+        impactReseau.setValeur(10.0d);
+        when(impactReseauMapper.toDomain((ImpactReseauEntity) any())).thenReturn(impactReseau);
+        when(impactReseauMapper.toEntityId(any())).thenReturn(impactReseauIdEntity);
+        when(impactReseauRepository.findById(any())).thenReturn(Optional.empty());
+
+        ImpactReseauId impactReseauId = new ImpactReseauId();
+        impactReseauId.setCritere(expectedCritere);
+        impactReseauId.setEtape(expectedEtape);
+        impactReseauId.setRefReseau("Ref Reseau");
+        assertThrows(ReferentielException.class, () -> impactReseauJpaAdapter.get(impactReseauId));
+        verify(impactReseauMapper).toEntityId((ImpactReseauId) any());
+        verify(impactReseauRepository).findById((ImpactReseauIdEntity) any());
+    }
+
+    /**
+     * Method under test: {@link ImpactReseauJpaAdapter#purge()}
+     */
+    @Test
+    void testPurge() {
+        doNothing().when(impactReseauRepository).deleteAll();
+        impactReseauJpaAdapter.purge();
+        verify(impactReseauRepository).deleteAll();
+    }
+
+    /**
+     * Methods under test:
+     *
+     * <ul>
+     *   <li>default or parameterless constructor of {@link ImpactReseauJpaAdapter}
+     *   <li>{@link ImpactReseauJpaAdapter#getAll()}
+     * </ul>
+     */
+    @Test
+    void testConstructor() {
+        Mockito.when(impactReseauRepository.findAll()).thenReturn(Collections.emptyList());
+        assertTrue((impactReseauJpaAdapter.getAll().isEmpty()));
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6de658438f8a7d6d26866b5cace366464cd26f31
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java
@@ -0,0 +1,169 @@
+package org.mte.numecoeval.referentiel.infrastructure.jpa;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.MixElectriqueJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.MixElectriqueEntity;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.MixElectriqueRepository;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MixElectriqueJpaAdapterTest {
+
+    @InjectMocks
+    private MixElectriqueJpaAdapter jpaAdapter;
+
+    @Mock
+    MixElectriqueRepository repository;
+
+    MixElectriqueMapper mapper = new MixElectriqueMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(jpaAdapter, "mixElectriqueMapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnDomain() {
+        var expectedCritere = "Changement climatique";
+        var expectedEntity = new MixElectriqueEntity()
+                .setCritere(expectedCritere)
+                .setPays("France")
+                .setSource("Test")
+                .setRaccourcisAnglais("FR")
+                .setValeur(0.120);
+
+        var wantedId = new MixElectriqueId()
+                .setPays(expectedEntity.getPays())
+                .setCritere(expectedCritere);
+        var wantedEntityId = mapper.toEntityId(wantedId);
+        Mockito.when(repository.findById(wantedEntityId)).thenReturn(Optional.of(expectedEntity));
+
+        var expectedDomain = assertDoesNotThrow(() -> jpaAdapter.get(wantedId));
+
+        assertNotNull(expectedDomain.getCritere());
+        Assertions.assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        Assertions.assertEquals(expectedEntity.getPays(), expectedDomain.getPays());
+        Assertions.assertEquals(expectedEntity.getRaccourcisAnglais(), expectedDomain.getRaccourcisAnglais());
+        Assertions.assertEquals(expectedEntity.getValeur(), expectedDomain.getValeur());
+        Assertions.assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void get_shouldThrowException() {
+        var wantedId = new MixElectriqueId()
+                .setPays("NonExistant")
+                .setCritere("Inexistant");
+        var wantedEntityId = mapper.toEntityId(wantedId);
+        Mockito.when(repository.findById(wantedEntityId)).thenReturn(Optional.empty());
+
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(wantedId));
+
+        assertEquals("Mix Electrique non trouvé pour l'id MixElectriqueId(pays=NonExistant, critere=Inexistant)", expectedException.getMessage());
+    }
+
+    @Test
+    void get_whenNull_shouldThrowException() {
+        ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(null));
+
+        assertEquals("Mix Electrique non trouvé pour l'id null", expectedException.getMessage());
+    }
+
+    @Test
+    void purge_shouldCallDeleteAll() {
+        jpaAdapter.purge();
+
+        Mockito.verify(repository, Mockito.times(1)).deleteAll();
+    }
+
+    @Test
+    void getAll_shouldCallfindAll() {
+        var expectedCritere = "Changement climatique";
+        var expectedEntity = new MixElectriqueEntity()
+                .setCritere(expectedCritere)
+                .setPays("France")
+                .setSource("Test")
+                .setRaccourcisAnglais("FR")
+                .setValeur(0.120);
+        Mockito.when(repository.findAll()).thenReturn(Collections.singletonList(expectedEntity));
+
+        var result = jpaAdapter.getAll();
+
+        Mockito.verify(repository, Mockito.times(1)).findAll();
+        assertNotNull(result);
+        assertEquals(1, result.size());
+
+        var expectedDomain = result.get(0);
+        assertNotNull(expectedDomain.getCritere());
+        Assertions.assertEquals(expectedEntity.getCritere(), expectedDomain.getCritere());
+        Assertions.assertEquals(expectedEntity.getPays(), expectedDomain.getPays());
+        Assertions.assertEquals(expectedEntity.getRaccourcisAnglais(), expectedDomain.getRaccourcisAnglais());
+        Assertions.assertEquals(expectedEntity.getValeur(), expectedDomain.getValeur());
+        Assertions.assertEquals(expectedEntity.getSource(), expectedDomain.getSource());
+    }
+
+    @Test
+    void saveAll_shouldCallsaveAll() {
+        var wantedCritere = "Changement climatique";
+        var domainToSave = new MixElectrique()
+                .setCritere(wantedCritere)
+                .setPays("France")
+                .setSource("Test")
+                .setRaccourcisAnglais("FR")
+                .setValeur(0.120);
+
+        var entityToSave = mapper.toEntity(domainToSave);
+
+        assertDoesNotThrow(() -> jpaAdapter.saveAll(Collections.singletonList(domainToSave)));
+
+        Mockito.verify(repository, Mockito.times(1)).saveAll(Collections.singletonList(entityToSave));
+    }
+
+    @Test
+    void save_shouldSaveAndReturnDomain() {
+        var wantedCritere = "Changement climatique";
+        var wantedDomain = new MixElectrique()
+                .setCritere(wantedCritere)
+                .setPays("France")
+                .setSource("Test")
+                .setRaccourcisAnglais("FR")
+                .setValeur(0.120);
+        var expectedEntity = mapper.toEntities(Collections.singletonList(wantedDomain)).get(0);
+
+        Mockito.when(repository.save(expectedEntity)).thenReturn(expectedEntity);
+
+        var expectedDomain = assertDoesNotThrow(() -> jpaAdapter.save(wantedDomain));
+
+        assertNotNull(expectedDomain.getCritere());
+        Assertions.assertEquals(wantedDomain.getCritere(), expectedDomain.getCritere());
+        Assertions.assertEquals(wantedDomain.getPays(), expectedDomain.getPays());
+        Assertions.assertEquals(wantedDomain.getRaccourcisAnglais(), expectedDomain.getRaccourcisAnglais());
+        Assertions.assertEquals(wantedDomain.getValeur(), expectedDomain.getValeur());
+        Assertions.assertEquals(wantedDomain.getSource(), expectedDomain.getSource());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void save_shouldSaveAndReturnNull(MixElectrique nullValue) {
+        var expectedDomain = assertDoesNotThrow(() -> jpaAdapter.save(nullValue));
+
+        assertNull(expectedDomain);
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3ac93f29b05b7686c65425b76321af816b81bde
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/correspondance/ReferentielCorrespondanceRefEquipementRestApiImplTest.java
@@ -0,0 +1,88 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.correspondance;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CorrespondanceRefEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.CorrespondanceRefEquipemenetCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.CorrespondanceRefEquipementFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielCorrespondanceRefEquipementRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielCorrespondanceRefEquipementRestApiImplTest {
+
+    @Autowired
+    private ReferentielCorrespondanceRefEquipementRestApiImpl referentielRestApi;
+
+    @MockBean
+    private CorrespondanceRefEquipementFacade referentielFacade;
+
+    @MockBean
+    private CorrespondanceRefEquipemenetCsvExportService csvExportService;
+
+    @Test
+    void get_shouldCallFacadeGetAndReturnCorrespondingDTO() throws ReferentielException {
+        var wantedId = "modeleSource";
+        CorrespondanceRefEquipementDTO expectedDto = CorrespondanceRefEquipementDTO.builder()
+                .modeleEquipementSource(wantedId)
+                .refEquipementCible("test")
+                .build();
+        when(referentielFacade.get(wantedId)).thenReturn(expectedDto);
+        CorrespondanceRefEquipementDTO resultDto = referentielRestApi.get(wantedId);
+        assertSame(expectedDto, resultDto);
+        verify(referentielFacade).get(wantedId);
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=correspondancesRefEquipement-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9d1a385387b1ec064b5ceca3272f043a8f40947
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/critere/ReferentielCritereRestApiImplTest.java
@@ -0,0 +1,87 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.CritereCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.CritereFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielCritereRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielCritereRestApiImplTest {
+    @Autowired
+    private ReferentielCritereRestApiImpl referentielRestApi;
+
+    @MockBean
+    private CritereFacade referentielFacade;
+
+    @MockBean
+    private CritereCsvExportService csvExportService;
+
+    @Test
+    void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() {
+        ArrayList<CritereDTO> critereDTOList = new ArrayList<>();
+        when(referentielFacade.getAll()).thenReturn(critereDTOList);
+        List<CritereDTO> actualAll = referentielRestApi.getAll();
+        assertSame(critereDTOList, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(referentielFacade).getAll();
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() throws UnsupportedEncodingException {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=criteres-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3929e969003d4fa3f0ffb9496e66f51e59be4427
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/etape/ReferentielEtapeRestApiImplTest.java
@@ -0,0 +1,87 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.EtapeCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.EtapeFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielEtapeRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielEtapeRestApiImplTest {
+    @Autowired
+    private ReferentielEtapeRestApiImpl referentielRestApi;
+
+    @MockBean
+    private EtapeFacade referentielFacade;
+
+    @MockBean
+    private EtapeCsvExportService csvExportService;
+
+    @Test
+    void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() {
+        ArrayList<EtapeDTO> EtapeDTOList = new ArrayList<>();
+        when(referentielFacade.getAll()).thenReturn(EtapeDTOList);
+        List<EtapeDTO> actualAll = referentielRestApi.getAll();
+        assertSame(EtapeDTOList, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(referentielFacade).getAll();
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() throws UnsupportedEncodingException {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=etapes-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3afe264b8e77ffbc8ec048e80c7328f3988d187b
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/hypothese/ReferentielHypotheseRestApiImplTest.java
@@ -0,0 +1,99 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.HypotheseCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.HypotheseIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.HypotheseFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielHypotheseRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielHypotheseRestApiImplTest {
+    @Autowired
+    private ReferentielHypotheseRestApiImpl referentielRestApi;
+
+    @MockBean
+    private HypotheseFacade referentielFacade;
+
+    @MockBean
+    private HypotheseCsvExportService csvExportService;
+
+    @Test
+    void get_shouldCallFacadeGetAndReturnMatchingDTO() throws ReferentielException {
+        String cle = "cle";
+        HypotheseIdDTO idDTO = new HypotheseIdDTO().setCode(cle);
+        var expectedDTO = HypotheseDTO.builder().code(cle).valeur("test").build();
+
+
+        when(referentielFacade.get(idDTO)).thenReturn(expectedDTO);
+        var receivedDTO = referentielRestApi.get(cle);
+        assertSame(receivedDTO, receivedDTO);
+        verify(referentielFacade).get(idDTO);
+    }
+
+    @Test
+    void get_whenNotFound_thenShouldThrowReferentielException() throws ReferentielException {
+        String cle = "cle";
+        HypotheseIdDTO idDTO = new HypotheseIdDTO().setCode(cle);
+
+        when(referentielFacade.get(idDTO)).thenThrow(new ReferentielException("Hypothèse non trouvé"));
+        var exception = assertThrows(ReferentielException.class,() -> referentielRestApi.get(cle));
+        assertEquals("Hypothèse non trouvé", exception.getMessage());
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() throws UnsupportedEncodingException {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=hypotheses-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1273d3335bd4bd0ceab730022b0f8cec45a535d
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactequipement/ReferentielImpactEquipementRestApiImplTest.java
@@ -0,0 +1,115 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactequipement;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactEquipementCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactEquipementIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactEquipementFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielImpactEquipementRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielImpactEquipementRestApiImplTest {
+    @Autowired
+    private ReferentielImpactEquipementRestApiImpl referentielRestApi;
+
+    @MockBean
+    private ImpactEquipementFacade referentielFacade;
+
+    @MockBean
+    private ImpactEquipementCsvExportService csvExportService;
+
+    @Test
+    void get_shouldCallFacadeGetAndReturnMatchingDTO() throws ReferentielException {
+        String refEquipement = "Ordinateur Portable";
+        String nomCritere = "Changement Climatique";
+        String codeEtapeACV = "UTILISATION";
+        var idDTO = new ImpactEquipementIdDTO(refEquipement,
+                codeEtapeACV,
+                nomCritere
+        );
+        var expectedDTO = ImpactEquipementDTO.builder()
+                .etape(codeEtapeACV)
+                .critere(nomCritere)
+                .refEquipement(refEquipement)
+                .source("Test")
+                .description("Test")
+                .valeur(1.0).build();
+
+        when(referentielFacade.get(idDTO)).thenReturn(expectedDTO);
+
+        var receivedDTO = referentielRestApi.get(refEquipement, nomCritere, codeEtapeACV);
+        assertSame(receivedDTO, receivedDTO);
+        verify(referentielFacade).get(idDTO);
+    }
+
+    @Test
+    void get_whenNotFound_thenShouldThrowReferentielException() throws ReferentielException {
+        String refEquipement = "Ordinateur Portable";
+        String nomCritere = "Changement Climatique";
+        String codeEtapeACV = "UTILISATION";
+        var idDTO = new ImpactEquipementIdDTO(refEquipement,
+                codeEtapeACV,
+                nomCritere
+        );
+
+        when(referentielFacade.get(idDTO)).thenThrow(new ReferentielException("Impact Equipement non trouvé"));
+        var exception = assertThrows(ReferentielException.class,() -> referentielRestApi.get(refEquipement, nomCritere, codeEtapeACV));
+        assertEquals("Impact Equipement non trouvé", exception.getMessage());
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() throws UnsupportedEncodingException {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=impactEquipement-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..244bae39ade449f1713afbf077fe1ca44624b394
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactmessagerie/ReferentielImpactMessagerieRestApiImplTest.java
@@ -0,0 +1,87 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactMessagerieCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactMessagerieFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielImpactMessagerieRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielImpactMessagerieRestApiImplTest {
+    @Autowired
+    private ReferentielImpactMessagerieRestApiImpl referentielRestApi;
+
+    @MockBean
+    private ImpactMessagerieFacade referentielFacade;
+
+    @MockBean
+    private ImpactMessagerieCsvExportService csvExportService;
+
+    @Test
+    void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() {
+        ArrayList<ImpactMessagerieDTO> dtos = new ArrayList<>();
+        when(referentielFacade.getAllImpactMessagerie()).thenReturn(dtos);
+        List<ImpactMessagerieDTO> actualAll = referentielRestApi.getAllImpactMessagerie();
+        assertSame(dtos, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(referentielFacade).getAllImpactMessagerie();
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() throws UnsupportedEncodingException {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=impactMessagerie-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9016bfe312de57626be5e16ca78ccdce564a6b8
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/impactreseau/ReferentielImpactReseauRestApiImplTest.java
@@ -0,0 +1,180 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.ImpactReseauCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.ImpactReseauIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.ImpactReseauFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielImpactReseauRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielImpactReseauRestApiImplTest {
+    @MockBean
+    private ImpactReseauFacade referentielFacade;
+
+    @MockBean
+    private ImpactReseauCsvExportService csvExportService;
+
+    @Autowired
+    private ReferentielImpactReseauRestApiImpl referentielRestApi;
+
+    @Test
+    void get_shouldCallFacadeGetAndReturnMatchingDTO() throws ReferentielException {
+        String refReseau = "ImpactReseauMobileMoyen";
+        String nomCritere = "Changement Climatique";
+        String codeEtapeACV = "UTILISATION";
+        var idDTO = ImpactReseauIdDTO.builder()
+                .refReseau(refReseau)
+                .etapeACV(codeEtapeACV)
+                .critere(nomCritere)
+                .build();
+        var expectedDTO = ImpactReseauDTO.builder()
+                .etapeACV(codeEtapeACV)
+                .critere(nomCritere)
+                .refReseau(refReseau)
+                .source("Test")
+                .valeur(1.0).build();
+
+        when(referentielFacade.get(idDTO)).thenReturn(expectedDTO);
+
+        var receivedDTO = referentielRestApi.get(refReseau, nomCritere, codeEtapeACV);
+        assertSame(receivedDTO, receivedDTO);
+        verify(referentielFacade).get(idDTO);
+    }
+
+    @Test
+    void get_whenNotFound_thenShouldThrowReferentielException() throws ReferentielException {
+        String refReseau = "ImpactReseauMobileMoyen";
+        String nomCritere = "Changement Climatique";
+        String codeEtapeACV = "UTILISATION";
+        var idDTO = ImpactReseauIdDTO.builder()
+                .refReseau(refReseau)
+                .etapeACV(codeEtapeACV)
+                .critere(nomCritere)
+                .build();
+
+        when(referentielFacade.get(idDTO)).thenThrow(new ReferentielException("Impact Réseau non trouvé"));
+        var exception = assertThrows(ReferentielException.class,() -> referentielRestApi.get(refReseau, nomCritere, codeEtapeACV));
+        assertEquals("Impact Réseau non trouvé", exception.getMessage());
+    }
+
+    @Test
+    void add_shouldCallFacadeAddOrUpdate() throws ReferentielException {
+        ImpactReseauDTO impactReseauDTO = new ImpactReseauDTO("ImpactReseauMobileMoyen", "UTILISATION",
+                "Changement Climatique", "kg CO² eq", "La source est obligatoire", 10.0d, 10.0d);
+        when(referentielFacade.addOrUpdate(any())).thenReturn(impactReseauDTO);
+
+        ResponseEntity<ImpactReseauDTO> actualAddResult = referentielRestApi.add(impactReseauDTO);
+
+        assertTrue(actualAddResult.hasBody());
+        assertTrue(actualAddResult.getHeaders().isEmpty());
+        assertEquals(HttpStatus.OK, actualAddResult.getStatusCode());
+        assertEquals(impactReseauDTO, actualAddResult.getBody());
+        verify(referentielFacade).addOrUpdate(any());
+    }
+
+    @Test
+    void add_whenEmptySource_shouldThrowBadRequestException() {
+        ImpactReseauDTO impactReseauDTO = new ImpactReseauDTO("ImpactReseauMobileMoyen", "UTILISATION",
+                "Changement Climatique", "kg CO² eq", null, 10.0d, 10.0d);
+
+        var exception = assertThrows(ResponseStatusException.class, () -> referentielRestApi.add(impactReseauDTO));
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("La source est obligatoire", exception.getReason());
+    }
+
+    @Test
+    void add_whenNullValue_shouldThrowBadRequestException() {
+        var exception = assertThrows(ResponseStatusException.class, () -> referentielRestApi.add(null));
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("Le corps de la requête ne peut être null", exception.getReason());
+    }
+
+    @Test
+    void update_shouldCallFacadeAddOrUpdate() throws ReferentielException {
+        when(referentielFacade.addOrUpdate(any())).thenReturn(new ImpactReseauDTO());
+        ImpactReseauDTO impactReseauDTO = new ImpactReseauDTO("ImpactReseauMobileMoyen", "UTILISATION",
+                "Changement Climatique", "kg CO² eq", "La source est obligatoire", 10.0d, 10.0d);
+
+        ResponseEntity<ImpactReseauDTO> actualAddResult = referentielRestApi.update(impactReseauDTO);
+
+        assertTrue(actualAddResult.hasBody());
+        assertTrue(actualAddResult.getHeaders().isEmpty());
+        assertEquals(HttpStatus.OK, actualAddResult.getStatusCode());
+        verify(referentielFacade).addOrUpdate(any());
+    }
+
+    @Test
+    void update_whenEmptySource_shouldThrowBadRequestException() throws ReferentielException {
+        when(referentielFacade.addOrUpdate(any())).thenReturn(new ImpactReseauDTO());
+        ImpactReseauDTO impactReseauDTO = new ImpactReseauDTO("ImpactReseauMobileMoyen", "UTILISATION",
+                "Changement Climatique", "kg CO² eq", "", 10.0d, 10.0d);
+
+        var exception = assertThrows(ResponseStatusException.class, () -> referentielRestApi.update(impactReseauDTO));
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("La source est obligatoire", exception.getReason());
+    }
+
+    @Test
+    void update_whenNullValue_shouldThrowBadRequestException() {
+        var exception = assertThrows(ResponseStatusException.class, () -> referentielRestApi.update(null));
+        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+        assertEquals("Le corps de la requête ne peut être null", exception.getReason());
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=impactReseaux-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cf890c6900a59c54c5c7303d17e15bfbd78f2c1
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/mixelectrique/ReferentielMixElectriqueRestApiImplTest.java
@@ -0,0 +1,108 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.mixelectrique;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.MixElectriqueDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.MixElectriqueCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.MixElectriqueIdDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.MixElectriqueFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielMixElecRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielMixElectriqueRestApiImplTest {
+    @Autowired
+    private ReferentielMixElecRestApiImpl referentielRestApi;
+
+    @MockBean
+    private MixElectriqueFacade referentielFacade;
+
+    @MockBean
+    private MixElectriqueCsvExportService csvExportService;
+
+    @Test
+    void get_shouldCallFacadeGetAndReturnMatchingDTO() throws ReferentielException {
+        String pays = "France";
+        String nomCritere = "Changement Climatique";
+        var idDTO = new MixElectriqueIdDTO(pays,
+                nomCritere
+        );
+        var expectedDTO = MixElectriqueDTO.builder()
+                .critere(nomCritere)
+                .pays(pays)
+                .source("Test")
+                .valeur(1.0).build();
+
+        when(referentielFacade.get(idDTO)).thenReturn(expectedDTO);
+
+        var receivedDTO = referentielRestApi.get(pays, nomCritere);
+        assertSame(receivedDTO, receivedDTO);
+        verify(referentielFacade).get(idDTO);
+    }
+
+    @Test
+    void get_whenNotFound_thenShouldThrowReferentielException() throws ReferentielException {
+        String pays = "France";
+        String nomCritere = "Changement Climatique";
+        var idDTO = new MixElectriqueIdDTO(pays,
+                nomCritere
+        );
+
+        when(referentielFacade.get(idDTO)).thenThrow(new ReferentielException("Mix Electrique non trouvé"));
+        var exception = assertThrows(ReferentielException.class,() -> referentielRestApi.get(pays, nomCritere));
+        assertEquals("Mix Electrique non trouvé", exception.getMessage());
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=mixElec-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
+
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..41fb1b49a08862a416e14b15f7a051952923aa50
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImplTest.java
@@ -0,0 +1,97 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeEquipementCsvExportService;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeEquipementFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.server.ResponseStatusException;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ContextConfiguration(classes = {ReferentielTypeEquipementRestApiImpl.class})
+@ExtendWith(SpringExtension.class)
+class ReferentielTypeEquipementRestApiImplTest {
+    @Autowired
+    private ReferentielTypeEquipementRestApiImpl referentielRestApi;
+
+    @MockBean
+    private TypeEquipementFacade referentielFacade;
+
+    @MockBean
+    private TypeEquipementCsvExportService csvExportService;
+
+    @Test
+    void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() {
+        ArrayList<TypeEquipementDTO> typeEquipementDTOS = new ArrayList<>();
+        when(referentielFacade.getAllTypesEquipement()).thenReturn(typeEquipementDTOS);
+        List<TypeEquipementDTO> actualAll = referentielRestApi.getTypesEquipement();
+        assertSame(typeEquipementDTOS, actualAll);
+        assertTrue(actualAll.isEmpty());
+        verify(referentielFacade).getAllTypesEquipement();
+    }
+
+    @Test
+    void getTypeEquipement_shouldCallFacadeGetAndReturnDTO() throws ReferentielException {
+        String expectedType = "Switch";
+        TypeEquipementDTO expectedDTO = TestDataFactory.TypeEquipementFactory.dto(expectedType, true, 1.0, "test", "test","test");
+        when(referentielFacade.getTypeEquipementForType(expectedType)).thenReturn(expectedDTO);
+        TypeEquipementDTO actualResponse = referentielRestApi.getTypeEquipement(expectedType);
+        assertSame(expectedDTO, actualResponse);
+        verify(referentielFacade).getTypeEquipementForType(expectedType);
+    }
+
+    @Test
+    void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8)));
+        verify(referentielFacade).purgeAndAddAll(any());
+    }
+
+    @Test
+    void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null);
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(file));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException {
+        doNothing().when(referentielFacade).purgeAndAddAll(any());
+        ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> referentielRestApi.importCSV(null));
+        assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode());
+        assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason());
+    }
+
+    @Test
+    void exportCSV_shouldReturnCSVFile() {
+        var servletResponse = new MockHttpServletResponse();
+
+        assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse));
+
+        assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType());
+        String headerContentDisposition = servletResponse.getHeader("Content-Disposition");
+        assertNotNull(headerContentDisposition);
+        assertTrue(headerContentDisposition.contains("attachment; filename=typeEquipement-"));
+        assertEquals(200, servletResponse.getStatus());
+
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b43464fbe9ee4533f4d3989e806e00cacea12b27
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CorrespondanceRefEquipementFacadeTest.java
@@ -0,0 +1,112 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CorrespondanceRefEquipementMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CorrespondanceRefEquipementFacadeTest {
+
+    @InjectMocks
+    CorrespondanceRefEquipementFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<CorrespondanceRefEquipement, String> persistencePort;
+
+    private CorrespondanceRefEquipementMapper mapper = new CorrespondanceRefEquipementMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = "modele";
+        var expectedDomainID = "modele";
+        var expectedDomain = TestDataFactory.CorrespondanceRefEquipementFactory.domain(
+                "modele", "refCible");
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var result = Assertions.assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+        assertEquals(expectedDomain.getModeleEquipementSource(), result.getModeleEquipementSource());
+        assertEquals(expectedDomain.getRefEquipementCible(), result.getRefEquipementCible());
+    }
+
+    @Test
+    void get_withNonMachingDTOShouldReturnNull() throws ReferentielException {
+        var wantedDTOId = "modele";
+        var expectedDomainID = "modele";
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(null);
+
+        var result = Assertions.assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+        assertNull(result);
+    }
+
+    @Test
+    void getAll_shouldReturnMatchingAllDTOs() throws ReferentielException {
+        var expectedDomains = Arrays.asList(
+                TestDataFactory.CorrespondanceRefEquipementFactory.domain("modele", "refCible"),
+                TestDataFactory.CorrespondanceRefEquipementFactory.domain("modele2", "refCible")
+                );
+
+        Mockito.when(persistencePort.getAll()).thenReturn(expectedDomains);
+
+        var result = Assertions.assertDoesNotThrow(() -> facadeToTest.getAll());
+
+        assertEquals(2, result.size());
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.CorrespondanceRefEquipementFactory.dto(
+                        "modele01",  "refCible"
+                ),
+                TestDataFactory.CorrespondanceRefEquipementFactory.dto(
+                        "modele02",  "refCible"
+                )
+        );
+        ArgumentCaptor<Collection<CorrespondanceRefEquipement>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain -> dto.getModeleEquipementSource().equals(domain.getModeleEquipementSource()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var domain = matchingDomain.get();
+
+            assertEquals(dto.getModeleEquipementSource(), domain.getModeleEquipementSource());
+            assertEquals(dto.getRefEquipementCible(), domain.getRefEquipementCible());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b38d138899793860175d5bdffa3e4fe173a35ffa
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/CritereFacadeTest.java
@@ -0,0 +1,96 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Critere;
+import org.mte.numecoeval.referentiel.domain.model.id.CritereId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CritereMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.CritereMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mte.numecoeval.referentiel.factory.TestDataFactory.DEFAULT_CRITERE;
+import static org.mte.numecoeval.referentiel.factory.TestDataFactory.DEFAULT_UNITE;
+
+class CritereFacadeTest {
+
+    @InjectMocks
+    CritereFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<Critere, CritereId> persistencePort;
+
+    private CritereMapper mapper = new CritereMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void getAll_ShouldAllReturnMatchingDTO() {
+        var expectedDomains = Arrays.asList(
+                TestDataFactory.CritereFactory.domain(DEFAULT_CRITERE, "test", DEFAULT_UNITE),
+                TestDataFactory.CritereFactory.domain("Acidification", "Autre Test", "m3 eau")
+        );
+
+        Mockito.when(persistencePort.getAll()).thenReturn(expectedDomains);
+
+        var result = assertDoesNotThrow( () -> facadeToTest.getAll() );
+
+        assertEquals(expectedDomains.size(), result.size());
+
+        expectedDomains.forEach( expectedDomain -> {
+            var matchingDTO = result.stream()
+                    .filter(critereDTO -> expectedDomain.getNomCritere().equals(critereDTO.getNomCritere()))
+                    .findAny();
+
+            assertTrue(matchingDTO.isPresent(), "Il n'existe pas de DTO correspondant au domain");
+            var resultDTO = matchingDTO.get();
+            assertEquals(expectedDomain.getNomCritere(), resultDTO.getNomCritere());
+            assertEquals(expectedDomain.getDescription(), resultDTO.getDescription());
+            assertEquals(expectedDomain.getUnite(), resultDTO.getUnite());
+
+        });
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.CritereFactory.dto(DEFAULT_CRITERE, "test", DEFAULT_UNITE),
+                TestDataFactory.CritereFactory.dto("Acidification", "Autre Test", "m3 eau")
+        );
+        ArgumentCaptor<Collection<Critere>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain -> dto.getNomCritere().equals(domain.getNomCritere()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var critere = matchingDomain.get();
+            assertEquals(dto.getNomCritere(), critere.getNomCritere());
+            assertEquals(dto.getDescription(), critere.getDescription());
+            assertEquals(dto.getUnite(), critere.getUnite());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5514c7bab7aa5506bcc45b6bb3f97ae24a284b00
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/EtapeFacadeTest.java
@@ -0,0 +1,92 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Etape;
+import org.mte.numecoeval.referentiel.domain.model.id.EtapeId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.EtapeMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.EtapeMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EtapeFacadeTest {
+
+    @InjectMocks
+    EtapeFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<Etape, EtapeId> persistencePort;
+
+    private EtapeMapper mapper = new EtapeMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void getAll_ShouldAllReturnMatchingDTO() {
+        var expectedDomains = Arrays.asList(
+                TestDataFactory.EtapeFactory.domain(TestDataFactory.DEFAULT_CRITERE, "test"),
+                TestDataFactory.EtapeFactory.domain("Acidification", "Autre Test")
+        );
+
+        Mockito.when(persistencePort.getAll()).thenReturn(expectedDomains);
+
+        var result = assertDoesNotThrow( () -> facadeToTest.getAll() );
+
+        assertEquals(expectedDomains.size(), result.size());
+
+        expectedDomains.forEach( expectedDomain -> {
+            var matchingDTO = result.stream()
+                    .filter(dto -> expectedDomain.getCode().equals(dto.getCode()))
+                    .findAny();
+
+            assertTrue(matchingDTO.isPresent(), "Il n'existe pas de DTO correspondant au domain");
+            var resultDTO = matchingDTO.get();
+            assertEquals(expectedDomain.getCode(), resultDTO.getCode());
+            assertEquals(expectedDomain.getLibelle(), resultDTO.getLibelle());
+
+        });
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.EtapeFactory.dto(TestDataFactory.DEFAULT_CRITERE, "test"),
+                TestDataFactory.EtapeFactory.dto("Acidification", "Autre Test")
+        );
+        ArgumentCaptor<Collection<Etape>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedCriteres = valueCapture.getValue();
+        assertNotNull(expectedCriteres);
+        assertEquals(dtosToSave.size(), expectedCriteres.size());
+        dtosToSave.forEach(dto -> {
+            var matchingCriteres = expectedCriteres.stream()
+                    .filter(domain -> dto.getCode().equals(domain.getCode()))
+                    .findAny();
+            assertTrue(matchingCriteres.isPresent());
+            var critere = matchingCriteres.get();
+            assertEquals(dto.getCode(), critere.getCode());
+            assertEquals(dto.getLibelle(), critere.getLibelle());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e40c311bcdb9ca408a4d61c9a58bf9747920e42
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java
@@ -0,0 +1,109 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.Hypothese;
+import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.HypotheseMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HypotheseFacadeTest {
+
+    @InjectMocks
+    HypotheseFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<Hypothese, HypotheseId> persistencePort;
+
+    private HypotheseMapper mapper = new HypotheseMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = TestDataFactory.HypotheseFactory.idDTO("code");
+        var expectedDomainID = TestDataFactory.HypotheseFactory.idDomain("code");
+        var expectedDomain = TestDataFactory.HypotheseFactory.domain("code", "1.1", "Test");
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var result = assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+        assertEquals(expectedDomain.getCode(), result.getCode());
+        assertEquals(expectedDomain.getValeur(), result.getValeur());
+        assertEquals(expectedDomain.getSource(), result.getSource());
+    }
+
+    @Test
+    void getAll_ShouldAllReturnMatchingDTO() {
+        var expectedDomains = Arrays.asList(
+                TestDataFactory.HypotheseFactory.domain("code", "2.0", "Test"),
+                TestDataFactory.HypotheseFactory.domain("code2", "3.0", "Test")
+        );
+
+        Mockito.when(persistencePort.getAll()).thenReturn(expectedDomains);
+
+        var result = assertDoesNotThrow( () -> facadeToTest.getAll() );
+
+        assertEquals(expectedDomains.size(), result.size());
+
+        expectedDomains.forEach( expectedDomain -> {
+            var matchingDTO = result.stream()
+                    .filter(critereDTO -> expectedDomain.getCode().equals(critereDTO.getCode()))
+                    .findAny();
+
+            assertTrue(matchingDTO.isPresent(), "Il n'existe pas de DTO correspondant au domain");
+            var resultDTO = matchingDTO.get();
+            assertEquals(expectedDomain.getCode(), resultDTO.getCode());
+            assertEquals(expectedDomain.getValeur(), resultDTO.getValeur());
+            assertEquals(expectedDomain.getSource(), resultDTO.getSource());
+
+        });
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.HypotheseFactory.dto("hyp", "1.0", "Test"),
+                TestDataFactory.HypotheseFactory.dto("hyp2", "m3", "Autre Test")
+        );
+        ArgumentCaptor<Collection<Hypothese>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingCriteres = expectedDomains.stream()
+                    .filter(domain -> dto.getCode().equals(domain.getCode()))
+                    .findAny();
+            assertTrue(matchingCriteres.isPresent());
+            var critere = matchingCriteres.get();
+            assertEquals(dto.getCode(), critere.getCode());
+            assertEquals(dto.getSource(), critere.getSource());
+            assertEquals(dto.getValeur(), critere.getValeur());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..19f6fe324d1105f5386dd7d6ebf93499f1e9f13e
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactEquipementFacadeTest.java
@@ -0,0 +1,113 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactEquipementId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactEquipementMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ImpactEquipementFacadeTest {
+
+    @InjectMocks
+    ImpactEquipementFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<ImpactEquipement, ImpactEquipementId> persistencePort;
+
+    private ImpactEquipementMapper mapper = new ImpactEquipementMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = TestDataFactory.ImpactEquipementFactory.idDTO(
+                TestDataFactory.DEFAULT_ETAPE,
+                TestDataFactory.DEFAULT_CRITERE,
+                "Ecran 27 pouces"
+        );
+        var expectedDomainID = TestDataFactory.ImpactEquipementFactory.idDomain(
+                TestDataFactory.DEFAULT_ETAPE,
+                TestDataFactory.DEFAULT_CRITERE,
+                "Ecran 27 pouces"
+        );
+        var expectedDomain = TestDataFactory.ImpactEquipementFactory.domain(
+                TestDataFactory.EtapeFactory.domain(TestDataFactory.DEFAULT_ETAPE, "Test"),
+                TestDataFactory.CritereFactory.domain(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                "Ecran 27 pouces", "Test", "Monitor", 0.12, 0.0012
+        );
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var dto = assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+        Assertions.assertEquals(expectedDomain.getEtape(), dto.getEtape());
+        Assertions.assertEquals(expectedDomain.getCritere(), dto.getCritere());
+        Assertions.assertEquals(expectedDomain.getRefEquipement(), dto.getRefEquipement());
+        Assertions.assertEquals(expectedDomain.getType(), dto.getType());
+        Assertions.assertEquals(expectedDomain.getSource(), dto.getSource());
+        Assertions.assertEquals(expectedDomain.getValeur(), dto.getValeur());
+        Assertions.assertEquals(expectedDomain.getConsoElecMoyenne(), dto.getConsoElecMoyenne());
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.ImpactEquipementFactory.dto(
+                        TestDataFactory.DEFAULT_ETAPE,
+                        TestDataFactory.DEFAULT_CRITERE,
+                        "Ecran 27 pouces", "Test", "Monitor", 0.12, 0.0012,
+                        "test"),
+                TestDataFactory.ImpactEquipementFactory.dto(
+                        "FIN_DE_VIE",
+                        "Acidification",
+                        "Ecran 27 pouces", "Test", "Monitor", 0.12, 0.0012,
+                        "test")
+        );
+        ArgumentCaptor<Collection<ImpactEquipement>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain ->
+                            dto.getEtape().equals(domain.getEtape())
+                            && dto.getCritere().equals(domain.getCritere())
+                            && dto.getRefEquipement().equals(domain.getRefEquipement()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var domain = matchingDomain.get();
+            assertEquals(dto.getEtape(), domain.getEtape());
+            assertEquals(dto.getCritere(), domain.getCritere());
+            assertEquals(dto.getRefEquipement(), domain.getRefEquipement());
+            assertEquals(dto.getType(), domain.getType());
+            assertEquals(dto.getSource(), domain.getSource());
+            assertEquals(dto.getValeur(), domain.getValeur());
+            assertEquals(dto.getConsoElecMoyenne(), domain.getConsoElecMoyenne());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c9fc73ca37eb2ed39af6f9a202768e8faa81f2b
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactMessagerieFacadeTest.java
@@ -0,0 +1,126 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactMessagerie;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactMessagerieMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mte.numecoeval.referentiel.factory.TestDataFactory.DEFAULT_CRITERE;
+import static org.mte.numecoeval.referentiel.factory.TestDataFactory.DEFAULT_UNITE;
+
+class ImpactMessagerieFacadeTest {
+
+    @InjectMocks
+    ImpactMessagerieFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<ImpactMessagerie, String> persistencePort;
+
+    private ImpactMessagerieMapper mapper = new ImpactMessagerieMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = DEFAULT_CRITERE;
+        var expectedDomainID = DEFAULT_CRITERE;
+        var expectedDomain = TestDataFactory.ImpactMessagerieFactory.domain(
+                TestDataFactory.CritereFactory.domain(DEFAULT_CRITERE, DEFAULT_UNITE, DEFAULT_CRITERE),
+                2.0, 0.0005, "test"
+        );
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var result = Assertions.assertDoesNotThrow(() -> facadeToTest.getImpactMessagerieForCritere(wantedDTOId));
+
+        assertEquals(expectedDomain.getCritere(), result.getCritere());
+        assertEquals(expectedDomain.getConstanteCoefficientDirecteur(), result.getConstanteCoefficientDirecteur());
+        assertEquals(expectedDomain.getConstanteOrdonneeOrigine(), result.getConstanteOrdonneeOrigine());
+        assertEquals(expectedDomain.getSource(), result.getSource());
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.ImpactMessagerieFactory.dto(
+                        TestDataFactory.CritereFactory.dto(DEFAULT_CRITERE, DEFAULT_UNITE, DEFAULT_CRITERE),
+                        2.0, 0.0005, "test"
+                ),
+                TestDataFactory.ImpactMessagerieFactory.dto(
+                        TestDataFactory.CritereFactory.dto("Acidification", "m3", "Autre Test"),
+                        0.005051, 0.0000000523, "test"
+                )
+        );
+        ArgumentCaptor<Collection<ImpactMessagerie>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain -> dto.getCritere().equals(domain.getCritere()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var domain = matchingDomain.get();
+            assertEquals(dto.getCritere(), domain.getCritere());
+            assertEquals(dto.getConstanteCoefficientDirecteur(), domain.getConstanteCoefficientDirecteur());
+            assertEquals(dto.getConstanteOrdonneeOrigine(), domain.getConstanteOrdonneeOrigine());
+            assertEquals(dto.getSource(), domain.getSource());
+        });
+    }
+
+    @Test
+    void getAllImpactMessagerie_ShouldReturnAllDataAvailable() throws ReferentielException {
+        var domainsAvailable = Arrays.asList(
+                TestDataFactory.ImpactMessagerieFactory.domain(
+                        TestDataFactory.CritereFactory.domain(DEFAULT_CRITERE, DEFAULT_UNITE, DEFAULT_CRITERE),
+                        2.0, 0.0005, "test"
+                ),
+                TestDataFactory.ImpactMessagerieFactory.domain(
+                        TestDataFactory.CritereFactory.domain("Acidification", "m3", "Autre Test"),
+                        0.005051, 0.0000000523, "test"
+                )
+        );
+        Mockito.when(persistencePort.getAll()).thenReturn(domainsAvailable);
+
+        var expectedDTOs = Assertions.assertDoesNotThrow(() -> facadeToTest.getAllImpactMessagerie());
+
+        Mockito.verify(persistencePort, Mockito.times(1)).getAll();
+
+        domainsAvailable.forEach(domain -> {
+            var matchingDTO = expectedDTOs.stream()
+                    .filter(dto -> domain.getCritere().equals(dto.getCritere()))
+                    .findAny();
+            assertTrue(matchingDTO.isPresent());
+            var dto = matchingDTO.get();
+            assertEquals(domain.getCritere(), dto.getCritere());
+            assertEquals(domain.getConstanteCoefficientDirecteur(), dto.getConstanteCoefficientDirecteur());
+            assertEquals(domain.getConstanteOrdonneeOrigine(), dto.getConstanteOrdonneeOrigine());
+            assertEquals(domain.getSource(), dto.getSource());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3587b1fc4c9ea629e63cbb7abd3325997070db20
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/ImpactReseauFacadeTest.java
@@ -0,0 +1,154 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.ImpactReseau;
+import org.mte.numecoeval.referentiel.domain.model.id.ImpactReseauId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactReseauMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.ImpactReseauMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ImpactReseauFacadeTest {
+
+    @InjectMocks
+    ImpactReseauFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<ImpactReseau, ImpactReseauId> persistencePort;
+
+    private ImpactReseauMapper mapper = new ImpactReseauMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = TestDataFactory.ImpactReseauFactory.idDTO(
+                TestDataFactory.EtapeFactory.idDTO(TestDataFactory.DEFAULT_ETAPE),
+                TestDataFactory.CritereFactory.idDTO(TestDataFactory.DEFAULT_CRITERE),
+                "impactReseauMobileMoyen"
+        );
+        var expectedDomainID = TestDataFactory.ImpactReseauFactory.idDomain(
+                TestDataFactory.EtapeFactory.idDomain(TestDataFactory.DEFAULT_ETAPE),
+                TestDataFactory.CritereFactory.idDomain(TestDataFactory.DEFAULT_CRITERE),
+                "impactReseauMobileMoyen"
+        );
+        var expectedDomain = TestDataFactory.ImpactReseauFactory.domain(
+                TestDataFactory.EtapeFactory.domain(TestDataFactory.DEFAULT_ETAPE, "Test"),
+                TestDataFactory.CritereFactory.domain(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                "impactReseauMobileMoyen", "Test", 0.12, 0.0012
+        );
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var dto = assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+
+        Assertions.assertEquals(expectedDomain.getEtape(), dto.getEtapeACV());
+        Assertions.assertEquals(expectedDomain.getCritere(), dto.getCritere());
+        Assertions.assertEquals(expectedDomain.getRefReseau(), dto.getRefReseau());
+        Assertions.assertEquals(expectedDomain.getSource(), dto.getSource());
+        Assertions.assertEquals(expectedDomain.getValeur(), dto.getValeur());
+        Assertions.assertEquals(expectedDomain.getConsoElecMoyenne(), dto.getConsoElecMoyenne());
+    }
+
+    @Test
+    void addOrUpdate_shouldCallSaveThenReturnMatchingDTO() throws ReferentielException {
+        var dtoToSave = TestDataFactory.ImpactReseauFactory.dto(
+                TestDataFactory.EtapeFactory.dto(TestDataFactory.DEFAULT_ETAPE, "Test"),
+                TestDataFactory.CritereFactory.dto(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                "impactReseauMobileMoyen", "Test", 0.12, 0.0012
+        );
+        Mockito.when(persistencePort.save(Mockito.any())).thenAnswer(invocationOnMock -> invocationOnMock.getArgument(0));
+        ArgumentCaptor<ImpactReseau> valueCapture = ArgumentCaptor.forClass(ImpactReseau.class);
+
+        var savedDTO = assertDoesNotThrow(() -> facadeToTest.addOrUpdate(dtoToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).save(valueCapture.capture());
+
+        var domainSaved = valueCapture.getValue();
+        assertEquals(domainSaved.getEtape(), savedDTO.getEtapeACV());
+        assertEquals(domainSaved.getCritere(), savedDTO.getCritere());
+        assertEquals(domainSaved.getRefReseau(), savedDTO.getRefReseau());
+        assertEquals(domainSaved.getSource(), savedDTO.getSource());
+        assertEquals(domainSaved.getValeur(), savedDTO.getValeur());
+        assertEquals(domainSaved.getConsoElecMoyenne(), savedDTO.getConsoElecMoyenne());
+
+        assertEquals(dtoToSave, savedDTO);
+    }
+
+    @Test
+    void addOrUpdate_whenErrorOnSave_shouldThrowException() throws ReferentielException {
+        var dtoToSave = TestDataFactory.ImpactReseauFactory.dto(
+                TestDataFactory.EtapeFactory.dto("NonExistante", "Test"),
+                TestDataFactory.CritereFactory.dto("NonExistant", TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                "impactReseauMobileMoyen", "Test", 0.12, 0.0012
+        );
+        ConstraintViolationException expectedSaveException = new ConstraintViolationException("Erreur de contrainte sur la table parente", null, "ETAPE");
+        Mockito.when(persistencePort.save(Mockito.any())).thenThrow(expectedSaveException);
+
+        var exception = assertThrows(RuntimeException.class, () -> facadeToTest.addOrUpdate(dtoToSave));
+
+        assertEquals(expectedSaveException, exception);
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.ImpactReseauFactory.dto(
+                        TestDataFactory.EtapeFactory.dto(TestDataFactory.DEFAULT_ETAPE, "Test"),
+                        TestDataFactory.CritereFactory.dto(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                        "impactReseauMobileMoyen", "Monitor", 0.12, 0.0012
+                ),
+                TestDataFactory.ImpactReseauFactory.dto(
+                        TestDataFactory.EtapeFactory.dto("FIN_DE_VIE", "Autre Test"),
+                        TestDataFactory.CritereFactory.dto("Acidification", "m3", "Autre Test"),
+                        "impactReseauMobileMoyen", "Monitor", 0.12, 0.0012
+                )
+        );
+        ArgumentCaptor<Collection<ImpactReseau>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain ->
+                            dto.getEtapeACV().equals(domain.getEtape())
+                            && dto.getCritere().equals(domain.getCritere())
+                            && dto.getRefReseau().equals(domain.getRefReseau()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var domain = matchingDomain.get();
+            assertEquals(dto.getEtapeACV(), domain.getEtape());
+            assertEquals(dto.getCritere(), domain.getCritere());
+            assertEquals(dto.getRefReseau(), domain.getRefReseau());
+            assertEquals(dto.getSource(), domain.getSource());
+            assertEquals(dto.getValeur(), domain.getValeur());
+            assertEquals(dto.getConsoElecMoyenne(), domain.getConsoElecMoyenne());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacadeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e88502887af3c1789617ae8604d13f13c743a820
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/MixElectriqueFacadeTest.java
@@ -0,0 +1,103 @@
+package org.mte.numecoeval.referentiel.infrastructure.restapi.facade;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.domain.model.MixElectrique;
+import org.mte.numecoeval.referentiel.domain.model.id.MixElectriqueId;
+import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort;
+import org.mte.numecoeval.referentiel.factory.TestDataFactory;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapper;
+import org.mte.numecoeval.referentiel.infrastructure.mapper.MixElectriqueMapperImpl;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MixElectriqueFacadeTest {
+
+    @InjectMocks
+    MixElectriqueFacade facadeToTest;
+
+    @Mock
+    private ReferentielPersistencePort<MixElectrique, MixElectriqueId> persistencePort;
+
+    private MixElectriqueMapper mapper = new MixElectriqueMapperImpl();
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+        ReflectionTestUtils.setField(facadeToTest, "mapper", mapper);
+    }
+
+    @Test
+    void get_shouldReturnMatchingDTO() throws ReferentielException {
+        var wantedDTOId = TestDataFactory.MixElectriqueFactory.idDTO(
+                TestDataFactory.CritereFactory.idDTO(TestDataFactory.DEFAULT_CRITERE),
+                "France"
+        );
+        var expectedDomainID = TestDataFactory.MixElectriqueFactory.idDomain(
+                TestDataFactory.CritereFactory.idDomain(TestDataFactory.DEFAULT_CRITERE),
+                "France"
+        );
+        var expectedDomain = TestDataFactory.MixElectriqueFactory.domain(
+                TestDataFactory.CritereFactory.domain(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                "France", "FR", 1.0, "test"
+        );
+
+        Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain);
+
+        var result = assertDoesNotThrow(() -> facadeToTest.get(wantedDTOId));
+
+        Assertions.assertEquals(expectedDomain.getCritere(), result.getCritere());
+        Assertions.assertEquals(expectedDomain.getPays(), result.getPays());
+        Assertions.assertEquals(expectedDomain.getRaccourcisAnglais(), result.getRaccourcisAnglais());
+        Assertions.assertEquals(expectedDomain.getValeur(), result.getValeur());
+        Assertions.assertEquals(expectedDomain.getSource(), result.getSource());
+    }
+
+    @Test
+    void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException {
+        var dtosToSave = Arrays.asList(
+                TestDataFactory.MixElectriqueFactory.dto(
+                        TestDataFactory.CritereFactory.dto(TestDataFactory.DEFAULT_CRITERE, TestDataFactory.DEFAULT_UNITE, TestDataFactory.DEFAULT_CRITERE),
+                        "France", "FR", 1.0, "test"
+                ),
+                TestDataFactory.MixElectriqueFactory.dto(
+                        TestDataFactory.CritereFactory.dto("Acidification", "m3", "Autre Test"),
+                        "France", "FR", 1.0, "test"
+                )
+        );
+        ArgumentCaptor<Collection<MixElectrique>> valueCapture = ArgumentCaptor.forClass(Collection.class);
+
+        assertDoesNotThrow(() -> facadeToTest.purgeAndAddAll(dtosToSave));
+
+        Mockito.verify(persistencePort, Mockito.times(1)).purge();
+        Mockito.verify(persistencePort, Mockito.times(1)).saveAll(valueCapture.capture());
+
+        var expectedDomains = valueCapture.getValue();
+        assertNotNull(expectedDomains);
+        assertEquals(dtosToSave.size(), expectedDomains.size());
+        dtosToSave.forEach(dto -> {
+            var matchingDomain = expectedDomains.stream()
+                    .filter(domain -> dto.getCritere().equals(domain.getCritere())
+                            && dto.getPays().equals(domain.getPays()))
+                    .findAny();
+            assertTrue(matchingDomain.isPresent());
+            var domain = matchingDomain.get();
+            assertEquals(dto.getCritere(), domain.getCritere());
+            assertEquals(dto.getPays(), domain.getPays());
+            assertEquals(dto.getRaccourcisAnglais(), domain.getRaccourcisAnglais());
+            assertEquals(dto.getValeur(), domain.getValeur());
+            assertEquals(dto.getSource(), domain.getSource());
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/AbstractStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/AbstractStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..71c6e4c77baf437fe5ce54549a218756b045dd3f
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/AbstractStepDefinitions.java
@@ -0,0 +1,65 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere.ReferentielAdministrationCritereRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape.ReferentielAdministrationEtapeRestApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Objects;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@Transactional
+public abstract class AbstractStepDefinitions {
+
+    @Autowired
+    protected Environment environment;
+
+    protected Response response;
+
+    /**
+     * Configuration par défaut pour les clients d'API
+     */
+    protected void setupRestAssured() {
+        RestAssured.baseURI = "http://localhost";
+        RestAssured.port = Integer.parseInt(Objects.requireNonNull(environment.getProperty("server.port")));
+    }
+
+    /**
+     * Initialisation des référentiels étapes et critères avec des valeurs par défaut.
+     * @throws FileNotFoundException
+     * @throws NoSuchMethodException
+     */
+    protected void initAlimentationEtapeEtCritere() throws FileNotFoundException, NoSuchMethodException {
+        RestAssured.baseURI = "http://localhost";
+        RestAssured.port = Integer.parseInt(Objects.requireNonNull(environment.getProperty("server.port")));
+        File fileCritere = ResourceUtils.getFile("classpath:" + "csv/ref_Critere.csv");
+        File fileEtape = ResourceUtils.getFile("classpath:" + "csv/ref_etapeACV.csv");
+        //chargement Etape
+        String path = Arrays.stream(ReferentielAdministrationCritereRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .multiPart("file", fileCritere)
+                .post(path)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+
+        path = Arrays.stream(ReferentielAdministrationEtapeRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", fileEtape)
+                .post(path)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CorrespondanceRefEquipementStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CorrespondanceRefEquipementStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a5f7896dbd0d354d173f0d98f3f29fea280b287
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CorrespondanceRefEquipementStepDefinitions.java
@@ -0,0 +1,71 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.DataTableType;
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import org.mte.numecoeval.referentiel.domain.model.CorrespondanceRefEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.CorrespondanceRefEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.correspondance.ReferentielAdministrationCorrespondanceRefEquipementRestApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class CorrespondanceRefEquipementStepDefinitions extends AbstractStepDefinitions {
+
+    @Autowired
+    CorrespondanceRefEquipementJpaAdapter jpaAdapter;
+
+    @DataTableType
+    public CorrespondanceRefEquipement correspondanceRefEquipement(Map<String, String> entry) {
+        return CorrespondanceRefEquipement.builder()
+                .modeleEquipementSource(entry.get("modeleEquipementSource"))
+                .refEquipementCible(entry.get("refEquipementCible"))
+                .build();
+    }
+
+    @Quand("le fichier CSV des correspondances d'équipements {string} est importé par API et la réponse est {int}")
+    public void importReferentielCorrespondanceRefEquipements(String nomFichier, int codeReponseHttpAttendu) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        initAlimentationEtapeEtCritere();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        String requestPath = Arrays.stream(ReferentielAdministrationCorrespondanceRefEquipementRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
+    }
+
+    @Et("La récupération de tous les correspondances d'équipements renvoie {int} lignes")
+    public void getAllCorrespondanceRefEquipement(int nombreLignesAttendues) throws NoSuchMethodException {
+        List<CorrespondanceRefEquipement> domains = jpaAdapter.getAll();
+
+        assertEquals(nombreLignesAttendues, domains.size());
+    }
+
+    @Alors("Vérifications des correspondances d'équipements disponibles")
+    public void checkImpactEquipements(List<CorrespondanceRefEquipement> dataTable) {
+        List<CorrespondanceRefEquipement> datasInDatabase = jpaAdapter.getAll();
+
+        assertEquals(dataTable.size(), datasInDatabase.size());
+        dataTable.forEach(expected -> {
+            var dataInDatabase = datasInDatabase.stream().filter(data -> data.getModeleEquipementSource().equals(expected.getModeleEquipementSource())).findFirst().orElse(null);
+            assertNotNull(dataInDatabase, "Il existe une correspondance d'équipement avec le modèle %s".formatted(expected.getModeleEquipementSource()));
+
+            assertEquals(expected.getRefEquipementCible(), dataInDatabase.getRefEquipementCible(), "CorrespondanceRefEquipement %s : la référence cible ne matche pas".formatted(expected.getRefEquipementCible()));
+        });
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CritereStepdefs.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CritereStepdefs.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c51f11023d4717822db39e14608b3d0505a5f46
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/CritereStepdefs.java
@@ -0,0 +1,74 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import io.restassured.http.ContentType;
+import io.restassured.response.Response;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.CritereDTO;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportCriterePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere.ReferentielAdministrationCritereRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.critere.ReferentielCritereRestApi;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CritereStepdefs extends AbstractStepDefinitions {
+
+    private List<CritereDTO> critereDTOS;
+
+    private List<CritereDTO> critereCSV;
+
+    @Quand("le fichier CSV {string} est inject")
+    public void leFichierCSVEstInject(String nomFichier) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+
+        // Chargement des données
+        critereCSV = new ImportCriterePortImpl().importCSV(new FileInputStream(file)).getObjects();
+
+        String requestPath = Arrays.stream(ReferentielAdministrationCritereRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        //check que le status est OK
+        assertEquals(200, response.getStatusCode());
+    }
+
+    @Alors("Il existe {int} elements dans le referentiel critere")
+    public void ilExisteElementsDansLeReferentielCritere(int nombreElements) throws NoSuchMethodException {
+        String requestPath = Arrays.stream(ReferentielCritereRestApi.class.getMethod("getAll")
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .get(requestPath)
+                .thenReturn();
+        critereDTOS = Arrays.asList(response.as(CritereDTO[].class));
+        assertEquals(nombreElements, response.as(List.class).size());
+
+    }
+
+    @Et("chacun des elements du referential ajouté est identique au element du fichier csv")
+    public void chacunDesElementsDuReferentialAjouteEstIdentiqueAuElementDuFichierCsv() {
+        List<CritereDTO> resultEgalite = critereCSV.stream().filter(critereEntity ->
+                critereDTOS.stream().anyMatch(api ->
+                        Optional.of(critereEntity.getDescription()).equals(Optional.of(api.getDescription()))
+                                && critereEntity.getNomCritere().equals(api.getNomCritere())
+                                && critereEntity.getUnite().equals(api.getUnite())
+                )).toList();
+        assertEquals(critereCSV.size(), resultEgalite.size());
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/EtapeStepdefs.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/EtapeStepdefs.java
new file mode 100644
index 0000000000000000000000000000000000000000..67807c3ca177d13fc4d8120919fbce52b6bb18de
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/EtapeStepdefs.java
@@ -0,0 +1,76 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import io.restassured.http.ContentType;
+import io.restassured.response.Response;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.EtapeDTO;
+import org.mte.numecoeval.referentiel.domain.data.ResultatImport;
+import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportEtapePortImpl;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape.ReferentielAdministrationEtapeRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.etape.ReferentielEtapeRestApi;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class EtapeStepdefs extends AbstractStepDefinitions {
+    private List<EtapeDTO> etapeCVS;
+    private EtapeDTO[] etapesAPI;
+
+    @Quand("le fichier CSV {string} est injecte")
+    public void leFichierCSVEstInjecte(String nomFichier) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        //stockage des dtos etapes pour verifications avec la ressource rest api apres alimentation
+        ResultatImport<EtapeDTO> resultatImport = new ImportEtapePortImpl().importCSV(new FileInputStream(file));
+        etapeCVS = resultatImport.getObjects();
+        String requestPath = Arrays.stream(ReferentielAdministrationEtapeRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        //check que le status est OK
+        assertEquals(200, response.getStatusCode());
+    }
+
+    @Alors("Il existe {int} elements dans le referentiel Etape ACV")
+    public void ilExisteElementsDansLeReferentielEtapeACV(int taille) throws NoSuchMethodException {
+        String requestPath = Arrays.stream(ReferentielEtapeRestApi.class.getMethod("getAll")
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .get(requestPath)
+                .thenReturn();
+        etapesAPI = response.as(EtapeDTO[].class);
+        assertEquals(taille, response.as(List.class).size());
+
+
+    }
+
+
+    @Et("chacun des elements du referentiel ajouté est identique au element du fichier csv")
+    public void chacunDesElementsDuReferentielAjoutéEstIdentiqueAuElementDuFichierCsv() {
+
+        List<EtapeDTO> resultEgalite = etapeCVS.stream().filter(csv ->
+                        Arrays.stream(etapesAPI).collect(Collectors.toList()).stream().anyMatch(api ->
+                                csv.getLibelle().equals(api.getLibelle())
+                                        && csv.getCode().equals(api.getCode())
+                        ))
+                .collect(Collectors.toList());
+
+        assertEquals(etapeCVS.size(), resultEgalite.size());
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/HypotheseStepdefs.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/HypotheseStepdefs.java
new file mode 100644
index 0000000000000000000000000000000000000000..0eb99ad11bcbdb35f0537de5a256cc41583753ff
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/HypotheseStepdefs.java
@@ -0,0 +1,65 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Quand;
+import io.restassured.http.ContentType;
+import io.restassured.path.json.JsonPath;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese.ReferentielAdministrationHypotheseRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.hypothese.ReferentielHypotheseRestApi;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class HypotheseStepdefs extends AbstractStepDefinitions {
+
+    @Quand("le fichier CSV REF HYPOTHESE{string} est inject")
+    public void leFichierCSVREFHYPOTHESEEstInject(String nomFichier) throws FileNotFoundException, NoSuchMethodException {
+
+        setupRestAssured();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        String requestPath = Arrays.stream(ReferentielAdministrationHypotheseRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+
+    }
+
+    @Alors("le statut http est {int}")
+    public void checkReponseApi(int codeHttpAttendu) {
+        assertEquals(codeHttpAttendu, response.getStatusCode());
+    }
+
+    @Quand("lors de la recherche de hypothese avec la cle {string}")
+    public void lorsDeLaRechercheDeHypotheseAvecLaCle(String cle) throws NoSuchMethodException {
+        setupRestAssured();
+        String requestPath = Arrays.stream(ReferentielHypotheseRestApi.class.getMethod("get", String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .contentType(ContentType.JSON)
+                .param("cle", cle)
+                .get(requestPath)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+
+    }
+
+    @Alors("Le resultat est : cle = {string} valeur={string} et source={string}")
+    public void leResultatEstCleValeurEtSource(String cle, String valeur, String source) {
+        JsonPath jsonPath = response.jsonPath();
+        assertEquals(cle, jsonPath.get("code"));
+        assertEquals(source, jsonPath.get("source"));
+        assertEquals(valeur, jsonPath.get("valeur"));
+
+
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactImpactEquipementStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactImpactEquipementStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..959e3e91e06f85ab0996a4a79f5fe3bdbb2f40d9
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactImpactEquipementStepDefinitions.java
@@ -0,0 +1,82 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.DataTableType;
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.mte.numecoeval.referentiel.domain.model.ImpactEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.ImpactEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactequipement.ReferentielAdministrationImpactEquipementRestApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ImpactImpactEquipementStepDefinitions extends AbstractStepDefinitions {
+
+    @Autowired
+    ImpactEquipementJpaAdapter jpaAdapter;
+
+    @DataTableType
+    public ImpactEquipement impactEquipement(Map<String, String> entry) {
+        var impact = new ImpactEquipement();
+        impact.setEtape(entry.get("etape"));
+        impact.setCritere(entry.get("critere"));
+        impact.setRefEquipement(entry.get("refEquipement"));
+        impact.setValeur(NumberUtils.createDouble(entry.get("valeur")));
+        impact.setConsoElecMoyenne(NumberUtils.createDouble(entry.get("consoElecMoyenne")));
+        impact.setSource(entry.get("source"));
+        impact.setType(entry.get("type"));
+        impact.setDescription(entry.get("description"));
+        return impact;
+    }
+
+    @Quand("le fichier CSV des impacts d'équipements {string} est importé par API et la réponse est {int}")
+    public void importReferentielImpactEquipements(String nomFichier, int codeReponseHttpAttendu) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        initAlimentationEtapeEtCritere();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        String requestPath = Arrays.stream(ReferentielAdministrationImpactEquipementRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
+    }
+
+    @Et("La récupération de tous les impacts d'équipements renvoie {int} lignes")
+    public void getAllImpactEquipements(int nombreLignesAttendues) throws NoSuchMethodException {
+        List<ImpactEquipement> impactEquipements = jpaAdapter.getAll();
+
+        assertEquals(nombreLignesAttendues, impactEquipements.size());
+    }
+
+    @Alors("Vérifications des impacts équipements disponibles")
+    public void checkImpactEquipements(List<ImpactEquipement> dataTable) {
+        List<ImpactEquipement> impactEquipements = jpaAdapter.getAll();
+
+        assertEquals(dataTable.size(), impactEquipements.size());
+        dataTable.forEach( expected ->
+                assertTrue(
+                        impactEquipements.stream().anyMatch(impactEquipement1 -> impactEquipement1.equals(expected)),
+                        "L'équipement étape: %s, critere: %s, refEquipement: %s n'est pas disponible".formatted(
+                                expected.getEtape(),
+                                expected.getCritere(),
+                                expected.getRefEquipement()
+                        )
+                )
+        );
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactMessagerieStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactMessagerieStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f546f6e4501a6c411098999e2241167a76cccb3
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactMessagerieStepDefinitions.java
@@ -0,0 +1,67 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactMessagerieDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie.ReferentielImpactMessagerieRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactmessagerie.ReferentielInterneImpactMessagerieRestApi;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ImpactMessagerieStepDefinitions extends AbstractStepDefinitions {
+
+    List<ImpactMessagerieDTO> impactsMessageriesDisponibles;
+
+    @Quand("le fichier CSV des impacts messageries {string} est importé par API et la réponse est {int}")
+    public void importReferentielImpactMessagerie(String nomFichier, int codeReponseHttpAttendu) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        String requestPath = Arrays.stream(ReferentielInterneImpactMessagerieRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
+    }
+
+    @Et("La récupération de tous les impacts de messagerie renvoie {int} lignes")
+    public void getAllImpactMessagerie(int nombreLignesAttendues) throws NoSuchMethodException {
+        String requestPath = Arrays.stream(ReferentielImpactMessagerieRestApi.class.getMethod("getAllImpactMessagerie")
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .get(requestPath)
+                .thenReturn();
+
+        assertEquals(200, response.getStatusCode());
+        impactsMessageriesDisponibles = Arrays.asList(response.as(ImpactMessagerieDTO[].class));
+        assertEquals(nombreLignesAttendues, impactsMessageriesDisponibles.size());
+    }
+
+    @Alors("un impact messagerie pour le critère {string} a une fonction y = {string}x + {string} et de source {string}")
+    public void checkImpactMessagerieDisponible(String critere, String constanteCoefficientDirecteur, String constanteOrdonneeOrigine, String source) {
+
+        assertTrue(
+                impactsMessageriesDisponibles.stream().anyMatch(impactMessagerieDTO ->
+                        StringUtils.equals(critere, impactMessagerieDTO.getCritere())
+                        && Double.valueOf(constanteCoefficientDirecteur).equals(impactMessagerieDTO.getConstanteCoefficientDirecteur())
+                        && Double.valueOf(constanteOrdonneeOrigine).equals(impactMessagerieDTO.getConstanteOrdonneeOrigine())
+                        && StringUtils.equals(source, impactMessagerieDTO.getSource())
+                )
+        );
+
+    }
+}
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactReseauStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactReseauStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0edc8e5bdfa511483818ff9a7eb0968be48e7a0
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/ImpactReseauStepDefinitions.java
@@ -0,0 +1,258 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Quand;
+import io.restassured.http.ContentType;
+import io.restassured.response.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ImpactReseauDTO;
+import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau.ReferentielAdministrationImpactReseauRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.impactreseau.ReferentielImpactReseauRestApi;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.*;
+
+@Slf4j
+public class ImpactReseauStepDefinitions  extends AbstractStepDefinitions {
+
+    @Quand("on ajoute un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string}")
+    public void onAjouteUnFacteurImpactReseauDontLaRefReseauEstEtapeACVEstCritereEstLa(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException, FileNotFoundException {
+        log.debug("Debut creation d'un impact reseau dans table ref_impactReseau");
+        initAlimentationEtapeEtCritere();
+        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
+        impactReseau.setRefReseau(refReseau);
+        impactReseau.setEtapeACV(etapeACV);
+        impactReseau.setCritere(critere);
+        impactReseau.setSource(source);
+        impactReseau.setValeur(Double.valueOf(valeur));
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .body(impactReseau)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
+        //verification de la sortie
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(source, impactReseauResultat.getSource());
+        assertEquals(critere, impactReseauResultat.getCritere());
+        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
+        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
+        log.debug("Debut creation d'un impact reseau dans table ref_impactReseau");
+    }
+
+    @Alors("impact reseau est persister dans la table ref_impactReseau  avec les elements suivants: la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string}")
+    public void impactReseauEstPersisterDansLaTableRef_impactReseau(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException {
+        log.debug("Debut recuperation depuis table ref_impactReseau pour verification de la CAF1");
+        //check avec la ressource get
+        //invocation de la ressource restapi ajout impact reseau
+        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .queryParam("refReseau", refReseau)
+                .queryParam("etapeacv", etapeACV)
+                .queryParam("critere", critere)
+                .get(requestPath)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
+        //verification de la sortie
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(source, impactReseauResultat.getSource());
+        assertEquals(critere, impactReseauResultat.getCritere());
+        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
+        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
+        log.debug("END recuperation depuis table ref_impactReseau pour verification de la CAF1");
+    }
+
+    @Quand("on persiste un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string}")
+    public void onPersisteUnFacteurImpactReseauDontLaRefReseauEstEtapeACVEstCritereEstLaSourceEst(String refReseau, String etapeACV, String critere, String source) throws NoSuchMethodException, FileNotFoundException {
+        log.debug("Debut creation à vide dans table ref_impactReseau");
+        //invoquation de la ressource restapi ajout impact reseau
+        setupRestAssured();
+        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
+        impactReseau.setRefReseau(refReseau);
+        impactReseau.setEtapeACV(etapeACV);
+        impactReseau.setCritere(critere);
+        impactReseau.setSource(source);
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .body(impactReseau)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
+        //verification de la sortie
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(source, impactReseauResultat.getSource());
+        assertEquals(critere, impactReseauResultat.getCritere());
+        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
+        log.debug("Fin creation à vide  dans table ref_impactReseau");
+    }
+
+
+    @Alors("il est possible de modifier impact  Reseau avec les élements suivants: le refReseau est {string}, etapeACV est  {string} ,  critere est {string} la source est {string}, valeur est {string} et l'unité est {string}")
+    public void ilEstPossibleDeModifierImpactReseau(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws ReferentielException, NoSuchMethodException {
+        log.debug("Debut modification impact reseau depuis table ref_impactReseau");
+        //check avec REST API  GeT
+        String requestPathGet = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        Response responseGet = given()
+                .contentType(ContentType.JSON)
+                .queryParam("refReseau", refReseau)
+                .queryParam("etapeacv", etapeACV)
+                .queryParam("critere", critere)
+                .get(requestPathGet)
+                .thenReturn();
+        assertEquals(200, responseGet.getStatusCode());
+        ImpactReseauDTO impactReseauResultatGet = responseGet.as(ImpactReseauDTO.class);
+        //verification de la sortie
+        assertEquals(etapeACV, impactReseauResultatGet.getEtapeACV());
+        assertEquals(refReseau, impactReseauResultatGet.getRefReseau());
+        assertEquals(critere, impactReseauResultatGet.getCritere());
+        assertEquals(source, impactReseauResultatGet.getSource());
+        assertNull(impactReseauResultatGet.getConsoElecMoyenne());
+        //upadate avec rest api update
+        //modification de l'impact vide
+        //setupRestAssured();
+        String requestPathUpdate = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("update", ImpactReseauDTO.class)
+                .getAnnotation(PutMapping.class).path()).findFirst().orElse(null);
+        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
+        impactReseau.setRefReseau(refReseau);
+        impactReseau.setEtapeACV(etapeACV);
+        impactReseau.setCritere(critere);
+        impactReseau.setSource(source);
+        impactReseau.setValeur(Double.valueOf(valeur));
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .body(impactReseau)
+                .post(requestPathUpdate)
+                .thenReturn();
+        assertEquals(200, response.getStatusCode());
+        ImpactReseauDTO impactReseauResultatUpdate = response.as(ImpactReseauDTO.class);
+        //verification de la sortie
+        assertEquals(refReseau, impactReseauResultatUpdate.getRefReseau());
+        assertEquals(refReseau, impactReseauResultatUpdate.getRefReseau());
+        assertEquals(source, impactReseauResultatUpdate.getSource());
+        assertEquals(critere, impactReseauResultatUpdate.getCritere());
+        assertEquals(etapeACV, impactReseauResultatUpdate.getEtapeACV());
+        assertEquals(Double.valueOf(valeur), impactReseauResultatUpdate.getValeur());
+        log.debug("Fin modification impact reseau depuis table ref_impactReseau");
+    }
+
+    @Quand("on ajoute un facteur impact reseau dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string}  la valeur est {string} et l'unité est {string}")
+    public void onAjouteUnFacteurImpactReseauDontLaRefReseau(String refReseau, String etapeACV, String critere, String valeur, String unite) throws NoSuchMethodException, FileNotFoundException {
+        log.debug("Debut creation impact reseau sans source dans table ref_impactReseau");
+        //invoquation de la ressource restapi ajout impact reseau
+        setupRestAssured();
+        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("add", ImpactReseauDTO.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        ImpactReseauDTO impactReseau = new ImpactReseauDTO();
+        impactReseau.setRefReseau(refReseau);
+        impactReseau.setEtapeACV(etapeACV);
+        impactReseau.setCritere(critere);
+        impactReseau.setValeur(Double.valueOf(valeur));
+        response = given()
+                .contentType(ContentType.JSON)
+                .body(impactReseau)
+                .post(requestPath)
+                .thenReturn();
+        log.error("Fin creation impact reseau sans source dans table ref_impactReseau");
+    }
+
+
+    @Alors("Impossible d ajouter l'impact réseau dans la table ref_impactreseau")
+    public void impossibleDAjouterLImpactReseauDansLaTableRef_impactreseau() {
+        assertEquals(500, response.getStatusCode());
+        ErrorResponseDTO impactReseauResultat = response.as(ErrorResponseDTO.class);
+        //assertEquals("La source est obligatoire", impactReseauResultat.getMessage());
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, impactReseauResultat.getStatus());
+        assertEquals(500, impactReseauResultat.getCode());
+        assertNotNull(impactReseauResultat.getTimestamp());
+    }
+
+    @Quand("le fichier CSV {string} est envoyé")
+    public void leFichierCSVEstEnvoye(String fichier) throws IOException, NoSuchMethodException {
+        File file = ResourceUtils.getFile("classpath:" + fichier);
+        setupRestAssured();
+        String requestPath = Arrays.stream(ReferentielAdministrationImpactReseauRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        //check que le status est OK
+        assertEquals(200, response.getStatusCode());
+    }
+
+    @Alors("l impact reseau  refReseal est {string}, etapeACV est  {string} ,  critere est {string} la source est {string} la valeur est {string} et l'unité est {string} existe")
+    public void lImpactReseauRefResealEstE(String refReseau, String etapeACV, String critere, String source, String valeur, String unite) throws NoSuchMethodException {
+        //recuperataion d'un resultat ajouter
+        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        Response response = given()
+                .contentType(ContentType.JSON)
+                .queryParam("refReseau", refReseau)
+                .queryParam("etapeacv", etapeACV)
+                .queryParam("critere", critere)
+                .get(requestPath)
+                .thenReturn();
+        ImpactReseauDTO impactReseauDTO = response.as(ImpactReseauDTO.class);
+        assertEquals(200, response.getStatusCode());
+        ImpactReseauDTO impactReseauResultat = response.as(ImpactReseauDTO.class);
+        //verification de la sortie aleatoire
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(refReseau, impactReseauResultat.getRefReseau());
+        assertEquals(source, impactReseauResultat.getSource());
+        assertEquals(critere, impactReseauResultat.getCritere());
+        assertEquals(etapeACV, impactReseauResultat.getEtapeACV());
+        assertEquals(Double.valueOf(valeur), impactReseauResultat.getValeur());
+    }
+
+
+    @Quand("on cherche l impact reseau  dont la refReseau est {string}, etapeACV est  {string} ,  critere est {string}")
+    public void onChercheLImpactReseauquinexistePAs(String refReseau, String etapeACV, String critere) throws NoSuchMethodException, FileNotFoundException {
+        setupRestAssured();
+        String requestPath = Arrays.stream(ReferentielImpactReseauRestApi.class.getMethod("get", String.class, String.class, String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .contentType(ContentType.JSON)
+                .queryParam("refReseau", refReseau)
+                .queryParam("etapeacv", etapeACV)
+                .queryParam("critere", critere)
+                .get(requestPath)
+                .thenReturn();
+    }
+
+    @Alors("lecture reponse impact resau n existe pas")
+    public void lectureReponseImpactResauNExistePas() {
+        assertEquals(404, response.getStatusCode());
+        ErrorResponseDTO impactReseauResultat = response.as(ErrorResponseDTO.class);
+        assertEquals("Impact Réseau non trouvé", impactReseauResultat.getMessage());
+        assertEquals(HttpStatus.NOT_FOUND, impactReseauResultat.getStatus());
+        assertEquals(404, impactReseauResultat.getCode());
+        assertNotNull(impactReseauResultat.getTimestamp());
+    }
+
+}
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/TypeEquipementStepDefinitions.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/TypeEquipementStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4f2ce2e4501796f68f0e7fd90d78598753d4bb4
--- /dev/null
+++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/steps/TypeEquipementStepDefinitions.java
@@ -0,0 +1,95 @@
+package org.mte.numecoeval.referentiel.steps;
+
+import io.cucumber.java.DataTableType;
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Et;
+import io.cucumber.java.fr.Quand;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.mte.numecoeval.referentiel.domain.model.TypeEquipement;
+import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.TypeEquipementJpaAdapter;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement.ReferentielAdministrationTypeEquipementRestApi;
+import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequipement.ReferentielTypeEquipementRestApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static io.restassured.RestAssured.given;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class TypeEquipementStepDefinitions extends AbstractStepDefinitions {
+
+    @Autowired
+    TypeEquipementJpaAdapter jpaAdapter;
+
+    @DataTableType
+    public TypeEquipement typeEquipement(Map<String, String> entry) {
+        return TypeEquipement.builder()
+                .type(entry.get("type"))
+                .source(StringUtils.defaultString(entry.get("source")))
+                .commentaire(StringUtils.defaultString(entry.get("commentaire")))
+                .serveur(Boolean.parseBoolean(entry.get("serveur")))
+                .refEquipementParDefaut(StringUtils.defaultString(entry.get("refEquipementParDefaut")))
+                .dureeVieDefaut(NumberUtils.createDouble(entry.get("dureeVieDefaut")))
+                .build();
+    }
+
+    @Quand("le fichier CSV des types d'équipements {string} est importé par API et la réponse est {int}")
+    public void importReferentielTypeEquipements(String nomFichier, int codeReponseHttpAttendu) throws FileNotFoundException, NoSuchMethodException {
+        setupRestAssured();
+        initAlimentationEtapeEtCritere();
+        File file = ResourceUtils.getFile("classpath:" + nomFichier);
+        String requestPath = Arrays.stream(ReferentielAdministrationTypeEquipementRestApi.class.getMethod("importCSV", MultipartFile.class)
+                .getAnnotation(PostMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .multiPart("file", file)
+                .post(requestPath)
+                .thenReturn();
+        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
+    }
+
+    @Et("La récupération de tous les types d'équipements renvoie {int} lignes")
+    public void getAllTypeEquipement(int nombreLignesAttendues) throws NoSuchMethodException {
+        List<TypeEquipement> typeEquipements = jpaAdapter.getAll();
+
+        assertEquals(nombreLignesAttendues, typeEquipements.size());
+    }
+
+    @Alors("Vérifications des types d'équipements disponibles")
+    public void checkImpactEquipements(List<TypeEquipement> dataTable) {
+        List<TypeEquipement> datasInDatabase = jpaAdapter.getAll();
+
+        assertEquals(dataTable.size(), datasInDatabase.size());
+        dataTable.forEach(expected -> {
+            var dataInDatabase = datasInDatabase.stream().filter(data -> data.getType().equals(expected.getType())).findFirst().orElse(null);
+            assertNotNull(dataInDatabase, "Il existe un type d'équipement avec le type %s".formatted(expected.getType()));
+
+            assertEquals(expected.getCommentaire(), dataInDatabase.getCommentaire(), "TypeEquipement %s : le commentaire ne matche pas".formatted(expected.getType()));
+            assertEquals(expected.getSource(), dataInDatabase.getSource(), "TypeEquipement %s : la source ne matche pas".formatted(expected.getType()));
+            assertEquals(expected.getDureeVieDefaut(), dataInDatabase.getDureeVieDefaut(), "TypeEquipement %s : la durée de vie par défaut ne matche pas".formatted(expected.getType()));
+            assertEquals(expected.getRefEquipementParDefaut(), dataInDatabase.getRefEquipementParDefaut(), "TypeEquipement %s : la référence d'équipement par défaut ne matche pas".formatted(expected.getType()));
+            assertEquals(expected.isServeur(), dataInDatabase.isServeur(), "TypeEquipement %s : le flag serveur ne matche pas".formatted(expected.getType()));
+        });
+    }
+
+    @Et("La récupération unitaire d\'un type équipement {string} répond {int}")
+    public void getTypeEquipementAndCheckHttpStatus(String type, int codeReponseHttpAttendu) throws NoSuchMethodException {
+
+        String requestPath = Arrays.stream(ReferentielTypeEquipementRestApi.class.getMethod("getTypeEquipement", String.class)
+                .getAnnotation(GetMapping.class).path()).findFirst().orElse(null);
+        response = given()
+                .pathParam("type", type)
+                .get(requestPath)
+                .thenReturn();
+        assertEquals(codeReponseHttpAttendu, response.getStatusCode());
+    }
+}
diff --git a/services/api-referentiel/src/test/resources/application-test.yaml b/services/api-referentiel/src/test/resources/application-test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..974db9b1a8a999ebf1915b9ee72cdec241a2d5d8
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/application-test.yaml
@@ -0,0 +1,25 @@
+#CONFIGURATION BASES
+spring:
+  sql:
+    init:
+      mode: never
+      platform: hsqldb
+  # Base de données
+  datasource:
+    # HSQLDB
+    generate-unique-name: true
+    url: "jdbc:hsqldb:file:target/classes/db/default.db"
+    username: sa
+    password: sa
+    driver-class-name: org.hsqldb.jdbc.JDBCDriver
+    tomcat:
+      test-on-borrow: false
+      jmx-enabled: false
+      max-active: 100
+  jpa:
+    # HSQLDB
+    generate-ddl: true
+    database-platform: org.hibernate.dialect.HSQLDialect
+    hibernate:
+      ddl-auto: create-drop
+
diff --git a/services/api-referentiel/src/test/resources/csv/ref_Critere.csv b/services/api-referentiel/src/test/resources/csv/ref_Critere.csv
new file mode 100644
index 0000000000000000000000000000000000000000..f275ab0ba74c6e521de749ae6d5d5df05cc18bf1
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_Critere.csv
@@ -0,0 +1,6 @@
+nomCritere;description;unite
+Changement climatique;;kg CO_{2} eq
+Émissions de particules fines;;Diseaseincidence
+Radiations ionisantes;;kBq U-235 eq
+Acidification;;mol H^{+} eq
+Épuisement des ressources naturelles (minérales et métaux);;kg Sb eq
diff --git a/services/api-referentiel/src/test/resources/csv/ref_Hypothese.csv b/services/api-referentiel/src/test/resources/csv/ref_Hypothese.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a1a6b28614a66c174a8d3e58047a24c3dfa46a90
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_Hypothese.csv
@@ -0,0 +1,3 @@
+cle;valeur;source
+PUEPardDfault;1.6;expertise IJO
+DureeVieServeurParDefaut;3;US 46
diff --git a/services/api-referentiel/src/test/resources/csv/ref_ImpactMessagerie.csv b/services/api-referentiel/src/test/resources/csv/ref_ImpactMessagerie.csv
new file mode 100644
index 0000000000000000000000000000000000000000..49e5fa58a87ab9acf3f85c96e16abd90794f6ccb
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_ImpactMessagerie.csv
@@ -0,0 +1,2 @@
+critere;constanteCoefficientDirecteur;constanteOrdonneeOrigine;source
+Changement climatique;0.0112;5.9606;"US #66"
diff --git a/services/api-referentiel/src/test/resources/csv/ref_MixElectrique.csv b/services/api-referentiel/src/test/resources/csv/ref_MixElectrique.csv
new file mode 100644
index 0000000000000000000000000000000000000000..64eae19eeeb817b63528cc615b57e89323daf9d9
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_MixElectrique.csv
@@ -0,0 +1,21 @@
+pays  ;raccourcisAnglais;critere                                                   ;valeur                   ;source
+France;FR               ;Acidification                                             ;0.913                    ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Changement climatique                                     ;149                      ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Radiations ionisantes                                     ;69.1                     ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Épuisement des ressources naturelles (minérales et métaux);0.00913                  ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Émissions de particules fines                             ;0.00000523               ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Acidification                                             ;0.05573787269904         ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Changement climatique                                     ;11.0082325332            ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Radiations ionisantes                                     ;0.02997901628064         ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Épuisement des ressources naturelles (minérales et métaux);0.00000043143695751072003;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Émissions de particules fines                             ;0.0000003353284653936    ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Acidification                                             ;0.01120932               ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Changement climatique                                     ;1.9485359999999998       ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Radiations ionisantes                                     ;0.38956                  ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Épuisement des ressources naturelles (minérales et métaux);0.0009197928000000001    ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Émissions de particules fines                             ;0.00043580159999999995   ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Acidification                                             ;0.0219                   ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Changement climatique                                     ;1.46                     ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Radiations ionisantes                                     ;0.166                    ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Épuisement des ressources naturelles (minérales et métaux);0.00000388               ;Ref_Base_donnee_reference_20480728.xlsx
+France;FR               ;Émissions de particules fines                             ;0.0000000775             ;Ref_Base_donnee_reference_20480728.xlsx
diff --git a/services/api-referentiel/src/test/resources/csv/ref_etapeACV.csv b/services/api-referentiel/src/test/resources/csv/ref_etapeACV.csv
new file mode 100644
index 0000000000000000000000000000000000000000..d9a41e0350f80cde95d53d8e4baf1e9c25c5f484
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_etapeACV.csv
@@ -0,0 +1,5 @@
+code;libelle
+FABRICATION;Fabrication
+DISTRIBUTION;Distribution
+UTILISATION;Utilisation
+FIN_DE_VIE;Fin de vie
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/ref_impactEquipement.csv b/services/api-referentiel/src/test/resources/csv/ref_impactEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..8d5c0e533d400fb63823ed266173e5955d0b1b23
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_impactEquipement.csv
@@ -0,0 +1,109 @@
+refEquipement;etapeacv;critere;consoElecMoyenne;valeur;source;type
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Acidification;29.1;0.913;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Changement climatique;29.1;149;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Radiations ionisantes;29.1;69.1;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.00913;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Émissions de particules fines;29.1;0.00000523;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Acidification;29.1;0.05573787269904;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Changement climatique;29.1;11.0082325332;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Radiations ionisantes;29.1;0.02997901628064;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.00000043143695751072003;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Émissions de particules fines;29.1;0.0000003353284653936;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Acidification;29.1;0.01120932;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Changement climatique;29.1;1.9485359999999998;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Radiations ionisantes;29.1;50.38956;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.0000009197928000000001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Émissions de particules fines;29.1;0.00000043580159999999995;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Acidification;29.1;0.0219;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Changement climatique;29.1;1.46;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Radiations ionisantes;29.1;0.166;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);29.1;0.00000388;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Émissions de particules fines;29.1;0.0000000775;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FABRICATION;Acidification;29.1;1.78;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FABRICATION;Changement climatique;29.1;308;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FABRICATION;Radiations ionisantes;29.1;98.1;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FABRICATION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.012;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FABRICATION;Émissions de particules fines;29.1;0.0000101;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";DISTRIBUTION;Acidification;29.1;0.09322822755018001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";DISTRIBUTION;Changement climatique;29.1;18.41257941565;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";DISTRIBUTION;Radiations ionisantes;29.1;0.050143473659880006;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.00000072162967297924;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";DISTRIBUTION;Émissions de particules fines;29.1;0.0000005608767784262;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";UTILISATION;Acidification;29.1;0.01120932;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";UTILISATION;Changement climatique;29.1;1.9485359999999998;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";UTILISATION;Radiations ionisantes;29.1;50.38956;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);29.1;0.0000009197928000000001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";UTILISATION;Émissions de particules fines;29.1;0.00000043580159999999995;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FIN_DE_VIE;Acidification;29.1;0.0222;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FIN_DE_VIE;Changement climatique;29.1;1.48;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FIN_DE_VIE;Radiations ionisantes;29.1;0.187;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);29.1;0.00000383;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur portable 15.6 16 Go RAM 512 Go SSD carte graphique";FIN_DE_VIE;Émissions de particules fines;29.1;0.0000000774;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);18.6;0.00000016364437964909999;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";DISTRIBUTION;Émissions de particules fines;18.6;0.00000013479328674935998;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";UTILISATION;Acidification;18.6;0.00716472;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";UTILISATION;Changement climatique;18.6;1.245456;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";UTILISATION;Radiations ionisantes;18.6;32.20776;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);18.6;0.0000005879088000000001;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";UTILISATION;Émissions de particules fines;18.6;0.0000002785536;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";FIN_DE_VIE;Acidification;18.6;0.00498;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";FIN_DE_VIE;Changement climatique;18.6;0.404;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";FIN_DE_VIE;Radiations ionisantes;18.6;0.0736;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);18.6;0.00000019;Ref_Base_donnee_reference_20220728.xlsx;
+"Tablette 11.1 6 Go RAM 512 Go SSD";FIN_DE_VIE;Émissions de particules fines;18.6;0.0000000176;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FABRICATION;Acidification;3.9;0.268;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FABRICATION;Changement climatique;3.9;44.1;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FABRICATION;Radiations ionisantes;3.9;12.2;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FABRICATION;Épuisement des ressources naturelles (minérales et métaux);3.9;0.00263;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FABRICATION;Émissions de particules fines;3.9;0.00000151;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";DISTRIBUTION;Acidification;3.9;0.008213194002682;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";DISTRIBUTION;Changement climatique;3.9;1.5308100265771998;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";DISTRIBUTION;Radiations ionisantes;3.9;0.010082124523881202;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);3.9;0.000000059421842323899996;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";DISTRIBUTION;Émissions de particules fines;3.9;0.00000004894555773144;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";UTILISATION;Acidification;3.9;0.00150228;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";UTILISATION;Changement climatique;3.9;0.261144;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";UTILISATION;Radiations ionisantes;3.9;6.75324;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);3.9;0.0000001232712;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";UTILISATION;Émissions de particules fines;3.9;0.00000005840639999999999;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FIN_DE_VIE;Acidification;3.9;0.00428;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FIN_DE_VIE;Changement climatique;3.9;0.244;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FIN_DE_VIE;Radiations ionisantes;3.9;0.039;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);3.9;0.000000123;Ref_Base_donnee_reference_20220728.xlsx;
+"Smartphone 6.72 OLED 11 Go RAM 341 Go SSD";FIN_DE_VIE;Émissions de particules fines;3.9;0.0000000118;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FABRICATION;Acidification;100;1.87;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FABRICATION;Changement climatique;100;289;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FABRICATION;Radiations ionisantes;100;1330;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FABRICATION;Épuisement des ressources naturelles (minérales et métaux);100;0.0279;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FABRICATION;Émissions de particules fines;100;0.0000108;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";DISTRIBUTION;Acidification;100;0.11085933300800001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";DISTRIBUTION;Changement climatique;100;3.1848028296;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";DISTRIBUTION;Radiations ionisantes;100;0.0065306696856;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);100;0.00000011291803934400001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";DISTRIBUTION;Émissions de particules fines;100;0.0000005823743571200001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";UTILISATION;Acidification;100;0.03852;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";UTILISATION;Changement climatique;100;6.695999999999999;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";UTILISATION;Radiations ionisantes;100;173.16;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);100;0.0000031608000000000003;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";UTILISATION;Émissions de particules fines;100;0.0000014975999999999999;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FIN_DE_VIE;Acidification;100;0.0966;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FIN_DE_VIE;Changement climatique;100;6.61;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FIN_DE_VIE;Radiations ionisantes;100;0.625;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);100;0.0000135;Ref_Base_donnee_reference_20220728.xlsx;
+"Ordinateur fixe (sans écran) 8 Go RAM 250 Go SSD 1 000 Go HDD carte graphique";FIN_DE_VIE;Émissions de particules fines;100;0.000000363;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FABRICATION;Acidification;70;0.394;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FABRICATION;Changement climatique;70;59;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FABRICATION;Radiations ionisantes;70;143;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FABRICATION;Épuisement des ressources naturelles (minérales et métaux);70;0.0117;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FABRICATION;Émissions de particules fines;70;0.00000247;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";DISTRIBUTION;Acidification;70;0.044321516904000005;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";DISTRIBUTION;Changement climatique;70;1.2732828948000001;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";DISTRIBUTION;Radiations ionisantes;70;0.0026109591228;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);70;0.000000045144586872;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";DISTRIBUTION;Émissions de particules fines;70;0.00000023283303456000003;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";UTILISATION;Acidification;70;0.026964;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";UTILISATION;Changement climatique;70;4.6872;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";UTILISATION;Radiations ionisantes;70;121.212;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";UTILISATION;Épuisement des ressources naturelles (minérales et métaux);70;0.00000221256;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);70;0.000012;Ref_Base_donnee_reference_20220728.xlsx;
+"Ecran d'ordinateur LCD 24";FIN_DE_VIE;Émissions de particules fines;70;0.000000149;Ref_Base_donnee_reference_20220728.xlsx;
diff --git a/services/api-referentiel/src/test/resources/csv/ref_impactreseau.csv b/services/api-referentiel/src/test/resources/csv/ref_impactreseau.csv
new file mode 100644
index 0000000000000000000000000000000000000000..e8e363c6c311fc900ebfbe7b94e32b9c00dc470a
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/ref_impactreseau.csv
@@ -0,0 +1,101 @@
+refReseau;etapeACV;critere;valeur;unite;consoElecMoyenne;source
+impactReseauMobileMoyen;DISTRIBUTION;Acidification;138.28;;;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Acidification;148.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Acidification;1.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Acidification;18.8;;;RefTest V1.00
+impactReseauMobileMoyen;DISTRIBUTION;Changement climatique;1.428;;;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+impactReseauMobileMoyen;DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);78.28;;;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Épuisement des ressources naturelles (minérales et métaux);87.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);54.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Épuisement des ressources naturelles (minérales et métaux);34.76;;;RefTest V1.00
+impactReseauMobileMoyen;DISTRIBUTION;Radiations ionisantes;138.28;;;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Radiations ionisantes;148.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Radiations ionisantes;1.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Radiations ionisantes;18.8;;;RefTest V1.00
+impactReseauMobileMoyen;DISTRIBUTION;Émissions de particules fines;138.28;;;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Émissions de particules fines;148.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Émissions de particules fines;1.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Émissions de particules fines;18.8;;;RefTest V1.00
+impactReseauMobileFRANCE;DISTRIBUTION;Acidification;138.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FABRICATION;Acidification;148.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FIN_DE_VIE;Acidification;1.28;;;RefTest V1.00
+impactReseauMobileFRANCE;UTILISATION;Acidification;18.8;;;RefTest V1.00
+impactReseauMobileFRANCE;DISTRIBUTION;Changement climatique;1.428;;;RefTest V1.00
+impactReseauMobileFRANCE;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobileFRANCE;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+impactReseauMobileFRANCE;DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);78.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FABRICATION;Épuisement des ressources naturelles (minérales et métaux);87.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);54.28;;;RefTest V1.00
+impactReseauMobileFRANCE;UTILISATION;Épuisement des ressources naturelles (minérales et métaux);34.76;;;RefTest V1.00
+impactReseauMobileFRANCE;DISTRIBUTION;Radiations ionisantes;138.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FABRICATION;Radiations ionisantes;148.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FIN_DE_VIE;Radiations ionisantes;1.28;;;RefTest V1.00
+impactReseauMobileFRANCE;UTILISATION;Radiations ionisantes;18.8;;;RefTest V1.00
+impactReseauMobileFRANCE;DISTRIBUTION;Émissions de particules fines;138.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FABRICATION;Émissions de particules fines;148.28;;;RefTest V1.00
+impactReseauMobileFRANCE;FIN_DE_VIE;Émissions de particules fines;1.28;;;RefTest V1.00
+impactReseauMobileFRANCE;UTILISATION;Émissions de particules fines;18.8;;;RefTest V1.00
+impactReseauMobile4G;DISTRIBUTION;Acidification;138.28;;;RefTest V1.00
+impactReseauMobile4G;FABRICATION;Acidification;148.28;;;RefTest V1.00
+impactReseauMobile4G;FIN_DE_VIE;Acidification;1.28;;;RefTest V1.00
+impactReseauMobile4G;UTILISATION;Acidification;18.8;;;RefTest V1.00
+impactReseauMobile4G;DISTRIBUTION;Changement climatique;1.428;;;RefTest V1.00
+impactReseauMobile4G;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobile4G;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobile4G;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+impactReseauMobile4G;DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);78.28;;;RefTest V1.00
+impactReseauMobile4G;FABRICATION;Épuisement des ressources naturelles (minérales et métaux);87.28;;;RefTest V1.00
+impactReseauMobile4G;FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);54.28;;;RefTest V1.00
+impactReseauMobile4G;UTILISATION;Épuisement des ressources naturelles (minérales et métaux);34.76;;;RefTest V1.00
+impactReseauMobile4G;DISTRIBUTION;Radiations ionisantes;138.28;;;RefTest V1.00
+impactReseauMobile4G;FABRICATION;Radiations ionisantes;148.28;;;RefTest V1.00
+impactReseauMobile4G;FIN_DE_VIE;Radiations ionisantes;1.28;;;RefTest V1.00
+impactReseauMobile4G;UTILISATION;Radiations ionisantes;18.8;;;RefTest V1.00
+impactReseauMobile4G;DISTRIBUTION;Émissions de particules fines;138.28;;;RefTest V1.00
+impactReseauMobile4G;FABRICATION;Émissions de particules fines;148.28;;;RefTest V1.00
+impactReseauMobile4G;FIN_DE_VIE;Émissions de particules fines;1.28;;;RefTest V1.00
+impactReseauMobile4G;UTILISATION;Émissions de particules fines;18.8;;;RefTest V1.00
+impactReseauMobile5G;DISTRIBUTION;Acidification;138.28;;;RefTest V1.00
+impactReseauMobile5G;FABRICATION;Acidification;148.28;;;RefTest V1.00
+impactReseauMobile5G;FIN_DE_VIE;Acidification;1.28;;;RefTest V1.00
+impactReseauMobile5G;UTILISATION;Acidification;18.8;;;RefTest V1.00
+impactReseauMobile5G;DISTRIBUTION;Changement climatique;1.428;;;RefTest V1.00
+impactReseauMobile5G;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobile5G;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobile5G;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+impactReseauMobile5G;DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);78.28;;;RefTest V1.00
+impactReseauMobile5G;FABRICATION;Épuisement des ressources naturelles (minérales et métaux);87.28;;;RefTest V1.00
+impactReseauMobile5G;FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);54.28;;;RefTest V1.00
+impactReseauMobile5G;UTILISATION;Épuisement des ressources naturelles (minérales et métaux);34.76;;;RefTest V1.00
+impactReseauMobile5G;DISTRIBUTION;Radiations ionisantes;138.28;;;RefTest V1.00
+impactReseauMobile5G;FABRICATION;Radiations ionisantes;148.28;;;RefTest V1.00
+impactReseauMobile5G;FIN_DE_VIE;Radiations ionisantes;1.28;;;RefTest V1.00
+impactReseauMobile5G;UTILISATION;Radiations ionisantes;18.8;;;RefTest V1.00
+impactReseauMobile5G;DISTRIBUTION;Émissions de particules fines;138.28;;;RefTest V1.00
+impactReseauMobile5G;FABRICATION;Émissions de particules fines;148.28;;;RefTest V1.00
+impactReseauMobile5G;FIN_DE_VIE;Émissions de particules fines;1.28;;;RefTest V1.00
+impactReseauMobile5G;UTILISATION;Émissions de particules fines;18.8;;;RefTest V1.00
+impactReseauMobile2G;DISTRIBUTION;Acidification;138.28;;;RefTest V1.00
+impactReseauMobile2G;FABRICATION;Acidification;148.28;;;RefTest V1.00
+impactReseauMobile2G;FIN_DE_VIE;Acidification;1.28;;;RefTest V1.00
+impactReseauMobile2G;UTILISATION;Acidification;18.8;;;RefTest V1.00
+impactReseauMobile2G;DISTRIBUTION;Changement climatique;1.428;;;RefTest V1.00
+impactReseauMobile2G;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobile2G;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobile2G;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+impactReseauMobile2G;DISTRIBUTION;Épuisement des ressources naturelles (minérales et métaux);78.28;;;RefTest V1.00
+impactReseauMobile2G;FABRICATION;Épuisement des ressources naturelles (minérales et métaux);87.28;;;RefTest V1.00
+impactReseauMobile2G;FIN_DE_VIE;Épuisement des ressources naturelles (minérales et métaux);54.28;;;RefTest V1.00
+impactReseauMobile2G;UTILISATION;Épuisement des ressources naturelles (minérales et métaux);34.76;;;RefTest V1.00
+impactReseauMobile2G;DISTRIBUTION;Radiations ionisantes;138.28;;;RefTest V1.00
+impactReseauMobile2G;FABRICATION;Radiations ionisantes;148.28;;;RefTest V1.00
+impactReseauMobile2G;FIN_DE_VIE;Radiations ionisantes;1.28;;;RefTest V1.00
+impactReseauMobile2G;UTILISATION;Radiations ionisantes;18.8;;;RefTest V1.00
+impactReseauMobile2G;DISTRIBUTION;Émissions de particules fines;138.28;;;RefTest V1.00
+impactReseauMobile2G;FABRICATION;Émissions de particules fines;148.28;;;RefTest V1.00
+impactReseauMobile2G;FIN_DE_VIE;Émissions de particules fines;1.28;;;RefTest V1.00
+
diff --git a/services/api-referentiel/src/test/resources/csv/sprint10/ref_CorrespondanceRefEquipement.csv b/services/api-referentiel/src/test/resources/csv/sprint10/ref_CorrespondanceRefEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..c16f1e6f5ddc30a51faf623d85ba40f489e72abb
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/sprint10/ref_CorrespondanceRefEquipement.csv
@@ -0,0 +1,4 @@
+modeleEquipementSource;refEquipementCible
+Fairphone V1;smartphone01
+Fairphone V2;smartphone01
+Ecran 27 pouces;ecran01
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/sprint10/ref_ImpactEquipement.csv b/services/api-referentiel/src/test/resources/csv/sprint10/ref_ImpactEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..13f505c0712f68a675b8f1a00255cc516b0619d4
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/sprint10/ref_ImpactEquipement.csv
@@ -0,0 +1,7 @@
+refEquipement;etapeacv;critere;consoElecMoyenne;valeur;source;type;description
+"computer monitor-01-23";FIN_DE_VIE;Acidification;35.81692801813716;0.020296259210277726;reftest_20221013;computer monitor;Description Impact Equipement computer monitor
+"digital price tag - power unit-01";FABRICATION;Radiations ionisantes;;5.89E+01;reftest_20221013;digital price tag - power unit;Description Impact Equipement digital price tag - power unit
+"docking station-01";FABRICATION;Radiations ionisantes;1.28;3.50E+01;reftest_20221013;docking station;Description Impact Equipement docking station
+"empty 42u bay-01";FABRICATION;Radiations ionisantes;;5.87E+01;reftest_20221013;empty 42u bay;Description Impact Equipement empty 42u bay
+"feature phone-01";FABRICATION;Radiations ionisantes;0.09;5.11E+00;reftest_20221013;feature phone;Description Impact Equipement feature phone
+"firewall-01";FABRICATION;Radiations ionisantes;876;2.65E+02;reftest_20221013;firewall;Description Impact Equipement firewall
diff --git a/services/api-referentiel/src/test/resources/csv/sprint10/ref_TypeEquipement.csv b/services/api-referentiel/src/test/resources/csv/sprint10/ref_TypeEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..f5d8fc3e97e0a5a9736915d8026507766bee8c67
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/sprint10/ref_TypeEquipement.csv
@@ -0,0 +1,18 @@
+type;serveur;commentaire;dureeVieDefaut;refEquipementParDefaut;source
+ServeurCalcul;true;commentaires;6;serveur_par_defaut;Test
+ServeurStockage;true;;6;serveur_par_defaut;Test
+Armoire;false;;7;armoir_par_defaut;Test
+NAS;false;;6;baie_stockage_par_defaut;Test
+Switch;false;;6;switch_par_defaut;Test
+OrdinateurPortable;false;;4;laptop_par_defaut;Test
+OrdinateurDeBureau;false;;5;desktop_par_defaut;Test
+Tablette;false;;2.5;tablette_par_defaut;Test
+TelephoneMobile;false;commentaires;2.5;smartphone_par_defaut;Test
+TelephoneFixe;false;;10;telephone_fixe_par_defaut;Test
+EquipementReseau;false;commentaires;5;switch_par_defaut;Test
+BorneWifi;false;;4;borneWifi_par_defaut;Test
+Imprimante;false;;5;imprimante_par_defaut;Test
+Ecran;false;;8;ecran_par_defaut;Test
+AccessoirePosteDeTravail;false;souris calvier, camera casque;7;stationTravail_par_defaut;Test
+Connectique;false;;7;;Test
+Autre;false;;2;;Test
diff --git a/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement.csv b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..2e13fbcde325ad0fa0bb08e77fdfddb1f03e7447
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement.csv
@@ -0,0 +1,4 @@
+modeleEquipementSource;refEquipementCible
+modele01;refCible01
+modele02;refCible01
+modele03;refCible02
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..47834cbafb0974bdee5d1ab36d65a2a2e10434a5
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_errorInMiddle.csv
@@ -0,0 +1,6 @@
+modeleEquipementSource;refEquipementCible
+modele01;refCible01
+modele02;refCible01
+;;Ceci;N'estPas;UneLigne;Valide
+Tests;;Ceci;N'estPasNonPlus;UneLigne;Valide
+modele03;refCible02
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_utilitaires.csv b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_utilitaires.csv
new file mode 100644
index 0000000000000000000000000000000000000000..2e13fbcde325ad0fa0bb08e77fdfddb1f03e7447
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/correspondanceRefEquipement_utilitaires.csv
@@ -0,0 +1,4 @@
+modeleEquipementSource;refEquipementCible
+modele01;refCible01
+modele02;refCible01
+modele03;refCible02
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/unit/critere.csv b/services/api-referentiel/src/test/resources/csv/unit/critere.csv
new file mode 100644
index 0000000000000000000000000000000000000000..2e4ba08304fe5fa38b4506d7cdf174c8c893f6f3
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/critere.csv
@@ -0,0 +1,6 @@
+nomCritere;description;unite
+Changement climatique;;kg CO_{2} eq
+Émissions de particules fines;Émissions de particules fines;Diseaseincidence
+Radiations ionisantes;Description de Tests;kBq U-235 eq
+Acidification;;mol H^{+} eq
+Épuisement des ressources naturelles (minérales et métaux);;kg Sb eq
diff --git a/services/api-referentiel/src/test/resources/csv/unit/critere_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/critere_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..7c31b93cadb938b35a8e456844a9db5ed5f636db
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/critere_errorInMiddle.csv
@@ -0,0 +1,7 @@
+nomCritere;description;unite
+Changement climatique;;kg CO_{2} eq
+Émissions de particules fines;Émissions de particules fines;Diseaseincidence
+;Le reste de la ligne n'a pas d'importance;Test;Pas;Le;Bon;Nombre;De;Colonne
+Radiations ionisantes;Description de Tests;kBq U-235 eq
+Acidification;;mol H^{+} eq
+Épuisement des ressources naturelles (minérales et métaux);;kg Sb eq
diff --git a/services/api-referentiel/src/test/resources/csv/unit/csvHelper.csv b/services/api-referentiel/src/test/resources/csv/unit/csvHelper.csv
new file mode 100644
index 0000000000000000000000000000000000000000..7c564e13707692c785c81b091a1fa16d2c0ea07a
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/csvHelper.csv
@@ -0,0 +1,3 @@
+cle;valeurDouble
+PUEPardDfault;1.6
+DureeVieServeurParDefaut;3
diff --git a/services/api-referentiel/src/test/resources/csv/unit/etapeACV.csv b/services/api-referentiel/src/test/resources/csv/unit/etapeACV.csv
new file mode 100644
index 0000000000000000000000000000000000000000..d9a41e0350f80cde95d53d8e4baf1e9c25c5f484
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/etapeACV.csv
@@ -0,0 +1,5 @@
+code;libelle
+FABRICATION;Fabrication
+DISTRIBUTION;Distribution
+UTILISATION;Utilisation
+FIN_DE_VIE;Fin de vie
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/unit/etapeACV_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/etapeACV_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..dea9b4f7e854003fb8cf902bea5508a8f4d16bb8
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/etapeACV_errorInMiddle.csv
@@ -0,0 +1,5 @@
+code;libelle
+FABRICATION;Fabrication
+DISTRIBUTION;Distribution
+;Cette ligne n'a pas de code et est une erreur
+FIN_DE_VIE;Fin de vie
diff --git a/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv b/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a1a6b28614a66c174a8d3e58047a24c3dfa46a90
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv
@@ -0,0 +1,3 @@
+cle;valeur;source
+PUEPardDfault;1.6;expertise IJO
+DureeVieServeurParDefaut;3;US 46
diff --git a/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..66f419ba89de4a72df7b2341bce92633b44f34dd
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv
@@ -0,0 +1,5 @@
+cle;valeur;source
+PUEPardDfault;1.6;expertise IJO
+;PasUnChiffreMaisPasGrave;Test;Pas;Le;Bon;Nombre;De;Colonne
+ErreurValeur;;Test;Pas;Le;Bon;Nombre;De;Colonne
+DureeVieServeurParDefaut;3;US 46
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactEquipement.csv b/services/api-referentiel/src/test/resources/csv/unit/impactEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..c55231f9fe7d3f86bf29640465f97e5076fec363
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactEquipement.csv
@@ -0,0 +1,5 @@
+refEquipement;etapeacv;critere;consoElecMoyenne;valeur;source;type
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Changement climatique;30.1;149;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Changement climatique;29.1;11.0082325332;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Changement climatique;28.1;1.9485359999999998;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Changement climatique;1.1;1.46;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactEquipement_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/impactEquipement_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..bfd62dd039a54ad68bf2d90907eed0eefb5b22f4
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactEquipement_errorInMiddle.csv
@@ -0,0 +1,8 @@
+refEquipement;etapeacv;critere;consoElecMoyenne;valeur;source;type;description
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FABRICATION;Changement climatique;30.1;149;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable;description Ordinateur Portable 1
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";DISTRIBUTION;Changement climatique;29.1;11.0082325332;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable;description Ordinateur Portable 2
+;SansRefEquipement;Critère inconnu;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs;
+SansEtape;;Critère inconnu;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs;
+SansCritere;SansCritere;;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs;
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";UTILISATION;Changement climatique;28.1;1.9485359999999998;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable;description Ordinateur Portable 3
+"Ordinateur portable 14.5 8 Go RAM 564 Go SSD";FIN_DE_VIE;Changement climatique;1.1;1.46;Ref_Base_donnee_reference_20220728.xlsx;Ordinateur Portable;description Ordinateur Portable 4
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie.csv b/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie.csv
new file mode 100644
index 0000000000000000000000000000000000000000..8b416bf62f5d3a256a66346a76a6e7301dd0cb71
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie.csv
@@ -0,0 +1,6 @@
+critere;constanteCoefficientDirecteur;constanteOrdonneeOrigine;source
+Changement climatique;0.5;0;Tests
+Émissions de particules fines;1.000111;1.451;Tests
+Radiations ionisantes;0.00005;0.02315412;Tests
+Acidification;1.224586;0.042;Tests
+Épuisement des ressources naturelles (minérales et métaux);2.020;0.678;Tests
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..2a7c036879bee15c403492c412999987ec7c191d
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactMessagerie_errorInMiddle.csv
@@ -0,0 +1,4 @@
+critere;constanteCoefficientDirecteur;constanteOrdonneeOrigine;source
+Changement climatique;0.5;0;Tests
+;CritereAbsent;Messagerie;CritereAbsent;AutresColonnes;Inutiles
+Acidification;1.224586;0.042;Tests
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactreseau.csv b/services/api-referentiel/src/test/resources/csv/unit/impactreseau.csv
new file mode 100644
index 0000000000000000000000000000000000000000..d459911d45749e7911f3580666aa6f4279bd4006
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactreseau.csv
@@ -0,0 +1,7 @@
+refReseau;etapeACV;critere;valeur;unite;consoElecMoyenne;source
+impactReseauMobileMoyen;DISTRIBUTION;Changement climatique;1.428;;0.0020;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+impactReseauMobileMoyen;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+
+
diff --git a/services/api-referentiel/src/test/resources/csv/unit/impactreseau_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/impactreseau_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..869d874e13a138adfe9b5fe3fd2a93c0c096b646
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/impactreseau_errorInMiddle.csv
@@ -0,0 +1,10 @@
+refReseau;etapeACV;critere;valeur;unite;consoElecMoyenne;source
+impactReseauMobileMoyen;DISTRIBUTION;Changement climatique;1.428;;0.0020;RefTest V1.00
+impactReseauMobileMoyen;FABRICATION;Changement climatique;518.28;;;RefTest V1.00
+;RefReseauAbsent;RefReseauAbsent;;;;Test;Ces;Colonnes;Sont;Des;Erreurs
+RefEtapeAbsent;;RefEtapeAbsent;;;;Test;Ces;Colonnes;Sont;Des;Erreurs
+RefCritereAbsent;RefCritereAbsent;;;;;Test;Ces;Colonnes;Sont;Des;Erreurs
+impactReseauMobileMoyen;FIN_DE_VIE;Changement climatique;64.28;;;RefTest V1.00
+impactReseauMobileMoyen;UTILISATION;Changement climatique;76.28;;;RefTest V1.00
+
+
diff --git a/services/api-referentiel/src/test/resources/csv/unit/mixElectrique.csv b/services/api-referentiel/src/test/resources/csv/unit/mixElectrique.csv
new file mode 100644
index 0000000000000000000000000000000000000000..3c401da91bbb4bf29a78b4e2ee239afdbf1609f0
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/mixElectrique.csv
@@ -0,0 +1,5 @@
+pays      ;raccourcisAnglais;critere              ;valeur            ;source
+France    ;FR               ;Changement climatique;149               ;Ref_Base_donnee_reference_20480728.xlsx
+Brésil    ;BR               ;Changement climatique;11.0082325332     ;Ref_Base_donnee_reference_20480728.xlsx
+Angleterre;EN               ;Changement climatique;1.9485359999999998;Ref_Base_donnee_reference_20480728.xlsx
+USA       ;US               ;Changement climatique;1.46              ;Ref_Base_donnee_reference_20480728.xlsx
diff --git a/services/api-referentiel/src/test/resources/csv/unit/mixElectrique_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/mixElectrique_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..69025ee85e469ddeb7469cddc661d985b2571f95
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/mixElectrique_errorInMiddle.csv
@@ -0,0 +1,8 @@
+pays      ;raccourcisAnglais;critere              ;valeur            ;source
+France    ;FR               ;Changement climatique;149               ;Ref_Base_donnee_reference_20480728.xlsx
+Brésil    ;BR               ;Changement climatique;11.0082325332     ;Ref_Base_donnee_reference_20480728.xlsx
+;PaysAbsent;PaysAbsent;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs
+RaccourciPaysAbsent;;RaccourciPaysAbsent;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs
+CritereAbsent;CritereAbsent;;0.0;0.0;;Test;Ces;Colonnes;Sont;Des;Erreurs
+Angleterre;EN               ;Changement climatique;1.9485359999999998;Ref_Base_donnee_reference_20480728.xlsx
+USA       ;US               ;Changement climatique;1.46              ;Ref_Base_donnee_reference_20480728.xlsx
diff --git a/services/api-referentiel/src/test/resources/csv/unit/typeEquipement.csv b/services/api-referentiel/src/test/resources/csv/unit/typeEquipement.csv
new file mode 100644
index 0000000000000000000000000000000000000000..030ca4ded058814aea0494053c080de605adae79
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/typeEquipement.csv
@@ -0,0 +1,3 @@
+type;serveur;commentaire;dureeVieDefaut;source;refEquipementParDefaut
+Serveur;true;"Test simple";6.0;"Exemple de serveur basique";"serveur_par_defaut"
+Laptop;false;"Test simple";5.0;"ADEME, durée de vie des EEE, UF utiliser une ordinateur, écran non cathodique et LCD, https://vu.fr/bOQZ";"laptop_par_defaut"
diff --git a/services/api-referentiel/src/test/resources/csv/unit/typeEquipement_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/typeEquipement_errorInMiddle.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a53451b340c2897ad416dd032fe12e4bd710fe10
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/typeEquipement_errorInMiddle.csv
@@ -0,0 +1,4 @@
+type;serveur;commentaire;dureeVieDefaut;source;refEquipementParDefaut
+Serveur;true;"Test simple";6.0;"Exemple de serveur basique";"serveur_par_defaut"
+;TypeAbsent;"est une erreur";complete;"Sur toute";"La";"Ligne"
+Laptop;false;"Test simple";5.0;"ADEME, durée de vie des EEE, UF utiliser une ordinateur, écran non cathodique et LCD, https://vu.fr/bOQZ";"laptop_par_defaut"
diff --git a/services/api-referentiel/src/test/resources/csv/unit/wrongCSVFile.csv b/services/api-referentiel/src/test/resources/csv/unit/wrongCSVFile.csv
new file mode 100644
index 0000000000000000000000000000000000000000..7ab8b51e2d43fa6f1a8aff18a5a233f8b2c170e4
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/csv/unit/wrongCSVFile.csv
@@ -0,0 +1,2 @@
+mauvais
+fichier
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/logback.xml b/services/api-referentiel/src/test/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1590b19540cb03363e5b0f51632c759c23eb005e
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/logback.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+<!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+
+    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="FILE_LOG_CHARSET" value="${FILE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+<!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+</configuration>
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/services/api-referentiel/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000000000000000000000000000000000000..ca6ee9cea8ec189a088d50559325d4e84ff8ad09
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_criteres.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_criteres.feature
new file mode 100644
index 0000000000000000000000000000000000000000..afab48b85b94f1069409450e440e5d719b556fd8
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_criteres.feature
@@ -0,0 +1,17 @@
+#language: fr
+#encoding: utf-8
+
+Fonctionnalité: Gestion du referentiel DES CRITERES
+  Le but étant de rendre disponible le référentiel referentiel CRITERES afin de rendre possible
+  les calculs d'impacts environnementaux sur les équipements
+
+
+  Scénario: CAF1: alimentation en masse du referentiel CRITERES depuis un ficher csv
+    Quand le fichier CSV "csv/ref_Critere.csv" est inject
+    Alors Il existe 5 elements dans le referentiel critere
+    Et  chacun des elements du referential ajouté est identique au element du fichier csv
+
+
+
+
+
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_etape_acv.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_etape_acv.feature
new file mode 100644
index 0000000000000000000000000000000000000000..2addaecdb5b021d88d49f960acb9fba2551043e4
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_etape_acv.feature
@@ -0,0 +1,16 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Gestion du referentiel ETAPE ACV
+  Le but étant de rendre disponible le référentiel referentiel ETAPE ACV afin de rendre possible
+  les calculs d'impacts environnementaux sur les équipements
+
+
+  Scénario: CAF1: alimentation en masse du referentiel etape acv depuis un ficher csv
+    Quand le fichier CSV "csv/ref_etapeACV.csv" est injecte
+    Alors Il existe 4 elements dans le referentiel Etape ACV
+    Et  chacun des elements du referentiel ajouté est identique au element du fichier csv
+
+
+
+
+
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_facteurs_impact_reseau.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_facteurs_impact_reseau.feature
new file mode 100644
index 0000000000000000000000000000000000000000..d567c0bd1a16605d168526bab6229befabc1f3df
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_facteurs_impact_reseau.feature
@@ -0,0 +1,31 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Gestion du referentiel impact reseau
+  Le but étant de rendre disponible le référentiel refImpactReseau afin de rendre possible
+  les calculs d'impacts environnementaux sur les équipements
+
+
+  Scénario: CAF1: Ajouter un facteur impact lié au reseau dans la table ref_impactReseau
+    Quand on ajoute un facteur impact reseau dont la refReseau est "impactReseauMobileMoyen", etapeACV est  "UTILISATION" ,  critere est "Acidification" la source est "RefTest V1.00" la valeur est "8.28" et l'unité est "mol H^{+} eq"
+    Alors impact reseau est persister dans la table ref_impactReseau  avec les elements suivants: la refReseau est "impactReseauMobileMoyen", etapeACV est  "UTILISATION" ,  critere est "Acidification" la source est "RefTest V1.00" la valeur est "8.28" et l'unité est "mol H^{+} eq"
+
+
+  Scénario: CAF2: Ajouter un facteur impact lié au reseau dans la table ref_impactReseau sans unité ni valeur et modification des valeurs unite et valeur de l'impact reseau ajouté
+    Quand on persiste un facteur impact reseau dont la refReseau est "impactReseauMobileFRANCE", etapeACV est  "FABRICATION" ,  critere est "Radiations ionisantes" la source est "RefTest V1.00"
+    Alors il est possible de modifier impact  Reseau avec les élements suivants: le refReseau est "impactReseauMobileFRANCE", etapeACV est  "FABRICATION" ,  critere est "Radiations ionisantes" la source est "RefTest V1.00", valeur est "10" et l'unité est "kBq U-235 eq"
+
+  Scénario: CAF3: interdir l'ajout d'un facteur impact lié au reseau dans la table ref_impactReseau sans source
+    Quand on ajoute un facteur impact reseau dont la refReseau est "impactReseauMobileMoyenSansSource", etapeACV est  "UTILISATION" ,  critere est "Changement Climatique"  la valeur est "8.28" et l'unité est "CO2 eq / an"
+    Alors Impossible d ajouter l'impact réseau dans la table ref_impactreseau
+
+  Scénario: CAF4: alimentation en masse du referentiel impact reseau depuis un ficher csv
+    Quand le fichier CSV "csv/ref_impactreseau.csv" est envoyé
+    Alors l impact reseau  refReseal est "impactReseauMobile2G", etapeACV est  "UTILISATION" ,  critere est "Radiations ionisantes" la source est "RefTest V1.00" la valeur est "18.8" et l'unité est "kBq U-235 eq" existe
+
+
+  Scénario: CAF5: impact reseau qui n'existe pas
+    Quand on cherche l impact reseau  dont la refReseau est "nexistepas", etapeACV est  "nexistepas" ,  critere est "nexistepas"
+    Alors lecture reponse impact resau n existe pas
+
+
+
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_hypothese.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_hypothese.feature
new file mode 100644
index 0000000000000000000000000000000000000000..4a29f7174acb57cd6e455d7812f60b35c2fb5ba1
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_hypothese.feature
@@ -0,0 +1,19 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Gestion du referentiel DES HYPOTHESES
+  Le but étant de rendre disponible le référentiel referentiel DES HYPOTHESES afin de rendre possible
+  les calculs d'impacts environnementaux sur les équipements
+
+
+  Scénario: CAF1: alimentation en masse du referentiel DES HYPOTHESES depuis un ficher csv
+    Quand le fichier CSV REF HYPOTHESE"csv/ref_Hypothese.csv" est inject
+    Alors le statut http est 200
+
+
+  Scénario: CAF2: recherche d'une hypothese
+    Quand lors de la recherche de hypothese avec la cle "PUEPardDfault"
+    Alors Le resultat est : cle = "PUEPardDfault" valeur="1.6" et source="expertise IJO"
+
+
+
+
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_impact_equipement.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_impact_equipement.feature
new file mode 100644
index 0000000000000000000000000000000000000000..4b6a862aff1b5c0f77012836479448bf2fff85e5
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_impact_equipement.feature
@@ -0,0 +1,25 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Gestion du referentiel ref_ImpactEquipement
+  Chargement et Mise à disposition du référentiel des impacts d'équipements.
+
+
+  Scénario: Sprint 10 - Taiga 869: Ajout d'une colonne description
+    Quand le fichier CSV des impacts d'équipements "csv/sprint10/ref_ImpactEquipement.csv" est importé par API et la réponse est 200
+    Alors La récupération de tous les impacts d'équipements renvoie 6 lignes
+    Et Vérifications des impacts équipements disponibles
+      | etape       | critere               | refEquipement                     | valeur               | consoElecMoyenne  | source             | type                           | description                                                  |
+      | FIN_DE_VIE  | Acidification         | computer monitor-01-23            | 0.020296259210277726 | 35.81692801813716 | reftest_20221013 | computer monitor               | Description Impact Equipement computer monitor               |
+      | FABRICATION | Radiations ionisantes | digital price tag - power unit-01 | 5.89E+01             |                   | reftest_20221013 | digital price tag - power unit | Description Impact Equipement digital price tag - power unit |
+      | FABRICATION | Radiations ionisantes | docking station-01                | 3.50E+01             | 1.28              | reftest_20221013 | docking station                | Description Impact Equipement docking station                |
+      | FABRICATION | Radiations ionisantes | empty 42u bay-01                  | 5.87E+01             |                   | reftest_20221013 | empty 42u bay                  | Description Impact Equipement empty 42u bay                  |
+      | FABRICATION | Radiations ionisantes | feature phone-01                  | 5.11E+00             | 0.09              | reftest_20221013 | feature phone                  | Description Impact Equipement feature phone                  |
+      | FABRICATION | Radiations ionisantes | firewall-01                       | 2.65E+02             | 876               | reftest_20221013 | firewall                       | Description Impact Equipement firewall                       |
+
+
+
+
+
+
+
+
diff --git a/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_sprint10.feature b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_sprint10.feature
new file mode 100644
index 0000000000000000000000000000000000000000..c60c9988efe00a25520134de3d144ce22a54506e
--- /dev/null
+++ b/services/api-referentiel/src/test/resources/org/mte/numecoeval/referentiel/referentiel_sprint10.feature
@@ -0,0 +1,42 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Sprint 10 - Features du Sprint 10 (type équipement par défaut, correspondances...)
+  Nouvelles features disponibles:
+  - Reférentiel TypeEquipement avec le refEquipementParDefaut correctement géré
+  - Nouveau référentiel CorrespondanceRefEquipement
+
+
+  Scénario: Sprint 10 - Taiga 862: Ajout d'une colonne refEquipementParDefaut dans ref_TypeEquipement
+    Quand le fichier CSV des types d'équipements "csv/sprint10/ref_TypeEquipement.csv" est importé par API et la réponse est 200
+    Alors La récupération de tous les types d'équipements renvoie 17 lignes
+    Et La récupération unitaire d'un type équipement "ServeurCalcul" répond 200
+    Et Vérifications des types d'équipements disponibles
+      | type                     | serveur | commentaire                   | dureeVieDefaut | refEquipementParDefaut    | source |
+      | ServeurCalcul            | true    | commentaires                  | 6              | serveur_par_defaut        | Test   |
+      | ServeurStockage          | true    |                               | 6              | serveur_par_defaut        | Test   |
+      | Armoire                  | false   |                               | 7              | armoir_par_defaut         | Test   |
+      | NAS                      | false   |                               | 6              | baie_stockage_par_defaut  | Test   |
+      | Switch                   | false   |                               | 6              | switch_par_defaut         | Test   |
+      | OrdinateurPortable       | false   |                               | 4              | laptop_par_defaut         | Test   |
+      | OrdinateurDeBureau       | false   |                               | 5              | desktop_par_defaut        | Test   |
+      | Tablette                 | false   |                               | 2.5            | tablette_par_defaut       | Test   |
+      | TelephoneMobile          | false   | commentaires                  | 2.5            | smartphone_par_defaut     | Test   |
+      | TelephoneFixe            | false   |                               | 10             | telephone_fixe_par_defaut | Test   |
+      | EquipementReseau         | false   | commentaires                  | 5              | switch_par_defaut         | Test   |
+      | BorneWifi                | false   |                               | 4              | borneWifi_par_defaut      | Test   |
+      | Imprimante               | false   |                               | 5              | imprimante_par_defaut     | Test   |
+      | Ecran                    | false   |                               | 8              | ecran_par_defaut          | Test   |
+      | AccessoirePosteDeTravail | false   | souris calvier, camera casque | 7              | stationTravail_par_defaut | Test   |
+      | Connectique              | false   |                               | 7              |                           | Test   |
+      | Autre                    | false   |                               | 2              |                           | Test   |
+
+
+  Scénario: Sprint 10 - Taiga 319: Import des données de correspondances de références d'équipements
+    Quand le fichier CSV des correspondances d'équipements "csv/sprint10/ref_CorrespondanceRefEquipement.csv" est importé par API et la réponse est 200
+    Alors La récupération de tous les correspondances d'équipements renvoie 3 lignes
+    Et Vérifications des correspondances d'équipements disponibles
+      | modeleEquipementSource | refEquipementCible |
+      | Fairphone V1           | smartphone01       |
+      | Fairphone V2           | smartphone01       |
+      | Ecran 27 pouces        | ecran01            |
+
diff --git a/services/calculs/LICENSE b/services/calculs/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..7e131afa7da0169b169ddbbf4f1470b988a20be8
--- /dev/null
+++ b/services/calculs/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2023 pub / Numérique et Écologie / NumEcoEval - M4G
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/services/calculs/README.md b/services/calculs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d1a5f7b2c0370887b775ae7b17e86adba8d61ec8
--- /dev/null
+++ b/services/calculs/README.md
@@ -0,0 +1,27 @@
+# calculs
+
+Module contenant l'intégralité des règles de calculs et du code métier lié aux calculs d'impact d'équipement.
+
+**Ce module s'utilise comme une librairie et non comme une application.**
+
+## Requirements
+
+- Any JDK 17 Implementation
+    - [Coretto](https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/downloads-list.html)
+    - [Open JDK](https://jdk.java.net/java-se-ri/17)
+- [Maven 3](https://maven.apache.org/download.cgi)
+- IDE compatible with Maven 3 and JDK 17 are highly recommended to develop
+
+### Build
+
+To build the app :
+
+```bash
+mvn clean install
+```
+
+## License
+Le projet est sous licence Apache 2
+
+## Project status
+If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
diff --git a/services/calculs/ci_settings.xml b/services/calculs/ci_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5205903f74a7c01cd6aa2a74c856a197ee99824e
--- /dev/null
+++ b/services/calculs/ci_settings.xml
@@ -0,0 +1,16 @@
+<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
+    <servers>
+        <server>
+            <id>gitlab-maven</id>
+            <configuration>
+                <httpHeaders>
+                    <property>
+                        <name>Job-Token</name>
+                        <value>${env.CI_JOB_TOKEN}</value>
+                    </property>
+                </httpHeaders>
+            </configuration>
+        </server>
+    </servers>
+</settings>
diff --git a/services/calculs/dependency_check_suppressions.xml b/services/calculs/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e4bfe629077460e8a73135f51fe1dd571b06ee0
--- /dev/null
+++ b/services/calculs/dependency_check_suppressions.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+</suppressions>
diff --git a/services/calculs/pom.xml b/services/calculs/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..75e41b0c8b7cb0db889738a4327c665d6d0911dc
--- /dev/null
+++ b/services/calculs/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <artifactId>calculs</artifactId>
+    <version>1.2.3-SNAPSHOT</version>
+    <name>calculs</name>
+    <description>Module contenant l'intégralité des règles de calculs et du code métier lié aux calculs d'impact
+        d'équipement
+    </description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <properties>
+    </properties>
+    <dependencies>
+        <!-- Pour les JsonType -->
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+        </dependency>
+        <!-- Pour les loggers -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <!-- Utilitaires -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${apache-commons-lang3.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>${apache-commons-collection4.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${apache-commons-io.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Données de tests -->
+        <dependency>
+            <groupId>org.instancio</groupId>
+            <artifactId>instancio-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Tests fonctionnels -->
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-suite</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-java</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-junit-platform-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactApplication.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2b6d4b4d42593924978fcdb31f154b5d43c22ee
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactApplication.java
@@ -0,0 +1,34 @@
+package org.mte.numecoeval.calculs.domain.data.demande;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class DemandeCalculImpactApplication {
+
+    LocalDateTime dateCalcul;
+    Application application;
+    Integer nbApplications;
+    ImpactEquipementVirtuel impactEquipementVirtuel;
+
+    /**
+     * Renvoie le nombre d'application pour un calcul.
+     * @return si nbApplications est différent de null et supérieur à 0, renvoie {@link #nbApplications} sinon {@code 1}
+     */
+    public Integer getNbApplicationsForCalcul() {
+        if(nbApplications != null && nbApplications > 0){
+            return nbApplications;
+        }
+
+        return 1;
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementPhysique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..535d1b7752e34cdeaf23f35c48df00c5f808914d
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementPhysique.java
@@ -0,0 +1,90 @@
+package org.mte.numecoeval.calculs.domain.data.demande;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.collections4.CollectionUtils;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.referentiel.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class DemandeCalculImpactEquipementPhysique {
+
+    LocalDateTime dateCalcul;
+
+    EquipementPhysique equipementPhysique;
+
+    ReferentielEtapeACV etape;
+
+    ReferentielCritere critere;
+
+    ReferentielTypeEquipement typeEquipement;
+
+    ReferentielCorrespondanceRefEquipement correspondanceRefEquipement;
+
+    List<ReferentielHypothese> hypotheses;
+
+    List<ReferentielImpactEquipement> impactEquipements;
+
+    List<ReferentielMixElectrique> mixElectriques;
+
+    public Optional<ReferentielHypothese> getHypotheseFromCode(String code) {
+        if (code == null) {
+            return Optional.empty();
+        }
+        return CollectionUtils.emptyIfNull(hypotheses)
+                .stream()
+                .filter(hypothese -> code.equals(hypothese.getCode()))
+                .findFirst();
+    }
+
+    public Optional<ReferentielImpactEquipement> getImpactEquipement(String refEquipement) {
+        if (refEquipement == null) {
+            return Optional.empty();
+        }
+        return CollectionUtils.emptyIfNull(impactEquipements)
+                .stream()
+                .filter(Objects::nonNull)
+                .filter(impactEquipement -> refEquipement.equals(impactEquipement.getRefEquipement())
+                        && critere.getNomCritere().equals(impactEquipement.getCritere())
+                        && etape.getCode().equals(impactEquipement.getEtape())
+                )
+                .findFirst();
+    }
+
+    public Optional<ReferentielMixElectrique> getMixElectrique(String pays) {
+        if (pays == null) {
+            return Optional.empty();
+        }
+        return CollectionUtils.emptyIfNull(mixElectriques)
+                .stream()
+                .filter(Objects::nonNull)
+                .filter(mixElectrique -> pays.equals(mixElectrique.getPays())
+                        && critere.getNomCritere().equals(mixElectrique.getCritere())
+                )
+                .findFirst();
+    }
+
+    public String getRefEquipementCible() {
+        if (correspondanceRefEquipement != null) {
+            return correspondanceRefEquipement.getRefEquipementCible();
+        }
+        return null;
+    }
+
+    public String getRefEquipementParDefaut() {
+        if (typeEquipement != null) {
+            return typeEquipement.getRefEquipementParDefaut();
+        }
+        return null;
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementVirtuel.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementVirtuel.java
new file mode 100644
index 0000000000000000000000000000000000000000..abb39c39557c7d143901117024bc15d921db76f2
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactEquipementVirtuel.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.calculs.domain.data.demande;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class DemandeCalculImpactEquipementVirtuel {
+
+    LocalDateTime dateCalcul;
+    EquipementVirtuel equipementVirtuel;
+    Integer nbEquipementsVirtuels;
+    Integer nbTotalVCPU;
+    ImpactEquipementPhysique impactEquipement;
+    Double stockageTotalVirtuel;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactMessagerie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c10b3bea5a60cffb81e636bb1c031147855c614
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactMessagerie.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.calculs.domain.data.demande;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.domain.data.entree.Messagerie;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielCritere;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactMessagerie;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class DemandeCalculImpactMessagerie {
+
+    LocalDateTime dateCalcul;
+
+    Messagerie messagerie;
+
+    ReferentielCritere critere;
+
+    List<ReferentielImpactMessagerie> impactsMessagerie;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactReseau.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactReseau.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a76a7ad0a11c40ac071c8d9ac501555a609f5b5
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactReseau.java
@@ -0,0 +1,30 @@
+package org.mte.numecoeval.calculs.domain.data.demande;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielCritere;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielEtapeACV;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactReseau;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class DemandeCalculImpactReseau {
+
+    LocalDateTime dateCalcul;
+
+    EquipementPhysique equipementPhysique;
+
+    ReferentielEtapeACV etape;
+
+    ReferentielCritere critere;
+
+    List<ReferentielImpactReseau> impactsReseau;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Application.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Application.java
new file mode 100644
index 0000000000000000000000000000000000000000..74624e548f6092dbd2615fd7ed336ac4cb175bea
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Application.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.calculs.domain.data.entree;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+public class Application {
+   private String nomApplication;
+   private String typeEnvironnement;
+   private String nomEquipementVirtuel;
+   private String nomSourceDonneeEquipementVirtuel;
+
+   private String nomEquipementPhysique;
+   private String domaine;
+   private String sousDomaine;
+   private String nomLot;
+   private LocalDate dateLot;
+   private String nomOrganisation;
+   private String nomEntite;
+   private String nomSourceDonnee;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/DataCenter.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/DataCenter.java
new file mode 100644
index 0000000000000000000000000000000000000000..482552781c5a0a9406fa9c3b32a38fd4d3ea3635
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/DataCenter.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.calculs.domain.data.entree;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+public class DataCenter {
+
+   private String nomCourtDatacenter;
+   private String nomLongDatacenter;
+   private Double pue;
+   private String localisation;
+   private String nomLot;
+   private LocalDate dateLot;
+   private String nomOrganisation;
+   private String nomEntite;
+   private String nomSourceDonnee;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementPhysique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a054b521bdca26b1c432d0791ffb02230c6d67c
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementPhysique.java
@@ -0,0 +1,39 @@
+package org.mte.numecoeval.calculs.domain.data.entree;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Data
+@Builder
+public class EquipementPhysique {
+    private String nomEquipementPhysique;
+    private String modele;
+    private String type;
+    private Double consoElecAnnuelle;
+    private String statut;
+    private String paysDUtilisation;
+    private String utilisateur;
+    private LocalDate dateAchat;
+    private LocalDate dateRetrait;
+    private Double quantite;
+    private Float goTelecharge;
+    private Double nbJourUtiliseAn;
+    private String nbCoeur;
+    private String nomCourtDatacenter;
+    private DataCenter dataCenter;
+    private boolean serveur;
+    private Double dureeVieDefaut;
+    private List<EquipementVirtuel> equipementsVirtuels;
+    private String nomLot;
+    private LocalDate dateLot;
+    private String nomOrganisation;
+    private String nomEntite;
+    private String nomSourceDonnee;
+    private Integer nbEquipementsVirtuels;
+    private Integer nbTotalVCPU;
+    private String modeUtilisation;
+    private Double tauxUtilisation;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementVirtuel.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementVirtuel.java
new file mode 100644
index 0000000000000000000000000000000000000000..dad80c1a27a19dee0a200abb12bcc5a9fd59e191
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/EquipementVirtuel.java
@@ -0,0 +1,27 @@
+package org.mte.numecoeval.calculs.domain.data.entree;
+
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+public class EquipementVirtuel {
+   private Long id;
+   private String nomEquipementVirtuel;
+   private String nomEquipementPhysique;
+   private String nomSourceDonneeEquipementPhysique;
+   private Integer vCPU;
+   private String cluster;
+   private String nomLot;
+   private LocalDate dateLot;
+   private String nomOrganisation;
+   private String nomEntite;
+   private String nomSourceDonnee;
+   private Double consoElecAnnuelle;
+   private String typeEqv;
+   private Double capaciteStockage;
+   private Double cleRepartition;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Messagerie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Messagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..3df95aa446c20b71fccdada404969a205243a1a6
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/Messagerie.java
@@ -0,0 +1,21 @@
+package org.mte.numecoeval.calculs.domain.data.entree;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+public class Messagerie {
+    private Double volumeTotalMailEmis;
+    private Double nombreMailEmis;
+    private Double nombreMailEmisXDestinataires;
+    private Integer moisAnnee;
+    private String nomLot;
+    private LocalDate dateLot;
+    private String nomOrganisation;
+    private String nomEntite;
+    private String nomSourceDonnee;
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/erreur/TypeErreurCalcul.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/erreur/TypeErreurCalcul.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b5e35d783849c604d885f22be911d0751c2c410
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/erreur/TypeErreurCalcul.java
@@ -0,0 +1,14 @@
+package org.mte.numecoeval.calculs.domain.data.erreur;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum TypeErreurCalcul {
+
+    ERREUR_FONCTIONNELLE("ErrCalcFonc"),
+    ERREUR_TECHNIQUE("ErrCalcTech");
+
+    private final String code;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactApplication.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f6152589735ee740aaa8a4f1ac8b6553d07e843
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactApplication.java
@@ -0,0 +1,38 @@
+package org.mte.numecoeval.calculs.domain.data.indicateurs;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ImpactApplication {
+    LocalDateTime dateCalcul;
+    String versionCalcul;
+    String etapeACV;
+    String critere;
+    String source;
+    String statutIndicateur;
+    String trace;
+    String nomLot;
+    LocalDate dateLot;
+    String unite;
+    String nomOrganisation;
+    String nomEntite;
+    String nomSourceDonnee;
+    String nomEquipementPhysique;
+    String nomEquipementVirtuel;
+    String nomApplication;
+    String typeEnvironnement;
+    String domaine;
+    String sousDomaine;
+    Double impactUnitaire;
+    Double consoElecMoyenne;
+    Long idEntree;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementPhysique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..610d6bd2d194b01d38e7934594fe697e6ec85d4c
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementPhysique.java
@@ -0,0 +1,36 @@
+package org.mte.numecoeval.calculs.domain.data.indicateurs;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ImpactEquipementPhysique {
+    LocalDateTime dateCalcul;
+    String versionCalcul;
+    String etapeACV;
+    String critere;
+    String source;
+    String statutIndicateur;
+    String trace;
+    String nomLot;
+    LocalDate dateLot;
+    String unite;
+    String nomOrganisation;
+    String nomEntite;
+    String nomSourceDonnee;
+    String reference;
+    String nomEquipement;
+    String typeEquipement;
+    Double impactUnitaire;
+    Double consoElecMoyenne;
+    Double quantite;
+    String statutEquipementPhysique;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementVirtuel.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementVirtuel.java
new file mode 100644
index 0000000000000000000000000000000000000000..03965dc478515c30813ab101e9290b0b2468bf3a
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactEquipementVirtuel.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.calculs.domain.data.indicateurs;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ImpactEquipementVirtuel {
+    LocalDateTime dateCalcul;
+    String versionCalcul;
+    String etapeACV;
+    String critere;
+    String source;
+    String statutIndicateur;
+    String trace;
+    String nomLot;
+    LocalDate dateLot;
+    String unite;
+    String nomOrganisation;
+    String nomEntite;
+    String nomEquipement;
+    String nomSourceDonnee;
+    String nomEquipementVirtuel;
+    String cluster;
+    Double impactUnitaire;
+    Double consoElecMoyenne;
+    Long idEntree;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactMessagerie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..d87ca2658241a8caf1d373971eedd769ed4a26d3
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactMessagerie.java
@@ -0,0 +1,34 @@
+package org.mte.numecoeval.calculs.domain.data.indicateurs;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ImpactMessagerie {
+
+    LocalDateTime dateCalcul;
+    String versionCalcul;
+    String critere;
+    String source;
+    String statutIndicateur;
+    String trace;
+    String nomLot;
+    LocalDate dateLot;
+    String unite;
+    String nomOrganisation;
+    String nomEntite;
+    String nomSourceDonnee;
+    Double impactMensuel;
+    Integer moisAnnee;
+    Double volumeTotalMailEmis;
+    Double nombreMailEmis;
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactReseau.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactReseau.java
new file mode 100644
index 0000000000000000000000000000000000000000..b439f953b01e5a569351531bc6e7202cb3086687
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactReseau.java
@@ -0,0 +1,35 @@
+package org.mte.numecoeval.calculs.domain.data.indicateurs;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ImpactReseau {
+    LocalDateTime dateCalcul;
+    String etapeACV;
+    String critere;
+    String nomLot;
+    LocalDate dateLot;
+    String nomOrganisation;
+    String nomEquipement;
+    String nomEntite;
+    String nomSourceDonnee;
+
+
+    String versionCalcul;
+    String source;
+    String statutIndicateur;
+    String trace;
+    String unite;
+    Double impactUnitaire;
+    String reference;
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCorrespondanceRefEquipement.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCorrespondanceRefEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..0170b74f45258cdc82678b6f7839ede9316b3cfa
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCorrespondanceRefEquipement.java
@@ -0,0 +1,17 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ReferentielCorrespondanceRefEquipement {
+
+    String modeleEquipementSource;
+
+    String refEquipementCible;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java
new file mode 100644
index 0000000000000000000000000000000000000000..20969e5659b259d9119c2fed8f7fd541e5e33ed5
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class ReferentielCritere {
+    String nomCritere;
+    String unite;
+    String description;
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e42c59578ccf75c0eb96b00407d831a63608f38
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java
@@ -0,0 +1,12 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class ReferentielEtapeACV {
+    String code;
+    String libelle;
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java
new file mode 100644
index 0000000000000000000000000000000000000000..351db7d66d9947e2ac313724bf41f43e823a7507
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java
@@ -0,0 +1,14 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class ReferentielHypothese {
+
+    private String code;
+    private Double valeur;
+    private String source;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactEquipement.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..7aa514cd4808e05407038779ed340d1f269dcd63
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactEquipement.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class ReferentielImpactEquipement {
+    String refEquipement;
+    String etape;
+    String critere;
+    String source;
+    String type;
+    Double valeur;
+    Double consoElecMoyenne;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactMessagerie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..127756ae7ea32e49e0e2f9099099fd47d151d43f
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactMessagerie.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class ReferentielImpactMessagerie {
+    private Double constanteCoefficientDirecteur;
+    private Double constanteOrdonneeOrigine;
+    private String critere;
+    private String source;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactReseau.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactReseau.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ed08356e812f8bd1fb850973b325d6b747a3aa2
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielImpactReseau.java
@@ -0,0 +1,19 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class ReferentielImpactReseau {
+
+    private String refReseau;
+    private String critere;
+    private String etapeACV;
+    private String unite;
+    private String source;
+    private Double impactReseauMobileMoyen;
+    private Double consoElecMoyenne;
+
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielMixElectrique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielMixElectrique.java
new file mode 100644
index 0000000000000000000000000000000000000000..67ca444976078a561a1864094094daf591fa4207
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielMixElectrique.java
@@ -0,0 +1,14 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class ReferentielMixElectrique {
+    String pays;
+    String raccourcisAnglais;
+    String critere;
+    Double valeur;
+    String source;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeEquipement.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeEquipement.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a762ff5acb8a82fdd5d36366bfef40ab65e81fb
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeEquipement.java
@@ -0,0 +1,24 @@
+package org.mte.numecoeval.calculs.domain.data.referentiel;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Builder
+@AllArgsConstructor
+@Getter
+@Setter
+public class ReferentielTypeEquipement {
+    String type;
+
+    Boolean serveur;
+
+    String commentaire;
+
+    Double dureeVieDefaut;
+
+    String source;
+
+    String refEquipementParDefaut;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc99e3b335011d4d6505df09d9031f0884f2ee23
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ConsoElecAnMoyenne {
+    private Double valeur;
+    private Double valeurEquipementConsoElecAnnuelle;
+    private Double valeurReferentielConsoElecMoyenne;
+    private String sourceReferentielImpactEquipement;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVie.java
new file mode 100644
index 0000000000000000000000000000000000000000..1697802d26401dc1ea96a00c489736255873adfa
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVie.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DureeDeVie {
+    private Double valeur;
+    private String dateAchat;
+    private String dateRetrait;
+    private DureeDeVieParDefaut dureeDeVieParDefaut;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb046fc9dabf3a04fd721242479f381e525fe352
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DureeDeVieParDefaut {
+    private  Double valeur;
+    private Double valeurEquipementDureeVieDefaut;
+    private Double valeurReferentielHypothese;
+    private String sourceReferentielHypothese;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f6e0e459f790242b1391067eae37902067ac2a8
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class MixElectrique {
+    private Double valeur;
+    private boolean isServeur;
+    private Double dataCenterPue;
+    private Double valeurReferentielMixElectrique;
+    private String sourceReferentielMixElectrique;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactApplication.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6da1f22d306c88d20fca972716e90556cf93a6a
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactApplication.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TraceCalculImpactApplication {
+
+    String formule;
+    String erreur;
+    Integer nbApplications;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementPhysique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementPhysique.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8236a86cc4aed6439fa5fc27fb7b85f97f8ab98
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementPhysique.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TraceCalculImpactEquipementPhysique {
+    private String formule;
+    private ConsoElecAnMoyenne consoElecAnMoyenne;
+    private MixElectrique mixElectrique;
+    private Double valeurReferentielImpactEquipement;
+    private String sourceReferentielImpactEquipement;
+    private DureeDeVie dureeDeVie;
+    private String erreur;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementVirtuel.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementVirtuel.java
new file mode 100644
index 0000000000000000000000000000000000000000..910b9402278dd376bcd8395af7802ff405dc0172
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactEquipementVirtuel.java
@@ -0,0 +1,16 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TraceCalculImpactEquipementVirtuel {
+    String formule;
+    String erreur;
+    Integer nbEquipementsVirtuels;
+    Integer nbTotalVCPU;
+    Double stockageTotalVirtuel;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactMessagerie.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactMessagerie.java
new file mode 100644
index 0000000000000000000000000000000000000000..b13e97b987be11669b5bbaaef0a1a1e92cc21129
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactMessagerie.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TraceCalculImpactMessagerie {
+    private String critere;
+    private Double volumeTotalMailEmis;
+    private Double nombreMailEmis;
+    private Double constanteCoefficientDirecteur;
+    private Double poidsMoyenMail;
+    private Double constanteOrdonneeOrigine;
+    private Double nombreMailEmisXDestinataires;
+    private String formule;
+    private String erreur;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactReseau.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactReseau.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae8dd1e0118cd535bb1c6a3ce01e27897c8d18fe
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactReseau.java
@@ -0,0 +1,20 @@
+package org.mte.numecoeval.calculs.domain.data.trace;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class TraceCalculImpactReseau {
+
+    private String critere;
+    private String etapeACV;
+    private String sourceReferentielReseau;
+    private String equipementPhysique;
+    private String impactReseauMobileMoyen;
+    private String goTelecharge;
+    private String formule;
+    private String erreur;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactException.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactException.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6efb40b2e8e939b5ca22461608432ef168d336c
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactException.java
@@ -0,0 +1,15 @@
+package org.mte.numecoeval.calculs.domain.exception;
+
+public class CalculImpactException extends Exception{
+
+    private final String errorType;
+
+    public CalculImpactException(String errorType,String message) {
+        super(message);
+        this.errorType = errorType;
+    }
+
+    public String getErrorType() {
+        return errorType;
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactRuntimeException.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc4fd98eae5e835bb09c91bab48e98152901284c
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/exception/CalculImpactRuntimeException.java
@@ -0,0 +1,25 @@
+package org.mte.numecoeval.calculs.domain.exception;
+
+public class CalculImpactRuntimeException extends RuntimeException{
+
+    private final String errorType;
+
+    public CalculImpactRuntimeException(String message) {
+        super(message);
+        this.errorType = null;
+    }
+
+    public CalculImpactRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+        this.errorType = null;
+    }
+
+    public CalculImpactRuntimeException(String errorType, String message ) {
+        super(message);
+        this.errorType = errorType;
+    }
+
+    public String getErrorType() {
+        return errorType;
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactApplicationService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactApplicationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..197a7964407f7ce00bc52031671a02c45f75f91c
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactApplicationService.java
@@ -0,0 +1,10 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactApplication;
+
+public interface CalculImpactApplicationService {
+
+    ImpactApplication calculImpactApplicatif(DemandeCalculImpactApplication demandeCalcul);
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementPhysiqueService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementPhysiqueService.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f32ad22c12844600bd38dafea96720a2e6a1dc3
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementPhysiqueService.java
@@ -0,0 +1,9 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+
+public interface CalculImpactEquipementPhysiqueService {
+
+    ImpactEquipementPhysique calculerImpactEquipementPhysique(DemandeCalculImpactEquipementPhysique demandeCalculImpactEquipementPhysique);
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementVirtuelService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementVirtuelService.java
new file mode 100644
index 0000000000000000000000000000000000000000..68bb60360af6679ce1db69d1853c739e136bf1b7
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactEquipementVirtuelService.java
@@ -0,0 +1,9 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+
+public interface CalculImpactEquipementVirtuelService {
+
+    ImpactEquipementVirtuel calculerImpactEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demandeCalcul);
+}
\ No newline at end of file
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactMessagerieService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactMessagerieService.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4ad44395299d1e99f83a7dc9656571f6f57dd80
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactMessagerieService.java
@@ -0,0 +1,10 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactMessagerie;
+
+public interface CalculImpactMessagerieService {
+
+    ImpactMessagerie calculerImpactMessagerie(DemandeCalculImpactMessagerie demandeCalcul);
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactReseauService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactReseauService.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d2b8b5bd7a4c2a29f152db7e20a5fc77f3024aa
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactReseauService.java
@@ -0,0 +1,12 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau;
+
+public interface CalculImpactReseauService {
+
+    String REF_RESEAU = "impactReseauMobileMoyen";
+
+    ImpactReseau calculerImpactReseau(DemandeCalculImpactReseau demandeCalcul);
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/DureeDeVieEquipementPhysiqueService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/DureeDeVieEquipementPhysiqueService.java
new file mode 100644
index 0000000000000000000000000000000000000000..2eb64689e557ea19a0dc4e61097c43f87c8b534b
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/DureeDeVieEquipementPhysiqueService.java
@@ -0,0 +1,13 @@
+package org.mte.numecoeval.calculs.domain.port.input.service;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVieParDefaut;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+
+public interface DureeDeVieEquipementPhysiqueService {
+
+    DureeDeVieParDefaut calculerDureeVieDefaut(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException;
+
+    DureeDeVie calculerDureeVie(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException;
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2ff97428a7bbf4f85bfd9f5686905a611ce8f43
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java
@@ -0,0 +1,129 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactApplication;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactApplicationService;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactApplicationUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactVirtuelUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceUtils;
+
+@Slf4j
+@AllArgsConstructor
+public class CalculImpactApplicationServiceImpl implements CalculImpactApplicationService {
+
+    private static final String VERSION_CALCUL = "1.1";
+
+    private ObjectMapper objectMapper;
+
+    @Override
+    public ImpactApplication calculImpactApplicatif(DemandeCalculImpactApplication demandeCalcul) {
+        ImpactApplication impactErreur;
+        try {
+            return calculerImpact(demandeCalcul);
+        } catch (CalculImpactException e) {
+            log.debug("Erreur de calcul d'impact d'équipement virtuel : Type : {}, Cause: {}, Etape: {}, Critere: {}, Nom Equipment Physique: {}, Nom Equipement Virtuel: {}, Nom Application: {}, Type Environnement: {}",
+                    e.getErrorType(), e.getMessage(),
+                    demandeCalcul.getImpactEquipementVirtuel().getEtapeACV(),
+                    demandeCalcul.getImpactEquipementVirtuel().getCritere(),
+                    demandeCalcul.getApplication().getNomEquipementPhysique(),
+                    demandeCalcul.getApplication().getNomEquipementVirtuel(),
+                    demandeCalcul.getApplication().getNomApplication(),
+                    demandeCalcul.getApplication().getTypeEnvironnement()
+            );
+
+            impactErreur = buildImpactForError(demandeCalcul, e);
+        } catch (Exception e) {
+            log.debug("Erreur de calcul d'impact d'équipement virtuel : Type : {}, Cause: {}, Etape: {}, Critere: {}, Nom Equipment Physique: {}, Nom Equipement Virtuel: {}, Nom Application: {}, Type Environnement: {}",
+                    TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage(),
+                    demandeCalcul.getImpactEquipementVirtuel().getEtapeACV(),
+                    demandeCalcul.getImpactEquipementVirtuel().getCritere(),
+                    demandeCalcul.getApplication().getNomEquipementPhysique(),
+                    demandeCalcul.getApplication().getNomEquipementVirtuel(),
+                    demandeCalcul.getApplication().getNomApplication(),
+                    demandeCalcul.getApplication().getTypeEnvironnement()
+            );
+            impactErreur = buildImpactForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage()));
+        }
+
+        return impactErreur;
+    }
+
+    private ImpactApplication buildImpactForError(DemandeCalculImpactApplication demandeCalcul, CalculImpactException exception) {
+        return ImpactApplication.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .versionCalcul(VERSION_CALCUL)
+                .etapeACV(demandeCalcul.getImpactEquipementVirtuel().getEtapeACV())
+                .critere(demandeCalcul.getImpactEquipementVirtuel().getCritere())
+                .statutIndicateur("ERREUR")
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactVirtuelUtils.buildTraceErreur(exception)))
+                .nomLot(demandeCalcul.getApplication().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getApplication().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getApplication().getDateLot())
+                .unite(demandeCalcul.getImpactEquipementVirtuel().getUnite())
+                .nomOrganisation(demandeCalcul.getApplication().getNomOrganisation())
+                .nomEntite(demandeCalcul.getApplication().getNomEntite())
+                .nomEquipementPhysique(demandeCalcul.getApplication().getNomEquipementPhysique())
+                .nomEquipementVirtuel(demandeCalcul.getApplication().getNomEquipementVirtuel())
+                .nomApplication(demandeCalcul.getApplication().getNomApplication())
+                .typeEnvironnement(demandeCalcul.getApplication().getTypeEnvironnement())
+                .domaine(demandeCalcul.getApplication().getDomaine())
+                .sousDomaine(demandeCalcul.getApplication().getSousDomaine())
+                .impactUnitaire(null)
+                .consoElecMoyenne(null)
+                .build();
+    }
+
+    private ImpactApplication calculerImpact(DemandeCalculImpactApplication demandeCalcul) throws CalculImpactException {
+        if (!"OK".equals(demandeCalcul.getImpactEquipementVirtuel().getStatutIndicateur())) {
+            throw new CalculImpactException(
+                    TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "L'indicateur d'impact équipement virtuel associé est au statut : " + demandeCalcul.getImpactEquipementVirtuel().getStatutIndicateur()
+            );
+        }
+        if (demandeCalcul.getImpactEquipementVirtuel().getImpactUnitaire() == null) {
+            throw new CalculImpactException(
+                    TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "L'indicateur d'impact équipement virtuel associé est null."
+            );
+        }
+
+        var nbApplications = demandeCalcul.getNbApplicationsForCalcul();
+
+        var resultCalcul = new CalculImpactApplicationResult(
+                demandeCalcul.getImpactEquipementVirtuel().getImpactUnitaire() / nbApplications,
+                demandeCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne() != null ? demandeCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne() / nbApplications : null
+        );
+
+        return ImpactApplication.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .nomApplication(demandeCalcul.getApplication().getNomApplication())
+                .typeEnvironnement(demandeCalcul.getApplication().getTypeEnvironnement())
+                .domaine(demandeCalcul.getApplication().getDomaine())
+                .sousDomaine(demandeCalcul.getApplication().getSousDomaine())
+                .etapeACV(demandeCalcul.getImpactEquipementVirtuel().getEtapeACV())
+                .critere(demandeCalcul.getImpactEquipementVirtuel().getCritere())
+                .unite(demandeCalcul.getImpactEquipementVirtuel().getUnite())
+                .nomEquipementVirtuel(demandeCalcul.getApplication().getNomEquipementVirtuel())
+                .nomEquipementPhysique(demandeCalcul.getApplication().getNomEquipementPhysique())
+                .nomOrganisation(demandeCalcul.getApplication().getNomOrganisation())
+                .nomEntite(demandeCalcul.getApplication().getNomEntite())
+                .nomLot(demandeCalcul.getApplication().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getApplication().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getApplication().getDateLot())
+                .versionCalcul(VERSION_CALCUL)
+                .statutIndicateur("OK")
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactApplicationUtils.buildTrace(demandeCalcul)))
+                .impactUnitaire(resultCalcul.valeurImpact)
+                .consoElecMoyenne(resultCalcul.consoElecMoyenne)
+                .build();
+    }
+
+    private record CalculImpactApplicationResult(Double valeurImpact, Double consoElecMoyenne) {
+    }
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a35d29cddf2b1173eca02136f512883077ebbf53
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java
@@ -0,0 +1,284 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactEquipement;
+import org.mte.numecoeval.calculs.domain.data.trace.ConsoElecAnMoyenne;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.data.trace.MixElectrique;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactEquipementPhysiqueUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceUtils;
+
+import java.util.Optional;
+
+@Slf4j
+@AllArgsConstructor
+public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEquipementPhysiqueService {
+
+    private static final String VERSION_CALCUL = "1.0";
+    public static final String NB_JOUR_UTILISE_PAR_DEFAUT = "NbJourUtiliseParDefaut";
+    public static final String ERREUR_DE_CALCUL_IMPACT_EQUIPEMENT_MESSAGE = "Erreur de calcul impact équipement: Type: {}, Cause: {}, Etape: {}, Critere: {}, Equipement Physique: {}, RefEquipementRetenu: {}, RefEquipementParDefaut: {}";
+    private final DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService;
+
+    private final ObjectMapper objectMapper;
+
+
+    public ImpactEquipementPhysique calculerImpactEquipementPhysique(DemandeCalculImpactEquipementPhysique demandeCalcul) {
+        log.debug("Début de calcul d'impact d'équipement physique : {}, {}, {} ",
+                demandeCalcul.getEtape().getCode(),
+                demandeCalcul.getCritere().getNomCritere(),
+                demandeCalcul.getEquipementPhysique().getNomEquipementPhysique());
+        ImpactEquipementPhysique impactErreur = null;
+
+        try {
+            return getCalculImpactEquipementPhysique(demandeCalcul);
+        } catch (CalculImpactException e) {
+            log.debug(ERREUR_DE_CALCUL_IMPACT_EQUIPEMENT_MESSAGE, e.getErrorType(), e.getMessage(),
+                    demandeCalcul.getEtape().getCode(),
+                    demandeCalcul.getCritere().getNomCritere(),
+                    demandeCalcul.getEquipementPhysique().getNomEquipementPhysique(),
+                    demandeCalcul.getRefEquipementCible(),
+                    demandeCalcul.getRefEquipementParDefaut());
+            impactErreur = buildCalculImpactForError(demandeCalcul, e);
+        } catch (Exception e) {
+            log.debug("{} : Erreur de calcul impact équipement physique: Erreur technique de l'indicateur : {}", TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage());
+            impactErreur = buildCalculImpactForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), "Erreur publication de l'indicateur : " + e.getMessage()));
+        }
+
+        return impactErreur;
+    }
+
+    private ImpactEquipementPhysique getCalculImpactEquipementPhysique(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+        double valeurImpactUnitaire;
+        Double consoElecMoyenne = null;
+        TraceCalculImpactEquipementPhysique traceCalculImpactEquipementPhysique;
+        var quantite = demandeCalcul.getEquipementPhysique().getQuantite();
+        double tauxUtilisationEqPhysique = getTauxUtilisationEqPhysique(demandeCalcul);
+        if ("UTILISATION".equals(demandeCalcul.getEtape().getCode())) {
+            var consoElecAnMoyenne = getConsoElecAnMoyenne(demandeCalcul);
+            var mixElectrique = getMixElectrique(demandeCalcul);
+            valeurImpactUnitaire = quantite
+                    * consoElecAnMoyenne.getValeur()
+                    * mixElectrique.getValeur()
+                    * tauxUtilisationEqPhysique
+            ;
+            consoElecMoyenne = consoElecAnMoyenne.getValeur();
+            traceCalculImpactEquipementPhysique = TraceCalculImpactEquipementPhysiqueUtils.buildTracePremierScenario(quantite, consoElecAnMoyenne, mixElectrique, tauxUtilisationEqPhysique);
+        } else {
+            var refImpactEquipementOpt = getImpactEquipement(demandeCalcul);
+            if (refImpactEquipementOpt.isPresent()) {
+                ReferentielImpactEquipement referentielImpactEquipement = refImpactEquipementOpt.get();
+                var valeurReferentiel = referentielImpactEquipement.getValeur();
+                valeurImpactUnitaire = quantite * valeurReferentiel * tauxUtilisationEqPhysique;
+                DureeDeVie dureeVie = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+                if (dureeVie != null && dureeVie.getValeur() != null && dureeVie.getValeur() > 0) {
+                    var valeurDureeVie = dureeVie.getValeur();
+                    valeurImpactUnitaire = valeurImpactUnitaire / valeurDureeVie;
+                    traceCalculImpactEquipementPhysique = TraceCalculImpactEquipementPhysiqueUtils.buildTraceSecondScenario(quantite, valeurReferentiel, referentielImpactEquipement.getSource(), dureeVie, tauxUtilisationEqPhysique);
+                } else {
+                    throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Durée de vie de l'équipement inconnue");
+                }
+            } else {
+                throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel Impact Equipement inconnu");
+            }
+        }
+
+        var calcul = buildCalculImpactEquipementPhysique(demandeCalcul, valeurImpactUnitaire, consoElecMoyenne);
+        calcul.setTrace(TraceUtils.getTraceFromTraceur(objectMapper, traceCalculImpactEquipementPhysique));
+        return calcul;
+    }
+
+    private Optional<ReferentielImpactEquipement> getImpactEquipement(DemandeCalculImpactEquipementPhysique demandeCalcul) {
+
+        Optional<ReferentielImpactEquipement> resultFromRefEquipementCible = Optional.empty();
+        if (StringUtils.isNotBlank(demandeCalcul.getRefEquipementCible())) {
+            resultFromRefEquipementCible = demandeCalcul.getImpactEquipement(
+                    demandeCalcul.getCorrespondanceRefEquipement().getRefEquipementCible()
+            );
+        }
+        if (resultFromRefEquipementCible.isEmpty()) {
+            return demandeCalcul.getImpactEquipement(
+                    demandeCalcul.getRefEquipementParDefaut()
+            );
+        }
+        return resultFromRefEquipementCible;
+    }
+
+    private ImpactEquipementPhysique buildCalculImpactEquipementPhysique(DemandeCalculImpactEquipementPhysique demandeCalcul, Double valeurImpactUnitaire, Double consoElecMoyenne) {
+        return ImpactEquipementPhysique
+                .builder()
+                .nomEquipement(demandeCalcul.getEquipementPhysique().getNomEquipementPhysique())
+                .etapeACV(demandeCalcul.getEtape().getCode())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .versionCalcul(VERSION_CALCUL)
+                .reference(StringUtils.defaultIfEmpty(demandeCalcul.getRefEquipementCible(), demandeCalcul.getRefEquipementParDefaut()))
+                .typeEquipement(demandeCalcul.getEquipementPhysique().getType())
+                .quantite(demandeCalcul.getEquipementPhysique().getQuantite())
+                .statutEquipementPhysique(demandeCalcul.getEquipementPhysique().getStatut())
+                .statutIndicateur("OK")
+                .impactUnitaire(valeurImpactUnitaire)
+                .unite(demandeCalcul.getCritere().getUnite())
+                .consoElecMoyenne(consoElecMoyenne)
+                .nomLot(demandeCalcul.getEquipementPhysique().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementPhysique().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementPhysique().getDateLot())
+                .nomEntite(demandeCalcul.getEquipementPhysique().getNomEntite())
+                .nomOrganisation(demandeCalcul.getEquipementPhysique().getNomOrganisation())
+                .build();
+    }
+
+    private ImpactEquipementPhysique buildCalculImpactForError(DemandeCalculImpactEquipementPhysique demandeCalcul, CalculImpactException exception) {
+        return ImpactEquipementPhysique
+                .builder()
+                .nomEquipement(demandeCalcul.getEquipementPhysique().getNomEquipementPhysique())
+                .etapeACV(demandeCalcul.getEtape().getCode())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .versionCalcul(VERSION_CALCUL)
+                .reference(StringUtils.defaultIfEmpty(demandeCalcul.getRefEquipementCible(), demandeCalcul.getRefEquipementParDefaut()))
+                .typeEquipement(demandeCalcul.getEquipementPhysique().getType())
+                .quantite(demandeCalcul.getEquipementPhysique().getQuantite())
+                .statutEquipementPhysique(demandeCalcul.getEquipementPhysique().getStatut())
+                .statutIndicateur("ERREUR")
+                .impactUnitaire(null)
+                .unite(demandeCalcul.getCritere().getUnite())
+                .consoElecMoyenne(null)
+                .nomLot(demandeCalcul.getEquipementPhysique().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementPhysique().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementPhysique().getDateLot())
+                .nomEntite(demandeCalcul.getEquipementPhysique().getNomEntite())
+                .nomOrganisation(demandeCalcul.getEquipementPhysique().getNomOrganisation())
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactEquipementPhysiqueUtils.buildTraceErreur(exception)))
+                .build();
+    }
+
+    private ConsoElecAnMoyenne getConsoElecAnMoyenne(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+        if (demandeCalcul.getEquipementPhysique().getConsoElecAnnuelle() != null) {
+            var valeur = demandeCalcul.getEquipementPhysique().getConsoElecAnnuelle();
+            return ConsoElecAnMoyenne.builder()
+                    .valeurEquipementConsoElecAnnuelle(valeur)
+                    .valeur(valeur)
+                    .build();
+        }
+
+
+        if (StringUtils.isAllBlank(demandeCalcul.getRefEquipementCible(), demandeCalcul.getRefEquipementParDefaut())) {
+            throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel Impact Equipement inconnu");
+        }
+
+        var referentielImpactEquipementOpt = getImpactEquipement(demandeCalcul);
+        if (referentielImpactEquipementOpt.isEmpty()) {
+            throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel Impact Equipement inconnu");
+        }
+
+        if (referentielImpactEquipementOpt.get().getConsoElecMoyenne() == null) {
+            throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "Donnée de consommation electrique manquante : equipementPhysique : " + demandeCalcul.getEquipementPhysique().getNomEquipementPhysique() +
+                            ", RefEquipementCible : " + demandeCalcul.getRefEquipementCible() +
+                            ", RefEquipementParDefaut : " + demandeCalcul.getRefEquipementParDefaut()
+            );
+        }
+
+        var valeur = referentielImpactEquipementOpt.get().getConsoElecMoyenne();
+        return ConsoElecAnMoyenne.builder()
+                .sourceReferentielImpactEquipement(referentielImpactEquipementOpt.get().getSource())
+                .valeurReferentielConsoElecMoyenne(valeur)
+                .valeur(valeur)
+                .build();
+
+    }
+
+    private MixElectrique getMixElectrique(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+        // Taiga #918 - EquipementPhysique.dataCenter != null est équivalent à EquipementPhysique.nomCourtDatacenter est renseigné + le DataCenter existe dans les données
+        if (demandeCalcul.getEquipementPhysique().getDataCenter() != null
+                && StringUtils.isNotBlank(demandeCalcul.getEquipementPhysique().getDataCenter().getLocalisation())) {
+            var pays = demandeCalcul.getEquipementPhysique().getDataCenter().getLocalisation();
+            var refMixElecOpt = demandeCalcul.getMixElectrique(pays);
+            if (refMixElecOpt.isPresent()) {
+                var refMixElec = refMixElecOpt.get().getValeur();
+                var pue = getDataCenterPUE(demandeCalcul);
+                return MixElectrique.builder()
+                        .isServeur(true)
+                        .dataCenterPue(pue)
+                        .valeurReferentielMixElectrique(refMixElec)
+                        .sourceReferentielMixElectrique(refMixElecOpt.get().getSource())
+                        .valeur(refMixElec * pue)
+                        .build();
+            }
+        }
+        if (StringUtils.isNotBlank(demandeCalcul.getEquipementPhysique().getPaysDUtilisation())) {
+            var refMixElecOpt = demandeCalcul.getMixElectrique(demandeCalcul.getEquipementPhysique().getPaysDUtilisation());
+            if (refMixElecOpt.isPresent()) {
+                var refMixElec = refMixElecOpt.get();
+                return MixElectrique.builder()
+                        .valeurReferentielMixElectrique(refMixElec.getValeur())
+                        .sourceReferentielMixElectrique(refMixElec.getSource())
+                        .valeur(refMixElec.getValeur())
+                        .build();
+            }
+        }
+        throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                "Il n'existe pas de Mix électrique pour cet équipement : critere: " + demandeCalcul.getCritere().getNomCritere() +
+                        " - equipement: " + demandeCalcul.getEquipementPhysique().getNomEquipementPhysique() +
+                        " - Pays d'utilisation: " + demandeCalcul.getEquipementPhysique().getPaysDUtilisation() +
+                        " - NomCourtDatacenter: " + demandeCalcul.getEquipementPhysique().getNomCourtDatacenter()
+
+        );
+
+    }
+
+    private Double getDataCenterPUE(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+        if (demandeCalcul.getEquipementPhysique().getDataCenter().getPue() != null) {
+            return demandeCalcul.getEquipementPhysique().getDataCenter().getPue();
+        }
+        var optionalPUEParDefaut = demandeCalcul.getHypotheseFromCode("PUEParDefaut");
+        if (optionalPUEParDefaut.isPresent()) {
+            return optionalPUEParDefaut.get().getValeur();
+        }
+        throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                "Le PUE est manquant et ne permet le calcul de l'impact à l'usage de l'équipement :" +
+                        " equipement: " + demandeCalcul.getEquipementPhysique().getNomEquipementPhysique() +
+                        " - RefEquipementCible: " + demandeCalcul.getRefEquipementCible() +
+                        " - refEquipementParDefaut: " + demandeCalcul.getRefEquipementParDefaut() +
+                        " - NomCourtDatacenter: " + demandeCalcul.getEquipementPhysique().getNomCourtDatacenter()
+
+        );
+    }
+
+
+    /**
+     * compute the tauxUtilisationEquipementPhysique
+     * if the tauxUtilisation has been completed, we directly use this value
+     * else we retrieve the value of modeUtilisation and get the corresponding default value in ref_hypotheses
+     *
+     * @param demandeCalcul la demande de calcul
+     * @return le taux d'utilsiation pour l'equipement physique
+     */
+    private Double getTauxUtilisationEqPhysique(DemandeCalculImpactEquipementPhysique demandeCalcul) {
+        var tauxUtilisation = demandeCalcul.getEquipementPhysique().getTauxUtilisation();
+
+        if (tauxUtilisation != null && tauxUtilisation > 0.0 && tauxUtilisation <= 1.0) {
+            return tauxUtilisation;
+        }
+
+        if (demandeCalcul.getEquipementPhysique().getModeUtilisation() == null) {
+            return 1.0;
+        }
+
+        var tauxUtilisationEqPhysique = demandeCalcul.getHypotheseFromCode("taux_utilisation_" + demandeCalcul.getEquipementPhysique().getModeUtilisation());
+        if (tauxUtilisationEqPhysique.isPresent()) {
+            return tauxUtilisationEqPhysique.get().getValeur();
+        }
+        return 1.0;
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef137c98ed35cecf4b70a9bd130065e6026c36b2
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java
@@ -0,0 +1,163 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementVirtuelService;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactVirtuelUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceUtils;
+
+@Slf4j
+@AllArgsConstructor
+public class CalculImpactEquipementVirtuelServiceImpl implements CalculImpactEquipementVirtuelService {
+
+    private static final String VERSION_CALCUL = "1.1";
+    public static final String TYPE_EQUIPEMENT_VIRTUEL_STOCKAGE = "stockage";
+    public static final String TYPE_EQUIPEMENT_VIRTUEL_CALCUL = "calcul";
+    private final ObjectMapper objectMapper;
+
+    @Override
+    public ImpactEquipementVirtuel calculerImpactEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        ImpactEquipementVirtuel impactErreur;
+        try {
+            return calculerImpact(demandeCalcul);
+        } catch (CalculImpactException e) {
+            log.debug("Erreur de calcul d'impact d'équipement virtuel : Type : {}, Cause: {}, Etape: {}, Critere: {}, Nom Equipment Physique: {}, Nom Equipement Virtuel: {}",
+                    e.getErrorType(), e.getMessage(),
+                    demandeCalcul.getImpactEquipement().getEtapeACV(),
+                    demandeCalcul.getImpactEquipement().getCritere(),
+                    demandeCalcul.getEquipementVirtuel().getNomEquipementPhysique(),
+                    demandeCalcul.getEquipementVirtuel().getNomEquipementVirtuel());
+
+            impactErreur = buildImpactForError(demandeCalcul, e);
+        } catch (Exception e) {
+            log.debug("Erreur de calcul d'impact d'équipement virtuel : Type : {}, Cause: {}, Etape: {}, Critere: {}, Nom Equipment Physique: {}, Nom Equipement Virtuel: {}",
+                    TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage(),
+                    demandeCalcul.getImpactEquipement().getEtapeACV(),
+                    demandeCalcul.getImpactEquipement().getCritere(),
+                    demandeCalcul.getEquipementVirtuel().getNomEquipementPhysique(),
+                    demandeCalcul.getEquipementVirtuel().getNomEquipementVirtuel());
+            impactErreur = buildImpactForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage()));
+        }
+
+        return impactErreur;
+    }
+
+    private ImpactEquipementVirtuel calculerImpact(DemandeCalculImpactEquipementVirtuel demandeCalcul) throws CalculImpactException {
+        if (!"OK".equals(demandeCalcul.getImpactEquipement().getStatutIndicateur())) {
+            throw new CalculImpactException(
+                    TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "L'indicateur d'impact équipement associé est au statut : " + demandeCalcul.getImpactEquipement().getStatutIndicateur()
+            );
+        }
+        if (demandeCalcul.getImpactEquipement().getImpactUnitaire() == null) {
+            throw new CalculImpactException(
+                    TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "L'impact unitaire de l'équipement physique parent est null"
+            );
+        }
+
+        Double valeurImpactEquipementPhysique = demandeCalcul.getImpactEquipement().getImpactUnitaire();
+        Double consoElecMoyenneEquipementPhysique = demandeCalcul.getImpactEquipement().getConsoElecMoyenne();
+
+        TraceCalculImpactEquipementVirtuel trace = TraceCalculImpactVirtuelUtils.buildTrace(demandeCalcul);
+
+        CalculImpactUnitaireEquipementVirtuel result = calculImpactUnitaire(demandeCalcul, valeurImpactEquipementPhysique, consoElecMoyenneEquipementPhysique);
+
+        return ImpactEquipementVirtuel.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .versionCalcul(VERSION_CALCUL)
+                .etapeACV(demandeCalcul.getImpactEquipement().getEtapeACV())
+                .critere(demandeCalcul.getImpactEquipement().getCritere())
+                .unite(demandeCalcul.getImpactEquipement().getUnite())
+                .statutIndicateur("OK")
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, trace))
+                .nomLot(demandeCalcul.getEquipementVirtuel().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementVirtuel().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementVirtuel().getDateLot())
+                .nomOrganisation(demandeCalcul.getEquipementVirtuel().getNomOrganisation())
+                .nomEntite(demandeCalcul.getEquipementVirtuel().getNomEntite())
+                .nomEquipement(demandeCalcul.getEquipementVirtuel().getNomEquipementPhysique())
+                .nomEquipementVirtuel(demandeCalcul.getEquipementVirtuel().getNomEquipementVirtuel())
+                .cluster(demandeCalcul.getEquipementVirtuel().getCluster())
+                .impactUnitaire(result.valeurImpactUnitaire())
+                .consoElecMoyenne(result.consoElecMoyenne())
+                .idEntree(demandeCalcul.getEquipementVirtuel().getId())
+                .build();
+    }
+
+    private ImpactEquipementVirtuel buildImpactForError(DemandeCalculImpactEquipementVirtuel demandeCalcul, CalculImpactException exception) {
+        return ImpactEquipementVirtuel.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .versionCalcul(VERSION_CALCUL)
+                .etapeACV(demandeCalcul.getImpactEquipement().getEtapeACV())
+                .critere(demandeCalcul.getImpactEquipement().getCritere())
+                .unite(demandeCalcul.getImpactEquipement().getUnite())
+                .statutIndicateur("ERREUR")
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactVirtuelUtils.buildTraceErreur(exception)))
+                .nomLot(demandeCalcul.getEquipementVirtuel().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementVirtuel().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementVirtuel().getDateLot())
+                .nomOrganisation(demandeCalcul.getEquipementVirtuel().getNomOrganisation())
+                .nomEntite(demandeCalcul.getEquipementVirtuel().getNomEntite())
+                .nomEquipement(demandeCalcul.getEquipementVirtuel().getNomEquipementPhysique())
+                .nomEquipementVirtuel(demandeCalcul.getEquipementVirtuel().getNomEquipementVirtuel())
+                .cluster(demandeCalcul.getEquipementVirtuel().getCluster())
+                .impactUnitaire(null)
+                .consoElecMoyenne(null)
+                .idEntree(demandeCalcul.getEquipementVirtuel().getId())
+                .build();
+    }
+
+    private static CalculImpactUnitaireEquipementVirtuel calculImpactUnitaire(DemandeCalculImpactEquipementVirtuel demandeCalcul, Double valeurImpactEquipementPhysique, Double consoElecMoyenneEquipementPhysique) throws CalculImpactException {
+        double valeurImpactUnitaire;
+        Double consoElecMoyenne;
+        if (cleRepartitionEstDisponible(demandeCalcul)) {
+            valeurImpactUnitaire = valeurImpactEquipementPhysique * demandeCalcul.getEquipementVirtuel().getCleRepartition();
+            consoElecMoyenne = consoElecMoyenneEquipementPhysique != null ? consoElecMoyenneEquipementPhysique * demandeCalcul.getEquipementVirtuel().getCleRepartition() : null;
+        } else if (calculPourCalculEstDisponible(demandeCalcul)) {
+            valeurImpactUnitaire = valeurImpactEquipementPhysique * demandeCalcul.getEquipementVirtuel().getVCPU() / demandeCalcul.getNbTotalVCPU();
+            consoElecMoyenne = consoElecMoyenneEquipementPhysique != null ? consoElecMoyenneEquipementPhysique * demandeCalcul.getEquipementVirtuel().getVCPU() / demandeCalcul.getNbTotalVCPU() : null;
+        } else if (calculPourStockageEstDisponible(demandeCalcul)) {
+            valeurImpactUnitaire = valeurImpactEquipementPhysique * demandeCalcul.getEquipementVirtuel().getCapaciteStockage() / demandeCalcul.getStockageTotalVirtuel();
+            consoElecMoyenne = consoElecMoyenneEquipementPhysique != null ? consoElecMoyenneEquipementPhysique * demandeCalcul.getEquipementVirtuel().getCapaciteStockage() / demandeCalcul.getStockageTotalVirtuel() : null;
+        } else if (calculParRepartiParNombreEquipementEstDisponible(demandeCalcul)) {
+            valeurImpactUnitaire = valeurImpactEquipementPhysique / demandeCalcul.getNbEquipementsVirtuels();
+            consoElecMoyenne = consoElecMoyenneEquipementPhysique != null ? consoElecMoyenneEquipementPhysique / demandeCalcul.getNbEquipementsVirtuels() : null;
+        } else {
+            throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Certaines données sur l'équipement virtuel sont manquantes ou incorrectes");
+        }
+        return new CalculImpactUnitaireEquipementVirtuel(valeurImpactUnitaire, consoElecMoyenne);
+    }
+
+    public static boolean calculParRepartiParNombreEquipementEstDisponible(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        return demandeCalcul.getNbEquipementsVirtuels() != null && demandeCalcul.getNbEquipementsVirtuels() >= 1;
+    }
+
+    public static boolean calculPourStockageEstDisponible(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        return TYPE_EQUIPEMENT_VIRTUEL_STOCKAGE.equals(demandeCalcul.getEquipementVirtuel().getTypeEqv()) && demandeCalcul.getStockageTotalVirtuel() != null;
+    }
+
+    public static boolean calculPourCalculEstDisponible(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        return TYPE_EQUIPEMENT_VIRTUEL_CALCUL.equals(demandeCalcul.getEquipementVirtuel().getTypeEqv()) && demandeCalcul.getNbTotalVCPU() != null;
+    }
+
+    public static boolean cleRepartitionEstDisponible(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        return demandeCalcul.getEquipementVirtuel().getCleRepartition() != null;
+    }
+
+    /**
+     * Record pour le stockage du résultat du calcul d'impact
+     *
+     * @param valeurImpactUnitaire impact unitaire pour l'équipement virtuel
+     * @param consoElecMoyenne     conso électrique moyenne pour l'équipement virtuel
+     */
+    private record CalculImpactUnitaireEquipementVirtuel(double valeurImpactUnitaire, Double consoElecMoyenne) {
+    }
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..35fa91dac13a1198ce21ddfa4feba080f2fa5cdb
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java
@@ -0,0 +1,106 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactMessagerieService;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactMessagerieUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceUtils;
+
+@Slf4j
+@AllArgsConstructor
+public class CalculImpactMessagerieServiceImpl implements CalculImpactMessagerieService {
+    private static final String VERSION_CALCUL = "1.0";
+    private final ObjectMapper objectMapper;
+
+    @Override
+    public ImpactMessagerie calculerImpactMessagerie(DemandeCalculImpactMessagerie demandeCalcul) {
+        ImpactMessagerie impactErreur;
+        try {
+            return calculerImpact(demandeCalcul);
+        } catch (CalculImpactException e) {
+            log.debug("Erreur de calcul d'impact de messagerie : Type : {}, Cause: {}, Critere: {}, Mois-Années: {}",
+                    e.getErrorType(), e.getMessage(),
+                    demandeCalcul.getCritere().getNomCritere(),
+                    demandeCalcul.getMessagerie().getMoisAnnee()
+            );
+
+            impactErreur = buildImpactForError(demandeCalcul, e);
+        } catch (Exception e) {
+            log.debug("Erreur générale de calcul d'impact de messagerie : Type : {}, Cause: {}, Critere: {}, Mois-Années: {}",
+                    TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage(),
+                    demandeCalcul.getCritere().getNomCritere(),
+                    demandeCalcul.getMessagerie().getMoisAnnee()
+            );
+            impactErreur = buildImpactForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage()));
+        }
+
+        return impactErreur;
+    }
+
+    private ImpactMessagerie calculerImpact(DemandeCalculImpactMessagerie demandeCalcul) throws CalculImpactException {
+        Double nombreMailEmis = demandeCalcul.getMessagerie().getNombreMailEmis();
+        var referentielImpactMessagerie = demandeCalcul.getImpactsMessagerie()
+                .stream()
+                .filter(refImpactMessagerie -> demandeCalcul.getCritere().getNomCritere().equals(refImpactMessagerie.getCritere()))
+                .findFirst()
+                .orElseThrow(() -> new CalculImpactException(
+                        TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel ImpactMessagerie indisponible pour le critère " + demandeCalcul.getCritere().getNomCritere())
+                );
+        if (nombreMailEmis > 0) {
+            var poidsMoyenMail = demandeCalcul.getMessagerie().getVolumeTotalMailEmis() / nombreMailEmis;
+            Double impactMensuel = (referentielImpactMessagerie.getConstanteCoefficientDirecteur() * poidsMoyenMail + referentielImpactMessagerie.getConstanteOrdonneeOrigine()) * demandeCalcul.getMessagerie().getNombreMailEmisXDestinataires();
+            return buildImpactMessagerie(demandeCalcul, referentielImpactMessagerie, impactMensuel);
+        }
+        throw new CalculImpactException(
+                TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                "Calcul d'impact messagerie : Critère : " + demandeCalcul.getCritere().getNomCritere() + ", Mois Années : " + demandeCalcul.getMessagerie().getMoisAnnee() + ", nombreMailEmis " + demandeCalcul.getMessagerie().getNombreMailEmis() + "=< 0.0"
+        );
+    }
+
+    private ImpactMessagerie buildImpactMessagerie(DemandeCalculImpactMessagerie demandeCalcul, ReferentielImpactMessagerie referentielImpactMessagerie, Double impact) {
+        return ImpactMessagerie.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .unite(demandeCalcul.getCritere().getUnite())
+                .moisAnnee(demandeCalcul.getMessagerie().getMoisAnnee())
+                .nombreMailEmis(demandeCalcul.getMessagerie().getNombreMailEmis())
+                .volumeTotalMailEmis(demandeCalcul.getMessagerie().getVolumeTotalMailEmis())
+                .impactMensuel(impact)
+                .statutIndicateur("OK")
+                .nomLot(demandeCalcul.getMessagerie().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getMessagerie().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getMessagerie().getDateLot())
+                .nomEntite(demandeCalcul.getMessagerie().getNomEntite())
+                .nomOrganisation(demandeCalcul.getMessagerie().getNomOrganisation())
+                .versionCalcul(VERSION_CALCUL)
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactMessagerieUtils.buildTrace(demandeCalcul, referentielImpactMessagerie)))
+                .build();
+    }
+
+    private ImpactMessagerie buildImpactForError(DemandeCalculImpactMessagerie demandeCalcul, CalculImpactException exception) {
+        return ImpactMessagerie.builder()
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .unite(demandeCalcul.getCritere().getUnite())
+                .moisAnnee(demandeCalcul.getMessagerie().getMoisAnnee())
+                .impactMensuel(null)
+                .nombreMailEmis(demandeCalcul.getMessagerie().getNombreMailEmis())
+                .volumeTotalMailEmis(demandeCalcul.getMessagerie().getVolumeTotalMailEmis())
+                .statutIndicateur("ERREUR")
+                .nomLot(demandeCalcul.getMessagerie().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getMessagerie().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getMessagerie().getDateLot())
+                .nomEntite(demandeCalcul.getMessagerie().getNomEntite())
+                .nomOrganisation(demandeCalcul.getMessagerie().getNomOrganisation())
+                .versionCalcul(VERSION_CALCUL)
+                .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactMessagerieUtils.buildTraceError(exception)))
+                .build();
+    }
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa94858196d3d6c25247ee0f162fe1f7c16ad12d
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java
@@ -0,0 +1,139 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactReseau;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactReseauService;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactReseauUtils;
+import org.mte.numecoeval.calculs.domain.traceur.TraceUtils;
+
+import java.util.Objects;
+
+@Slf4j
+@AllArgsConstructor
+public class CalculImpactReseauServiceImpl implements CalculImpactReseauService {
+
+    private static final String VERSION_CALCUL = "1.0";
+
+    private final ObjectMapper objectMapper;
+
+    @Override
+    public ImpactReseau calculerImpactReseau(DemandeCalculImpactReseau demandeCalcul) {
+        try {
+            if (demandeCalcul.getEquipementPhysique().getGoTelecharge() == null) {
+                throw new CalculImpactException(
+                        TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                        "Erreur de calcul impact réseau: Etape: %s, Critere: %s, Equipement Physique: %s : la valeur en_EqP(Equipement).goTelecharge est nulle"
+                                .formatted(
+                                        demandeCalcul.getEtape().getCode(),
+                                        demandeCalcul.getCritere().getNomCritere(),
+                                        demandeCalcul.getEquipementPhysique().getNomEquipementPhysique()
+                                )
+                );
+            }
+
+            var referentielImpactReseau = getReferentielImpactReseau(demandeCalcul, REF_RESEAU);
+
+            return calculerImpact(demandeCalcul, referentielImpactReseau);
+        } catch (CalculImpactException exception) {
+            log.debug("{} : {}", exception.getErrorType(), exception.getMessage());
+            return buildCalculForError(demandeCalcul, exception);
+        } catch (Exception exception) {
+            log.debug("{} : {}", TypeErreurCalcul.ERREUR_TECHNIQUE, exception.getMessage());
+            return buildCalculForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), exception.getMessage()));
+        }
+    }
+
+    private ReferentielImpactReseau getReferentielImpactReseau(DemandeCalculImpactReseau demandeCalcul, String refReseau) throws CalculImpactException {
+        var referentielImpactReseau = demandeCalcul.getImpactsReseau().stream()
+                .filter(Objects::nonNull)
+                .filter(refImpactReseau ->
+                        demandeCalcul.getEtape().getCode().equals(refImpactReseau.getEtapeACV())
+                                && demandeCalcul.getCritere().getNomCritere().equals(refImpactReseau.getCritere())
+                                && StringUtils.equals(refImpactReseau.getRefReseau(), refReseau)
+                )
+                .findFirst()
+                .orElseThrow(() -> new CalculImpactException(
+                                TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                                "Erreur de calcul impact réseau: Etape: %s, Critere: %s, RefReseau: %s, Equipement Physique: %s : La référence ImpactReseau n'existe pas."
+                                        .formatted(
+                                                demandeCalcul.getEtape().getCode(),
+                                                demandeCalcul.getCritere().getNomCritere(),
+                                                REF_RESEAU,
+                                                demandeCalcul.getEquipementPhysique().getNomEquipementPhysique()
+                                        )
+                        )
+                );
+
+        if (Objects.isNull(referentielImpactReseau.getImpactReseauMobileMoyen())) {
+            throw new CalculImpactException(
+                    TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),
+                    "Erreur de calcul impact réseau: Etape: %s, Critere: %s, RefReseau: %s, Equipement Physique: %s : L'impactReseauMobileMoyen de la référence est null."
+                            .formatted(
+                                    demandeCalcul.getEtape().getCode(),
+                                    demandeCalcul.getCritere().getNomCritere(),
+                                    REF_RESEAU,
+                                    demandeCalcul.getEquipementPhysique().getNomEquipementPhysique()
+                            )
+            );
+        }
+
+        return referentielImpactReseau;
+    }
+
+    private ImpactReseau calculerImpact(DemandeCalculImpactReseau demandeCalcul, ReferentielImpactReseau referentielImpactReseau) {
+        return ImpactReseau.builder()
+                .versionCalcul(VERSION_CALCUL)
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .nomLot(demandeCalcul.getEquipementPhysique().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementPhysique().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementPhysique().getDateLot())
+                .etapeACV(demandeCalcul.getEtape().getCode())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .statutIndicateur("OK")
+                .source(referentielImpactReseau.getSource())
+                .nomEntite(demandeCalcul.getEquipementPhysique().getNomEntite())
+                .nomOrganisation(demandeCalcul.getEquipementPhysique().getNomOrganisation())
+                .nomEquipement(demandeCalcul.getEquipementPhysique().getNomEquipementPhysique())
+                .impactUnitaire(
+                        demandeCalcul.getEquipementPhysique().getGoTelecharge() * referentielImpactReseau.getImpactReseauMobileMoyen()
+                )
+                .unite(referentielImpactReseau.getUnite())
+                .trace(
+                        TraceUtils.getTraceFromTraceur(
+                                objectMapper,
+                                TraceCalculImpactReseauUtils.buildTrace(demandeCalcul, referentielImpactReseau))
+                )
+                .build();
+    }
+
+    private ImpactReseau buildCalculForError(DemandeCalculImpactReseau demandeCalcul, CalculImpactException exception) {
+        return ImpactReseau.builder()
+                .versionCalcul(VERSION_CALCUL)
+                .dateCalcul(demandeCalcul.getDateCalcul())
+                .nomLot(demandeCalcul.getEquipementPhysique().getNomLot())
+                .nomSourceDonnee(demandeCalcul.getEquipementPhysique().getNomSourceDonnee())
+                .dateLot(demandeCalcul.getEquipementPhysique().getDateLot())
+                .etapeACV(demandeCalcul.getEtape().getCode())
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .statutIndicateur("ERREUR")
+                .nomEntite(demandeCalcul.getEquipementPhysique().getNomEntite())
+                .nomOrganisation(demandeCalcul.getEquipementPhysique().getNomOrganisation())
+                .nomEquipement(demandeCalcul.getEquipementPhysique().getNomEquipementPhysique())
+                .unite(demandeCalcul.getCritere().getUnite())
+                .impactUnitaire(null)
+                .unite(demandeCalcul.getCritere().getUnite())
+                .trace(TraceUtils.getTraceFromTraceur(
+                        objectMapper,
+                        TraceCalculImpactReseauUtils.buildTraceErreur(exception))
+                )
+                .build();
+    }
+
+}
\ No newline at end of file
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..717db5f02be59ada9e1a833dbb02339a95a34e1f
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java
@@ -0,0 +1,77 @@
+package org.mte.numecoeval.calculs.domain.port.input.service.impl;
+
+import lombok.AllArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVieParDefaut;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+
+@AllArgsConstructor
+public class DureeDeVieEquipementPhysiqueServiceImpl implements DureeDeVieEquipementPhysiqueService {
+
+    @Override
+    public DureeDeVie calculerDureeVie(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+        var dateAchat = demandeCalcul.getEquipementPhysique().getDateAchat();
+        var dateRetrait = demandeCalcul.getEquipementPhysique().getDateRetrait();
+        var result = DureeDeVie.builder().build();
+        if (dateAchat != null && dateRetrait != null) {
+
+            if (dateAchat.isBefore(dateRetrait)) {
+                Double valeur ;
+                if (ChronoUnit.MONTHS.between(dateAchat, dateRetrait) < 12) {
+                     valeur= 1d;
+                } else {
+                     valeur = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d;
+                }
+                result.setValeur(valeur);
+                result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE));
+                result.setDateRetrait(dateRetrait.format(DateTimeFormatter.ISO_DATE));
+            } else {
+                throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie de l'équipement n'a pas pu être déterminée");
+            }
+        }
+        // Taiga#864 - Si la date d'achat est présente et non la date de retrait, on prend la date du jour devient la date de retrait pour le calcul
+        else if (dateAchat != null) {
+            result.setValeur(
+                    ChronoUnit.DAYS.between(dateAchat, LocalDate.now()) / 365d
+            );
+            result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE));
+            result.setDateRetrait(LocalDate.now().format(DateTimeFormatter.ISO_DATE));
+        }
+        else {
+            var dureeDeVieParDefaut = calculerDureeVieDefaut(demandeCalcul);
+            result.setDureeDeVieParDefaut(dureeDeVieParDefaut);
+            result.setValeur(dureeDeVieParDefaut.getValeur());
+        }
+        return  result;
+    }
+
+    @Override
+    public DureeDeVieParDefaut calculerDureeVieDefaut(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException {
+
+        if(demandeCalcul.getTypeEquipement() != null && demandeCalcul.getTypeEquipement().getDureeVieDefaut() !=null){
+            return DureeDeVieParDefaut.builder()
+                    .valeurEquipementDureeVieDefaut(demandeCalcul.getTypeEquipement().getDureeVieDefaut())
+                    .valeur(demandeCalcul.getTypeEquipement().getDureeVieDefaut())
+                    .build();
+        }
+        var refHypotheseOpt= demandeCalcul.getHypotheseFromCode("dureeVieParDefaut");
+        if (refHypotheseOpt.isPresent() && refHypotheseOpt.get().getValeur() != null){
+            ReferentielHypothese hypothese = refHypotheseOpt.get();
+            return DureeDeVieParDefaut.builder()
+                    .valeurReferentielHypothese(hypothese.getValeur())
+                    .sourceReferentielHypothese(hypothese.getSource())
+                    .valeur(hypothese.getValeur())
+                    .build();
+        }
+        throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie par défaut de l'équipement n'a pas pu être déterminée");
+    }
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactApplicationUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactApplicationUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1f861fb539d9cd798057b444ff41a1621b8f85a
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactApplicationUtils.java
@@ -0,0 +1,29 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+
+public class TraceCalculImpactApplicationUtils {
+
+    private TraceCalculImpactApplicationUtils() {
+        // private constructor
+    }
+
+    public static TraceCalculImpactApplication buildTrace(DemandeCalculImpactApplication demandeCalcul) {
+        return TraceCalculImpactApplication.builder()
+                .formule("ImpactApplication = ImpactEquipementVirtuel(%s) / nbApplications(%s)".formatted(demandeCalcul.getImpactEquipementVirtuel().getImpactUnitaire(), demandeCalcul.getNbApplicationsForCalcul()))
+                .nbApplications(demandeCalcul.getNbApplications())
+                .build();
+    }
+
+    public static TraceCalculImpactApplication buildTraceError(CalculImpactException exception) {
+        var message = "Erreur lors du calcul de l'impact d'application";
+        if(exception != null) {
+            message = exception.getErrorType() + " : " + exception.getMessage();
+        }
+        return TraceCalculImpactApplication.builder()
+                .erreur(message)
+                .build();
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1aafb978376547ebca7a9c1ce70c12a64223142
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java
@@ -0,0 +1,49 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.mte.numecoeval.calculs.domain.data.trace.ConsoElecAnMoyenne;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.data.trace.MixElectrique;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class TraceCalculImpactEquipementPhysiqueUtils {
+
+    public static TraceCalculImpactEquipementPhysique buildTraceErreur(CalculImpactException exception) {
+        var message = "Erreur lors du calcul de l'impact d'équipement physique";
+        if (exception != null) {
+            message = exception.getErrorType() + " : " + exception.getMessage();
+        }
+        return TraceCalculImpactEquipementPhysique.builder()
+                .erreur(message)
+                .build();
+    }
+
+    public static TraceCalculImpactEquipementPhysique buildTracePremierScenario(Double quantite, ConsoElecAnMoyenne consoElecAnMoyenne, MixElectrique mixElectriqueValeur, Double taux_utilisation) {
+        return TraceCalculImpactEquipementPhysique.builder()
+                .formule(getFormulePremierScenario(quantite, consoElecAnMoyenne.getValeur(), mixElectriqueValeur.getValeur(), taux_utilisation))
+                .consoElecAnMoyenne(consoElecAnMoyenne)
+                .mixElectrique(mixElectriqueValeur)
+                .build();
+    }
+
+    public static TraceCalculImpactEquipementPhysique buildTraceSecondScenario(Double quantite, Double valeurRefrentiel, String sourceReferentiel, DureeDeVie dureeDeVie, Double taux_utilisation) {
+        return TraceCalculImpactEquipementPhysique.builder()
+                .formule(getFormuleSecondScenario(quantite, valeurRefrentiel, dureeDeVie.getValeur(), taux_utilisation))
+                .valeurReferentielImpactEquipement(valeurRefrentiel)
+                .sourceReferentielImpactEquipement(sourceReferentiel)
+                .dureeDeVie(dureeDeVie)
+                .build();
+    }
+
+    public static String getFormulePremierScenario(Double quantite, Double consoElecAnMoyenne, Double mixElectriqueValeur, Double taux_utilisation) {
+        return "ImpactEquipementPhysique = (Quantité(%s) * ConsoElecAnMoyenne(%s) * MixElectrique(%s) * TauxUtilisation(%s)) / 365".formatted(quantite, consoElecAnMoyenne, mixElectriqueValeur, taux_utilisation);
+    }
+
+    public static String getFormuleSecondScenario(Double quantite, Double valeurRefrentiel, Double dureeVie, Double taux_utilisation) {
+        return "ImpactEquipementPhysique = (Quantité(%s) * referentielImpactEquipement(%s) * TauxUtilisation(%s)) / dureeVie(%s)".formatted(quantite, valeurRefrentiel, taux_utilisation, dureeVie);
+    }
+
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactMessagerieUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactMessagerieUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1b28ac044d1a225092c1a9c8e5685e1b80961ae
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactMessagerieUtils.java
@@ -0,0 +1,50 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+
+public class TraceCalculImpactMessagerieUtils {
+
+    private TraceCalculImpactMessagerieUtils() {
+        // private constructor
+    }
+
+    public static TraceCalculImpactMessagerie buildTrace(DemandeCalculImpactMessagerie demandeCalcul, ReferentielImpactMessagerie referentielImpactMessagerie) {
+        return TraceCalculImpactMessagerie.builder()
+                .formule(getFormule(
+                        demandeCalcul.getMessagerie().getVolumeTotalMailEmis()/demandeCalcul.getMessagerie().getNombreMailEmis(),
+                        demandeCalcul.getMessagerie().getVolumeTotalMailEmis(),
+                        demandeCalcul.getMessagerie().getNombreMailEmis(),
+                        referentielImpactMessagerie.getConstanteCoefficientDirecteur(),
+                        referentielImpactMessagerie.getConstanteOrdonneeOrigine(),
+                        demandeCalcul.getMessagerie().getNombreMailEmisXDestinataires()
+                ))
+                .critere(demandeCalcul.getCritere().getNomCritere())
+                .volumeTotalMailEmis(demandeCalcul.getMessagerie().getVolumeTotalMailEmis())
+                .nombreMailEmis(demandeCalcul.getMessagerie().getNombreMailEmis())
+                .nombreMailEmisXDestinataires(demandeCalcul.getMessagerie().getNombreMailEmisXDestinataires())
+                .constanteCoefficientDirecteur(referentielImpactMessagerie.getConstanteCoefficientDirecteur())
+                .constanteOrdonneeOrigine(referentielImpactMessagerie.getConstanteOrdonneeOrigine())
+                .poidsMoyenMail(demandeCalcul.getMessagerie().getVolumeTotalMailEmis()/demandeCalcul.getMessagerie().getNombreMailEmis())
+                .build();
+    }
+
+    public static TraceCalculImpactMessagerie buildTraceError(CalculImpactException exception) {
+        var message = "Erreur lors du calcul de l'impact de messagerie";
+        if(exception != null) {
+            message = exception.getErrorType() + " : " + exception.getMessage();
+        }
+        return TraceCalculImpactMessagerie.builder()
+                .erreur(message)
+                .build();
+    }
+
+    private static String getFormule(Double poidsMoyenMail, Double volumeTotalMailEmis, Double nombreMailEmis, Double constanteCoefficientDirecteur, Double constanteOrdonneeOrigine, Double nombreMailEmisXDestinataires){
+        return """
+                poidsMoyenMail(%s) = volumeTotalMailEmis(%s)/nombreMailEmis(%s);
+                impactMensuel = (constanteCoefficientDirecteur (%s) * poidsMoyenMail(%s) + constanteOrdonneeOrigine(%s)) * nombreMailEmisXDestinataires(%s)
+                """.formatted(poidsMoyenMail,volumeTotalMailEmis,nombreMailEmis,constanteCoefficientDirecteur,poidsMoyenMail,constanteOrdonneeOrigine, nombreMailEmisXDestinataires);
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactReseauUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactReseauUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..69c37222e72052206f1b300af7a8b6badfc57a67
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactReseauUtils.java
@@ -0,0 +1,44 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+
+public class TraceCalculImpactReseauUtils {
+    private TraceCalculImpactReseauUtils() {
+    }
+
+    private static String getFormule(Float goTelecharge, String critere, String etapeACV, String equipementPhysique, Double impactReseauMobileMoyen) {
+        return "impactReseau = 'equipementPhysique.goTelecharge (%s) x ref_ImpactReseau(%s, %s, %s).valeur(%s)'".formatted(goTelecharge, critere, etapeACV, equipementPhysique, impactReseauMobileMoyen);
+    }
+
+    public static TraceCalculImpactReseau buildTraceErreur(CalculImpactException exception) {
+        var message = "Erreur lors du calcul de l'impact réseau pour un équipement physique";
+        if(exception != null) {
+            message = exception.getErrorType() + " : " + exception.getMessage();
+        }
+        return TraceCalculImpactReseau.builder()
+                .erreur(message)
+                .build();
+    }
+
+    public static TraceCalculImpactReseau buildTrace(DemandeCalculImpactReseau demandeCalculImpactReseau, ReferentielImpactReseau referentielImpactReseau){
+
+        return TraceCalculImpactReseau.builder()
+                .critere(demandeCalculImpactReseau.getCritere().getNomCritere())
+                .etapeACV(demandeCalculImpactReseau.getEtape().getCode())
+                .equipementPhysique(demandeCalculImpactReseau.getEquipementPhysique().getNomEquipementPhysique())
+                .impactReseauMobileMoyen(referentielImpactReseau.getImpactReseauMobileMoyen().toString())
+                .goTelecharge(demandeCalculImpactReseau.getEquipementPhysique().getGoTelecharge().toString())
+                .sourceReferentielReseau(referentielImpactReseau.getSource())
+                .formule(getFormule(
+                        demandeCalculImpactReseau.getEquipementPhysique().getGoTelecharge(),
+                        demandeCalculImpactReseau.getCritere().getNomCritere(),
+                        demandeCalculImpactReseau.getEtape().getCode(),
+                        referentielImpactReseau.getRefReseau(),
+                        referentielImpactReseau.getImpactReseauMobileMoyen()
+                ))
+                .build();
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactVirtuelUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactVirtuelUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..19c98a428ab2b1f96234886e1b6f3ba281469023
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactVirtuelUtils.java
@@ -0,0 +1,82 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementVirtuelServiceImpl;
+
+public class TraceCalculImpactVirtuelUtils {
+
+    private TraceCalculImpactVirtuelUtils(){}
+
+    public static TraceCalculImpactEquipementVirtuel buildTrace(DemandeCalculImpactEquipementVirtuel demandeCalcul) {
+        if(CalculImpactEquipementVirtuelServiceImpl.cleRepartitionEstDisponible(demandeCalcul)) {
+            return TraceCalculImpactEquipementVirtuel.builder()
+                    .formule(getFormuleForCleRepartition(demandeCalcul))
+                    .build();
+        }
+        else if(CalculImpactEquipementVirtuelServiceImpl.calculPourCalculEstDisponible(demandeCalcul)) {
+            return TraceCalculImpactEquipementVirtuel.builder()
+                    .formule(getFormuleWithTotalVCPU(demandeCalcul))
+                    .nbTotalVCPU(demandeCalcul.getNbTotalVCPU())
+                    .nbEquipementsVirtuels(demandeCalcul.getNbEquipementsVirtuels())
+                    .build();
+        }
+        else if(CalculImpactEquipementVirtuelServiceImpl.calculPourStockageEstDisponible(demandeCalcul)) {
+            return TraceCalculImpactEquipementVirtuel.builder()
+                    .formule(getFormuleForStockage(demandeCalcul))
+                    .stockageTotalVirtuel(demandeCalcul.getStockageTotalVirtuel())
+                    .build();
+        }
+
+        return TraceCalculImpactEquipementVirtuel.builder()
+                .formule(getFormuleWithNombreEquipementVirtuel(demandeCalcul))
+                .nbTotalVCPU(demandeCalcul.getNbTotalVCPU())
+                .nbEquipementsVirtuels(demandeCalcul.getNbEquipementsVirtuels())
+                .build();
+    }
+
+    public static TraceCalculImpactEquipementVirtuel buildTraceErreur(CalculImpactException exception) {
+        var message = "Erreur lors du calcul de l'impact d'équipement virtuel";
+        if(exception != null) {
+            message = exception.getErrorType() + " : " + exception.getMessage();
+        }
+        return TraceCalculImpactEquipementVirtuel.builder()
+                .erreur(message)
+                .build();
+    }
+
+    public static  String getFormuleWithTotalVCPU(DemandeCalculImpactEquipementVirtuel demandeCalcul){
+        return "valeurImpactUnitaire = valeurImpactEquipementPhysique(%s) * equipementVirtuel.vCPU(%s) / nbvCPU(%s)"
+                .formatted(
+                        demandeCalcul.getImpactEquipement().getImpactUnitaire(),
+                        demandeCalcul.getEquipementVirtuel().getVCPU(),
+                        demandeCalcul.getNbTotalVCPU()
+                        );
+    }
+
+    public static  String getFormuleForStockage(DemandeCalculImpactEquipementVirtuel demandeCalcul){
+        return "valeurImpactUnitaire = valeurImpactEquipementPhysique(%s) * equipementVirtuel.capaciteStockage(%s) / stockageTotalVirtuel(%s)"
+                .formatted(
+                        demandeCalcul.getImpactEquipement().getImpactUnitaire(),
+                        demandeCalcul.getEquipementVirtuel().getCapaciteStockage(),
+                        demandeCalcul.getStockageTotalVirtuel()
+                        );
+    }
+
+    public static  String getFormuleForCleRepartition(DemandeCalculImpactEquipementVirtuel demandeCalcul){
+        return "valeurImpactUnitaire = valeurImpactEquipementPhysique(%s) * equipementVirtuel.cleRepartition(%s)"
+                .formatted(
+                        demandeCalcul.getImpactEquipement().getImpactUnitaire(),
+                        demandeCalcul.getEquipementVirtuel().getCleRepartition()
+                        );
+    }
+
+    public static  String getFormuleWithNombreEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demandeCalcul){
+        return "valeurImpactUnitaire = valeurImpactEquipementPhysique(%s) / nbVM(%s)"
+                .formatted(
+                        demandeCalcul.getImpactEquipement().getImpactUnitaire(),
+                        demandeCalcul.getNbEquipementsVirtuels()
+                );
+    }
+}
diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..28f04788ccd899082d5dcbb5f329b2a67832ed33
--- /dev/null
+++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java
@@ -0,0 +1,23 @@
+package org.mte.numecoeval.calculs.domain.traceur;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class TraceUtils {
+
+    private TraceUtils() {
+        // private constructor
+    }
+
+    public static String getTraceFromTraceur(ObjectMapper objectMapper, Object traceur) {
+        String trace= "";
+        try {
+            trace = objectMapper.writeValueAsString(traceur);
+        } catch (JsonProcessingException e) {
+            log.error(e.getMessage());
+        }
+        return trace;
+    }
+}
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/CucumberIntegrationTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/CucumberIntegrationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..651063bd2d1614ab50109aa87cd3faa1572a2144
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/CucumberIntegrationTest.java
@@ -0,0 +1,51 @@
+package org.mte.numecoeval.calculs;
+
+import io.cucumber.spring.CucumberContextConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.suite.api.ConfigurationParameter;
+import org.junit.platform.suite.api.IncludeEngines;
+import org.junit.platform.suite.api.SelectClasspathResource;
+import org.junit.platform.suite.api.Suite;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.Environment;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.text.NumberFormat;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
+import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@CucumberContextConfiguration
+@SpringBootTest(classes = CucumberIntegrationTest.TestApplication.class)
+@ActiveProfiles(profiles = { "test" })
+@Suite
+@IncludeEngines("cucumber")
+@SelectClasspathResource("org/mte/numecoeval/calculs")
+@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty,html:target/cucumber-reports.html")
+@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "org.mte.numecoeval.calculs")
+public class CucumberIntegrationTest {
+
+    public static final DateTimeFormatter FORMATTER_FRENCH_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+
+    public static final NumberFormat NUMBER_FRENCH_FORMAT = NumberFormat.getInstance(Locale.FRENCH);
+
+    @Test
+    void testContextLoadOK(@Autowired Environment environment) {
+        assertNotNull(environment, "L'environnement est correctement chargé");
+    }
+
+    @SpringBootApplication
+    public static class TestApplication {
+
+        public static void main(String[] args) {
+            SpringApplication.run(TestApplication.class, args);
+        }
+
+    }
+}
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee8972137ef2d085a1fa861a1a09bc9b88175311
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java
@@ -0,0 +1,346 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.entree.Application;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactApplication;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactApplicationServiceImpl;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@ExtendWith(MockitoExtension.class)
+class CalculImpactApplicationServiceImplTest {
+
+    CalculImpactApplicationServiceImpl calculImpactApplicatifService ;
+
+    @BeforeEach
+    void setUp(){
+        calculImpactApplicatifService = new CalculImpactApplicationServiceImpl(new ObjectMapper());
+    }
+
+    @Test
+    void whenImpactEquipementVirtuelIsInError_ShouldReturnImpactError() {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("ERREUR")
+                .impactUnitaire(61.744d)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .trace("{\"erreur\":\"Erreur lors du calcul d'impact équipement virtuel\"}")
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(1)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+
+        assertNull(impactApplication.getImpactUnitaire());
+        assertNull(impactApplication.getConsoElecMoyenne());
+
+        assertEquals("ERREUR", impactApplication.getStatutIndicateur());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : L'indicateur d'impact équipement virtuel associé est au statut : ERREUR\"}", impactApplication.getTrace());
+    }
+
+    @Test
+    void whenImpactEquipementVirtuelIsNull_ShouldReturnImpactError() {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("OK")
+                .impactUnitaire(null)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .trace("{\"erreur\":\"Erreur lors du calcul d'impact équipement virtuel\"}")
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(1)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+
+        assertNull(impactApplication.getImpactUnitaire());
+        assertNull(impactApplication.getConsoElecMoyenne());
+
+        assertEquals("ERREUR", impactApplication.getStatutIndicateur());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : L'indicateur d'impact équipement virtuel associé est null.\"}", impactApplication.getTrace());
+    }
+
+    @ParameterizedTest
+    @ValueSource(ints = 0)
+    void whenNbApplicationIs0_ShouldApplyRatio1AndReturnImpactOK(Integer nbApplications) {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("OK")
+                .impactUnitaire(61.744d)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(nbApplications)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire(), impactApplication.getImpactUnitaire());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne(), impactApplication.getConsoElecMoyenne());
+
+        assertEquals("OK", impactApplication.getStatutIndicateur());
+        assertEquals("{\"formule\":\"ImpactApplication = ImpactEquipementVirtuel(61.744) / nbApplications(1)\",\"nbApplications\":0}", impactApplication.getTrace());
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void whenNbApplicationIsNull_ShouldApplyRatio1AndReturnImpactOK(Integer nbApplications) {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("OK")
+                .impactUnitaire(61.744d)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(nbApplications)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire(), impactApplication.getImpactUnitaire());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne(), impactApplication.getConsoElecMoyenne());
+
+        assertEquals("OK", impactApplication.getStatutIndicateur());
+        assertEquals("{\"formule\":\"ImpactApplication = ImpactEquipementVirtuel(61.744) / nbApplications(1)\"}", impactApplication.getTrace());
+    }
+
+    @Test
+    void whenImpactEquipementVirtuelIsOK_ShouldReturnImpactOK() {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("OK")
+                .impactUnitaire(61.744d)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(1)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire(), impactApplication.getImpactUnitaire());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne(), impactApplication.getConsoElecMoyenne());
+
+        assertEquals("OK", impactApplication.getStatutIndicateur());
+        assertEquals("{\"formule\":\"ImpactApplication = ImpactEquipementVirtuel(61.744) / nbApplications(1)\",\"nbApplications\":1}", impactApplication.getTrace());
+    }
+
+    @Test
+    void taiga1025_whenNbApplicationsIsMoreThan1_ThenImpactShouldBeDividedAndImpactShouldBeOK() {
+        String applicationName ="MS-Word";
+        String environnement = "Production";
+        LocalDate dateLot = LocalDate.of(2023, 4, 1);
+        Application application = Application.builder()
+                .dateLot(dateLot)
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomApplication(applicationName)
+                .typeEnvironnement(environnement)
+                .domaine("Bureautique")
+                .sousDomaine("Licence")
+                .nomEquipementPhysique("nomEquipementPhysique")
+                .nomEquipementVirtuel("nomEquipementVirtuel")
+                .build();
+        ImpactEquipementVirtuel impactEquipementVirtuel = ImpactEquipementVirtuel.builder()
+                .dateLot(dateLot)
+                .etapeACV("Utilisation")
+                .critere("Critere")
+                .unite("kgCO2eq")
+                .dateCalcul(LocalDateTime.now().minusSeconds(10))
+                .statutIndicateur("OK")
+                .impactUnitaire(61.744d)
+                .consoElecMoyenne(61.744d)
+                .nomEquipement(application.getNomEquipementPhysique())
+                .nomEquipementVirtuel(application.getNomEquipementVirtuel())
+                .trace("{\"erreur\":\"Erreur lors du calcul d'impact équipement virtuel\"}")
+                .build();
+        DemandeCalculImpactApplication demanceCalcul = DemandeCalculImpactApplication.builder()
+                .application(application)
+                .dateCalcul(LocalDateTime.now())
+                .nbApplications(10)
+                .impactEquipementVirtuel(impactEquipementVirtuel)
+                .build();
+
+        // When
+        var impactApplication = calculImpactApplicatifService.calculImpactApplicatif(demanceCalcul);
+
+        assertContentIndicateur(demanceCalcul, impactApplication);
+
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire()/demanceCalcul.getNbApplications(), impactApplication.getImpactUnitaire());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne()/demanceCalcul.getNbApplications(), impactApplication.getConsoElecMoyenne());
+
+        assertEquals("OK", impactApplication.getStatutIndicateur());
+        assertEquals("{\"formule\":\"ImpactApplication = ImpactEquipementVirtuel(61.744) / nbApplications(10)\",\"nbApplications\":10}", impactApplication.getTrace());
+    }
+
+    private static void assertContentIndicateur(DemandeCalculImpactApplication demanceCalcul, ImpactApplication impactApplication) {
+        assertNotNull(impactApplication);
+        assertEquals(demanceCalcul.getApplication().getNomApplication(), impactApplication.getNomApplication());
+        assertEquals(demanceCalcul.getApplication().getTypeEnvironnement(), impactApplication.getTypeEnvironnement());
+        assertEquals(demanceCalcul.getApplication().getDomaine(), impactApplication.getDomaine());
+        assertEquals(demanceCalcul.getApplication().getSousDomaine(), impactApplication.getSousDomaine());
+
+        assertEquals(demanceCalcul.getApplication().getNomLot(), impactApplication.getNomLot());
+        assertEquals(demanceCalcul.getApplication().getDateLot(), impactApplication.getDateLot());
+        assertEquals(demanceCalcul.getApplication().getNomEquipementPhysique(), impactApplication.getNomEquipementPhysique());
+        assertEquals(demanceCalcul.getApplication().getNomEquipementVirtuel(), impactApplication.getNomEquipementVirtuel());
+        assertEquals(demanceCalcul.getApplication().getNomOrganisation(), impactApplication.getNomOrganisation());
+        assertEquals(demanceCalcul.getApplication().getNomEntite(), impactApplication.getNomEntite());
+        assertEquals(demanceCalcul.getApplication().getNomSourceDonnee(), impactApplication.getNomSourceDonnee());
+
+        assertEquals(demanceCalcul.getDateCalcul(), impactApplication.getDateCalcul());
+
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getCritere(), impactApplication.getCritere());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getEtapeACV(), impactApplication.getEtapeACV());
+        assertEquals(demanceCalcul.getImpactEquipementVirtuel().getUnite(), impactApplication.getUnite());
+
+        assertEquals("1.1", impactApplication.getVersionCalcul());
+    }
+
+}
\ No newline at end of file
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffa130a08601b3757bb8c23d9baf34c0c4dd84ad
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java
@@ -0,0 +1,2293 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.entree.DataCenter;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.referentiel.*;
+import org.mte.numecoeval.calculs.domain.data.trace.ConsoElecAnMoyenne;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.data.trace.MixElectrique;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementPhysiqueServiceImpl;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.DureeDeVieEquipementPhysiqueServiceImpl;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactEquipementPhysiqueUtils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+
+@ExtendWith(MockitoExtension.class)
+class CalculImpactEquipementPhysiqueServiceTest {
+
+    private CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService;
+    private String etapeACV;
+    private ReferentielCritere critere;
+    private LocalDateTime dateCalcul;
+    private String refEquipementCible;
+    private String refEquipementParDefaut;
+    private EquipementPhysique equipementPhysique;
+    private ReferentielImpactEquipement referentielImpactEquipement;
+    private ReferentielMixElectrique referentielMixElectrique;
+    ReferentielCorrespondanceRefEquipement refEquipement;
+    ReferentielTypeEquipement typeEquipement;
+    ReferentielHypothese referentielHypothese;
+    @Mock
+    private DureeDeVieEquipementPhysiqueServiceImpl dureeDeVieEquipementPhysiqueService;
+
+    @Spy
+    private ObjectMapper objectMapper;
+
+    @BeforeEach
+    public void init() throws Exception {
+        MockitoAnnotations.openMocks(this);
+        calculImpactEquipementPhysiqueService = new CalculImpactEquipementPhysiqueServiceImpl(
+                dureeDeVieEquipementPhysiqueService,
+                objectMapper
+        );
+        etapeACV = "UTILISATION";
+        String etapeACV = "UTILISATION";
+        critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        dateCalcul = LocalDateTime.now();
+        refEquipementCible = "Apple Iphone 11";
+        refEquipementParDefaut = "Apple Iphone 11";
+        equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("COPE")
+                .build();
+        referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF1")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(refEquipementCible)
+                .consoElecMoyenne(0.09)
+                .build();
+        referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF1() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Apple Iphone 11";
+        String refEquipementParDefaut = "Apple Iphone 11";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                // Consommation electrique annuelle à null, celle du référentiel sera utilisé
+                .consoElecAnnuelle(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF1")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(refEquipementCible)
+                .consoElecMoyenne(0.09)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0073, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    /* même cas que le CAF1 mais avec une consoElecAnnuelle à 0 au lieu de null.
+     * Conformément au Taiga 895 : le 0 est bien appliqué et ramène le résultat à 0
+     */
+    @Test
+    void taiga895_shouldApplyConsoElecAnnuelWithConsoElecAnnuelleAt0_CAF1() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Apple Iphone 11";
+        String refEquipementParDefaut = "Apple Iphone 11";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                // Consommation electrique annuelle à 0, elle sera utilisé et rend le calcul à 0
+                .consoElecAnnuelle(0.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF1")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(0.09)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0, actualImpactUnitaireLimited);
+        assertEquals(0, actual.getConsoElecMoyenne());
+        assertNotEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF2_neededCorrection() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Ecran2";
+        String refEquipementParDefaut = "Ecran2";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran2")
+                .modele("Ecran2")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(30.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF2")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(70.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(3, RoundingMode.DOWN).doubleValue();
+        assertEquals(5.692, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF3_decimalFixing() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "OrdinateurBureau3";
+        String refEquipementParDefaut = "OrdinateurBureau3";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("OrdinateurBureau")
+                .nomEquipementPhysique("OrdinateurBureau3")
+                .modele("OrdinateurBureau3")
+                .paysDUtilisation("Irlande")
+                .nomCourtDatacenter(null)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF3")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(3504.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("Irlande")
+                .raccourcisAnglais("IR")
+                .source("CAF3")
+                .valeur(0.648118)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        // quantité * refEquipementPhysique.consoElecMoyenne * MixElec
+        assertEquals(BigDecimal.valueOf(1.0 * 3504.0 * 0.648118).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void taiga918_DataCenterReferencedAndUsedForPUE_CAF1() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia2")
+                .nomLongDatacenter("sequoia2")
+                .localisation("France")
+                .pue(1.43)
+                .build();
+        String refEquipementCible = "ref-Serveur1";
+        String refEquipementParDefaut = "ref-Serveur1";
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_100")
+                .dateAchat(LocalDate.of(2018, 10, 1))
+                .modele("ref-Serveur1")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia2")
+                .dataCenter(dataCenter)
+                .quantite(2.0)
+                .consoElecAnnuelle(500.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.08)
+                .build();
+
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        // quantité * equipementPhysique.consoElecAnnuelle * DataCenter.pue * MixElec(France)
+        assertEquals(BigDecimal.valueOf(2.0 * 500.0 * 1.43 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
+    }
+
+    @Test
+    void taiga918_DataCenterWithoutPUEAndDefaultPUEUsed_CAF2() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia3")
+                .nomLongDatacenter("sequoia3")
+                .localisation("France")
+                .pue(null)
+                .build();
+        String refEquipementCible = "ref-Serveur4";
+        String refEquipementParDefaut = "ref-Serveur4";
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_104")
+                .modele("ref-Serveur4")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia3")
+                .dataCenter(dataCenter)
+                .consoElecAnnuelle(500.0)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(2.0)
+                .code("PUEParDefaut")
+                .source("CAF2")
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF2")
+                .valeur(0.08)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        // quantité * equipementPhysique.consoElecAnnuelle * ref_Hypothese(PUEParDefaut).valeur * MixElec France
+        assertEquals(BigDecimal.valueOf(1.0 * 500.0 * 2.0 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
+    }
+
+    @Test
+    void taiga918_ConsoElecMoyenneUsedFromRef_CAF3() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia2")
+                .nomLongDatacenter("sequoia2")
+                .localisation("France")
+                .pue(1.43)
+                .build();
+        String refEquipementCible = "ref-Serveur2";
+        String refEquipementParDefaut = "ref-Serveur2";
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_101")
+                .modele("ref-Serveur2")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia2")
+                .dataCenter(dataCenter)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF2")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(10512.0)
+                .valeur(1139.839200000007)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF3")
+                .valeur(0.08)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        // quantité * refEquipementPhysique.consoElecMoyenne * DataCEnter.pue * MixElec France
+        assertEquals(BigDecimal.valueOf(1.0 * 10512.0 * 1.43 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void taiga918_CAF4_whenDonneesConsoElecAbsente_shouldReturnErreurCalcul() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia2")
+                .nomLongDatacenter("sequoia2")
+                .localisation("France")
+                .pue(1.43)
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "ref-Serveur3";
+        String refEquipementParDefaut = "ref-Serveur3";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_103")
+                .modele("ref-Serveur3")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia2")
+                .dataCenter(dataCenter)
+                .consoElecAnnuelle(null)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF4")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(null)
+                .valeur(1139.839200000007)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Donnée de consommation electrique manquante : equipementPhysique : Serveur_103, RefEquipementCible : ref-Serveur3, RefEquipementParDefaut : ref-Serveur3\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void taiga918_ecranCAF5() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "ref-Ecran";
+        String refEquipementParDefaut = "ref-Ecran";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran_1")
+                .modele("ref-Ecran")
+                .paysDUtilisation("France")
+                .serveur(false)
+                .nomCourtDatacenter(null)
+                .dataCenter(null)
+                .quantite(1.0)
+                .consoElecAnnuelle(100.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF5")
+                .valeur(0.08)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        // quantité * equipementPhysique.consoElecAnnuelle * MixElec France
+        assertEquals(BigDecimal.valueOf(1.0 * 100.0 * 0.08).setScale(4, RoundingMode.DOWN).doubleValue(), actualImpactUnitaireLimited);
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF4() throws Exception {
+
+        //Given
+        String etapeACV = "FABRICATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Ordinateur4";
+        String refEquipementParDefaut = "Ordinateur4";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Desktop")
+                .nomEquipementPhysique("Ordinateur4")
+                .modele("Ordinateur4")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF4")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(null)
+                .valeur(142.0)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(5.0d).build());
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(28.4, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF5() throws Exception {
+
+        //Given
+        String etapeACV = "FIN_DE_VIE";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "KyoceraTaskalfa3253Ci";
+        String refEquipementParDefaut = "KyoceraTaskalfa3253Ci";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Imprimante")
+                .nomEquipementPhysique("Imprimante5")
+                .modele("KyoceraTaskalfa3253Ci")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF5")
+                .etape(etapeACV)
+                .critere(critere.getNomCritere())
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(123.3)
+                .valeur(17.3)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .build();
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(6.0).build());
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(2.8833, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_CAF6() throws Exception {
+
+        //Given
+        String etapeACV = "DISTRIBUTION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Ecran6";
+        String refEquipementParDefaut = "Ecran6";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran6")
+                .modele("Ecran6")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF6")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(123.3)
+                .valeur(1.273)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(7.0).build());
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.1818, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldCalculerImpactEquipementPhysique_whenEtapeACVUTILISATIONAndEquipementConsoElecMoyenneFilled() throws Exception {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Apple Iphone 11";
+        String refEquipementParDefaut = "Apple Iphone 11";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .consoElecAnnuelle(0.09)
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0073, actualImpactUnitaireLimited);
+        assertEquals(equipementPhysique.getConsoElecAnnuelle(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldBuildTraceWithFirstFormulaScenario1() throws JsonProcessingException {
+
+        //GIVEN
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
+        String refEquipementCible = "Samsung SMP";
+        String refEquipementParDefaut = "Samsung SMP";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("Samsung S21")
+                .modele("Samsung SMP")
+                .consoElecAnnuelle(200d)
+                .paysDUtilisation("France")
+                .nbJourUtiliseAn(230d)
+                .serveur(false)
+                .quantite(3d)
+                .build();
+
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("Source-Mix")
+                .valeur(150d)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(LocalDateTime.now())
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormulePremierScenario(3d, 200d, 150d, 1.0);
+
+        var consoElecAnMoyenne = ConsoElecAnMoyenne.builder().valeurEquipementConsoElecAnnuelle(200d).valeur(200d).build();
+        var mixElectrique = MixElectrique.builder().valeur(150d).valeurReferentielMixElectrique(150d).sourceReferentielMixElectrique("Source-Mix").build();
+        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
+                .formule(formule)
+                .consoElecAnMoyenne(consoElecAnMoyenne)
+                .mixElectrique(mixElectrique)
+                .build();
+        var expected = objectMapper.writeValueAsString(trace);
+        //WHEN
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);
+        //THEN
+        assertEquals(expected, actual.getTrace());
+    }
+
+    @Test
+    void shouldBuildTraceWithFirstFormulaScenario2() throws JsonProcessingException {
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
+        DataCenter dataCenter = DataCenter.builder()
+                .localisation("Spain")
+                .pue(5d)
+                .build();
+        String refEquipementCible = "IBM E1080";
+        String refEquipementParDefaut = "IBM E1080";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .quantite(6d)
+                .modele("IBM E1080")
+                .serveur(true)
+                .dataCenter(dataCenter)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement("IBM E1080")
+                .source("source-RefEquipement")
+                .consoElecMoyenne(130d)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("Spain")
+                .source("Source-Mix")
+                .valeur(25d)
+                .build();
+
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(LocalDateTime.now())
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormulePremierScenario(6d, 130d, 5d * 25d, 1.0);
+
+        var consoElecAnMoyenne = ConsoElecAnMoyenne.builder()
+                .valeur(130d)
+                .valeurReferentielConsoElecMoyenne(130d)
+                .sourceReferentielImpactEquipement("source-RefEquipement")
+                .build();
+        var mixElectrique = MixElectrique.builder()
+                .valeur(125d)
+                .dataCenterPue(5d)
+                .valeurReferentielMixElectrique(25d)
+                .sourceReferentielMixElectrique("Source-Mix")
+                .isServeur(true)
+                .build();
+        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
+                .formule(formule)
+                .consoElecAnMoyenne(consoElecAnMoyenne)
+                .mixElectrique(mixElectrique)
+                .build();
+        var expected = objectMapper.writeValueAsString(trace);
+        //WHEN
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);
+        //THEN
+        assertEquals(expected, actual.getTrace());
+    }
+
+    @Test
+    void shouldBuildTraceWithSecondFormula() throws JsonProcessingException, CalculImpactException {
+        String etapeACV = "Fin de vie";
+        ReferentielCritere critere = ReferentielCritere.builder().nomCritere("Changement Climatique").unite("CO2").build();
+        LocalDate dateAchat = LocalDate.of(2020, 1, 22);
+        LocalDate dateRetrait = LocalDate.of(2021, 5, 12);
+        double quantite = 6d;
+        double tauxUtilisation = 1.0;
+        String refEquipementCible = "IBM E1080";
+        String refEquipementParDefaut = "IBM E1080";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .quantite(quantite)
+                .modele("IBM E1080")
+                .dateAchat(dateAchat)
+                .dateRetrait(dateRetrait)
+                .serveur(false)
+                .build();
+        double valeurRefrentiel = 100d;
+        String sourceReferentielImpactEquipement = "source-RefEquipement";
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement("IBM E1080")
+                .source(sourceReferentielImpactEquipement)
+                .consoElecMoyenne(130d)
+                .valeur(valeurRefrentiel)
+                .build();
+
+
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(LocalDateTime.now())
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul)).thenCallRealMethod();
+
+        var valeurDureeVie = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d;
+        DureeDeVie dureeDeVie = DureeDeVie.builder()
+                .valeur(valeurDureeVie)
+                .dateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE))
+                .dateRetrait(dateRetrait.format(DateTimeFormatter.ISO_DATE))
+                .build();
+
+        var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormuleSecondScenario(quantite, valeurRefrentiel, valeurDureeVie, tauxUtilisation);
+
+        TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder()
+                .formule(formule)
+                .dureeDeVie(dureeDeVie)
+                .valeurReferentielImpactEquipement(valeurRefrentiel)
+                .sourceReferentielImpactEquipement(sourceReferentielImpactEquipement)
+                .build();
+        var expected = objectMapper.writeValueAsString(trace);
+        //WHEN
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul);
+
+        //THEN
+        assertEquals(expected, actual.getTrace());
+    }
+
+    @Test
+    void taiga862_CAF1_calculImpactEquipementPhysiqueWithoutCorrespondanceShouldUseRefEquipementParDefaut() throws Exception {
+
+        //Given
+        String etapeACV = "DISTRIBUTION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementParDefaut = "EcranParDefaut";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran6")
+                .modele("Ecran6")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .source("CAF6")
+                .refEquipement(refEquipementParDefaut)
+                .consoElecMoyenne(123.3)
+                .valeur(1.273)
+                .build();
+
+        ReferentielCorrespondanceRefEquipement refEquipement = null;
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(7.0).build());
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.1818, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void taiga862_CAF1_calculImpactEquipementPhysiqueWithoutImpactForCorrespondanceShouldUseRefEquipementParDefaut() throws Exception {
+
+        //Given
+        String etapeACV = "DISTRIBUTION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementParDefaut = "EcranParDefaut";
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .source("CAF6")
+                .refEquipement(refEquipementParDefaut)
+                .consoElecMoyenne(123.3)
+                .valeur(1.273)
+                .build();
+        String refEquipementCible = "Ecran6";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran6")
+                .modele("Ecran6")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(7.0).build());
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.1818, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void tech_whenDureeDeVieUnknown_shouldReturnIndicateurWithError() {
+
+        //Given
+        String etapeACV = "FIN_DE_VIE";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia2")
+                .nomLongDatacenter("sequoia2")
+                .localisation("France")
+                .pue(1.43)
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "ref-Serveur3";
+        String refEquipementParDefaut = "ref-Serveur3";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_103")
+                .modele("ref-Serveur3")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia2")
+                .dataCenter(dataCenter)
+                .consoElecAnnuelle(null)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF4")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(100.0)
+                .valeur(1139.839200000007)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Durée de vie de l'équipement inconnue\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void verifyErrorWhenCallConsoElecAnMoyenneWithoutConsoInEntryWithImpactRefWithoutConso() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Apple Iphone 11";
+        String refEquipementParDefaut = "Apple Iphone 11";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF5")
+                .valeur(0.08)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF4")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(null)
+                .valeur(1139.839200000007)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Donnée de consommation electrique manquante : equipementPhysique : Apple Iphone 11, RefEquipementCible : Apple Iphone 11, RefEquipementParDefaut : Apple Iphone 11\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void verifyErrorWhenCallConsoElecAnMoyenneWithoutConsoInEntryAndNoImpactRef() {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementParDefaut = "EcranParDefaut";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Ecran")
+                .nomEquipementPhysique("Ecran6")
+                .modele("Ecran6")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Référentiel Impact Equipement inconnu\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void tech_whenNoReferentielImpactEquipement_shouldReturnIndicateurWithError() throws CalculImpactException {
+        //Given
+        String etapeACV = "FIN_DE_VIE";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        DataCenter dataCenter = DataCenter.builder()
+                .nomCourtDatacenter("sequoia2")
+                .nomLongDatacenter("sequoia2")
+                .localisation("France")
+                .pue(1.43)
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "ref-Serveur3";
+        String refEquipementParDefaut = "ref-Serveur3";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Serveur_103")
+                .modele("ref-Serveur3")
+                .paysDUtilisation("France")
+                .serveur(true)
+                .nomCourtDatacenter("sequoia2")
+                .dataCenter(dataCenter)
+                .consoElecAnnuelle(null)
+                .quantite(1.0)
+                .nbJourUtiliseAn(365.0)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(6.0)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.emptyList())
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Référentiel Impact Equipement inconnu\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void tech_whenMixElectriqueNotFound_shouldReturnIndicateurWithError() throws Exception {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Apple Iphone 11";
+        String refEquipementParDefaut = "Apple Iphone 11";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .consoElecAnnuelle(0.09)
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.emptyList())
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Il n'existe pas de Mix électrique pour cet équipement : critere: Changement Climatique - equipement: Apple Iphone 11 - Pays d'utilisation: France - NomCourtDatacenter: null\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void tech_whenMixElectriqueNotFoundWithDataCenter_shouldReturnIndicateurWithError() throws Exception {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "IBM X96";
+        String refEquipementParDefaut = "IBM X96";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("IBM X96")
+                .modele("IBM X96")
+                .paysDUtilisation("France")
+                .consoElecAnnuelle(0.09)
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .nomCourtDatacenter("TanaMana 2")
+                .dataCenter(
+                        DataCenter.builder()
+                                .nomCourtDatacenter("TanaMana 2")
+                                .nomLongDatacenter("TanaMana 2 - Rack B")
+                                .localisation("France")
+                                .pue(6.2)
+                                .build()
+                )
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.emptyList())
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Il n'existe pas de Mix électrique pour cet équipement : critere: Changement Climatique - equipement: IBM X96 - Pays d'utilisation: France - NomCourtDatacenter: TanaMana 2\"}",
+                actual.getTrace()
+        );
+    }
+
+    @Test
+    void tech_whenPUEUknown_shouldReturnIndicateurWithError() throws Exception {
+
+        //Given
+        String etapeACV = "UTILISATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "IBM X96";
+        String refEquipementParDefaut = "IBM X96";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Serveur")
+                .nomEquipementPhysique("Tanabana2-IBM X96")
+                .modele("IBM X96")
+                .paysDUtilisation("France")
+                .consoElecAnnuelle(0.09)
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .nomCourtDatacenter("TanaMana 2")
+                .dataCenter(
+                        DataCenter.builder()
+                                .nomCourtDatacenter("TanaMana 2")
+                                .nomLongDatacenter("TanaMana 2 - Rack B")
+                                .localisation("France")
+                                .pue(null)
+                                .build()
+                )
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        ReferentielMixElectrique referentielMixElectrique = ReferentielMixElectrique.builder()
+                .critere(critere.getNomCritere())
+                .pays("France")
+                .raccourcisAnglais("FR")
+                .source("CAF1")
+                .valeur(0.0813225)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertNull(actual.getImpactUnitaire());
+        assertEquals("ERREUR", actual.getStatutIndicateur());
+        assertEquals(
+                "{\"erreur\":\"ErrCalcFonc : Le PUE est manquant et ne permet le calcul de l'impact à l'usage de l'équipement : equipement: Tanabana2-IBM X96 - RefEquipementCible: IBM X96 - refEquipementParDefaut: IBM X96 - NomCourtDatacenter: TanaMana 2\"}",
+                actual.getTrace()
+        );
+    }
+
+    private void assertContentIndicateur(DemandeCalculImpactEquipementPhysique source, ImpactEquipementPhysique result) {
+        assertNotNull(result);
+        assertEquals(source.getEquipementPhysique().getNomEquipementPhysique(), result.getNomEquipement());
+        assertEquals(source.getEquipementPhysique().getType(), result.getTypeEquipement());
+        assertEquals(source.getEquipementPhysique().getStatut(), result.getStatutEquipementPhysique());
+        assertEquals(source.getEquipementPhysique().getQuantite(), result.getQuantite());
+
+        assertEquals(source.getEquipementPhysique().getNomLot(), result.getNomLot());
+        assertEquals(source.getEquipementPhysique().getDateLot(), result.getDateLot());
+        assertEquals(source.getEquipementPhysique().getNomOrganisation(), result.getNomOrganisation());
+        assertEquals(source.getEquipementPhysique().getNomEntite(), result.getNomEntite());
+        assertEquals(source.getEquipementPhysique().getNomSourceDonnee(), result.getNomSourceDonnee());
+
+        assertEquals(source.getDateCalcul(), result.getDateCalcul());
+
+        assertEquals(source.getCritere().getNomCritere(), result.getCritere());
+        assertEquals(source.getEtape().getCode(), result.getEtapeACV());
+        assertEquals(source.getCritere().getUnite(), result.getUnite());
+
+        assertEquals("1.0", result.getVersionCalcul());
+    }
+
+    @Test
+    void verifyFormulaForModeUtilisationCOPE() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("COPE")
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.8)
+                .code("taux_utilisation_COPE")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0058, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForModeUtilisationBYOD() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("BYOD")
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.57)
+                .code("taux_utilisation_BYOD")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0041, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForModeUtilisationModeUtilisationNull() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("")
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.57)
+                .code("taux_utilisation_BYOD")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0073, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForModeUtilisationModeUtilisationUnknown() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("COB")
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.57)
+                .code("taux_utilisation_BYOD")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0073, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForModeUtilisationModeUtilisationCOPEButNotInRefHypotheses() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("COPE")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.0073, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForNotTUILISATIONModeUtilisationCOPE() throws Exception {
+        //Given
+        String etapeACV = "FABRICATION";
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        String refEquipementCible = "Ordinateur4";
+        String refEquipementParDefaut = "Ordinateur4";
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Desktop")
+                .nomEquipementPhysique("Ordinateur4")
+                .modele("Ordinateur4")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .modeUtilisation("COPE")
+                .nbJourUtiliseAn(null)
+                .build();
+        ReferentielImpactEquipement referentielImpactEquipement = ReferentielImpactEquipement.builder()
+                .source("CAF4")
+                .critere(critere.getNomCritere())
+                .etape(etapeACV)
+                .refEquipement(equipementPhysique.getModele())
+                .consoElecMoyenne(null)
+                .valeur(142.0)
+                .build();
+        ReferentielCorrespondanceRefEquipement refEquipement = ReferentielCorrespondanceRefEquipement.builder()
+                .refEquipementCible(refEquipementCible)
+                .modeleEquipementSource(equipementPhysique.getModele())
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type(equipementPhysique.getType())
+                .refEquipementParDefaut(refEquipementParDefaut)
+                .dureeVieDefaut(null)
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.85)
+                .code("taux_utilisation_COPE")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .build();
+        when(dureeDeVieEquipementPhysiqueService.calculerDureeVie(any(DemandeCalculImpactEquipementPhysique.class))).thenReturn(DureeDeVie.builder().valeur(5.0d).build());
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertEquals(dateCalcul, actual.getDateCalcul());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(4, RoundingMode.DOWN).doubleValue();
+        assertEquals(24.14, actualImpactUnitaireLimited);
+        verify(dureeDeVieEquipementPhysiqueService, times(1)).calculerDureeVie(demandeCalcul);
+        assertNull(actual.getConsoElecMoyenne());
+    }
+
+    @Test
+    void verifyFormulaForUTILISATIONTauxUtilisationFilled() throws Exception {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022, 1, 1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .type("Téléphone")
+                .nomEquipementPhysique("Apple Iphone 11")
+                .modele("Apple Iphone 11")
+                .paysDUtilisation("France")
+                .quantite(1.0)
+                .nbJourUtiliseAn(216.0)
+                .consoElecAnnuelle(0.09)
+                .modeUtilisation("")
+                .tauxUtilisation(0.1)
+                .build();
+        ReferentielHypothese referentielHypothese = ReferentielHypothese.builder()
+                .valeur(0.57)
+                .code("taux_utilisation_BYOD")
+                .source("RCP_SI")
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .dateCalcul(dateCalcul)
+                .etape(ReferentielEtapeACV.builder().code(etapeACV).build())
+                .critere(critere)
+                .equipementPhysique(equipementPhysique)
+                .correspondanceRefEquipement(refEquipement)
+                .typeEquipement(typeEquipement)
+                .impactEquipements(Collections.singletonList(referentielImpactEquipement))
+                .mixElectriques(Collections.singletonList(referentielMixElectrique))
+                .hypotheses(Collections.singletonList(referentielHypothese))
+                .build();
+        //When
+        var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(
+                demandeCalcul
+        );
+        //Then
+        assertContentIndicateur(demandeCalcul, actual);
+        assertEquals("OK", actual.getStatutIndicateur());
+        assertNotNull(actual.getImpactUnitaire());
+        double actualImpactUnitaireLimited = BigDecimal.valueOf(actual.getImpactUnitaire()).setScale(5, RoundingMode.DOWN).doubleValue();
+        assertEquals(0.00073, actualImpactUnitaireLimited);
+        assertEquals(referentielImpactEquipement.getConsoElecMoyenne(), actual.getConsoElecMoyenne());
+    }
+}
\ No newline at end of file
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c197969a76a39744bf88fc1632fa99791e2b53fd
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java
@@ -0,0 +1,673 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementVirtuelService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementVirtuelServiceImpl;
+import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactVirtuelUtils;
+import org.springframework.boot.test.system.OutputCaptureExtension;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Slf4j
+@ExtendWith({MockitoExtension.class, OutputCaptureExtension.class})
+class CalculImpactEquipementVirtuelServiceTest {
+
+    @Spy
+    private ObjectMapper objectMapper;
+    private CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService;
+
+    @BeforeEach
+    void setUp() {
+        calculImpactEquipementVirtuelService = new CalculImpactEquipementVirtuelServiceImpl(objectMapper);
+    }
+
+    /**
+     * CAF 1
+     * Nombre total de vCPU renseigné
+     * calculIndicateurImpactEquipementPhysique * EqV.vCPU / NbvCPU
+     * Impact d’utilisation « VM1 »= 234,62784 x 7/19=86,442kgCO2eq
+     */
+    @Test
+    void whenTypeEqvIsCalculAndTotalVCPUIsNotNull_shouldReturnCalculImpactUsingTotalVCPU() {
+
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .vCPU(7)
+                .typeEqv("calcul")
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .consoElecMoyenne(100.0d)
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(7 + 3 + 9)
+                .build();
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        assertNotNull(impactEquipementVirtuel);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(86.44183578947367d, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(36.8421052631579d, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) * equipementVirtuel.vCPU(7) / nbvCPU(19)\",\"nbEquipementsVirtuels\":3,\"nbTotalVCPU\":19}", impactEquipementVirtuel.getTrace());
+    }
+
+
+    /**
+     * CAF3
+     * Nombre total de vCPU renseigné non renseigné et Nombre de VM > 1
+     * calculIndicateurImpactEquipementPhysique * 1 / NbVM
+     * Impact d’utilisation « VM3 »=234,62784 x 1/3=78.209279999 kgCO2eq
+     */
+    @Test
+    void whenTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(100.0d)
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(null)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(78.20927999999999, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(33.333333333333336, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel.getTrace());
+
+    }
+
+    /**
+     * Taiga 457
+     * Type d'équipement virtuel n'est pas "calcul" ET Nombre total de vCPU renseigné et Nombre de VM > 1
+     * calculIndicateurImpactEquipementPhysique * 1 / NbVM
+     * Impact d’utilisation « VM3 »=234,62784 x 1/3=78.209279999 kgCO2eq
+     */
+    @Test
+    void whenTypeEqvIsNotCalculAndTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .typeEqv("notCalcul")
+                .vCPU(7)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(100.0d)
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(7 + 3 + 9)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(78.20927999999999, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(33.333333333333336, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) / nbVM(3)\",\"nbEquipementsVirtuels\":3,\"nbTotalVCPU\":19}", impactEquipementVirtuel.getTrace());
+    }
+
+    /**
+     * CAF4
+     * Le nombre de VM est null et le nombre total de vCPU est null : le calcul est impossible et fini par une erreur Fonctionnelle.
+     * Impact d'utilisation « VM4 »= ErrCalcFonc("certaines données sur l'équipement virtuel sont manquantes ou incorrectes")
+     */
+    @Test
+    void whenTotalVCPUAndNbrVirtualEquipementAreNull_shouldReturnImpactError() {
+        EquipementVirtuel equipementVirtuel = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel.getNomEquipementPhysique())
+                .build();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementVirtuel(equipementVirtuel)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(null)
+                .nbTotalVCPU(null)
+                .build();
+
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
+        assertNull(impactEquipementVirtuel.getImpactUnitaire());
+        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
+        assertTrue(impactEquipementVirtuel.getTrace().contains("Certaines données sur l'équipement virtuel sont manquantes ou incorrectes"));
+    }
+
+    @Test
+    void whenNbrVirtualEquipementIs0_shouldReturnImpactError() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(100.0d)
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(0)
+                .nbTotalVCPU(null)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
+        assertNull(impactEquipementVirtuel.getImpactUnitaire());
+        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
+        assertTrue(impactEquipementVirtuel.getTrace().contains("Certaines données sur l'équipement virtuel sont manquantes ou incorrectes"));
+    }
+
+    /**
+     * Cas arrivé avec la V2.
+     * Si l'impact unitaire de l'équipement physique est à un statut différent de OK, alors l'impact résultant est en erreur.
+     */
+    @Test
+    void whenBaseImpactIsInError_shouldReturnImpactError() {
+
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .vCPU(7)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(null)
+                .unite("kgCO2eq")
+                .consoElecMoyenne(null)
+                .statutIndicateur("ERREUR")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(7 + 3 + 9)
+                .build();
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        assertNotNull(impactEquipementVirtuel);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertNull(impactEquipementVirtuel.getImpactUnitaire());
+        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
+        assertTrue(impactEquipementVirtuel.getTrace().contains("L'indicateur d'impact équipement associé est au statut : ERREUR"));
+    }
+
+    /**
+     * Cas arrivé avec la V2.
+     * Si l'impact unitaire de l'équipement physique est null, alors l'impact résultant est en erreur.
+     */
+    @Test
+    void whenBaseImpactWithNullValues_shouldReturnImpactError() {
+
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .vCPU(7)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(null)
+                .unite("kgCO2eq")
+                .consoElecMoyenne(null)
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(7 + 3 + 9)
+                .build();
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        assertNotNull(impactEquipementVirtuel);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertNull(impactEquipementVirtuel.getImpactUnitaire());
+        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("ERREUR", impactEquipementVirtuel.getStatutIndicateur());
+        assertTrue(impactEquipementVirtuel.getTrace().contains("L'impact unitaire de l'équipement physique parent est null"));
+    }
+
+
+    /**
+     * CAF5
+     * Si ConsoElecMoyenne est null et impact unitaire OK, calcul impact OK
+     */
+    @Test
+    void caf5() {
+
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .vCPU(7)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(2)
+                .nbTotalVCPU(null)
+                .build();
+
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(117.31392d, impactEquipementVirtuel.getImpactUnitaire());
+        assertNull(impactEquipementVirtuel.getConsoElecMoyenne());
+    }
+
+    @Test
+    void shouldGetTraceCalculVm() throws Exception {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("Vm1")
+                .vCPU(7)
+                .typeEqv("calcul")
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .impactUnitaire(234.62784d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(7+3+9)
+                .build();
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        var formule = TraceCalculImpactVirtuelUtils.getFormuleWithTotalVCPU(demandeCalcul);
+        var expected = objectMapper.writeValueAsString(TraceCalculImpactEquipementVirtuel.builder()
+                .nbTotalVCPU(demandeCalcul.getNbTotalVCPU())
+                .nbEquipementsVirtuels(demandeCalcul.getNbEquipementsVirtuels())
+                .formule(formule)
+                .build());
+
+        assertEquals(expected, impactEquipementVirtuel.getTrace());
+    }
+
+    /*
+    Taiga 437
+     */
+    @Test
+    void forTaiga437VM1_shouldReturnCalculImpactUsingProrataFormula() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("VM1")
+                .typeEqv("calcul")
+                .vCPU(8)
+                .capaciteStockage(5.0)
+                .cleRepartition(0.2)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(2840.d)
+                .impactUnitaire(2840.d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(10)
+                .nbTotalVCPU(null)
+                .stockageTotalVirtuel(null)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(568.0, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(568.0, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.cleRepartition(0.2)\"}", impactEquipementVirtuel.getTrace());
+    }
+
+    @Test
+    void forTaiga437VM2_shouldReturnCalculImpactUsingProrataOnCPUFormula() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("VM2")
+                .typeEqv("calcul")
+                .vCPU(8)
+                .capaciteStockage(null)
+                .cleRepartition(null)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(2840.d)
+                .impactUnitaire(2840.d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(10)
+                .nbTotalVCPU(16)
+                .stockageTotalVirtuel(null)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(1420.0, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(1420.0, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.vCPU(8) / nbvCPU(16)\",\"nbEquipementsVirtuels\":10,\"nbTotalVCPU\":16}", impactEquipementVirtuel.getTrace());
+    }
+
+    /*
+    Calcul au prorata du nombre d'équipement
+     */
+    @Test
+    void forTaiga437VM4_shouldReturnCalculImpactUsingProrataFormula() {
+        //GIVEN
+        EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("VM4")
+                .typeEqv("calcul")
+                .vCPU(null)
+                .capaciteStockage(5.0)
+                .cleRepartition(null)
+                .build();
+        EquipementVirtuel equipementVirtuel2 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("VM5")
+                .typeEqv("calcul")
+                .vCPU(null)
+                .capaciteStockage(10.0)
+                .cleRepartition(null)
+                .build();
+        EquipementVirtuel equipementVirtuel3 = EquipementVirtuel.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("equipement1")
+                .nomEquipementVirtuel("VM5")
+                .typeEqv("calcul")
+                .vCPU(null)
+                .capaciteStockage(30.0)
+                .cleRepartition(null)
+                .build();
+        ImpactEquipementPhysique impactEquipementPhysique = ImpactEquipementPhysique.builder()
+                .etapeACV("UTILISATION")
+                .critere("Changement climatique")
+                .typeEquipement("Serveur")
+                .consoElecMoyenne(2840.d)
+                .impactUnitaire(2840.d)
+                .unite("kgCO2eq")
+                .statutIndicateur("OK")
+                .nomEquipement(equipementVirtuel1.getNomEquipementPhysique())
+                .build();
+        LocalDateTime dateCalcul = LocalDateTime.now();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel1)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(null)
+                .stockageTotalVirtuel(null)
+                .build();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul2 = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel2)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(null)
+                .stockageTotalVirtuel(null)
+                .build();
+
+        DemandeCalculImpactEquipementVirtuel demandeCalcul3 = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(dateCalcul)
+                .equipementVirtuel(equipementVirtuel3)
+                .impactEquipement(impactEquipementPhysique)
+                .nbEquipementsVirtuels(3)
+                .nbTotalVCPU(null)
+                .stockageTotalVirtuel(null)
+                .build();
+
+        //WHEN
+        var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul);
+        var impactEquipementVirtuel2 = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul2);
+        var impactEquipementVirtuel3 = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul3);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactEquipementVirtuel);
+        assertContentIndicateur(demandeCalcul2, impactEquipementVirtuel2);
+        assertContentIndicateur(demandeCalcul3, impactEquipementVirtuel3);
+        assertEquals("OK", impactEquipementVirtuel.getStatutIndicateur());
+        assertEquals(946.6666666666666, impactEquipementVirtuel.getImpactUnitaire());
+        assertEquals(946.6666666666666, impactEquipementVirtuel.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel.getTrace());
+        assertEquals("OK", impactEquipementVirtuel2.getStatutIndicateur());
+        assertEquals(946.6666666666666, impactEquipementVirtuel2.getImpactUnitaire());
+        assertEquals(946.6666666666666, impactEquipementVirtuel2.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel2.getTrace());
+        assertEquals("OK", impactEquipementVirtuel3.getStatutIndicateur());
+        assertEquals(946.6666666666666, impactEquipementVirtuel3.getImpactUnitaire());
+        assertEquals(946.6666666666666, impactEquipementVirtuel3.getConsoElecMoyenne());
+        assertEquals("{\"formule\":\"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)\",\"nbEquipementsVirtuels\":3}", impactEquipementVirtuel3.getTrace());
+    }
+
+
+    private void assertContentIndicateur(DemandeCalculImpactEquipementVirtuel source, ImpactEquipementVirtuel result) {
+        assertNotNull(result);
+        assertEquals(source.getEquipementVirtuel().getNomEquipementPhysique(), result.getNomEquipement());
+        assertEquals(source.getEquipementVirtuel().getNomEquipementVirtuel(), result.getNomEquipementVirtuel());
+
+        assertEquals(source.getEquipementVirtuel().getNomLot(), result.getNomLot());
+        assertEquals(source.getEquipementVirtuel().getDateLot(), result.getDateLot());
+        assertEquals(source.getEquipementVirtuel().getNomOrganisation(), result.getNomOrganisation());
+        assertEquals(source.getEquipementVirtuel().getNomEntite(), result.getNomEntite());
+        assertEquals(source.getEquipementVirtuel().getNomSourceDonnee(), result.getNomSourceDonnee());
+
+        assertEquals(source.getDateCalcul(), result.getDateCalcul());
+
+        assertEquals(source.getImpactEquipement().getCritere(), result.getCritere());
+        assertEquals(source.getImpactEquipement().getEtapeACV(), result.getEtapeACV());
+        assertEquals(source.getImpactEquipement().getUnite(), result.getUnite());
+
+        assertEquals("1.1", result.getVersionCalcul());
+    }
+}
\ No newline at end of file
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..55c55784afca89f3a94aa202ddbcf5bf6dfeb0fc
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java
@@ -0,0 +1,154 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.entree.Messagerie;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielCritere;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactMessagerie;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactMessagerieService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactMessagerieServiceImpl;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CalculImpactMessagerieServiceTest {
+
+    ObjectMapper objectMapper = new ObjectMapper();
+    CalculImpactMessagerieService calculImpactMessagerieService = new CalculImpactMessagerieServiceImpl(objectMapper);
+    @Test
+    void whenValidMessagerie_shoudCalculerImpactMessagerie(){
+        //GIVEN
+        var dateCalcul = LocalDateTime.now();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        var referentielImpactMessagerie = ReferentielImpactMessagerie.builder()
+                .critere(critere.getNomCritere())
+                .source("Source RFT")
+                .constanteOrdonneeOrigine(20d)
+                .constanteCoefficientDirecteur(30d)
+                .build();
+        var messagerie = Messagerie.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .moisAnnee(202211)
+                .nombreMailEmis(300d)
+                .nombreMailEmisXDestinataires(900d)
+                .volumeTotalMailEmis(5000d)
+                .build();
+        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
+                .dateCalcul(dateCalcul)
+                .critere(critere)
+                .impactsMessagerie(Collections.singletonList(referentielImpactMessagerie))
+                .messagerie(messagerie)
+                .build();
+
+
+        //WHEN
+        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);
+
+        //THEN
+        assertContentIndicateur(demandeCalcul, impactMessagerie);
+        assertEquals(468000d , impactMessagerie.getImpactMensuel());
+        assertEquals("OK", impactMessagerie.getStatutIndicateur());
+        assertEquals("{\"critere\":\"Changement Climatique\",\"volumeTotalMailEmis\":5000.0,\"nombreMailEmis\":300.0,\"constanteCoefficientDirecteur\":30.0,\"poidsMoyenMail\":16.666666666666668,\"constanteOrdonneeOrigine\":20.0,\"nombreMailEmisXDestinataires\":900.0,\"formule\":\"poidsMoyenMail(16.666666666666668) = volumeTotalMailEmis(5000.0)/nombreMailEmis(300.0);\\nimpactMensuel = (constanteCoefficientDirecteur (30.0) * poidsMoyenMail(16.666666666666668) + constanteOrdonneeOrigine(20.0)) * nombreMailEmisXDestinataires(900.0)\\n\"}", impactMessagerie.getTrace());
+    }
+
+    @Test
+    void whenNonValidMessagerie_shouldReturnEmptyResult(){
+
+
+        var dateCalcul = LocalDateTime.now();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        var referentielImpactMessagerie = ReferentielImpactMessagerie.builder()
+                .critere(critere.getNomCritere())
+                .source("Source RFT")
+                .constanteOrdonneeOrigine(20d)
+                .constanteCoefficientDirecteur(30d)
+                .build();
+        var messagerie = Messagerie.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .moisAnnee(202211)
+                .nombreMailEmis(0d)
+                .nombreMailEmisXDestinataires(0d)
+                .volumeTotalMailEmis(0d)
+                .build();
+        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
+                .dateCalcul(dateCalcul)
+                .critere(critere)
+                .impactsMessagerie(Collections.singletonList(referentielImpactMessagerie))
+                .messagerie(messagerie)
+                .build();
+
+        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);
+
+        assertContentIndicateur(demandeCalcul, impactMessagerie);
+        assertNull(impactMessagerie.getImpactMensuel());
+        assertEquals("ERREUR", impactMessagerie.getStatutIndicateur());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : Calcul d'impact messagerie : Critère : Changement Climatique, Mois Années : 202211, nombreMailEmis 0.0=< 0.0\"}", impactMessagerie.getTrace());
+    }
+
+    @Test
+    void whenReferentielIsNotFound_shouldReturnEmptyResult(){
+
+
+        var dateCalcul = LocalDateTime.now();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        var messagerie = Messagerie.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .moisAnnee(202211)
+                .nombreMailEmis(0d)
+                .nombreMailEmisXDestinataires(0d)
+                .volumeTotalMailEmis(0d)
+                .build();
+        var demandeCalcul = DemandeCalculImpactMessagerie.builder()
+                .dateCalcul(dateCalcul)
+                .critere(critere)
+                .impactsMessagerie(Collections.emptyList())
+                .messagerie(messagerie)
+                .build();
+
+        var impactMessagerie = calculImpactMessagerieService.calculerImpactMessagerie(demandeCalcul);
+
+        assertContentIndicateur(demandeCalcul, impactMessagerie);
+        assertNull(impactMessagerie.getImpactMensuel());
+        assertEquals("ERREUR", impactMessagerie.getStatutIndicateur());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : Référentiel ImpactMessagerie indisponible pour le critère Changement Climatique\"}", impactMessagerie.getTrace());
+    }
+
+    private static void assertContentIndicateur(DemandeCalculImpactMessagerie demandeCalcul, ImpactMessagerie impactMessagerie) {
+        assertNotNull(impactMessagerie);
+        assertEquals("1.0", impactMessagerie.getVersionCalcul());
+        assertEquals(demandeCalcul.getDateCalcul(), impactMessagerie.getDateCalcul());
+        assertEquals(demandeCalcul.getCritere().getNomCritere(), impactMessagerie.getCritere());
+        assertEquals(demandeCalcul.getCritere().getUnite(), impactMessagerie.getUnite());
+        assertEquals(demandeCalcul.getMessagerie().getMoisAnnee(), impactMessagerie.getMoisAnnee());
+        assertEquals(demandeCalcul.getMessagerie().getNombreMailEmis(), impactMessagerie.getNombreMailEmis());
+        assertEquals(demandeCalcul.getMessagerie().getVolumeTotalMailEmis(), impactMessagerie.getVolumeTotalMailEmis());
+        assertEquals(demandeCalcul.getMessagerie().getNomLot(), impactMessagerie.getNomLot());
+        assertEquals(demandeCalcul.getMessagerie().getDateLot(), impactMessagerie.getDateLot());
+        assertEquals(demandeCalcul.getMessagerie().getNomEntite(), impactMessagerie.getNomEntite());
+        assertEquals(demandeCalcul.getMessagerie().getNomOrganisation(), impactMessagerie.getNomOrganisation());
+        assertEquals(demandeCalcul.getMessagerie().getNomSourceDonnee(), impactMessagerie.getNomSourceDonnee());
+    }
+}
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b20da91b6a9a25f4002b55a72f0a85b3e4a8a339
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java
@@ -0,0 +1,220 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockitoAnnotations;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielCritere;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielEtapeACV;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielImpactReseau;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactReseauService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactReseauServiceImpl;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CalculImpactReseauServiceTest {
+
+    private final String REF_RESEAU = "impactReseauMobileMoyen";
+
+    private CalculImpactReseauService calculImpactService;
+
+    ObjectMapper objectMapper = new ObjectMapper();
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        calculImpactService = new CalculImpactReseauServiceImpl(objectMapper);
+    }
+
+    @Test
+    void shouldReturnCorrectCalculImpact_whenValidInputs() {
+        // Given
+        LocalDateTime dateCalcul = LocalDateTime.now();
+        ReferentielEtapeACV etapeACV = ReferentielEtapeACV.builder()
+                .code("UTILISATION")
+                .build();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("Equipement 1")
+                .goTelecharge(3.5f)
+                .build();
+        ReferentielImpactReseau referentielImpactReseau = ReferentielImpactReseau.builder()
+                .etapeACV(etapeACV.getCode())
+                .critere(critere.getNomCritere())
+                .refReseau(REF_RESEAU)
+                .impactReseauMobileMoyen(4d)
+                .build();
+        var demandeCalcul = DemandeCalculImpactReseau.builder()
+                .dateCalcul(dateCalcul)
+                .equipementPhysique(equipementPhysique)
+                .etape(etapeACV)
+                .critere(critere)
+                .impactsReseau(Collections.singletonList(referentielImpactReseau))
+                .build();
+        Double expected = 4d * 3.5f;
+
+        //When
+        var impactReseau = assertDoesNotThrow(() -> calculImpactService.calculerImpactReseau(demandeCalcul));
+
+        //Then
+        assertNotNull(impactReseau.getImpactUnitaire());
+        assertEquals(expected, impactReseau.getImpactUnitaire());
+        assertContentIndicateur(demandeCalcul, impactReseau);
+        assertEquals("OK", impactReseau.getStatutIndicateur());
+        assertEquals(
+                "{\"critere\":\"Changement Climatique\",\"etapeACV\":\"UTILISATION\",\"equipementPhysique\":\"Equipement 1\",\"impactReseauMobileMoyen\":\"4.0\",\"goTelecharge\":\"3.5\",\"formule\":\"impactReseau = 'equipementPhysique.goTelecharge (3.5) x ref_ImpactReseau(Changement Climatique, UTILISATION, impactReseauMobileMoyen).valeur(4.0)'\"}",
+                impactReseau.getTrace()
+        );
+    }
+
+    @Test
+    void shouldReturnError_whenInvalidInputs() {
+        //Given
+        ReferentielEtapeACV etapeACV = ReferentielEtapeACV.builder()
+                .code("UTILISATION")
+                .build();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("Equipement 1")
+                .goTelecharge(null)
+                .build();
+        var demandeCalcul = DemandeCalculImpactReseau.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(equipementPhysique)
+                .etape(etapeACV)
+                .critere(critere)
+                .impactsReseau(Collections.emptyList())
+                .build();
+
+        //When
+        var impactReseau = calculImpactService.calculerImpactReseau(demandeCalcul);
+
+        //Then
+        assertContentIndicateur(demandeCalcul, impactReseau);
+        assertEquals("ERREUR", impactReseau.getStatutIndicateur());
+        assertNull(impactReseau.getImpactUnitaire());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : Erreur de calcul impact réseau: Etape: UTILISATION, Critere: Changement Climatique, Equipement Physique: Equipement 1 : la valeur en_EqP(Equipement).goTelecharge est nulle\"}", impactReseau.getTrace());
+    }
+
+    @Test
+    void shouldReturnError_whenInvalidReference() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("Equipement 1")
+                .goTelecharge(4.0f)
+                .build();
+        ReferentielEtapeACV etapeACV = ReferentielEtapeACV.builder()
+                .code("UTILISATION")
+                .build();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        ReferentielImpactReseau referentielImpactReseau = ReferentielImpactReseau.builder()
+                .etapeACV(etapeACV.getCode())
+                .critere(critere.getNomCritere())
+                .refReseau(REF_RESEAU)
+                .build();
+        var demandeCalcul = DemandeCalculImpactReseau.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(equipementPhysique)
+                .etape(etapeACV)
+                .critere(critere)
+                .impactsReseau(Collections.singletonList(referentielImpactReseau))
+                .build();
+
+        //When
+        var impactReseau = calculImpactService.calculerImpactReseau(demandeCalcul);
+
+        //Then
+        assertContentIndicateur(demandeCalcul, impactReseau);
+        assertEquals("ERREUR", impactReseau.getStatutIndicateur());
+        assertNull(impactReseau.getImpactUnitaire());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : Erreur de calcul impact réseau: Etape: UTILISATION, Critere: Changement Climatique, RefReseau: impactReseauMobileMoyen, Equipement Physique: Equipement 1 : L'impactReseauMobileMoyen de la référence est null.\"}", impactReseau.getTrace());
+    }
+
+    @Test
+    void shouldReturnError_whenReferenceNotFound() {
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .dateLot(LocalDate.of(2022,1,1))
+                .nomOrganisation("Test")
+                .nomLot("Test|20220101")
+                .nomSourceDonnee("Source_Test")
+                .nomEquipementPhysique("Equipement 1")
+                .goTelecharge(4.0f)
+                .dateLot(LocalDate.of(2023,1,1))
+                .build();
+        ReferentielEtapeACV etapeACV = ReferentielEtapeACV.builder()
+                .code("UTILISATION")
+                .build();
+        ReferentielCritere critere = ReferentielCritere.builder()
+                .nomCritere("Changement Climatique")
+                .unite("kg CO_{2} eq")
+                .build();
+        ReferentielImpactReseau referentielImpactReseau = ReferentielImpactReseau.builder()
+                .etapeACV(etapeACV.getCode())
+                .critere(critere.getNomCritere())
+                .refReseau(REF_RESEAU)
+                .build();
+        var demandeCalcul = DemandeCalculImpactReseau.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(equipementPhysique)
+                .etape(etapeACV)
+                .critere(critere)
+                .impactsReseau(Collections.singletonList(referentielImpactReseau))
+                .build();
+
+        //When
+        var impactReseau = calculImpactService.calculerImpactReseau(demandeCalcul);
+
+        //Then
+        assertContentIndicateur(demandeCalcul, impactReseau);
+        assertEquals("ERREUR", impactReseau.getStatutIndicateur());
+        assertNull(impactReseau.getImpactUnitaire());
+        assertEquals("{\"erreur\":\"ErrCalcFonc : Erreur de calcul impact réseau: Etape: UTILISATION, Critere: Changement Climatique, RefReseau: impactReseauMobileMoyen, Equipement Physique: Equipement 1 : L'impactReseauMobileMoyen de la référence est null.\"}", impactReseau.getTrace());
+    }
+
+    private static void assertContentIndicateur(DemandeCalculImpactReseau demandeCalcul, ImpactReseau impactReseau) {
+        assertEquals(demandeCalcul.getDateCalcul(), impactReseau.getDateCalcul());
+
+        assertEquals(demandeCalcul.getEtape().getCode(), impactReseau.getEtapeACV());
+        assertEquals(demandeCalcul.getCritere().getNomCritere(), impactReseau.getCritere());
+        assertEquals(demandeCalcul.getCritere().getNomCritere(), impactReseau.getCritere());
+
+        assertEquals(demandeCalcul.getEquipementPhysique().getNomLot(), impactReseau.getNomLot());
+        assertEquals(demandeCalcul.getEquipementPhysique().getDateLot(), impactReseau.getDateLot());
+        assertEquals(demandeCalcul.getEquipementPhysique().getNomEntite(), impactReseau.getNomEntite());
+        assertEquals(demandeCalcul.getEquipementPhysique().getNomOrganisation(), impactReseau.getNomOrganisation());
+        assertEquals(demandeCalcul.getEquipementPhysique().getNomEquipementPhysique(), impactReseau.getNomEquipement());
+        assertEquals(demandeCalcul.getEquipementPhysique().getNomSourceDonnee(), impactReseau.getNomSourceDonnee());
+
+        assertEquals("1.0", impactReseau.getVersionCalcul());
+    }
+
+}
\ No newline at end of file
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/DureeDeVieEquipementPhysiqueServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/DureeDeVieEquipementPhysiqueServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..044d18d58d88bde970c91d3a03baf860b2ba6ca7
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/DureeDeVieEquipementPhysiqueServiceTest.java
@@ -0,0 +1,228 @@
+package org.mte.numecoeval.calculs.domain.service;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielTypeEquipement;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.DureeDeVieEquipementPhysiqueServiceImpl;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@ExtendWith(MockitoExtension.class)
+class DureeDeVieEquipementPhysiqueServiceTest {
+
+    private final DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService = new DureeDeVieEquipementPhysiqueServiceImpl();
+
+    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/MM/yyyy");
+
+    @Test
+     void whenTypeEquipementDoesntHaveDureeDeVie_shouldUseHypotheseForDureeDeVie()throws Exception{
+
+        //Given
+        EquipementPhysique equipementPhysique = EquipementPhysique.builder()
+                .type("serveur")
+                .build();
+        ReferentielHypothese hypothese = ReferentielHypothese.builder()
+                .code("dureeVieParDefaut")
+                .valeur(1.17d)
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type("serveur")
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipementPhysique)
+                .hypotheses(Collections.singletonList(hypothese))
+                .typeEquipement(typeEquipement)
+                .build();
+
+        //When
+        var actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+
+        //Then
+        assertEquals(1.17d,actual.getValeur());
+    }
+
+
+    @Test
+     void shouldCalculerDureeVie1d_whenEquipementPhyisqueWithValidDates() throws Exception{
+        //Given
+        LocalDate dateAchat = LocalDate.parse("15/08/2020",formatter);
+        LocalDate dateRetrait = LocalDate.parse("15/06/2021",formatter);
+        var equipement = EquipementPhysique.builder()
+                .dateAchat(dateAchat)
+                .dateRetrait(dateRetrait)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(null)
+                .build();
+        //When
+        var actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+
+        //Then
+        assertEquals(1d,actual.getValeur());
+    }
+
+    @Test
+     void shouldCalculerDureeVie365_whenEquipementPhyisqueWithValidDates()throws Exception{
+        //Given
+        LocalDate dateAchat = LocalDate.parse("15/08/2020",formatter);
+        LocalDate dateRetrait = LocalDate.parse("15/10/2021",formatter);
+        var equipement = EquipementPhysique.builder()
+                .dateAchat(dateAchat)
+                .dateRetrait(dateRetrait)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(null)
+                .build();
+        //When
+        var actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+        var expected = 426d/365d;
+        //Then
+        assertEquals(expected,actual.getValeur());
+    }
+
+    @Test
+     void taiga864_whenEquipementPhysiqueDateRetraitIsNullShouldUseCurrentDayAsDateRetrait()throws Exception{
+        //Given
+        LocalDate dateAchat = LocalDate.now().minusDays(30);
+        var equipement = EquipementPhysique.builder()
+                .dateAchat(dateAchat)
+                .dateRetrait(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(null)
+                .build();
+        //When
+        var actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+        var expected = 30/365d;
+        //Then
+        assertEquals(expected,actual.getValeur());
+        assertEquals(dateAchat.format(DateTimeFormatter.ISO_DATE),actual.getDateAchat());
+        assertEquals(LocalDate.now().format(DateTimeFormatter.ISO_DATE),actual.getDateRetrait());
+    }
+
+    @Test
+     void shouldThrowException_whenInvalideDatesOrder()throws Exception{
+        //Given
+        LocalDate dateRetrait= LocalDate.parse("15/08/2020",formatter);
+        LocalDate dateAchat = LocalDate.parse("15/10/2021",formatter);
+        var equipement = EquipementPhysique.builder()
+                .dateAchat(dateAchat)
+                .dateRetrait(dateRetrait)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(null)
+                .build();
+        //When
+        CalculImpactException exception =
+                    //Then
+                assertThrows(CalculImpactException.class,
+                    ()-> dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul));
+
+        assertEquals(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), exception.getErrorType());
+        String expectedMessage = "La durée de vie de l'équipement n'a pas pu être déterminée";
+        String actualMessage = exception.getMessage();
+        assertTrue(actualMessage.contains(expectedMessage));
+    }
+
+    @Test
+     void shouldReturnDureeVieDefaut_whenMissingDate()throws Exception{
+        //Given
+        var equipement = EquipementPhysique.builder()
+                .type("laptop")
+                .build();
+        ReferentielHypothese hypothese = ReferentielHypothese.builder()
+                .code("dureeVieParDefaut")
+                .valeur(1.17d)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .hypotheses(Collections.singletonList(hypothese))
+                .typeEquipement(null)
+                .build();
+        //When
+        DureeDeVie actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+
+        //Then
+        assertEquals(1.17d,actual.getValeur());
+    }
+
+    @Test
+     void whenMissingDate_ShouldUseDureeDeVieTypeEquipementInPriority()throws Exception{
+        //Given
+        var equipement = EquipementPhysique.builder()
+                .type("laptop")
+                .build();
+        ReferentielHypothese hypothese = ReferentielHypothese.builder()
+                .code("dureeVieParDefaut")
+                .valeur(1.17d)
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type("laptop")
+                .dureeVieDefaut(3.5d)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(typeEquipement)
+                .hypotheses(Collections.singletonList(hypothese))
+                .build();
+        //When
+        DureeDeVie actual = dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul);
+
+        //Then
+        assertEquals(3.5d,actual.getValeur());
+    }
+
+    @Test
+     void whenMissingDureeForTypeAndHypothese_ShouldThrowException()throws Exception{
+        //Given
+        var equipement = EquipementPhysique.builder()
+                .type("laptop")
+                .build();
+        ReferentielHypothese hypothese = ReferentielHypothese.builder()
+                .code("dureeVieParDefaut")
+                .valeur(null)
+                .build();
+        ReferentielTypeEquipement typeEquipement = ReferentielTypeEquipement.builder()
+                .type("laptop")
+                .dureeVieDefaut(null)
+                .build();
+        DemandeCalculImpactEquipementPhysique demandeCalcul = DemandeCalculImpactEquipementPhysique
+                .builder()
+                .equipementPhysique(equipement)
+                .typeEquipement(typeEquipement)
+                .hypotheses(Collections.singletonList(hypothese))
+                .build();
+        //When
+        CalculImpactException exception = assertThrows(CalculImpactException.class, () -> dureeDeVieEquipementPhysiqueService.calculerDureeVie(demandeCalcul));
+
+        //Then
+        assertNotNull(exception, "Une exception doit être levée");
+        assertEquals(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), exception.getErrorType());
+        assertEquals("La durée de vie par défaut de l'équipement n'a pas pu être déterminée", exception.getMessage());
+    }
+
+}
\ No newline at end of file
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb172819f5c5d2bd15810f9bbde0b8583df10607
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java
@@ -0,0 +1,51 @@
+package org.mte.numecoeval.calculs.steps;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.cucumber.datatable.DataTable;
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Soit;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactEquipementVirtuelService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactEquipementVirtuelServiceImpl;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class CalculImpactEquipementVirtuelStepDefinitions {
+
+    DemandeCalculImpactEquipementVirtuel demandeCalculCourante;
+    
+    @Soit("Une demande de calcul pour un équipement virtuel tel que")
+    public void initDemandeCalculEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demande) {
+        demandeCalculCourante = demande;
+    }
+
+    @Alors("l'impact d'équipement virtuel résultant est tel que")
+    public void checkImpactEquipementVirtuel(DataTable dataTable) {
+        CalculImpactEquipementVirtuelService service = new CalculImpactEquipementVirtuelServiceImpl(new ObjectMapper());
+        var result = assertDoesNotThrow(() -> service.calculerImpactEquipementVirtuel(demandeCalculCourante));
+
+        assertNotNull(result);
+        Map<String, String> entry = dataTable.entries().get(0);
+        assertNotNull(entry);
+
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getVersionCalcul(), entry, "versionCalcul");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomLot(), entry, "nomLot");
+        DataTableTypeDefinitions.assertDateIfAvailable(result.getDateLot(), entry, "dateLot");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomOrganisation(), entry, "nomOrganisation");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomEntite(), entry, "nomEntite");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getCritere(), entry, "critere");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getEtapeACV(), entry, "etapeACV");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getStatutIndicateur(), entry, "statutIndicateur");
+        DataTableTypeDefinitions.assertDoubleIfAvailable(result.getImpactUnitaire(), entry, "impactUnitaire");
+        DataTableTypeDefinitions.assertDoubleIfAvailable(result.getConsoElecMoyenne(), entry, "consoElecMoyenne");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomSourceDonnee(), entry, "nomSourceDonnee");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getUnite(), entry, "unite");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomEquipementVirtuel(), entry, "nomEquipementVirtuel");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getNomEquipement(), entry, "nomEquipement");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getCluster(), entry, "cluster");
+        DataTableTypeDefinitions.assertStringIfAvailable(result.getTrace(), entry, "trace");
+    }
+}
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DataTableTypeDefinitions.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DataTableTypeDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf75dd9badb31f3241a4b3c62ada24a128a47cbf
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DataTableTypeDefinitions.java
@@ -0,0 +1,152 @@
+package org.mte.numecoeval.calculs.steps;
+
+import io.cucumber.java.DataTableType;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.mte.numecoeval.calculs.CucumberIntegrationTest;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel;
+import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese;
+import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielTypeEquipement;
+
+import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mte.numecoeval.calculs.CucumberIntegrationTest.NUMBER_FRENCH_FORMAT;
+
+@Slf4j
+public class DataTableTypeDefinitions {
+
+    public static void assertDateIfAvailable(LocalDate valueToTest, Map<String, String> entry, String key) {
+        assertEquals(getDateOrNull(entry, key), valueToTest);
+    }
+    public static void assertDoubleIfAvailable(Double valueToTest, Map<String, String> entry, String key) {
+        assertEquals(getDoubleOrNull(entry, key), valueToTest);
+    }
+    public static void assertIntegerIfAvailable(Integer valueToTest, Map<String, String> entry, String key) {
+        assertEquals(getIntegerOrNull(entry, key), valueToTest);
+    }
+    public static void assertStringIfAvailable(String valueToTest, Map<String, String> entry, String key) {
+        assertEquals(entry.getOrDefault(key, null), valueToTest);
+    }
+
+    private static LocalDate getDateOrNull(Map<String, String> entry, String key) {
+        if( StringUtils.isNotBlank(entry.get(key)) ) {
+            return LocalDate.parse(entry.get(key), CucumberIntegrationTest.FORMATTER_FRENCH_FORMAT);
+        }
+        return null;
+    }
+
+    private static Double getDoubleOrNull(Map<String, String> entry, String key) {
+        if( StringUtils.isNotBlank(entry.get(key)) ) {
+            try {
+                return NUMBER_FRENCH_FORMAT.parse(entry.get(key)).doubleValue();
+            }
+            catch (ParseException e) {
+                log.error("Erreur au parsing de la valeur {} : {}", entry.get(key), e.getMessage());
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private static Integer getIntegerOrNull(Map<String, String> entry, String key) {
+        if( StringUtils.isNotBlank(entry.get(key)) ) {
+            try {
+                return NUMBER_FRENCH_FORMAT.parse(entry.get(key)).intValue();
+            }
+            catch (ParseException e) {
+                log.error("Erreur au parsing de la valeur {} : {}", entry.get(key), e.getMessage());
+                return null;
+            }
+        }
+        return null;
+    }
+
+    @DataTableType
+    public DemandeCalculImpactEquipementPhysique demandeCalculImpactEquipementPhysique(Map<String, String> entry) {
+        var builder = DemandeCalculImpactEquipementPhysique.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(
+                        EquipementPhysique.builder()
+                                .nomEquipementPhysique(entry.getOrDefault("nomEquipementPhysique", null))
+                                .dateAchat(getDateOrNull(entry, "dateAchat"))
+                                .dateRetrait(getDateOrNull(entry, "dateRetrait"))
+                                .build()
+                );
+        var hypotheses = new ArrayList<ReferentielHypothese>();
+
+        if(StringUtils.isNotBlank(entry.get("refTypeEquipement.dureeVieDefaut"))) {
+            builder.typeEquipement(
+                    ReferentielTypeEquipement.builder()
+                            .dureeVieDefaut(getDoubleOrNull(entry, "refTypeEquipement.dureeVieDefaut"))
+                            .build()
+            );
+        }
+
+        if(StringUtils.isNotBlank(entry.get("hypothese.dureeVieParDefaut"))) {
+            hypotheses.add(
+                    ReferentielHypothese.builder()
+                            .code("dureeVieParDefaut")
+                            .valeur(getDoubleOrNull(entry, "hypothese.dureeVieParDefaut"))
+                            .build()
+            );
+        }
+
+        builder.hypotheses(hypotheses);
+
+        return builder.build();
+    }
+
+    @DataTableType
+    public DemandeCalculImpactEquipementVirtuel demandeCalculImpactEquipementVirtuel(Map<String, String> entry) {
+        var builder = DemandeCalculImpactEquipementVirtuel.builder()
+                .dateCalcul(LocalDateTime.now())
+                .nbEquipementsVirtuels(getIntegerOrNull(entry, "nbEquipementsVirtuels"))
+                .nbTotalVCPU(getIntegerOrNull(entry, "nbTotalVCPU"))
+                .stockageTotalVirtuel(getDoubleOrNull(entry, "stockageTotalVirtuel"))
+                .equipementVirtuel(
+                        EquipementVirtuel.builder()
+                                .nomLot(entry.getOrDefault("equipementVirtuel.nomLot", null))
+                                .dateLot(getDateOrNull(entry, "equipementVirtuel.dateLot"))
+                                .nomOrganisation(entry.getOrDefault("equipementVirtuel.nomOrganisation", null))
+                                .nomEntite(entry.getOrDefault("equipementVirtuel.nomEntite", null))
+                                .nomSourceDonnee(entry.getOrDefault("equipementVirtuel.nomSourceDonnee", null))
+                                .nomEquipementVirtuel(entry.getOrDefault("equipementVirtuel.nomEquipementVirtuel", null))
+                                .cluster(entry.getOrDefault("equipementVirtuel.cluster", null))
+                                .nomEquipementPhysique(entry.getOrDefault("equipementVirtuel.nomEquipementPhysique", null))
+                                .typeEqv(entry.getOrDefault("equipementVirtuel.typeEqv", null))
+                                .vCPU(getIntegerOrNull(entry, "equipementVirtuel.vCPU"))
+                                .consoElecAnnuelle(getDoubleOrNull(entry, "equipementVirtuel.consoElecAnnuelle"))
+                                .capaciteStockage(getDoubleOrNull(entry, "equipementVirtuel.capaciteStockage"))
+                                .cleRepartition(getDoubleOrNull(entry, "equipementVirtuel.cleRepartition"))
+                                .build()
+                );
+
+        var impactEquipement = ImpactEquipementPhysique.builder().build();
+        impactEquipement.setStatutIndicateur(entry.getOrDefault("impactEquipementPhysique.statutIndicateur", null));
+        impactEquipement.setEtapeACV(entry.getOrDefault("impactEquipementPhysique.etape", null));
+        impactEquipement.setCritere(entry.getOrDefault("impactEquipementPhysique.critere", null));
+        impactEquipement.setUnite(entry.getOrDefault("impactEquipementPhysique.unite", null));
+        impactEquipement.setNomLot(entry.getOrDefault("impactEquipementPhysique.nomLot", null));
+        impactEquipement.setNomOrganisation(entry.getOrDefault("impactEquipementPhysique.nomOrganisation", null));
+        impactEquipement.setDateLot(getDateOrNull(entry, "impactEquipementPhysique.dateLot"));
+        impactEquipement.setNomEntite(entry.getOrDefault("impactEquipementPhysique.nomEntite", null));
+        if(StringUtils.isNotBlank(entry.get("impactEquipementPhysique.impactUnitaire"))) {
+            impactEquipement.setImpactUnitaire(getDoubleOrNull(entry, "impactEquipementPhysique.impactUnitaire"));
+        }
+        if(StringUtils.isNotBlank(entry.get("impactEquipementPhysique.consoElecMoyenne"))) {
+            impactEquipement.setConsoElecMoyenne(getDoubleOrNull(entry, "impactEquipementPhysique.consoElecMoyenne"));
+        }
+        builder.impactEquipement(impactEquipement);
+
+        return builder.build();
+    }
+}
diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DureeDeVieStepDefinitions.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DureeDeVieStepDefinitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..abeee6a6a1e7d17f3515c1235449c8fc3e936929
--- /dev/null
+++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/DureeDeVieStepDefinitions.java
@@ -0,0 +1,86 @@
+package org.mte.numecoeval.calculs.steps;
+
+import io.cucumber.java.fr.Alors;
+import io.cucumber.java.fr.Soit;
+import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique;
+import org.mte.numecoeval.calculs.domain.data.trace.DureeDeVie;
+import org.mte.numecoeval.calculs.domain.exception.CalculImpactException;
+import org.mte.numecoeval.calculs.domain.port.input.service.DureeDeVieEquipementPhysiqueService;
+import org.mte.numecoeval.calculs.domain.port.input.service.impl.DureeDeVieEquipementPhysiqueServiceImpl;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mte.numecoeval.calculs.CucumberIntegrationTest.FORMATTER_FRENCH_FORMAT;
+
+public class DureeDeVieStepDefinitions {
+
+    DemandeCalculImpactEquipementPhysique demandeCalculCourante;
+
+    @Soit("Un équipement physique {string} avec la date d'achat {string} et la date de retrait {string}")
+    public void soitEquipementPhysiqueAvecDateAchatEtDateRetrait(String nomEquipementPhysique, String dateAchat, String dateRetrait) {
+        demandeCalculCourante = DemandeCalculImpactEquipementPhysique.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(
+                        EquipementPhysique.builder()
+                                .nomEquipementPhysique(nomEquipementPhysique)
+                                .dateAchat(LocalDate.parse(dateAchat, FORMATTER_FRENCH_FORMAT))
+                                .dateRetrait(LocalDate.parse(dateRetrait, FORMATTER_FRENCH_FORMAT))
+                                .build()
+                )
+                .build();
+    }
+
+    @Soit("Un équipement physique {string} avec la date d'achat {string}")
+    public void soitEquipementPhysiqueAvecDateAchat(String nomEquipementPhysique, String dateAchat) {
+        demandeCalculCourante = DemandeCalculImpactEquipementPhysique.builder()
+                .dateCalcul(LocalDateTime.now())
+                .equipementPhysique(
+                        EquipementPhysique.builder()
+                                .nomEquipementPhysique(nomEquipementPhysique)
+                                .dateAchat(LocalDate.parse(dateAchat, FORMATTER_FRENCH_FORMAT))
+                                .dateRetrait(null)
+                                .build()
+                )
+                .build();
+    }
+
+    @Alors("la durée de vie de l'équipement est {double}")
+    public void checkDureeDeVie(Double dureeDeVieAttendue) {
+
+        DureeDeVieEquipementPhysiqueService service = new DureeDeVieEquipementPhysiqueServiceImpl();
+        DureeDeVie result = assertDoesNotThrow(() -> service.calculerDureeVie(demandeCalculCourante));
+
+        assertNotNull(result);
+        assertEquals(dureeDeVieAttendue, result.getValeur());
+    }
+
+    @Alors("la durée de vie correspond à la différence entre la date d'achat et la date du jour")
+    public void checkDureeDeVieDateDuJour() {
+
+        DureeDeVieEquipementPhysiqueService service = new DureeDeVieEquipementPhysiqueServiceImpl();
+        DureeDeVie result = assertDoesNotThrow(() -> service.calculerDureeVie(demandeCalculCourante));
+
+        assertNotNull(result);
+        double differenceAvecDateDuJour = ChronoUnit.DAYS.between(demandeCalculCourante.getEquipementPhysique().getDateAchat(), LocalDate.now()) / 365d;
+        assertEquals(differenceAvecDateDuJour, result.getValeur());
+    }
+
+    @Soit("Une demande de calcule de durée de vie tel que")
+    public void initDemandeCalculDureeDeVie(DemandeCalculImpactEquipementPhysique demande) {
+        demandeCalculCourante = demande;
+    }
+
+    @Alors("le calcul de durée de vie lève une erreur de type {string} avec le message {string}")
+    public void checkErreurCalculDureeDeVie(String typeErreur, String messageErreur) {
+        DureeDeVieEquipementPhysiqueService service = new DureeDeVieEquipementPhysiqueServiceImpl();
+        CalculImpactException result = assertThrows(CalculImpactException.class, () -> service.calculerDureeVie(demandeCalculCourante));
+
+        assertNotNull(result);
+        assertEquals(typeErreur, result.getErrorType());
+        assertEquals(messageErreur, result.getMessage());
+    }
+}
diff --git a/services/calculs/src/test/resources/application-test.yaml b/services/calculs/src/test/resources/application-test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..13d59437dd8cc17d6d4451c52bfd6a6d03395177
--- /dev/null
+++ b/services/calculs/src/test/resources/application-test.yaml
@@ -0,0 +1,70 @@
+# Application
+numecoeval:
+  kafka:
+    topic:
+      name: "data"
+  referentiel:
+    endpoint:
+      typesEquipement: "/referentiel/typesEquipement"
+    server:
+      url: "http://localhost:19090"
+
+# Serveur Web
+server:
+  port: 18080
+  tomcat:
+    mbeanregistry:
+      enabled: true
+
+# Actuator
+management:
+  server:
+    port: 18080
+  security:
+    user:
+      name: "test"
+      password: "test"
+      roles: ACTUATOR_ADMIN
+  endpoints:
+    web:
+      exposure:
+        include: health,prometheus,httptrace,info,metrics,mappings
+
+#CONFIGURATION BASES
+spring:
+  sql:
+    init:
+      mode: never
+      platform: hsqldb
+  datasource:
+    url: jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1;sql.syntax_pgs=true
+    username: sa
+    password: sa
+    driverClassName: org.hsqldb.jdbc.JDBCDriver
+  jpa:
+    database-platform: org.hibernate.dialect.H2Dialect
+    hibernate:
+      ddl-auto: create-drop
+    show-sql: true
+  # Kafka
+  kafka:
+    client-id: api-exposition
+    bootstrap-servers: localhost:19093
+    producer:
+      key-serializer: org.apache.kafka.common.serialization.StringSerializer
+      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
+      properties:
+        spring:
+          json:
+            trusted:
+              packages: "org.mte.numecoeval.topic.*"
+    # Uniquement pour les tests
+    consumer:
+      group-id: api-exposition-test
+      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
+      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
+      properties:
+        spring:
+          json:
+            trusted:
+              packages: "*"
diff --git a/services/calculs/src/test/resources/logback-test.xml b/services/calculs/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9aee4ea0c1c352de369b0a644294522433e97755
--- /dev/null
+++ b/services/calculs/src/test/resources/logback-test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+<!--  Spring default.xml  -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
+    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
+    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
+
+    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-42.42logger{0}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-42.42logger{0} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <property name="FILE_LOG_CHARSET" value="${FILE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
+
+<!-- console-appender.xml-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${CONSOLE_LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+    </root>
+    <logger name="org.springframework.web" level="INFO"/>
+    <logger name="org.springframework.kafka" level="ERROR"/>
+    <logger name="org.apache.kafka" level="ERROR"/>
+    <logger name="kafka" level="ERROR"/>
+    <logger name="kafka.zookeeper" level="ERROR"/>
+</configuration>
\ No newline at end of file
diff --git a/services/calculs/src/test/resources/org/mte/numecoeval/calculs/CalculImpactUnitaire-EquipementVirtuel.feature b/services/calculs/src/test/resources/org/mte/numecoeval/calculs/CalculImpactUnitaire-EquipementVirtuel.feature
new file mode 100644
index 0000000000000000000000000000000000000000..dd7ef8de792ec318948ce777b695d0897d62dd90
--- /dev/null
+++ b/services/calculs/src/test/resources/org/mte/numecoeval/calculs/CalculImpactUnitaire-EquipementVirtuel.feature
@@ -0,0 +1,93 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: Calcul d'impact d'une machine virtuelle
+
+  Scénario: Calcul d'impact d'équipement Virtuel - Erreur car indicateur d'origine à null
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     | 19          |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAT0                        | Test                      | Gherkin                           | Test                    | Test                                    | calcul                    | 7                      |                                     |                                    |                                  | ERREUR                                    | 234,62784                               | 100                                       | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAT0                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                      |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAT0      | Changement climatique | UTILISATION | ERREUR           |                |                  | Gherkin         | kgCO2eq | Test  | Test          | Test    | {"erreur":"ErrCalcFonc : L'indicateur d'impact équipement associé est au statut : ERREUR"} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - Cas passant technique
+    # tableau complet avec tous les champs renseignés
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     | 19          |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAT1                        | Test                      | Gherkin                           | Test                    | Test                                    | calcul                    | 7                      |                                     |                                    |                                  | OK                                        | 234,62784                               | 100                                       | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAT1                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire     | consoElecMoyenne  | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                                              |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAT1      | Changement climatique | UTILISATION | OK               | 86,44183578947367d | 36,8421052631579d | Gherkin         | kgCO2eq | Test  | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) * equipementVirtuel.vCPU(7) / nbvCPU(19)","nbEquipementsVirtuels":3,"nbTotalVCPU":19} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - Cas passant technique - Alternatif sans consoElecMoyenne
+    # tableau complet avec tous les champs renseignés
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     | 19          |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAT1                        | Test                      | Gherkin                           | Test                    | Test                                    | calcul                    | 7                      |                                     |                                    |                                  | OK                                        | 234,62784                               |                                           | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAT1                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire     | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                                              |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAT1      | Changement climatique | UTILISATION | OK               | 86,44183578947367d |                  | Gherkin         | kgCO2eq | Test  | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(234.62784) * equipementVirtuel.vCPU(7) / nbvCPU(19)","nbEquipementsVirtuels":3,"nbTotalVCPU":19} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF1
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 10                    |             |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF1                        | Test                      | Gherkin                           | VM1                     | Test                                    | calcul                    | 8                      |                                     | 5,0                                | 0,2                              | OK                                        | 2840,00                                 | 2840,00                                   | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF1                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                               |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF1      | Changement climatique | UTILISATION | OK               | 568,0          | 568,0            | Gherkin         | kgCO2eq | VM1   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.cleRepartition(0.2)"} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF1 - Alternatif sans consoElecMoyenne
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 10                    |             |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF1                        | Test                      | Gherkin                           | VM1                     | Test                                    | calcul                    | 8                      |                                     | 5,0                                | 0,2                              | OK                                        | 2840,00                                 |                                           | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF1                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                               |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF1      | Changement climatique | UTILISATION | OK               | 568,0          |                  | Gherkin         | kgCO2eq | VM1   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.cleRepartition(0.2)"} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF2
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      |                       | 16          |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF2                        | Test                      | Gherkin                           | VM2                     | Test                                    | calcul                    | 8                      |                                     | 5,0                                |                                  | OK                                        | 2840,00                                 | 2840,00                                   | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF2                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                 |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF2      | Changement climatique | UTILISATION | OK               | 1420,0         | 1420,0           | Gherkin         | kgCO2eq | VM2   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.vCPU(8) / nbvCPU(16)","nbTotalVCPU":16} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF2 - Alternatif sans consoElecMoyenne
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      |                       | 16          |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF2                        | Test                      | Gherkin                           | VM2                     | Test                                    | calcul                    | 8                      |                                     | 5,0                                |                                  | OK                                        | 2840,00                                 |                                           | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF2                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                 |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF2      | Changement climatique | UTILISATION | OK               | 1420,0         |                  | Gherkin         | kgCO2eq | VM2   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) * equipementVirtuel.vCPU(8) / nbvCPU(16)","nbTotalVCPU":16} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF3
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     |             |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF3                        | Test                      | Gherkin                           | VM4                     | Test                                    | calcul                    |                        |                                     | 5,0                                |                                  | OK                                        | 2840,00                                 | 2840,00                                   | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF3                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire    | consoElecMoyenne  | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                           |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF3      | Changement climatique | UTILISATION | OK               | 946,6666666666666 | 946,6666666666666 | Gherkin         | kgCO2eq | VM4   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)","nbEquipementsVirtuels":3} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF3 - Alternatif sans consoElecMoyenne
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     |             |                      | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF3                        | Test                      | Gherkin                           | VM4                     | Test                                    | calcul                    |                        |                                     | 5,0                                |                                  | OK                                        | 2840,00                                 |                                           | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF3                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire    | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                           |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF3      | Changement climatique | UTILISATION | OK               | 946,6666666666666 |                  | Gherkin         | kgCO2eq | VM4   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(2840.0) / nbVM(3)","nbEquipementsVirtuels":3} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF5
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     |             | 100                  | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF5                        | Test                      | Gherkin                           | VM4                     | Test                                    | stockage                  |                        |                                     | 5,0                                |                                  | OK                                        | 100,00                                  | 100,00                                    | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF5                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                                                           |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF5      | Changement climatique | UTILISATION | OK               | 5,0            | 5,0              | Gherkin         | kgCO2eq | VM4   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(100.0) * equipementVirtuel.capaciteStockage(5.0) / stockageTotalVirtuel(100.0)","stockageTotalVirtuel":100.0} |
+
+  Scénario: Calcul d'impact d'équipement Virtuel - CAF5 - Alternatif sans consoElecMoyenne
+    Soit Une demande de calcul pour un équipement virtuel tel que
+      | nbEquipementsVirtuels | nbTotalVCPU | stockageTotalVirtuel | equipementVirtuel.nomLot | equipementVirtuel.dateLot | equipementVirtuel.nomOrganisation | equipementVirtuel.nomEntite | equipementVirtuel.cluster | equipementVirtuel.nomSourceDonnee | equipementVirtuel.nomEquipementVirtuel | equipementVirtuel.nomEquipementPhysique | equipementVirtuel.typeEqv | equipementVirtuel.vCPU | equipementVirtuel.consoElecAnnuelle | equipementVirtuel.capaciteStockage | equipementVirtuel.cleRepartition | impactEquipementPhysique.statutIndicateur | impactEquipementPhysique.impactUnitaire | impactEquipementPhysique.consoElecMoyenne | impactEquipementPhysique.etape | impactEquipementPhysique.critere | impactEquipementPhysique.unite | impactEquipementPhysique.nomLot | impactEquipementPhysique.dateLot | impactEquipementPhysique.nomOrganisation | impactEquipementPhysique.nomEntite |
+      | 3                     |             | 100                  | 01/01/2022-Tests         | 01/01/2022                | Tests                             | CAF5                        | Test                      | Gherkin                           | VM4                     | Test                                    | stockage                  |                        |                                     | 5,0                                |                                  | OK                                        | 100,00                                  |                                           | UTILISATION                    | Changement climatique            | kgCO2eq                        | Tests-01/01/2022                | 01/01/2022                       | Tests                                    | CAF5                               |
+    Alors l'impact d'équipement virtuel résultant est tel que
+      | versionCalcul | nomLot           | dateLot    | nomOrganisation | nomEntite | critere               | etapeACV    | statutIndicateur | impactUnitaire | consoElecMoyenne | nomSourceDonnee | unite   | nomEquipementVirtuel | nomEquipement | cluster | trace                                                                                                                                                                           |
+      | 1.1           | 01/01/2022-Tests | 01/01/2022 | Tests           | CAF5      | Changement climatique | UTILISATION | OK               | 5,0            |                  | Gherkin         | kgCO2eq | VM4   | Test          | Test    | {"formule":"valeurImpactUnitaire = valeurImpactEquipementPhysique(100.0) * equipementVirtuel.capaciteStockage(5.0) / stockageTotalVirtuel(100.0)","stockageTotalVirtuel":100.0} |
diff --git a/services/calculs/src/test/resources/org/mte/numecoeval/calculs/DureeDeVie-EquipementPhysique.feature b/services/calculs/src/test/resources/org/mte/numecoeval/calculs/DureeDeVie-EquipementPhysique.feature
new file mode 100644
index 0000000000000000000000000000000000000000..ef9b48d7c38a88fa51043c80064c56e70b29b796
--- /dev/null
+++ b/services/calculs/src/test/resources/org/mte/numecoeval/calculs/DureeDeVie-EquipementPhysique.feature
@@ -0,0 +1,47 @@
+#language: fr
+#encoding: utf-8
+Fonctionnalité: : Durée de Vie d'un équipement physique / Durée de vie des équipements par défaut
+  # JDDs - 1A à 1F
+  # Les noms d'équipement physique ont été simplifié
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait connues (période < 1 an)
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat  | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1A | 01/10/2022 | 01/03/2023  |                                  |                             |
+    Alors la durée de vie de l'équipement est 1
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait connues (période > 1 an)
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat  | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1B | 01/10/2021 | 01/03/2023  |                                  |                             |
+    Alors la durée de vie de l'équipement est 1,4136986301369863
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat connue mais Date retrait inconnue
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat  | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1C | 01/10/2022 |             |                                  |                             |
+    Alors la durée de vie correspond à la différence entre la date d'achat et la date du jour
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait inconnues - Equipement physique présent dans la table des références d'équipement
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1D |           |             | 6,7                              |                             |
+    Alors la durée de vie de l'équipement est 6,7
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait inconnues - Equipement physique non présent dans la table des références d'équipement - Durée de vie par défaut des équipements présent dans la table des hypothèses
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1E |           |             |                                  | 5,2                         |
+    Alors la durée de vie de l'équipement est 5,2
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait inconnues - Equipement physique non présent dans la table des références d'équipement - Durée de vie par défaut des équipements non présent dans la table des hypothèses
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1F |           |             |                                  |                             |
+    Alors le calcul de durée de vie lève une erreur de type "ErrCalcFonc" avec le message "La durée de vie par défaut de l'équipement n'a pas pu être déterminée"
+
+  Scénario: Calcul de la Durée de Vie avec Date d'achat et Date retrait mal renseignées (date de retrait avant date d'achat)
+    Soit Une demande de calcule de durée de vie tel que
+      | nomEquipementPhysique             | dateAchat  | dateRetrait | refTypeEquipement.dureeVieDefaut | hypothese.dureeVieParDefaut |
+      | 2023-04-OrdinateurPortable-test1F | 01/01/2023 | 01/02/2022  |                                  |                             |
+    Alors le calcul de durée de vie lève une erreur de type "ErrCalcFonc" avec le message "La durée de vie de l'équipement n'a pas pu être déterminée"
+
diff --git a/services/common/.gitignore b/services/common/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..20c8d182d7c273a6d0db62fbf6f998ffb1357150
--- /dev/null
+++ b/services/common/.gitignore
@@ -0,0 +1,32 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/common/.gitlab-ci-library.yml b/services/common/.gitlab-ci-library.yml
new file mode 100644
index 0000000000000000000000000000000000000000..333d3823909ad520f920c27976c1d29a58d341fc
--- /dev/null
+++ b/services/common/.gitlab-ci-library.yml
@@ -0,0 +1,47 @@
+include:
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/fragments/meta.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/fragments/meta-java.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/configuration/before-script-template.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/analysis/dependency-check.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/analysis/sonarqube.yml"
+
+stages:
+  - test-application
+  - build-application
+  - analysis
+
+cache:
+  paths:
+    - .m2/
+
+variables:
+  MAVEN_PROJECT_DIR: services/$COMPONENT
+  PROJECT_DIR: services/$COMPONENT
+  MAVEN_CLI_OPTS: "-s ci_settings.xml --batch-mode"
+  MAVEN_OPTS: "-Dmaven.repo.local=.m2"
+  DEPENDENCY_CHECK_SCAN_PATH: $CI_PROJECT_DIR/services/$COMPONENT
+  DEPENDENCY_CHECK_SUPPRESSION_PATH: $CI_PROJECT_DIR/services/$COMPONENT
+
+#Compilation et Tests pour les Merges requests et les commits
+test-application:
+  stage: test-application
+  extends:
+    - .tags-runner
+    - .java:test
+
+#Compilation+Déploiement dans le repository Gitlab
+build-application:
+  stage: build-application
+  extends:
+    - .tags-runner
+    - .java:build
diff --git a/services/common/.gitlab-ci-maven.yml b/services/common/.gitlab-ci-maven.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8a32043ea82b00b487775faeeb405233f45a6db2
--- /dev/null
+++ b/services/common/.gitlab-ci-maven.yml
@@ -0,0 +1,86 @@
+include:
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/fragments/meta.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/fragments/meta-java.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/configuration/before-script-template.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/build/build-image-kaniko.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/analysis/mte-image-scan.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/analysis/dependency-check.yml"
+  - project: "pub/numeco/m4g/ci-library"
+    ref: main
+    file: "/stages/analysis/sonarqube.yml"
+
+
+stages:
+  - test-application
+  - build-application
+  - build-image
+  - analysis
+
+variables:
+  MAVEN_PROJECT_DIR: services/$COMPONENT
+  PROJECT_DIR: services/$COMPONENT
+  MAVEN_CLI_OPTS: "-s $CI_PROJECT_DIR/services/common/ci_settings.xml --batch-mode"
+  MAVEN_OPTS: "-Dmaven.repo.local=.m2"
+  DEPENDENCY_CHECK_SCAN_PATH: $CI_PROJECT_DIR/services/$COMPONENT
+  DEPENDENCY_CHECK_SUPPRESSION_PATH: $CI_PROJECT_DIR/services/$COMPONENT
+  DOCKER_IMAGE: "$CI_REGISTRY_IMAGE/$COMPONENT:$CI_COMMIT_REF_NAME"
+
+#Compilation et Tests pour les Merges requests et les commits
+test-application:
+  stage: test-application
+  before_script:
+    - sed -i 's#${project.basedir}/../common#${project.basedir}/services/common#g' services/$COMPONENT/pom.xml
+  extends:
+    - .tags-runner
+    - .java:test
+
+#Compilation+Déploiement dans le repository Gitlab
+build-application:
+  stage: build-application
+  before_script: |
+    sed -i 's#${project.basedir}/../common#${project.basedir}/services/common#g' services/$COMPONENT/pom.xml
+    if [ "${COMPONENT}" = "api-referentiel" ];then
+      VERSION=$(cat services/$COMPONENT/pom.xml | grep "<version>" | head -n1 | sed "s# ##g" | sed "s#version##g" | sed "s#[<>/]##g")
+      echo "Version: $VERSION"
+      sed -i "s|version: .*|version: \"${VERSION}\"|" services/$COMPONENT/src/main/resources/application.yaml
+      cat services/$COMPONENT/src/main/resources/application.yaml
+    fi
+  extends:
+    - .tags-runner
+    - .java:build
+  only:
+    - main
+    - develop
+    - tags
+
+build-image:
+  stage: build-image
+  extends: .kaniko_build
+  before_script:
+    - cp -f services/common/Dockerfile .
+    - cp -f services/common/entrypoint.sh .
+    - cd target/
+    - rm -f *.original
+    - rm -f $(ls | grep .jar | grep -iv $COMPONENT)
+    - cd ../
+  variables:
+    DOCKER_USER: $CI_REGISTRY_USER
+    DOCKER_PASSWORD: $CI_REGISTRY_PASSWORD
+    REGISTRY_URL: $CI_REGISTRY
+    IMAGE_URL: $CI_REGISTRY_IMAGE/$COMPONENT
+  only:
+    - main
+    - develop
+    - tags
diff --git a/services/common/Dockerfile b/services/common/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..9ba5cf5d87a84da687f5ebd42624ee1420a3e190
--- /dev/null
+++ b/services/common/Dockerfile
@@ -0,0 +1,35 @@
+FROM openjdk:17-jdk-slim
+
+# Logs
+ENV LOGS_DIR=/app/logs
+
+RUN apt-get update ; apt-get upgrade --no-cache -f ; \
+    apt-get install -y openssl tzdata util-linux bash curl coreutils jq dos2unix
+
+# Utilisateur spring
+ENV GID_USER=1104
+ENV UID_USER=$GID_USER
+RUN adduser -q --group spring && adduser spring --ingroup spring --disabled-password --gecos ""  && \
+    mkdir /app && mkdir $LOGS_DIR && \
+    chown spring:spring -R /app && chown spring:spring -R $LOGS_DIR
+
+#Changement de la timezone
+ENV TZ Europe/Paris
+
+USER spring:spring
+
+#PORT Exposé par l'application
+ENV SERVER_PORT 8080
+ENV MANAGEMENT_SERVER_PORT $SERVER_PORT
+EXPOSE $SERVER_PORT
+
+# Copie de l'entrypoint
+COPY --chown=spring:spring entrypoint.sh /app/entrypoint.sh
+RUN chmod u+x /app/entrypoint.sh && dos2unix /app/entrypoint.sh
+
+# Copie du JAR
+ARG JAR_FILE=target/*.jar
+COPY --chown=spring:spring ${JAR_FILE} /app/app.jar
+WORKDIR /app
+
+ENTRYPOINT ["/app/entrypoint.sh"]
diff --git a/services/common/README.md b/services/common/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..16a1b3a4c28e172959922dc88c5002a9b926c217
--- /dev/null
+++ b/services/common/README.md
@@ -0,0 +1,3 @@
+# common
+
+Module Maven contenant les éléments communs aux applications
diff --git a/services/common/ci_settings.xml b/services/common/ci_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5205903f74a7c01cd6aa2a74c856a197ee99824e
--- /dev/null
+++ b/services/common/ci_settings.xml
@@ -0,0 +1,16 @@
+<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
+    <servers>
+        <server>
+            <id>gitlab-maven</id>
+            <configuration>
+                <httpHeaders>
+                    <property>
+                        <name>Job-Token</name>
+                        <value>${env.CI_JOB_TOKEN}</value>
+                    </property>
+                </httpHeaders>
+            </configuration>
+        </server>
+    </servers>
+</settings>
diff --git a/services/common/dependency_check_suppressions.xml b/services/common/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..790bf7a1a3b282690efe670d18df127d68d6f791
--- /dev/null
+++ b/services/common/dependency_check_suppressions.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : Snakeyaml n'est utilisé que par Spring Boot pour les fichiers application.yml
+    et non des fichiers externes.
+   ]]></notes>
+        <cve>CVE-2022-1471</cve>
+    </suppress>
+
+    <suppress>
+        <notes><![CDATA[
+   Non-applicable : json-smart est une dépendance transitive.
+   Les json sont limités à la taille des inventaires : la taille des listes n'a pas réellement de limite
+   et c'est souhaités comme cela (traitement de gros volumes de données).
+   ]]></notes>
+        <cve>CVE-2023-1370</cve>
+    </suppress>
+</suppressions>
diff --git a/services/common/entrypoint.sh b/services/common/entrypoint.sh
new file mode 100644
index 0000000000000000000000000000000000000000..bbdb9583747bbe45c70815700015a16085d2cb5a
--- /dev/null
+++ b/services/common/entrypoint.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+echo "Vérification de la présence du fichier d'environnement"
+if [ -d /run/secrets ]; then
+  echo "Chargement des fichiers d'environnement"
+  for secretFile in /run/secrets/*; do
+    if [ -f "$secretFile" ]; then
+      . $secretFile
+    fi
+  done
+fi
+
+echo "Lancement de l'application"
+exec java $NUMECOEVAL_JAVA_OPTIONS -jar /app/app.jar
diff --git a/services/common/pom.xml b/services/common/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..28812c5ff31f935c58e62dd91c42e3ad48e067c5
--- /dev/null
+++ b/services/common/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.mte.numecoeval</groupId>
+        <artifactId>core</artifactId>
+        <version>1.2.3-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <artifactId>common</artifactId>
+    <version>1.2.3-SNAPSHOT</version>
+    <name>common</name>
+    <description>Module commun</description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.validation</groupId>
+            <artifactId>jakarta.validation-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>2.2.8</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.openapitools</groupId>
+                <artifactId>openapi-generator-maven-plugin</artifactId>
+                <version>${openapi-generator-version}</version>
+                <executions>
+                    <execution>
+                        <id>generation_model_asyncapi</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>${project.basedir}/src/main/resources/static/asyncapi_merge.yaml
+                            </inputSpec>
+                            <output>${project.build.directory}/generated-sources</output>
+                            <modelPackage>org.mte.numecoeval.topic.data</modelPackage>
+                            <generateApis>false</generateApis>
+                            <generateModels>true</generateModels>
+                            <generateModelTests>false</generateModelTests>
+                            <generateApiTests>false</generateApiTests>
+                            <generateSupportingFiles>false</generateSupportingFiles>
+                            <generateModelDocumentation>false</generateModelDocumentation>
+                            <generateApiDocumentation>false</generateApiDocumentation>
+                            <generatorName>spring</generatorName>
+                            <library>spring-boot</library>
+                            <configOptions>
+                                <useJakartaEe>true</useJakartaEe>
+                                <useTags>true</useTags>
+                                <skipDefaultInterface>true</skipDefaultInterface>
+                                <dateLibrary>java8-localdatetime</dateLibrary>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <sourceFolder>src/gen/java</sourceFolder>
+                                <serializableModel>true</serializableModel>
+                                <interfaceOnly>true</interfaceOnly>
+                                <reactive>false</reactive>
+                                <useBeanValidation>false</useBeanValidation>
+                                <performBeanValidation>false</performBeanValidation>
+                                <useOptional>false</useOptional>
+                                <serviceInterface>false</serviceInterface>
+                                <serviceImplementation>false</serviceImplementation>
+                                <booleanGetterPrefix>is</booleanGetterPrefix>
+                                <additionalModelTypeAnnotations>
+                                    @lombok.AllArgsConstructor;@lombok.Builder;@lombok.NoArgsConstructor
+                                </additionalModelTypeAnnotations>
+                            </configOptions>
+                        </configuration>
+                    </execution>
+                </executions>
+
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/services/common/src/main/java/org/mte/numecoeval/common/exception/NumEcoEvalRuntimeException.java b/services/common/src/main/java/org/mte/numecoeval/common/exception/NumEcoEvalRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..b32f608ed517e4a7102bc896f2029d682af45fe7
--- /dev/null
+++ b/services/common/src/main/java/org/mte/numecoeval/common/exception/NumEcoEvalRuntimeException.java
@@ -0,0 +1,18 @@
+package org.mte.numecoeval.common.exception;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * RuntimeException spécifique à NumEcoEval.
+ */
+@Getter
+@AllArgsConstructor
+public class NumEcoEvalRuntimeException extends RuntimeException {
+
+    /**
+     * Description de l'erreur
+     */
+    private final String description;
+
+}
diff --git a/services/common/src/main/java/org/mte/numecoeval/common/utils/PreparedStatementUtils.java b/services/common/src/main/java/org/mte/numecoeval/common/utils/PreparedStatementUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..9545a1b1229d10a4a0dc4c9e5cd6fda9669e2b3d
--- /dev/null
+++ b/services/common/src/main/java/org/mte/numecoeval/common/utils/PreparedStatementUtils.java
@@ -0,0 +1,50 @@
+package org.mte.numecoeval.common.utils;
+
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+
+public class PreparedStatementUtils {
+
+    private PreparedStatementUtils() {
+        // Private constructor
+    }
+
+    public static void setDoubleValue(PreparedStatement ps, int index, Double value) throws SQLException {
+        if(Objects.isNull(value)) {
+            ps.setNull(index, Types.DOUBLE );
+        }
+        else {
+            ps.setDouble(index, value);
+        }
+    }
+
+    public static void setIntValue(PreparedStatement ps, int index, Integer value) throws SQLException {
+        if(Objects.isNull(value)) {
+            ps.setNull(index, Types.INTEGER );
+        }
+        else {
+            ps.setInt(index, value);
+        }
+    }
+
+    public static Timestamp getTimestampFromLocalDateTime(LocalDateTime localDateTime) {
+        if(Objects.isNull(localDateTime)) {
+            return null;
+        }
+        return Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTime));
+    }
+
+    public static Date getDateFromLocalDate(LocalDate localDate) {
+        if(Objects.isNull(localDate)) {
+            return null;
+        }
+        return Date.valueOf(DateTimeFormatter.ISO_LOCAL_DATE.format(localDate)) ;
+    }
+}
diff --git a/services/common/src/main/java/org/mte/numecoeval/common/utils/ResultSetUtils.java b/services/common/src/main/java/org/mte/numecoeval/common/utils/ResultSetUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..7298d64450113a02fe86f63fd7832f76ed13a7c8
--- /dev/null
+++ b/services/common/src/main/java/org/mte/numecoeval/common/utils/ResultSetUtils.java
@@ -0,0 +1,55 @@
+package org.mte.numecoeval.common.utils;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class ResultSetUtils {
+
+    private ResultSetUtils() {
+        // Nothing to do
+    }
+
+    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    public static LocalDate getLocalDate(ResultSet resultSet, String columnName) throws SQLException {
+        if (checkColumnInResultSet(resultSet, columnName)) return null;
+
+        return resultSet.getDate(columnName).toLocalDate();
+    }
+
+    public static LocalDateTime getLocalDateTime(ResultSet resultSet, String columnName) throws SQLException {
+        if (checkColumnInResultSet(resultSet, columnName)) return null;
+
+        return resultSet.getTimestamp(columnName).toLocalDateTime();
+    }
+
+    public static Integer getInteger(ResultSet resultSet, String columnName) throws SQLException {
+        if (checkColumnInResultSet(resultSet, columnName)) return null;
+
+        return resultSet.getInt(columnName);
+    }
+
+    public static Float getFloat(ResultSet resultSet, String columnName) throws SQLException {
+        if (checkColumnInResultSet(resultSet, columnName)) return null;
+
+        return resultSet.getFloat(columnName);
+    }
+
+    public static Double getDouble(ResultSet resultSet, String columnName) throws SQLException {
+        if (checkColumnInResultSet(resultSet, columnName)) return null;
+
+        return resultSet.getDouble(columnName);
+    }
+
+    private static boolean checkColumnInResultSet(ResultSet resultSet, String columnName) throws SQLException {
+        if (resultSet == null || "".equals(columnName)) {
+            return true;
+        }
+
+        var value = resultSet.getString(columnName);
+        return value == null || "".equals(value);
+    }
+}
diff --git a/services/common/src/main/resources/static/README.md b/services/common/src/main/resources/static/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0ee297a8fbcbefe11ef164d03bd472ff05f02ad8
--- /dev/null
+++ b/services/common/src/main/resources/static/README.md
@@ -0,0 +1,22 @@
+# Swagger OpenAPI
+
+Comment générer les fichiers openapi.
+
+Mode opératoire générique :
+
+- lancer le composant $COMPOSANT
+- aller sur http://localhost:$PORT/swagger-ui/index.html
+- Cliquer sur "/v3/api-docs/..."
+- copier le contenu dans https://editor.swagger.io/ et récupérer le yaml
+
+Fichiers openapi __générés__ par les composants:
+
+- api-referentiels-openapi.yaml, COMPOSANT : api-referentiels, PORT : 18080
+- api-expositiondonneesentrees-openapi.yaml, COMPOSANT : api-expositiondonneesentrees, PORT : 18081
+- api-event-calculs-openapi.yaml, COMPOSANT : api-event-calculs, PORT : 18092
+
+Fichiers pilotés __manuellement__ dans ce composant common:
+
+- asyncapi_*.yaml
+- api-event-calculs-async-openapi.yaml
+- api-event-calculs-sync-openapi.yaml
\ No newline at end of file
diff --git a/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml b/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2d849a925c872dd0f334a5e254848b81868a0379
--- /dev/null
+++ b/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml
@@ -0,0 +1,789 @@
+openapi: 3.0.1
+info:
+  title: NumEcoEval - API calculs
+  version: v1
+  license:
+    name: Apache 2.0
+  description: |
+    API permettant de réaliser des calculs unitaires d'impact écologiques. \
+tags:
+  - name: Calculs Equipement Physique
+    description: Endpoints liés aux calculs pour un équipement physique
+  - name: Calculs Equipement Virtuel
+    description: Endpoints liés aux calculs pour un équipement virtuel
+  - name: Calculs Application
+    description: Endpoints liés aux calculs pour une application
+  - name: Calculs Messagerie
+    description: Endpoints liés aux calculs pour un élément de messagerie
+  - name: Calculs Reseau
+    description: Endpoints liés aux calculs autour de l'usage du réseau
+paths:
+  /calculs/equipementPhysique:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique.
+      tags:
+        - Calculs Equipement Physique
+      operationId: calculerImpactEquipementPhysique
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculImpactEquipementPhysiqueRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+  /calculs/reseau/equipementPhysique:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique lié à l'usage du réseau.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique lié à l'usage du réseau.
+      tags:
+        - Calculs Reseau
+      operationId: calculerImpactReseau
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculImpactReseauEquipementPhysiqueRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactReseauRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactReseauRest"
+  /calculs/equipementVirtuel:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement virtuel.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement virtuel.
+        Une demande peut se baser sur le contenu de la sortie du calcul d'impact d'équipement physique.
+      tags:
+        - Calculs Equipement Virtuel
+      operationId: calculerImpactEquipementVirtuel
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculEquipementVirtuelRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+  /calculs/application:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour une application.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour une application.
+        Une demande peut se baser sur le contenu de la sortie du calcul d'impact d'équipement virtuel.
+      tags:
+        - Calculs Application
+      operationId: calculerImpactApplication
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculApplicationRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactApplicationRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactApplicationRest"
+  /calculs/messagerie:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un élément de messagerie.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un élément de messagerie
+      tags:
+        - Calculs Messagerie
+      operationId: calculerImpactMessagerie
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculMessagerieRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactMessagerieRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactMessagerieRest"
+components:
+  schemas:
+    ErreurRest:
+      description: Objet standard pour les réponses en cas d'erreur d'API
+      type: object
+      properties:
+        code:
+          description: Code de l'erreur
+          type: string
+        message:
+          description: Message de l'erreur
+          type: string
+        status:
+          description: Code Statut HTTP de la réponse
+          type: integer
+        timestamp:
+          description: Date & Heure de l'erreur
+          type: string
+          format: date-time
+    # Entrées
+    EquipementPhysiqueRest:
+      description: Représentation d'un équipement physique dans NumEcoEval
+      type: object
+      properties:
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        modele:
+          description: ""
+          type: string
+        type:
+          description: ""
+          type: string
+        statut:
+          description: ""
+          type: string
+        paysDUtilisation:
+          description: ""
+          type: string
+        utilisateur:
+          description: ""
+          type: string
+        dateAchat:
+          description: ""
+          type: string
+          format: date
+        dateRetrait:
+          description: ""
+          type: string
+          format: date
+        nbCoeur:
+          description: ""
+          type: string
+        modeUtilisation:
+          description: ""
+          type: string
+        tauxUtilisation:
+          description: ""
+          type: number
+          format: double
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nbJourUtiliseAn:
+          description: ""
+          type: number
+          format: double
+        goTelecharge:
+          description: ""
+          type: number
+          format: float
+        quantite:
+          description: ""
+          type: number
+          format: double
+          default: 1.0
+        consoElecAnnuelle:
+          description: ""
+          type: number
+          format: double
+        nbEquipementsVirtuels:
+          description: "Nombre d'équipements virtuels rattachés à l'équipement physique - Utilisé dans les traitements"
+          type: integer
+        nbTotalVCPU:
+          description: "Nombre total de VCPU (correspond à la somme des vCPU définis dans les équipements virtuels) ou null si un des équipements virtuels n'a pas de vCPU - Utilisé dans les traitements"
+          type: integer
+        dataCenter:
+          $ref: "#/components/schemas/DataCenterRest"
+    DataCenterRest:
+      description: Représentation d'un Data Center dans NumEcoEval
+      properties:
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nomLongDatacenter:
+          description: ""
+          type: string
+        pue:
+          description: ""
+          type: number
+          format: double
+        localisation:
+          description: ""
+          type: string
+    EquipementVirtuelRest:
+      description: Représentation d'un équipement virtuel dans NumEcoEval
+      properties:
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        vCPU:
+          description: ""
+          type: integer
+        cluster:
+          description: ""
+          type: string
+        typeEqv:
+          description: |
+            Le type d'équipement virtuel contient "calcul", "stockage" ou null.
+            Peut être omis entièrement si ce n'est pas applicable.
+          type: string
+        capaciteStockage:
+          description: |
+            Capacité de stockage de l'équipement virtuel en To.
+          type: number
+          format: double
+        cleRepartition:
+          description: |
+            La clé de repartition est exprimée comme une fraction.
+          type: number
+          format: double
+        consoElecAnnuelle:
+          description: |
+            Consommation électrique annuelle de l'équipement virtuel.
+          type: number
+          format: double
+    ApplicationRest:
+      description: Représentation d'une application dans NumEcoEval
+      properties:
+        nomApplication:
+          description: ""
+          type: string
+        typeEnvironnement:
+          description: ""
+          type: string
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        domaine:
+          description: ""
+          type: string
+        sousDomaine:
+          description: ""
+          type: string
+    MessagerieRest:
+      description: Représentation d'éléments de messagerie dans NumEcoEval
+      properties:
+        nombreMailEmis:
+          description: ""
+          type: integer
+        nombreMailEmisXDestinataires:
+          description: ""
+          type: integer
+        volumeTotalMailEmis:
+          description: ""
+          type: number
+          format: double
+        moisAnnee:
+          description: "Mois et Année rattachés au données, format MMAAAA"
+          type: integer
+        nomEntite:
+          description: ""
+          type: string
+
+
+    # Référentiels
+    CorrespondanceRefEquipementRest:
+      type: object
+      properties:
+        modeleEquipementSource:
+          type: string
+          description: Modèle de l'équipement
+        refEquipementCible:
+          type: string
+          description: Référence d'équipement correspondant au modèle de l'équipement
+      description: Référentiel de correspondance entre un modèle d'équipement physique
+        et une référence d'équipement dans les référentiels.
+    TypeEquipementRest:
+      type: object
+      properties:
+        type:
+          type: string
+        serveur:
+          type: boolean
+        commentaire:
+          type: string
+        dureeVieDefaut:
+          type: number
+          format: double
+        refEquipementParDefaut:
+          type: string
+      description: Référentiel de type d'équipement physique.
+    HypotheseRest:
+      type: object
+      properties:
+        code:
+          description: |
+            Code de l'hypothèse.
+          type: string
+        valeur:
+          description: "Valeur de l'hypothèse"
+          type: number
+          format: double
+    EtapeRest:
+      type: object
+      properties:
+        code:
+          type: string
+        libelle:
+          type: string
+    CritereRest:
+      type: object
+      properties:
+        nomCritere:
+          type: string
+          description: Nom du critère d'impact écologique
+        unite:
+          type: string
+          description: Unité du critère d'impact écologique
+    MixElectriqueRest:
+      type: object
+      properties:
+        pays:
+          type: string
+        critere:
+          type: string
+        valeur:
+          type: number
+          format: double
+      description: Référentiel de critère d'impact écologique
+    ImpactReseauRest:
+      type: object
+      properties:
+        refReseau:
+          type: string
+        etapeACV:
+          type: string
+        critere:
+          type: string
+        unite:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+      description: Référentiel d'impact écologique pour l'usage du réseau par un équipement
+    ImpactEquipementRest:
+      type: object
+      properties:
+        refEquipement:
+          type: string
+        etape:
+          type: string
+        critere:
+          type: string
+        type:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+      description: Référentiel d'impact écologique pour un équipement physique
+    ImpactMessagerieRest:
+      type: object
+      description: Référentiel - L'équation d'impact est une fonction affine de la forme a * x + b
+      properties:
+        constanteCoefficientDirecteur:
+          description: Cette constante correspond à "a" dans la fonction affine
+          type: number
+          format: double
+        constanteOrdonneeOrigine:
+          description: Cette constante correspond à "b" dans la fonction affine
+          type: number
+          format: double
+        critere:
+          description: Critère associé à l'impact
+          type: string
+
+    # Indicateurs
+    IndicateurImpactEquipementPhysiqueRest:
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipement:
+          type: string
+        typeEquipement:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+        quantite:
+          type: integer
+          format: int32
+        statutEquipementPhysique:
+          type: string
+    IndicateurImpactReseauRest:
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        impactUnitaire:
+          type: number
+          format: double
+    IndicateurImpactEquipementVirtuelRest:
+      description: Indicateur d'impact écologique d'un équipement virtuel
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        source:
+          type: string
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipementVirtuel:
+          type: string
+        nomEquipement:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        cluster:
+          type: string
+        consoElecMoyenne:
+          type: number
+          format: double
+    IndicateurImpactApplicationRest:
+      description: Impact d'application
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomApplication:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        domaine:
+          type: string
+        sousDomaine:
+          type: string
+        typeEnvironnement:
+          type: string
+        consoElecMoyenne:
+          type: number
+          format: double
+    IndicateurImpactMessagerieRest:
+      description: Indicateur d'impact de messagerie
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        impactMensuel:
+          type: number
+          format: double
+        moisAnnee:
+          type: integer
+        volumeTotalMailEmis:
+          type: number
+          format: double
+        nombreMailEmis:
+          type: number
+          format: double
+
+
+    # Demandes de calculs unitaires
+    DemandeCalculImpactEquipementPhysiqueRest:
+      description:
+        Demande de calcul d'impact d'équipement physique.
+        Contient tous les éléments nécéssaire au calcul d'impact (équipement physique, référentiels)
+      properties:
+        equipementPhysique:
+          $ref: "#/components/schemas/EquipementPhysiqueRest"
+        typeEquipement:
+          $ref: "#/components/schemas/TypeEquipementRest"
+        correspondanceRefEquipement:
+          $ref: "#/components/schemas/CorrespondanceRefEquipementRest"
+        hypotheses:
+          type: array
+          items:
+            $ref: "#/components/schemas/HypotheseRest"
+        etape:
+          $ref: "#/components/schemas/EtapeRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        mixElectriques:
+          description: Mix électrique du pays d'utilisation de l'équipement physique
+          type: array
+          items:
+            $ref: "#/components/schemas/MixElectriqueRest"
+        impactEquipements:
+          description: |
+            Référentiels des Critères d'impact d'équipements.
+            La liste ne peut contenir maximum 2 entrées : 
+            - 1 pour la référence par défaut (typeEquipement.refEquipementParDefaut)
+            - 1 pour la correspondance cible (correspondanceRefEquipement.refEquipementCible)
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactEquipementRest"
+    DemandeCalculImpactReseauEquipementPhysiqueRest:
+      description: |
+        Demande de calcul d'impact d'équipement physique.
+        Contient tous les éléments nécéssaire au calcul d'impact (équipement physique, référentiels)
+      properties:
+        equipementPhysique:
+          $ref: "#/components/schemas/EquipementPhysiqueRest"
+        etape:
+          $ref: "#/components/schemas/EtapeRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        impactsReseau:
+          description: |
+            Référentiels des Critères d'impact réseau.
+            La référence réseau doit être "impactReseauMobileMoyen".
+          type: array
+          maxItems: 1
+          items:
+            $ref: "#/components/schemas/ImpactReseauRest"
+    DemandeCalculEquipementVirtuelRest:
+      description: Objet regroupant toutes les données nécessaires au calcul unitaire d'indicateur d'impact écologique pour un équipement virtuel.
+      required:
+        - equipementVirtuel
+        - impactEquipement
+      properties:
+        equipementVirtuel:
+          $ref: "#/components/schemas/EquipementVirtuelRest"
+        nbTotalVCPU:
+          description: |
+            Nombre total de CPU virtuels sur l'équipement physique parent.
+            Si renseigné, sera utilisé en priorité.
+            Ne sera utilisé que si le type d'équipement virtuel n'est pas "calcul".
+          type: integer
+        nbEquipementsVirtuels:
+          description: |
+            Nombre total d'équipements virtuels sur l'équipement physique parent.
+          type: integer
+        stockageTotalVirtuel:
+          description: |
+            Stockage total en To pour tous les équipements virtuels sur l'équipement physique parent.
+            Ne sera utilisé que si le type d'équipement virtuel n'est pas "stockage".
+          type: number
+          format: double
+        impactEquipement:
+          $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+    DemandeCalculApplicationRest:
+      description: Demande de calcul unitaire d'indicateur d'impact écologique pour une application
+      properties:
+        application:
+          $ref: "#/components/schemas/ApplicationRest"
+        nbApplications:
+          description: Nombre d'applications rattachées à l'équipement virtuel portant l'application
+          type: integer
+        impactEquipementVirtuel:
+          $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+    DemandeCalculMessagerieRest:
+      description: Objet regroupant toutes les données pour le calcul des indicateurs d'impact de messagerie dans NumEcoEval
+      type: object
+      properties:
+        messagerie:
+          $ref: "#/components/schemas/MessagerieRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        impactsMessagerie:
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactMessagerieRest"
\ No newline at end of file
diff --git a/services/common/src/main/resources/static/api-event-calculs-openapi.yaml b/services/common/src/main/resources/static/api-event-calculs-openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..05125bcc30281d7396000431e4eb1b45f324b9b9
--- /dev/null
+++ b/services/common/src/main/resources/static/api-event-calculs-openapi.yaml
@@ -0,0 +1,782 @@
+openapi: 3.0.1
+info:
+  title: NumEcoEval - API calculs
+  version: v1
+  license:
+    name: Apache 2.0
+  description: |
+    API permettant de réaliser des calculs unitaires d'impact écologiques. \
+tags:
+  - name: Calculs Equipement Physique
+    description: Endpoints liés aux calculs pour un équipement physique
+  - name: Calculs Equipement Virtuel
+    description: Endpoints liés aux calculs pour un équipement virtuel
+  - name: Calculs Application
+    description: Endpoints liés aux calculs pour une application
+  - name: Calculs Messagerie
+    description: Endpoints liés aux calculs pour un élément de messagerie
+  - name: Calculs Reseau
+    description: Endpoints liés aux calculs autour de l'usage du réseau
+paths:
+  /calculs/equipementPhysique:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique.
+      tags:
+        - Calculs Equipement Physique
+      operationId: calculerImpactEquipementPhysique
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculImpactEquipementPhysiqueRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+  /calculs/reseau/equipementPhysique:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique lié à l'usage du réseau.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique lié à l'usage du réseau.
+      tags:
+        - Calculs Reseau
+      operationId: calculerImpactReseau
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculImpactReseauEquipementPhysiqueRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactReseauRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactReseauRest"
+  /calculs/equipementVirtuel:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un équipement virtuel.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement virtuel.
+        Une demande peut se baser sur le contenu de la sortie du calcul d'impact d'équipement physique.
+      tags:
+        - Calculs Equipement Virtuel
+      operationId: calculerImpactEquipementVirtuel
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculEquipementVirtuelRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+  /calculs/application:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour une application.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour une application.
+        Une demande peut se baser sur le contenu de la sortie du calcul d'impact d'équipement virtuel.
+      tags:
+        - Calculs Application
+      operationId: calculerImpactApplication
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculApplicationRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactApplicationRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactApplicationRest"
+  /calculs/messagerie:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique pour un élément de messagerie.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un élément de messagerie
+      tags:
+        - Calculs Messagerie
+      operationId: calculerImpactMessagerie
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/DemandeCalculMessagerieRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "400":
+          description: Indicateur en erreur
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactMessagerieRest"
+        "200":
+          description: Indicateur calculé.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/IndicateurImpactMessagerieRest"
+components:
+  schemas:
+    ErreurRest:
+      description: Objet standard pour les réponses en cas d'erreur d'API
+      type: object
+      properties:
+        code:
+          description: Code de l'erreur
+          type: string
+        message:
+          description: Message de l'erreur
+          type: string
+        status:
+          description: Code Statut HTTP de la réponse
+          type: integer
+        timestamp:
+          description: Date & Heure de l'erreur
+          type: string
+          format: date-time
+    # Entrées
+    EquipementPhysiqueRest:
+      description: Représentation d'un équipement physique dans NumEcoEval
+      type: object
+      properties:
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        modele:
+          description: ""
+          type: string
+        type:
+          description: ""
+          type: string
+        statut:
+          description: ""
+          type: string
+        paysDUtilisation:
+          description: ""
+          type: string
+        utilisateur:
+          description: ""
+          type: string
+        dateAchat:
+          description: ""
+          type: string
+          format: date
+        dateRetrait:
+          description: ""
+          type: string
+          format: date
+        nbCoeur:
+          description: ""
+          type: string
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nbJourUtiliseAn:
+          description: ""
+          type: number
+          format: double
+        goTelecharge:
+          description: ""
+          type: number
+          format: float
+        quantite:
+          description: ""
+          type: number
+          format: double
+          default: 1.0
+        consoElecAnnuelle:
+          description: ""
+          type: number
+          format: double
+        nbEquipementsVirtuels:
+          description: "Nombre d'équipements virtuels rattachés à l'équipement physique - Utilisé dans les traitements"
+          type: integer
+        nbTotalVCPU:
+          description: "Nombre total de VCPU (correspond à la somme des vCPU définis dans les équipements virtuels) ou null si un des équipements virtuels n'a pas de vCPU - Utilisé dans les traitements"
+          type: integer
+        dataCenter:
+          $ref: "#/components/schemas/DataCenterRest"
+    DataCenterRest:
+      description: Représentation d'un Data Center dans NumEcoEval
+      properties:
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nomLongDatacenter:
+          description: ""
+          type: string
+        pue:
+          description: ""
+          type: number
+          format: double
+        localisation:
+          description: ""
+          type: string
+    EquipementVirtuelRest:
+      description: Représentation d'un équipement virtuel dans NumEcoEval
+      properties:
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        vCPU:
+          description: ""
+          type: integer
+        cluster:
+          description: ""
+          type: string
+        typeEqv:
+          description: |
+            Le type d'équipement virtuel contient "calcul", "stockage" ou null.
+            Peut être omis entièrement si ce n'est pas applicable.
+          type: string
+        capaciteStockage:
+          description: |
+            Capacité de stockage de l'équipement virtuel en To.
+          type: number
+          format: double
+        cleRepartition:
+          description: |
+            La clé de repartition est exprimée comme une fraction.
+          type: number
+          format: double
+        consoElecAnnuelle:
+          description: |
+            Consommation électrique annuelle de l'équipement virtuel.
+          type: number
+          format: double
+    ApplicationRest:
+      description: Représentation d'une application dans NumEcoEval
+      properties:
+        nomApplication:
+          description: ""
+          type: string
+        typeEnvironnement:
+          description: ""
+          type: string
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        domaine:
+          description: ""
+          type: string
+        sousDomaine:
+          description: ""
+          type: string
+    MessagerieRest:
+      description: Représentation d'éléments de messagerie dans NumEcoEval
+      properties:
+        nombreMailEmis:
+          description: ""
+          type: integer
+        nombreMailEmisXDestinataires:
+          description: ""
+          type: integer
+        volumeTotalMailEmis:
+          description: ""
+          type: number
+          format: double
+        moisAnnee:
+          description: "Mois et Année rattachés au données, format MMAAAA"
+          type: integer
+        nomEntite:
+          description: ""
+          type: string
+
+
+    # Référentiels
+    CorrespondanceRefEquipementRest:
+      type: object
+      properties:
+        modeleEquipementSource:
+          type: string
+          description: Modèle de l'équipement
+        refEquipementCible:
+          type: string
+          description: Référence d'équipement correspondant au modèle de l'équipement
+      description: Référentiel de correspondance entre un modèle d'équipement physique
+        et une référence d'équipement dans les référentiels.
+    TypeEquipementRest:
+      type: object
+      properties:
+        type:
+          type: string
+        serveur:
+          type: boolean
+        commentaire:
+          type: string
+        dureeVieDefaut:
+          type: number
+          format: double
+        refEquipementParDefaut:
+          type: string
+      description: Référentiel de type d'équipement physique.
+    HypotheseRest:
+      type: object
+      properties:
+        code:
+          description: |
+            Code de l'hypothèse.
+          type: string
+        valeur:
+          description: "Valeur de l'hypothèse"
+          type: number
+          format: double
+    EtapeRest:
+      type: object
+      properties:
+        code:
+          type: string
+        libelle:
+          type: string
+    CritereRest:
+      type: object
+      properties:
+        nomCritere:
+          type: string
+          description: Nom du critère d'impact écologique
+        unite:
+          type: string
+          description: Unité du critère d'impact écologique
+    MixElectriqueRest:
+      type: object
+      properties:
+        pays:
+          type: string
+        critere:
+          type: string
+        valeur:
+          type: number
+          format: double
+      description: Référentiel de critère d'impact écologique
+    ImpactReseauRest:
+      type: object
+      properties:
+        refReseau:
+          type: string
+        etapeACV:
+          type: string
+        critere:
+          type: string
+        unite:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+      description: Référentiel d'impact écologique pour l'usage du réseau par un équipement
+    ImpactEquipementRest:
+      type: object
+      properties:
+        refEquipement:
+          type: string
+        etape:
+          type: string
+        critere:
+          type: string
+        type:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+      description: Référentiel d'impact écologique pour un équipement physique
+    ImpactMessagerieRest:
+      type: object
+      description: Référentiel - L'équation d'impact est une fonction affine de la forme a * x + b
+      properties:
+        constanteCoefficientDirecteur:
+          description: Cette constante correspond à "a" dans la fonction affine
+          type: number
+          format: double
+        constanteOrdonneeOrigine:
+          description: Cette constante correspond à "b" dans la fonction affine
+          type: number
+          format: double
+        critere:
+          description: Critère associé à l'impact
+          type: string
+
+    # Indicateurs
+    IndicateurImpactEquipementPhysiqueRest:
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipement:
+          type: string
+        typeEquipement:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+        quantite:
+          type: integer
+          format: int32
+        statutEquipementPhysique:
+          type: string
+    IndicateurImpactReseauRest:
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        impactUnitaire:
+          type: number
+          format: double
+    IndicateurImpactEquipementVirtuelRest:
+      description: Indicateur d'impact écologique d'un équipement virtuel
+      type: object
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        source:
+          type: string
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipementVirtuel:
+          type: string
+        nomEquipement:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        cluster:
+          type: string
+        consoElecMoyenne:
+          type: number
+          format: double
+    IndicateurImpactApplicationRest:
+      description: Impact d'application
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        etapeACV:
+          type: string
+          description: "Code de l'étape ACV associé à l'indicateur, peut être null\
+            \ pour certains indicateurs"
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        nomEquipementVirtuel:
+          description: ""
+          type: string
+        nomApplication:
+          type: string
+        impactUnitaire:
+          type: number
+          format: double
+        domaine:
+          type: string
+        sousDomaine:
+          type: string
+        typeEnvironnement:
+          type: string
+        consoElecMoyenne:
+          type: number
+          format: double
+    IndicateurImpactMessagerieRest:
+      description: Indicateur d'impact de messagerie
+      properties:
+        dateCalcul:
+          type: string
+          description: "Date et Heure du calcul, même valeur pour tous les indicateurs\
+            \ créés avec le même lot d'objets d'entrées"
+          format: date-time
+        versionCalcul:
+          type: string
+        critere:
+          type: string
+          description: "Nom du critère associé à l'indicateur, peut être null pour\
+            \ certains indicateurs"
+        statutIndicateur:
+          type: string
+          description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\
+            \ et \"ERREUR\" si l'indicateur est en erreur"
+        trace:
+          type: string
+          description: Trace du calcul ayant produit l'indicateur
+        unite:
+          type: string
+          description: "Unite du critère associé, peut être null"
+        impactMensuel:
+          type: number
+          format: double
+        moisAnnee:
+          type: integer
+        volumeTotalMailEmis:
+          type: number
+          format: double
+        nombreMailEmis:
+          type: number
+          format: double
+
+
+    # Demandes de calculs unitaires
+    DemandeCalculImpactEquipementPhysiqueRest:
+      description:
+        Demande de calcul d'impact d'équipement physique.
+        Contient tous les éléments nécéssaire au calcul d'impact (équipement physique, référentiels)
+      properties:
+        equipementPhysique:
+          $ref: "#/components/schemas/EquipementPhysiqueRest"
+        typeEquipement:
+          $ref: "#/components/schemas/TypeEquipementRest"
+        correspondanceRefEquipement:
+          $ref: "#/components/schemas/CorrespondanceRefEquipementRest"
+        hypotheses:
+          type: array
+          items:
+            $ref: "#/components/schemas/HypotheseRest"
+        etape:
+          $ref: "#/components/schemas/EtapeRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        mixElectriques:
+          description: Mix électrique du pays d'utilisation de l'équipement physique
+          type: array
+          items:
+            $ref: "#/components/schemas/MixElectriqueRest"
+        impactEquipements:
+          description: |
+            Référentiels des Critères d'impact d'équipements.
+            La liste ne peut contenir maximum 2 entrées : 
+            - 1 pour la référence par défaut (typeEquipement.refEquipementParDefaut)
+            - 1 pour la correspondance cible (correspondanceRefEquipement.refEquipementCible)
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactEquipementRest"
+    DemandeCalculImpactReseauEquipementPhysiqueRest:
+      description: |
+        Demande de calcul d'impact d'équipement physique.
+        Contient tous les éléments nécéssaire au calcul d'impact (équipement physique, référentiels)
+      properties:
+        equipementPhysique:
+          $ref: "#/components/schemas/EquipementPhysiqueRest"
+        etape:
+          $ref: "#/components/schemas/EtapeRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        impactsReseau:
+          description: |
+            Référentiels des Critères d'impact réseau.
+            La référence réseau doit être "impactReseauMobileMoyen".
+          type: array
+          maxItems: 1
+          items:
+            $ref: "#/components/schemas/ImpactReseauRest"
+    DemandeCalculEquipementVirtuelRest:
+      description: Objet regroupant toutes les données nécessaires au calcul unitaire d'indicateur d'impact écologique pour un équipement virtuel.
+      required:
+        - equipementVirtuel
+        - impactEquipement
+      properties:
+        equipementVirtuel:
+          $ref: "#/components/schemas/EquipementVirtuelRest"
+        nbTotalVCPU:
+          description: |
+            Nombre total de CPU virtuels sur l'équipement physique parent.
+            Si renseigné, sera utilisé en priorité.
+            Ne sera utilisé que si le type d'équipement virtuel n'est pas "calcul".
+          type: integer
+        nbEquipementsVirtuels:
+          description: |
+            Nombre total d'équipements virtuels sur l'équipement physique parent.
+          type: integer
+        stockageTotalVirtuel:
+          description: |
+            Stockage total en To pour tous les équipements virtuels sur l'équipement physique parent.
+            Ne sera utilisé que si le type d'équipement virtuel n'est pas "stockage".
+          type: number
+          format: double
+        impactEquipement:
+          $ref: "#/components/schemas/IndicateurImpactEquipementPhysiqueRest"
+    DemandeCalculApplicationRest:
+      description: Demande de calcul unitaire d'indicateur d'impact écologique pour une application
+      properties:
+        application:
+          $ref: "#/components/schemas/ApplicationRest"
+        nbApplications:
+          description: Nombre d'applications rattachées à l'équipement virtuel portant l'application
+          type: integer
+        impactEquipementVirtuel:
+          $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest"
+    DemandeCalculMessagerieRest:
+      description: Objet regroupant toutes les données pour le calcul des indicateurs d'impact de messagerie dans NumEcoEval
+      type: object
+      properties:
+        messagerie:
+          $ref: "#/components/schemas/MessagerieRest"
+        critere:
+          $ref: "#/components/schemas/CritereRest"
+        impactsMessagerie:
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactMessagerieRest"
\ No newline at end of file
diff --git a/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml b/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fc99e3ad7b1bc92c41175d0d6c21fd576af7237c
--- /dev/null
+++ b/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml
@@ -0,0 +1,92 @@
+openapi: 3.0.1
+info:
+  title: NumEcoEval - API sync calculs by ids
+  version: v1
+  license:
+    name: Apache 2.0
+  description: |
+    API permettant de réaliser des calculs synchrones d'impact écologiques à partir d'ids. \
+paths:
+  /sync/calculs:
+    post:
+      summary: Endpoint pour le calcul unitaire d'impact écologique synchrone pour une liste d'id d'équipements physiques et de messageries.
+      description: |
+        Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique.
+      tags:
+        - Calculs Equipement Physique et Messagerie
+      operationId: syncCalculByIds
+      requestBody:
+        required: true
+        content:
+          'application/json':
+            schema:
+              $ref: "#/components/schemas/SyncCalculRest"
+      responses:
+        "500":
+          description: Erreur interne du service
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ErreurRest"
+        "200":
+          description: Réponse résumée, volume traité.
+          content:
+            'application/json':
+              schema:
+                $ref: "#/components/schemas/ReponseCalculRest"
+components:
+  schemas:
+    ErreurRest:
+      description: Objet standard pour les réponses en cas d'erreur d'API
+      type: object
+      properties:
+        code:
+          description: Code de l'erreur
+          type: string
+        message:
+          description: Message de l'erreur
+          type: string
+        status:
+          description: Code Statut HTTP de la réponse
+          type: integer
+        timestamp:
+          description: Date & Heure de l'erreur
+          type: string
+          format: date-time
+    # Entrées
+    SyncCalculRest:
+      description: Représentation d'un équipement physique dans NumEcoEval
+      type: object
+      properties:
+        equipementPhysiqueIds:
+          description: ""
+          type: array
+          items:
+            type: integer
+            format: int64
+        messagerieIds:
+          description: ""
+          type: array
+          items:
+            type: integer
+            format: int64
+    # Indicateurs
+    ReponseCalculRest:
+      type: object
+      properties:
+        nbrEquipementPhysique:
+          type: integer
+          format: int64
+          description: "Nombre total d'équipements physiques traités"
+        nbrEquipementVirtuel:
+          type: integer
+          format: int64
+          description: "Nombre total d'équipements virtuels traités"
+        nbrApplication:
+          type: integer
+          format: int64
+          description: "Nombre total d'applications traités"
+        nbrMessagerie:
+          type: integer
+          format: int64
+          description: "Nombre total de messageries traités"
diff --git a/services/common/src/main/resources/static/api-referentiels-openapi.yaml b/services/common/src/main/resources/static/api-referentiels-openapi.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5aa7407325becbc6d78c8dce1d2bbb6fb54020e2
--- /dev/null
+++ b/services/common/src/main/resources/static/api-referentiels-openapi.yaml
@@ -0,0 +1,1484 @@
+openapi: 3.0.1
+info:
+  title: API des référentiels de NumEcoEval
+  description: |
+    Endpoints permettant de manipuler les référentiels de NumEcoEval.
+    Les endpoints CRUD sont générés via Spring DataRest.
+
+    Les endpoints d'export CSV permettent d'exporter l'intégralité d'un référentiel
+    sous forme de fichier CSV ré-importable via les endpoints d'imports.
+
+    Les endpoints d'import fonctionnent en annule & remplace et supprimeront l'intégralité
+    du référentiel et utiliseront le contenu du CSV pour peupler le référentiel.
+
+    Les endpoints internes sont utilisés par les différents modules de NumEcoEval.
+  license:
+    name: Apache 2.0
+    url: https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/api-referentiel/-/blob/main/LICENSE.txt
+  version: v0.0.1
+externalDocs:
+  description: NumEcoEval Documentation
+  url: https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/docs
+paths:
+  /referentiel/typeEquipement/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les impacts des types d'équipements sous format csv
+      operationId: exportTypeEquipementCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel Type Equipement par csv : annule et remplace.'
+      operationId: importTypeEquipementCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/mixelecs/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les impacts des mix électrique sous format csv
+      operationId: exportImpactEquipementCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel ImpactEquipement par csv : annule et remplace.'
+      operationId: importImpactEquipementCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactreseaux/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les impacts réseaux sous format csv
+      operationId: exportImpactReseauxCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel ImpactReseau par csv : annule et remplace.'
+      operationId: importImpactReseauxCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactequipements/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les impacts d'équipements sous format csv
+      operationId: exportImpactEquipementCSV_1
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel ImpactEquipement par csv : annule et remplace.'
+      description: 'Alimentation du référentiel ImpactEquipement par csv : annule et remplace.'
+      operationId: importImpactEquipementCSV_1
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactMessagerie/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les impacts de messagerie sous format csv
+      operationId: exportImpactMessagerieCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel Impact Messagerie par csv : annule et remplace.'
+      description: 'Alimentation du référentiel Impact Messagerie par csv : annule et remplace.'
+      operationId: importImpactMessagerieCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/hypotheses/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les hypothèses sous format csv
+      operationId: exportHypothesesCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation des Hypothèses par csv : annule et remplace.'
+      description: 'Alimentation des Hypothèses par csv : annule et remplace.'
+      operationId: importHypothesesCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/etapes/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les etapes sous format csv
+      operationId: exportEtapesCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation Etape ACV par csv : annule et remplace.'
+      description: 'Alimentation Etape ACV par csv : annule et remplace.'
+      operationId: importEtapesCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/criteres/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les criteres sous format csv
+      operationId: exportCriteresCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: Alimentation des Criteres par csv  (annule et remplace).
+      description: Alimentation des Criteres par csv  (annule et remplace).
+      operationId: importCriteresCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/correspondanceRefEquipement/csv:
+    get:
+      tags:
+        - Export Référentiels
+      summary: Exporter les correspondances de RefEquipement sous format csv
+      operationId: exportCorrespondanceRefEquipementCSV
+      responses:
+        '200':
+          description: OK
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+    post:
+      tags:
+        - Import Référentiels
+      summary: 'Alimentation du référentiel des correspondances de RefEquipement par csv : annule et remplace.'
+      operationId: importCorrespondanceRefEquipementCSV
+      requestBody:
+        content:
+          multipart/form-data:
+            schema:
+              required:
+                - file
+              type: object
+              properties:
+                file:
+                  type: string
+                  format: binary
+      responses:
+        '200':
+          description: Rapport d'import du fichier CSV
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/RapportImportDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /version:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération de la version courante
+      description: |
+        Endpoint interne utilisé pour connaître la version installée
+      operationId: getVersion
+      responses:
+        '200':
+          description: Version
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/VersionDTO'
+        '400':
+          description: Bad Request
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Not Found
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/typesEquipement:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération de tous les types d'équipement
+      description: |
+        Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval.
+        Renvoie l'intégralité des types d'équipements utilisables par NumEcoEval.
+
+        Les types d'équipement servent notamment à alimenter la durée de vie par défaut des équipements
+        reçues.
+      operationId: getAllTypeEquipement
+      responses:
+        '200':
+          description: Types Equipement
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/TypeEquipementDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Types Equipement  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/typesEquipement/{type}:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'un type d'équipement via son type
+      description: |
+        V2 - Endpoint interne utilisé à l'enrichissement données pour un équipement physique.
+      operationId: getTypeEquipement
+      parameters:
+        - name: type
+          in: path
+          description: type recherché
+          required: true
+          schema:
+            type: string
+            description: type recherché
+      responses:
+        '200':
+          description: Types Equipement
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/TypeEquipementDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Types Equipement non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/mixelecs:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'un Mix électrique
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Récupération d'un mix électrique en fonction de paramètres:
+        <ul>
+            <li>Le pays de l'équipement: pays</li>
+            <li>Le critère d'impact: critere</li>
+        </ul>
+        .
+      operationId: getMixElectrique
+      parameters:
+        - name: pays
+          in: query
+          description: Pays recherché
+          required: true
+          schema:
+            type: string
+            description: Pays recherché
+        - name: critere
+          in: query
+          description: Nom du critère d'impact écologique
+          required: true
+          schema:
+            type: string
+            description: Nom du critère d'impact écologique
+      responses:
+        '200':
+          description: mix Electrique trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/MixElectriqueDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: mix Electrique  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/mixelecs/{pays}:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération de Mix électriques par pays
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Récupération de mix électriques en fonction de paramètres:
+        <ul>
+            <li>Le pays de l'équipement: pays</li>
+        </ul>
+        Cas spécifique avec pays = _all pour retourner tous les Mix electriques.
+      operationId: getMixElectriqueParPays
+      parameters:
+        - name: pays
+          in: path
+          description: Pays recherché
+          required: true
+          schema:
+            type: string
+            description: Pays recherché
+      responses:
+        '200':
+          description: mix Electrique trouvé
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/MixElectriqueDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: mix Electrique  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactsMessagerie:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération des impacts de messagerie
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Renvoie l'intégralité des impacts de messagerie.
+      operationId: getAllImpactMessagerie
+      responses:
+        '200':
+          description: ' Référentiel Impact Messagerie'
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/ImpactMessagerieDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: ' Référentiel Impact Messagerie  non trouvé'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactsMessagerie/{critere}:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'un impact de messagerie
+      description: |
+        Endpoint interne utilisé dans l'enrichissement des données pour un calcul dans le module api-enrichissement de NumEcoEval.
+        Renvoie un élément du référentiel des impacts de messagerie.
+      operationId: getImpactMessagerie
+      parameters:
+        - name: critere
+          in: path
+          description: Critère recherché
+          required: true
+          schema:
+            type: string
+            description: Critère recherché
+      responses:
+        '200':
+          description: ' Référentiel Impact Messagerie'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ImpactMessagerieDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: ' Référentiel Impact Messagerie  non trouvé'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactreseaux:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'un Impact Réseau
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Récupération d'un impact écologique vis à vis de l'usage du réseau en fonction de 3 paramètres:
+        <ul>
+            <li>La référence d'impact réseau: refReseau</li>
+            <li>Le critère d'impact: critere</li>
+            <li>L'étape ACV: etapeACV</li>
+        </ul>
+        .
+      operationId: getImpactReseau
+      parameters:
+        - name: refReseau
+          in: query
+          description: Référence de réseau recherché
+          required: true
+          schema:
+            type: string
+            description: Référence de réseau recherché
+        - name: critere
+          in: query
+          description: Nom du critère d'impact écologique
+          required: true
+          schema:
+            type: string
+            description: Nom du critère d'impact écologique
+        - name: etapeacv
+          in: query
+          description: Code de l'étape ACV
+          required: true
+          schema:
+            type: string
+            description: Code de l'étape ACV
+      responses:
+        '200':
+          description: impact reseau trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ImpactReseauDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Impact Reseau  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/impactequipements:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'un Impact Equipement
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Récupération d'un impact équipement en fonction de 3 paramètres:
+        <ul>
+            <li>La référence d'équipement: refEquipement</li>
+            <li>Le critère d'impact: critere</li>
+            <li>L'étape ACV: etapeACV</li>
+        </ul>
+        .
+      operationId: getImpactEquipement
+      parameters:
+        - name: refEquipement
+          in: query
+          description: Référence de l'équipement recherché
+          required: true
+          schema:
+            type: string
+            description: Référence de l'équipement recherché
+        - name: critere
+          in: query
+          description: Nom du critère d'impact écologique
+          required: true
+          schema:
+            type: string
+            description: Nom du critère d'impact écologique
+        - name: etapeacv
+          in: query
+          description: Code de l'étape ACV
+          required: true
+          schema:
+            type: string
+            description: Code de l'étape ACV
+      responses:
+        '200':
+          description: impact equipement trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ImpactEquipementDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Impact Equipement  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/hypothese:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'une hypothèse par son code
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Renvoie une hypothèse en fonction de sa clé.
+      operationId: getHypothese
+      parameters:
+        - name: cle
+          in: query
+          description: Clé de l'hypothèse
+          required: true
+          schema:
+            type: string
+            description: Clé de l'hypothèse
+      responses:
+        '200':
+          description: Hypothèse trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HypotheseDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Hypothèse non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/etapes:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération de toutes les étapes ACV
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+        Renvoie l'intégralité des étapes du cycle de vie (étapes ACV) des équipements.
+      operationId: getAllEtapes
+      responses:
+        '200':
+          description: etape acv non trouvé
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/EtapeDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Impact Reseau  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/criteres:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération de tous les critères d'impacts écologiques
+      description: |
+        Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval.
+      operationId: getAllCriteres
+      responses:
+        '200':
+          description: impact reseau trouvé
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/CritereDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Impact Reseau  non trouvé
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+  /referentiel/correspondanceRefEquipement:
+    get:
+      tags:
+        - Interne NumEcoEval
+      summary: Endpoint interne à NumEcoEval - Récupération d'une correspondance de refEquipement à partir d'un modèle d'équipement.
+      description: |
+        Endpoint interne utilisé dans l'import de données d'entrées dans NumEcoEval
+        pour déterminer la référence d'équipement à utiliser dans les référentiels'.
+      operationId: getCorrespondanceRefEquipement
+      parameters:
+        - name: modele
+          in: query
+          required: true
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Correspondance trouvée
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/CorrespondanceRefEquipementDTO'
+        '400':
+          description: Invalid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '404':
+          description: Correspondance non trouvée
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+        '500':
+          description: Internal Server Error
+          content:
+            application/hal+json:
+              schema:
+                $ref: '#/components/schemas/ErrorResponseDTO'
+components:
+  schemas:
+    ErrorResponseDTO:
+      type: object
+      properties:
+        code:
+          type: integer
+          description: Code de l'erreur
+          format: int32
+        message:
+          type: string
+          description: Message de l'erreur
+        status:
+          type: string
+          description: Statut HTTP de la réponse
+          enum:
+            - 100 CONTINUE
+            - 101 SWITCHING_PROTOCOLS
+            - 102 PROCESSING
+            - 103 EARLY_HINTS
+            - 103 CHECKPOINT
+            - 200 OK
+            - 201 CREATED
+            - 202 ACCEPTED
+            - 203 NON_AUTHORITATIVE_INFORMATION
+            - 204 NO_CONTENT
+            - 205 RESET_CONTENT
+            - 206 PARTIAL_CONTENT
+            - 207 MULTI_STATUS
+            - 208 ALREADY_REPORTED
+            - 226 IM_USED
+            - 300 MULTIPLE_CHOICES
+            - 301 MOVED_PERMANENTLY
+            - 302 FOUND
+            - 302 MOVED_TEMPORARILY
+            - 303 SEE_OTHER
+            - 304 NOT_MODIFIED
+            - 305 USE_PROXY
+            - 307 TEMPORARY_REDIRECT
+            - 308 PERMANENT_REDIRECT
+            - 400 BAD_REQUEST
+            - 401 UNAUTHORIZED
+            - 402 PAYMENT_REQUIRED
+            - 403 FORBIDDEN
+            - 404 NOT_FOUND
+            - 405 METHOD_NOT_ALLOWED
+            - 406 NOT_ACCEPTABLE
+            - 407 PROXY_AUTHENTICATION_REQUIRED
+            - 408 REQUEST_TIMEOUT
+            - 409 CONFLICT
+            - 410 GONE
+            - 411 LENGTH_REQUIRED
+            - 412 PRECONDITION_FAILED
+            - 413 PAYLOAD_TOO_LARGE
+            - 413 REQUEST_ENTITY_TOO_LARGE
+            - 414 URI_TOO_LONG
+            - 414 REQUEST_URI_TOO_LONG
+            - 415 UNSUPPORTED_MEDIA_TYPE
+            - 416 REQUESTED_RANGE_NOT_SATISFIABLE
+            - 417 EXPECTATION_FAILED
+            - 418 I_AM_A_TEAPOT
+            - 419 INSUFFICIENT_SPACE_ON_RESOURCE
+            - 420 METHOD_FAILURE
+            - 421 DESTINATION_LOCKED
+            - 422 UNPROCESSABLE_ENTITY
+            - 423 LOCKED
+            - 424 FAILED_DEPENDENCY
+            - 425 TOO_EARLY
+            - 426 UPGRADE_REQUIRED
+            - 428 PRECONDITION_REQUIRED
+            - 429 TOO_MANY_REQUESTS
+            - 431 REQUEST_HEADER_FIELDS_TOO_LARGE
+            - 451 UNAVAILABLE_FOR_LEGAL_REASONS
+            - 500 INTERNAL_SERVER_ERROR
+            - 501 NOT_IMPLEMENTED
+            - 502 BAD_GATEWAY
+            - 503 SERVICE_UNAVAILABLE
+            - 504 GATEWAY_TIMEOUT
+            - 505 HTTP_VERSION_NOT_SUPPORTED
+            - 506 VARIANT_ALSO_NEGOTIATES
+            - 507 INSUFFICIENT_STORAGE
+            - 508 LOOP_DETECTED
+            - 509 BANDWIDTH_LIMIT_EXCEEDED
+            - 510 NOT_EXTENDED
+            - 511 NETWORK_AUTHENTICATION_REQUIRED
+        timestamp:
+          type: string
+          description: Date & Heure de l'erreur
+          format: date-time
+      description: Objet standard pour les réponses en cas d'erreur d'API
+    RapportImportDTO:
+      type: object
+      properties:
+        fichier:
+          type: string
+        erreurs:
+          type: array
+          items:
+            type: string
+        nbrLignesImportees:
+          type: integer
+          format: int64
+    VersionDTO:
+      type: object
+      properties:
+        version:
+          type: string
+          description: La version
+      description: Version applicative
+    TypeEquipementDTO:
+      type: object
+      properties:
+        type:
+          type: string
+          description: Type de l'équipment physique, clé du référentiel
+        serveur:
+          type: boolean
+          description: Flag indiquant si l'équipement physique est un serveur
+        commentaire:
+          type: string
+          description: Commentaire de l'entrée dans le référentiel
+        dureeVieDefaut:
+          type: number
+          description: Durée de vie par défaut de ce type d'équipement physique
+          format: double
+        source:
+          type: string
+          description: Source de l'information du référentiel
+        refEquipementParDefaut:
+          type: string
+          description: Référence de l'équipement par défaut, permet des correspondances en cas d'absence de correspondance direct
+      description: Référentiel des types d'équipements physiques utilisables dans le système. La clé du référentiel est le champ type.
+    MixElectriqueDTO:
+      type: object
+      properties:
+        pays:
+          type: string
+          description: Pays concerné, fait partie de la clé du référentiel
+        raccourcisAnglais:
+          type: string
+          description: Code du pays concerné en anglais
+        critere:
+          type: string
+          description: Critère d'impact écologique concerné, fait partie de la clé du référentiel
+        valeur:
+          type: number
+          description: Valeur du référentiel
+          format: double
+        source:
+          type: string
+          description: Source de la valeur du référentiel
+      description: Référentiel des mix électrique couvrant l'usage de l'électricité vis à vis du pays d'utilisation de l'équipement. La clé du référentiel est composé des champs pays et critere.
+    ImpactMessagerieDTO:
+      type: object
+      properties:
+        constanteCoefficientDirecteur:
+          type: number
+          description: Coefficient directeur de la fonction affine
+          format: double
+        constanteOrdonneeOrigine:
+          type: number
+          description: Constante de la fonction affine
+          format: double
+        critere:
+          type: string
+          description: Critère de l'impact écologique d'une messagerie, clé du référentiel
+        source:
+          type: string
+          description: Source de l'impact écologique d'une messagerie
+      description: Référentiel de l'impact écologique d'une messagerie. La clé est le champ critere. Chaque entrée représente les composants d'une fonction affine (Ax+b).
+    ImpactReseauDTO:
+      type: object
+      properties:
+        refReseau:
+          type: string
+          description: Référence de l'usage du réseau, fait partie de la clé du référentiel
+        etapeACV:
+          type: string
+          description: Étape ACV concerné pour l'usage du réseau, fait partie de la clé du référentiel
+        critere:
+          type: string
+          description: Critère d'impact écologique concerné pour l'usage du réseau, fait partie de la clé du référentiel
+        unite:
+          type: string
+          description: Unité de l'impact écologique concerné pour l'usage du réseau. Champ Déprécié
+          deprecated: true
+        source:
+          type: string
+          description: Source de l'impact écologique
+        valeur:
+          type: number
+          description: Valeur de l'impact écologique
+          format: double
+        consoElecMoyenne:
+          type: number
+          description: Consommation électrique moyenne de l'impact écologique
+          format: double
+      description: Référentiel de l'impact écologique d'un équipement physique vis à vis de l'usage du réseau dans les référentiels. La clé est composé des champs refReseau, etapeACV et critere.
+    ImpactEquipementDTO:
+      type: object
+      properties:
+        refEquipement:
+          type: string
+          description: Référence de l'équipement physique, fait partie de la clé dans le référentiel
+        etape:
+          type: string
+          description: Étape ACV concernée, fait partie de la clé dans le référentiel
+        critere:
+          type: string
+          description: Critère d'impact écologique concerné, fait partie de la clé dans le référentiel
+        source:
+          type: string
+          description: Source de l'impact écologique pour cette équipement physique
+        type:
+          type: string
+          description: Type de l'équipement physique concerné
+        valeur:
+          type: number
+          description: Valeur de l'impact écologique
+          format: double
+        consoElecMoyenne:
+          type: number
+          description: Consommation électrique moyenne
+          format: double
+        description:
+          type: string
+          description: Description de l'entrée dans le référentiel
+      description: Référentiel de l'impact écologique d'un équipement physique dans les référentiels. La clé est composé des champs refEquipement, etape et critere.
+    HypotheseDTO:
+      type: object
+      properties:
+        code:
+          type: string
+          description: Code de l'hypothèse, clé du référentiel
+        valeur:
+          type: string
+          description: Valeur de l'hypothèse
+        source:
+          type: string
+          description: Source de l'hypothèse
+      description: Référentiel des hypothèses utilisées pour les calculs
+    EtapeDTO:
+      type: object
+      properties:
+        code:
+          pattern: '[A-Z]+'
+          type: string
+          description: Code de l'étape. Ne contient que des majuscules, clé du référentiel
+        libelle:
+          type: string
+          description: Libellé de l'étape
+      description: Référentiel d'étape dans le cycle de vie d'un équipement (Etape ACV)
+    CritereDTO:
+      type: object
+      properties:
+        nomCritere:
+          type: string
+          description: Nom du critère d'impact écologique, clé du référentiel
+        unite:
+          type: string
+          description: Unité du critère d'impact écologique
+        description:
+          type: string
+          description: Description du critère d'impact écologique
+      description: Référentiel de critère d'impact écologique
+    CorrespondanceRefEquipementDTO:
+      type: object
+      properties:
+        modeleEquipementSource:
+          type: string
+          description: Modèle de l'équipement, clé du référentiel
+        refEquipementCible:
+          type: string
+          description: Référence d'équipement correspondant au modèle de l'équipement
+      description: Référentiel de correspondance entre un modèle d'équipement physique et une référence d'équipement dans les référentiels.
diff --git a/services/common/src/main/resources/static/asyncapi_equipement_physique.yaml b/services/common/src/main/resources/static/asyncapi_equipement_physique.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..704d8b3ce986bce1220326578b1380361962a736
--- /dev/null
+++ b/services/common/src/main/resources/static/asyncapi_equipement_physique.yaml
@@ -0,0 +1,335 @@
+asyncapi: 2.6.0
+info:
+  title: api-event-calcul-enrichissement-eqp
+  version: '1.0'
+  description: |
+    Lecture d'un équipement physique
+    puis récupération des référentiels nécessaires au calcul via REST
+    puis production d'un message pour demande de calcul d'impacts de l'équipement physique
+servers:
+  bootstrap:
+    url: localhost:9092
+    protocol: kafka
+channels:
+  entree_equipementPhysique:
+    description: Topic d'envoie des données d'entrées pour les équipements physiques à enrichir
+    publish:
+      message:
+        $ref: '#/components/messages/EntreeEquipementPhysique'
+  calcul_equipementPhysique:
+    description: Topic d'envoie des données d'entrées pour les équipements physiques à calculer
+    subscribe:
+      message:
+        $ref: '#/components/messages/CalculEquipementPhysique'
+components:
+  messages:
+    EntreeEquipementPhysique:
+      name: EntreeEquipementPhysique
+      title: Message des données d'entrée pour un équipement Physique dans NumEcoEval
+      summary: Données d'un équipement physique pour un calcul dans NumEcoEval
+      contentType: application/json
+      payload:
+        $ref: "#/components/schemas/EquipementPhysiqueDTO"
+    CalculEquipementPhysique:
+      name: CalculEquipementPhysique
+      title: Message pour le calcul d'impact d'un équipement physique
+      summary: Intégralité des données permettant le calcul d'un équipement physique pour un calcul dans NumEcoEval
+      contentType: application/json
+      payload:
+        $ref: "#/components/schemas/CalculEquipementPhysiqueDTO"
+  schemas:
+    CalculEquipementPhysiqueDTO:
+      $id: CalculEquipementPhysiqueDTO
+      description: Objet regroupant toutes les données pour le calcul des indicateurs d'un équipement physique dans NumEcoEval
+      type: object
+      properties:
+        equipementPhysique:
+          $ref: "#/components/schemas/EquipementPhysiqueDTO"
+        typeEquipement:
+          description: Référentiel rattaché au type d'équipement de l'équipement physique
+          $ref: "#/components/schemas/TypeEquipementDTO"
+        correspondanceRefEquipement:
+          description: Correspondance de référence d'équipement actuel pour le modèle de l'équipement
+          $ref: "#/components/schemas/CorrespondanceRefEquipementDTO"
+        hypotheses:
+          description: Hypothèses disponibles pour le calcul
+          type: array
+          items:
+            $ref: "#/components/schemas/HypotheseDTO"
+        etapes:
+          description: Référentiels des Étapes ACV
+          type: array
+          items:
+            $ref: "#/components/schemas/EtapeDTO"
+        criteres:
+          description: Référentiels des Critères d'impact écologiques
+          type: array
+          items:
+            $ref: "#/components/schemas/CritereDTO"
+        mixElectriques:
+          description: Mix électrique du pays d'utilisation de l'équipement physique
+          type: array
+          items:
+            $ref: "#/components/schemas/MixElectriqueDTO"
+        impactsReseau:
+          description: Référentiels des Critères d'impact écologiques
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactReseauDTO"
+        impactsEquipement:
+          description: Référentiels d'impacts écologiques pour cet équipement
+          type: array
+          items:
+            $ref: "#/components/schemas/ImpactEquipementDTO"
+    EquipementPhysiqueDTO:
+      $id: EquipementPhysiqueDTO
+      description: Représentation d'un équipement physique dans NumEcoEval
+      type: object
+      properties:
+        id:
+          description: ""
+          type: integer
+          format: int64
+        nomEquipementPhysique:
+          description: ""
+          type: string
+        modele:
+          description: ""
+          type: string
+        type:
+          description: ""
+          type: string
+        statut:
+          description: ""
+          type: string
+        paysDUtilisation:
+          description: ""
+          type: string
+        utilisateur:
+          description: ""
+          type: string
+        dateAchat:
+          description: ""
+          type: string
+          format: date
+        dateRetrait:
+          description: ""
+          type: string
+          format: date
+        nbCoeur:
+          description: ""
+          type: string
+        modeUtilisation:
+          description: ""
+          type: string
+        tauxUtilisation:
+          description: ""
+          type: number
+          format: double
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nbJourUtiliseAn:
+          description: ""
+          type: number
+          format: double
+        goTelecharge:
+          description: ""
+          type: number
+          format: float
+        quantite:
+          description: ""
+          type: number
+          format: double
+        consoElecAnnuelle:
+          description: ""
+          type: number
+          format: double
+        serveur:
+          description: ""
+          type: boolean
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+        dateLot:
+          description: ""
+          type: string
+          format: date
+        nomOrganisation:
+          description: ""
+          type: string
+        nbEquipementsVirtuels:
+          description: "Nombre d'équipements virtuels rattachés à l'équipement physique - Utilisé dans les traitements"
+          type: integer
+        nbTotalVCPU:
+          description: "Nombre total de VCPU (correspond à la somme des vCPU définis dans les équipements virtuels) ou null si un des équipements virtuels n'a pas de vCPU - Utilisé dans les traitements"
+          type: integer
+        dataCenter:
+          $ref: "#/components/schemas/DataCenterDTO"
+        stockageTotalVirtuel:
+          description: |
+            Stockage total en To pour tous les équipements virtuels sur l'équipement physique parent.
+            Ne sera utilisé que si le type d'équipement virtuel n'est pas "stockage".
+          type: number
+          format: double
+    DataCenterDTO:
+      $id: DataCenterDTO
+      description: Représentation d'un Data Center dans NumEcoEval
+      properties:
+        id:
+          description: ""
+          type: integer
+          format: int64
+        nomCourtDatacenter:
+          description: ""
+          type: string
+        nomLongDatacenter:
+          description: ""
+          type: string
+        pue:
+          description: ""
+          type: number
+          format: double
+        localisation:
+          description: ""
+          type: string
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+        dateLot:
+          description: ""
+          type: string
+          format: date
+        nomOrganisation:
+          description: ""
+          type: string
+    CorrespondanceRefEquipementDTO:
+      type: object
+      properties:
+        modeleEquipementSource:
+          type: string
+          description: Modèle de l'équipement
+        refEquipementCible:
+          type: string
+          description: Référence d'équipement correspondant au modèle de l'équipement
+      description: Référentiel de correspondance entre un modèle d'équipement physique
+        et une référence d'équipement dans les référentiels.
+    TypeEquipementDTO:
+      type: object
+      properties:
+        type:
+          type: string
+        serveur:
+          type: boolean
+        commentaire:
+          type: string
+        dureeVieDefaut:
+          type: number
+          format: double
+        source:
+          type: string
+        refEquipementParDefaut:
+          type: string
+      description: Référentiel de type d'équipement physique.
+    HypotheseDTO:
+      type: object
+      properties:
+        code:
+          type: string
+        valeur:
+          type: string
+        source:
+          type: string
+    EtapeDTO:
+      type: object
+      properties:
+        code:
+          type: string
+        libelle:
+          type: string
+    CritereDTO:
+      type: object
+      properties:
+        nomCritere:
+          type: string
+          description: Nom du critère d'impact écologique
+        unite:
+          type: string
+          description: Unité du critère d'impact écologique
+        description:
+          type: string
+          description: Description du critère d'impact écologique
+    MixElectriqueDTO:
+      type: object
+      properties:
+        pays:
+          type: string
+        raccourcisAnglais:
+          type: string
+        critere:
+          type: string
+        valeur:
+          type: number
+          format: double
+        source:
+          type: string
+      description: Référentiel de critère d'impact écologique
+    ImpactReseauDTO:
+      type: object
+      properties:
+        refReseau:
+          type: string
+        etapeACV:
+          type: string
+        critere:
+          type: string
+        unite:
+          type: string
+        source:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+      description: Référentiel d'impact écologique pour l'usage du réseau par un équipement
+    ImpactEquipementDTO:
+      type: object
+      properties:
+        refEquipement:
+          type: string
+        etape:
+          type: string
+        critere:
+          type: string
+        source:
+          type: string
+        type:
+          type: string
+        valeur:
+          type: number
+          format: double
+        consoElecMoyenne:
+          type: number
+          format: double
+        description:
+          type: string
+      description: Référentiel d'impact écologique pour un équipement physique
+  operationTraits:
+    kafka:
+      bindings:
+        kafka:
+          groupId: api-event-calcul-enrichissement-eqp
diff --git a/services/common/src/main/resources/static/asyncapi_merge.yaml b/services/common/src/main/resources/static/asyncapi_merge.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b92b45a095c8ac4a977d6e0e92d074a78edccbc9
--- /dev/null
+++ b/services/common/src/main/resources/static/asyncapi_merge.yaml
@@ -0,0 +1,26 @@
+openapi: 3.0.1
+info:
+  title: Temporaire - Modeles utilisés pour les échanges AsyncAPI
+  version: 0.0.1
+paths:
+  /unused:
+    get:
+      operationId: unused
+      description: "Non utilisé - juste présent pour la compliance"
+      responses:
+        default:
+          description: Types Equipement
+          content:
+            application/json:
+              schema:
+                type: string
+components:
+  schemas:
+    CalculEquipementPhysiqueDTO:
+      $ref: "./asyncapi_equipement_physique.yaml#/components/schemas/CalculEquipementPhysiqueDTO"
+    EquipementPhysiqueDTO:
+      $ref: "./asyncapi_equipement_physique.yaml#/components/schemas/EquipementPhysiqueDTO"
+    DataCenterDTO:
+      $ref: "./asyncapi_equipement_physique.yaml#/components/schemas/DataCenterDTO"
+    MessagerieDTO:
+      $ref: "./asyncapi_messagerie.yaml#/components/schemas/MessagerieDTO"
diff --git a/services/common/src/main/resources/static/asyncapi_messagerie.yaml b/services/common/src/main/resources/static/asyncapi_messagerie.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1fbf243ee63678e31e3a3cdb95ecd1132f7521e4
--- /dev/null
+++ b/services/common/src/main/resources/static/asyncapi_messagerie.yaml
@@ -0,0 +1,68 @@
+asyncapi: 2.6.0
+info:
+  title: api-event-donneesEntrees-messagerie
+  version: '1.0'
+  description: |
+    Lecture en base de données des éléments de messagerie au statut A_INGERER,
+    Mise à jour des données lues au statut INGERE et envoie d'un message par éléments de messagerie pour enrichissement.
+servers:
+  bootstrap:
+    url: localhost:9092
+    protocol: kafka
+channels:
+  entree_messagerie:
+    description: Topic d'envoie des données de messagerie à enrichir
+    subscribe:
+      message:
+        $ref: '#/components/messages/MessageEntreeMessagerie'
+components:
+  messages:
+    MessageEntreeMessagerie:
+      name: MessageEntreeMessagerie
+      title: Entrée d'un élément de messagerie dans NumEcoEval
+      summary: Données d'un élément de messagerie pour un calcul dans NumEcoEval
+      contentType: application/json
+      payload:
+        $ref: "#/components/schemas/MessagerieDTO"
+  schemas:
+
+    MessagerieDTO:
+      description: Représentation d'éléments de messagerie dans NumEcoEval
+      properties:
+        id:
+          description: ""
+          type: integer
+          format: int64
+        nombreMailEmis:
+          description: ""
+          type: integer
+        nombreMailEmisXDestinataires:
+          description: ""
+          type: integer
+        volumeTotalMailEmis:
+          description: ""
+          type: integer
+        moisAnnee:
+          description: "Mois et Année rattachés au données, format MMAAAA"
+          type: integer
+        nomEntite:
+          description: ""
+          type: string
+        nomSourceDonnee:
+          description: "Nom de la source de la donnée"
+          type: string
+        nomLot:
+          description: "Nom du lot rattaché"
+          type: string
+        dateLot:
+          description: ""
+          type: string
+          format: date
+        nomOrganisation:
+          description: ""
+          type: string
+  operationTraits:
+    kafka:
+      bindings:
+        kafka:
+          groupId: api-event-donneesEntrees-messagerie
diff --git a/services/common/src/test/java/org/mte/numecoeval/common/utils/PreparedStatementUtilsTest.java b/services/common/src/test/java/org/mte/numecoeval/common/utils/PreparedStatementUtilsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d122b29d03f30a2fa4f610f302d178999dfff81d
--- /dev/null
+++ b/services/common/src/test/java/org/mte/numecoeval/common/utils/PreparedStatementUtilsTest.java
@@ -0,0 +1,93 @@
+package org.mte.numecoeval.common.utils;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class PreparedStatementUtilsTest {
+
+    @Mock
+    PreparedStatement preparedStatement;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void whenNullValue_getDateFromLocalDate_shouldReturnNull(LocalDate value) {
+        assertNull(PreparedStatementUtils.getDateFromLocalDate(value));
+    }
+
+    @Test
+    void whenValueIsAvailable_getDateFromLocalDate_shouldReturnLocalDate() {
+        var value = LocalDate.of(2022,1,1);
+
+        var result = PreparedStatementUtils.getDateFromLocalDate(value);
+
+        assertEquals(Date.valueOf("2022-01-01"), result);
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void whenNullValue_getTimestampFromLocalDateTime_shouldReturnNull(LocalDateTime value) {
+        assertNull(PreparedStatementUtils.getTimestampFromLocalDateTime(value));
+    }
+
+    @Test
+    void whenValueIsAvailable_getTimestampFromLocalDateTime_shouldReturnLocalDate() {
+        var value = LocalDateTime.of(2022,1,1, 15,15,6);
+
+        var result = PreparedStatementUtils.getTimestampFromLocalDateTime(value);
+
+        assertEquals(Timestamp.valueOf("2022-01-01 15:15:06.000"), result);
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void whenNullValue_setIntValue_shouldSetNull(Integer value) throws SQLException {
+        PreparedStatementUtils.setIntValue(preparedStatement, 1, value);
+
+        Mockito.verify(preparedStatement, Mockito.times(1)).setNull(1, Types.INTEGER);
+    }
+
+    @Test
+    void whenValueIsAvailable_setIntValue_shouldSetIntWithValue() throws SQLException {
+        var value = 1;
+        PreparedStatementUtils.setIntValue(preparedStatement, 1, value);
+
+        Mockito.verify(preparedStatement, Mockito.times(1)).setInt(1, value);
+    }
+
+    @ParameterizedTest
+    @NullSource
+    void whenNullValue_setDoubleValue_shouldSetNull(Double value) throws SQLException {
+        PreparedStatementUtils.setDoubleValue(preparedStatement, 1, value);
+
+        Mockito.verify(preparedStatement, Mockito.times(1)).setNull(1, Types.DOUBLE);
+    }
+
+    @Test
+    void whenValueIsAvailable_setDoubleValue_shouldSetDoubleWithValue() throws SQLException {
+        var value = 1.2;
+        PreparedStatementUtils.setDoubleValue(preparedStatement, 1, value);
+
+        Mockito.verify(preparedStatement, Mockito.times(1)).setDouble(1, value);
+    }
+}
diff --git a/services/common/src/test/java/org/mte/numecoeval/common/utils/ResultSetUtilsTest.java b/services/common/src/test/java/org/mte/numecoeval/common/utils/ResultSetUtilsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a1cdc2356bc5b6f95cb3d6462f03d75805360a9
--- /dev/null
+++ b/services/common/src/test/java/org/mte/numecoeval/common/utils/ResultSetUtilsTest.java
@@ -0,0 +1,110 @@
+package org.mte.numecoeval.common.utils;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.sql.Date;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.time.LocalDate;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.when;
+
+class ResultSetUtilsTest {
+
+    @Mock
+    ResultSet resultSet;
+
+    @BeforeEach
+    void setup() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    void whenColumnIsNull_getMethodsUsingCheckColumnInResultSet_shouldReturn(String columnName) throws SQLException {
+        assertNull(ResultSetUtils.getLocalDate(resultSet, columnName));
+        assertNull(ResultSetUtils.getLocalDateTime(resultSet, columnName));
+        assertNull(ResultSetUtils.getFloat(resultSet, columnName));
+        assertNull(ResultSetUtils.getInteger(resultSet, columnName));
+        assertNull(ResultSetUtils.getDouble(resultSet, columnName));
+    }
+
+    @Test
+    void whenResultSetIsNull_getMethodsUsingCheckColumnInResultSet_shouldReturn() throws SQLException {
+        var columnName = "colonne";
+        assertNull(ResultSetUtils.getLocalDate(null, columnName));
+        assertNull(ResultSetUtils.getLocalDateTime(null, columnName));
+        assertNull(ResultSetUtils.getFloat(null, columnName));
+        assertNull(ResultSetUtils.getInteger(null, columnName));
+        assertNull(ResultSetUtils.getDouble(null, columnName));
+    }
+
+    @Test
+    void whenValueIsAvailable_getLocalDate_shouldReturnLocalDate() throws SQLException {
+        var columnName = "test";
+        var dateTime = 1683310020L;
+        when(resultSet.getString(columnName)).thenReturn(new Date(dateTime).toString());
+        when(resultSet.getDate(columnName)).thenReturn(new Date(dateTime));
+
+        var result = ResultSetUtils.getLocalDate(resultSet, columnName);
+
+        assertEquals(LocalDate.of(1970,1,20), result);
+    }
+
+    @Test
+    void whenValueIsAvailable_getLocalDateTime_shouldReturnLocalDate() throws SQLException {
+        var columnName = "test";
+        var dateTime = 1683310020L;
+        when(resultSet.getString(columnName)).thenReturn(new Date(dateTime).toString());
+        var originalTimestamp = new Timestamp(dateTime);
+        when(resultSet.getTimestamp(columnName)).thenReturn(originalTimestamp);
+
+        var result = ResultSetUtils.getLocalDateTime(resultSet, columnName);
+
+        assertEquals(originalTimestamp.toLocalDateTime(), result);
+    }
+
+    @Test
+    void whenValueIsAvailable_getFloat_shouldReturnLocalDate() throws SQLException {
+        var columnName = "test";
+        var value = Float.valueOf(6.6f);
+        when(resultSet.getString(columnName)).thenReturn(value.toString());
+        when(resultSet.getFloat(columnName)).thenReturn(value);
+
+        var result = ResultSetUtils.getFloat(resultSet, columnName);
+
+        assertEquals(value, result);
+    }
+
+    @Test
+    void whenValueIsAvailable_getDouble_shouldReturnLocalDate() throws SQLException {
+        var columnName = "test";
+        var value = Double.valueOf(6.6);
+        when(resultSet.getString(columnName)).thenReturn(value.toString());
+        when(resultSet.getDouble(columnName)).thenReturn(value);
+
+        var result = ResultSetUtils.getDouble(resultSet, columnName);
+
+        assertEquals(value, result);
+    }
+
+    @Test
+    void whenValueIsAvailable_getInteger_shouldReturnLocalDate() throws SQLException {
+        var columnName = "test";
+        var value = Integer.valueOf(6);
+        when(resultSet.getString(columnName)).thenReturn(value.toString());
+        when(resultSet.getInt(columnName)).thenReturn(value);
+
+        var result = ResultSetUtils.getInteger(resultSet, columnName);
+
+        assertEquals(value, result);
+    }
+}
diff --git a/services/core/.gitignore b/services/core/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..20c8d182d7c273a6d0db62fbf6f998ffb1357150
--- /dev/null
+++ b/services/core/.gitignore
@@ -0,0 +1,32 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/services/core/README.md b/services/core/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..90384e90336c715923e3b3c2ee27cd16ad71b659
--- /dev/null
+++ b/services/core/README.md
@@ -0,0 +1,3 @@
+# core
+
+POM parents des modules du projet
diff --git a/services/core/ci_settings.xml b/services/core/ci_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5205903f74a7c01cd6aa2a74c856a197ee99824e
--- /dev/null
+++ b/services/core/ci_settings.xml
@@ -0,0 +1,16 @@
+<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
+    <servers>
+        <server>
+            <id>gitlab-maven</id>
+            <configuration>
+                <httpHeaders>
+                    <property>
+                        <name>Job-Token</name>
+                        <value>${env.CI_JOB_TOKEN}</value>
+                    </property>
+                </httpHeaders>
+            </configuration>
+        </server>
+    </servers>
+</settings>
diff --git a/services/core/dependency_check_suppressions.xml b/services/core/dependency_check_suppressions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fbf9371b9855dacda4603cfaba33e10d71151dd1
--- /dev/null
+++ b/services/core/dependency_check_suppressions.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
+</suppressions>
diff --git a/services/core/pom.xml b/services/core/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1714c7b883d80c8891f6e4d1a965606a2973c2ee
--- /dev/null
+++ b/services/core/pom.xml
@@ -0,0 +1,377 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.0.7</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>org.mte.numecoeval</groupId>
+    <artifactId>core</artifactId>
+    <version>1.2.3-SNAPSHOT</version>
+    <name>core</name>
+    <packaging>pom</packaging>
+    <description>Projet parent du projet NumEcoEval</description>
+
+    <repositories>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+    </repositories>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <url>https://gitlab-forge.din.developpement-durable.gouv.fr/api/v4/projects/20519/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <properties>
+        <java.version>17</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+        <!-- Utilitaires -->
+        <apache-commons-lang3.version>3.12.0</apache-commons-lang3.version>
+        <apache-commons-collection4.version>4.4</apache-commons-collection4.version>
+        <apache-commons-io.version>2.11.0</apache-commons-io.version>
+        <apache-commons-csv.version>1.9.0</apache-commons-csv.version>
+        <mapstruct.version>1.5.3.Final</mapstruct.version>
+
+        <!-- CVE multiples sur Snakeyaml (CVE-2020-13936, CVE-2022-38749, CVE-2022-38751, CVE-2022-38750, CVE-2022-38752)-->
+        <snakeyaml.version>1.33</snakeyaml.version>
+        <!-- CVE sur Postgres (CVE-2022-41946) -->
+        <postgresql.version>42.5.4</postgresql.version>
+
+        <!-- CVE sur Spring CVE-2023-20863-->
+        <spring-framework.version>6.0.8</spring-framework.version>
+
+        <!-- Documentation automatique des API REST en OpenAPI 3.0 -->
+        <springdoc-openapi-ui.version>2.0.4</springdoc-openapi-ui.version>
+
+        <!-- OpenAPI Generator (API REST generator) -->
+        <openapi-generator-version>6.4.0</openapi-generator-version>
+        <jackson-databind-nullable-version>0.2.6</jackson-databind-nullable-version>
+        <!-- scs-multiapi-maven-plugin (Async API generator)-->
+        <scs-multiapi-maven-plugin.version>4.5.0</scs-multiapi-maven-plugin.version>
+
+        <!-- Tests -->
+        <meanbean.version>2.0.3</meanbean.version>
+        <equalsverifier.version>3.10.1</equalsverifier.version>
+        <wiremock.version>2.34.0</wiremock.version>
+        <javafaker.version>1.0.2</javafaker.version>
+        <cucumber-bom.version>7.11.1</cucumber-bom.version>
+        <jacoco.version>0.8.8</jacoco.version>
+        <instancio-junit.version>2.2.0</instancio-junit.version>
+        <surefireArgLine>-Dfile.encoding=UTF-8</surefireArgLine>
+        <embedded-database-spring-test.version>2.2.0</embedded-database-spring-test.version>
+        <embedded-postgres.version>2.0.3</embedded-postgres.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.mte.numecoeval</groupId>
+                <artifactId>common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.meanbean</groupId>
+                <artifactId>meanbean</artifactId>
+                <version>${meanbean.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version>${commons-lang3.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-collections4</artifactId>
+                <version>${apache-commons-collection4.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${apache-commons-io.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-csv</artifactId>
+                <version>${apache-commons-csv.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mapstruct</groupId>
+                <artifactId>mapstruct</artifactId>
+                <version>${mapstruct.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+                <version>${springdoc-openapi-ui.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-common</artifactId>
+                <version>${springdoc-openapi-ui.version}</version>
+            </dependency>
+
+            <!-- OpenAPI Generator -->
+            <dependency>
+                <groupId>org.openapitools</groupId>
+                <artifactId>jackson-databind-nullable</artifactId>
+                <version>${jackson-databind-nullable-version}</version>
+            </dependency>
+
+            <!-- Cucumber (Tests) -->
+            <dependency>
+                <groupId>io.cucumber</groupId>
+                <artifactId>cucumber-bom</artifactId>
+                <version>${cucumber-bom.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>nl.jqno.equalsverifier</groupId>
+                <artifactId>equalsverifier</artifactId>
+                <version>${equalsverifier.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+
+            <!-- Donnnées aléatoires -->
+            <dependency>
+                <groupId>com.github.javafaker</groupId>
+                <artifactId>javafaker</artifactId>
+                <version>${javafaker.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.instancio</groupId>
+                <artifactId>instancio-junit</artifactId>
+                <version>${instancio-junit.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <!-- Wiremock-->
+            <dependency>
+                <groupId>com.github.tomakehurst</groupId>
+                <artifactId>wiremock-jre8-standalone</artifactId>
+                <version>${wiremock.version}</version>
+                <scope>test</scope>
+                <exclusions>
+                    <exclusion>
+                        <groupId>junit</groupId>
+                        <artifactId>junit</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!-- Base de données de tests-->
+            <dependency>
+                <groupId>io.zonky.test</groupId>
+                <artifactId>embedded-database-spring-test</artifactId>
+                <version>${embedded-database-spring-test.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>io.zonky.test</groupId>
+                <artifactId>embedded-postgres</artifactId>
+                <version>${embedded-postgres.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+    <profiles>
+        <profile>
+            <id>FULL</id>
+            <modules>
+                <module>../common</module>
+                <module>../calculs</module>
+                <module>../api-referentiel</module>
+                <module>../api-expositiondonneesentrees</module>
+                <module>../api-event-donneesEntrees</module>
+                <module>../api-event-calculs</module>
+            </modules>
+        </profile>
+        <!-- Dependency Check en local-->
+        <profile>
+            <id>DEPENDENCY-CHECK</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.owasp</groupId>
+                        <artifactId>dependency-check-maven</artifactId>
+                        <version>8.1.2</version>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                                <configuration>
+                                    <suppressionFile>${project.basedir}/dependency_check_suppressions.xml
+                                    </suppressionFile>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <!--	Bypass des tests	-->
+        <profile>
+            <id>SKIP-ALL-TEST</id>
+            <properties>
+                <skip.unit.tests>true</skip.unit.tests>
+                <skip.integration.tests>true</skip.integration.tests>
+                <maven.test.failure.ignore>true</maven.test.failure.ignore>
+            </properties>
+        </profile>
+    </profiles>
+
+    <build>
+
+
+        <plugins>
+            <!-- Processors pour les annotations -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>${java.version}</source> <!-- depending on your project -->
+                    <target>${java.version}</target> <!-- depending on your project -->
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>org.mapstruct</groupId>
+                            <artifactId>mapstruct-processor</artifactId>
+                            <version>${mapstruct.version}</version>
+                        </path>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                            <version>${lombok.version}</version>
+                        </path>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok-mapstruct-binding</artifactId>
+                            <version>0.2.0</version>
+                        </path>
+                        <path>
+                            <groupId>com.github.therapi</groupId>
+                            <artifactId>therapi-runtime-javadoc-scribe</artifactId>
+                            <version>0.15.0</version>
+                        </path>
+                        <path>
+                            <groupId>org.instancio</groupId>
+                            <artifactId>instancio-processor</artifactId>
+                            <version>2.2.0</version>
+                        </path>
+                        <!-- other annotation processors -->
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+
+            <!-- Correction nécessaire pour la gestion de l'UTF-8 sous Windows -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <redirectTestOutputToFile>true</redirectTestOutputToFile>
+                    <argLine>@{surefireArgLine}</argLine>
+                </configuration>
+            </plugin>
+
+            <!-- Plugin pour le reporting de la couverture du code -->
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <version>${jacoco.version}</version>
+                <executions>
+                    <execution>
+                        <id>pre-unit-test</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            <!-- Sets the path to the file which contains the execution data. -->
+                            <destFile>${project.build.directory}/jacoco.exec</destFile>
+                            <!-- Exclusion des codes générés et des loaders ayant des méthodes
+                                trop longues -->
+                            <excludes>
+                                <exclude>**/generated/**</exclude>
+                                <exclude>**/generated/*</exclude>
+                                <exclude>**/domain/model/**</exclude>
+                                <exclude>**/domain/exception/**</exclude>
+                                <exclude>**/domain/data/**</exclude>
+                                <exclude>**/infrastructure/client/**</exclude>
+                                <exclude>**/infrastructure/configuration/**</exclude>
+                                <exclude>**/infrastructure/config/**</exclude>
+                                <exclude>**/infrastructure/jpa/entity/**</exclude>
+                                <exclude>**/infrastructure/mapper/**</exclude>
+                                <exclude>**/infrastructure/restapi/dto/**</exclude>
+                                <exclude>**/infrastructure/controller/**</exclude>
+                                <exclude>**/infrastructure/repository/**</exclude>
+                                <exclude>**/infrastructure/kafkalistener/**</exclude>
+                            </excludes>
+                            <propertyName>surefireArgLine</propertyName>
+                        </configuration>
+                    </execution>
+                    <!-- Reporting TUs -->
+                    <execution>
+                        <id>post-unit-test</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                        <configuration>
+                            <!-- Sets the path to the file which contains the execution data. -->
+                            <dataFile>${project.build.directory}/jacoco.exec</dataFile>
+                            <!-- Sets the output directory for the code coverage report. -->
+                            <outputDirectory>${project.build.directory}/jacoco</outputDirectory>
+                            <!-- Exclusion des codes générés -->
+                            <excludes>
+                                <exclude>**/generated/**</exclude>
+                                <exclude>**/generated/*</exclude>
+                                <exclude>**/domain/model/**</exclude>
+                                <exclude>**/domain/exception/**</exclude>
+                                <exclude>**/domain/data/**</exclude>
+                                <exclude>**/infrastructure/client/**</exclude>
+                                <exclude>**/infrastructure/configuration/**</exclude>
+                                <exclude>**/infrastructure/config/**</exclude>
+                                <exclude>**/infrastructure/jpa/entity/**</exclude>
+                                <exclude>**/infrastructure/mapper/**</exclude>
+                                <exclude>**/infrastructure/restapi/dto/**</exclude>
+                                <exclude>**/infrastructure/controller/**</exclude>
+                                <exclude>**/infrastructure/repository/**</exclude>
+                                <exclude>**/infrastructure/kafkalistener/**</exclude>
+                            </excludes>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+
+    </build>
+</project>