diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bf9b106..3bdded7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -307,29 +307,27 @@ The main advantages in my opinion are:
`client` (adapter for an external service)
- `extension` refers to the file extension such as `ts`
-> [!TIP]
-> **FRONTEND** naming convention:
->
-> If the file's default export is a **React component** — use **[PascalCase](http://c2.com/cgi/wiki?PascalCase)**.
-> For everything else — use **[camelCase](https://wiki.c2.com/?CamelCase)**.
-
-
+
> [!NOTE]
-> **What are `PascalCase` and `camelCase`?**
+> **What are `PascalCase`, `snake_case`, and `camelCase`?**
>
> - **[PascalCase](http://c2.com/cgi/wiki?PascalCase)** is a naming convention where the first letter of every word
- > is capitalized, with no spaces or underscores between words: `YouTubeEmbed`.
-> - **[camelCase](https://wiki.c2.com/?CamelCase)** is a naming convention where the first word starts with a lowercase
- > letter and each subsequent word begins with an uppercase letter, with no spaces or underscores: `useJuryVote`.
+ > is capitalized, with no spaces or underscores between words such as `YouTubeEmbed`.
+> - **[snake_case](https://en.wikipedia.org/wiki/Snake_case)**
+> is a naming convention where words are lowercase and separated
+> with underscores (`_`), such as `first_name`.
+> - **[camelCase](https://wiki.c2.com/?CamelCase)** is a naming convention
+> where the first word starts with a lowercase letter and each subsequent
+> word begins with an uppercase letter, with no spaces or underscores
+> such as `useJuryVote`.
-#### Database Schema
+#### Database
-This section describes how the database is structured.
-The *learn-dev* platform uses a PostgreSQL relational database to persist entities.
+The *learn-dev* platform uses a **PostgreSQL** relational database to persist entities.
-##### Database Naming Conventions
+#### Database Naming Conventions
Here are the naming conventions for the **name** of our database **tables**:
@@ -341,10 +339,72 @@ Here are the naming conventions for the **name** of our database **tables**:
Do not use an underscore as the first character.
-##### Database ERD Diagram
+#### Database Schema
+
+This section describes the data model using the progressive 3 diagrams
+(MCD, MLD, and MPD) from the Merise methodology.
+This gives a view from high-level conceptual model (MCD), logical model (MLD) to
+physical model (MPD) with all the database details.
+
+
+#### MCD Diagram
+
+*MCD* stands for 🇫🇷 **Modèle Conceptuel de Données** (Conceptual Data Model).
+The *MCD diagram* is part of the *Merise* methodology and shows the entities
+and relationships without the (database) technical details.
+
+It is a high-level **business-domain** oriented diagram
+that shows the **data (entities)**, their **relationships** and **cardinalities**,
+with **NO technical and implementation details**.
+
+**Learn-dev MCD Diagram**:
+
+> 
+
+
+#### MLD Diagram
+
+*MLD* stands for 🇫🇷 **Modèle Logique de Données** (Logical Data Model).
+The **MLD diagram** is part of the _Merise_ methodology and shows
+the *Logical Data Model*.
+
+It shows the relational structure in a database-agnostic way.
+It is a transformed version of the MCD where:
+- entities become tables,
+- `1..N` relationships become foreign keys,
+- `N..N` relationships become junction tables,
+- `1..1` relationships become foreign keys.
+
+The *MLD* is shared with domain experts and application developers.
+*Domain experts* can verify that the relational structure accurately reflects
+the business.
+*Application developers* can then start creating the entities.
+
+**Learn-dev MLD Diagram**:
+
+> 
+
+
+#### MPD Diagram
+
+*MPD* stands for 🇫🇷*Modèle Physique des Données* (Physical Data Model).
+
+This diagram is exhaustive and database-specific.
+It contains all the tables, fields, keys,
+database-specific data types, and constraints...
+It is aimed at database administrators and application developers.
+It can be used to implement the data model in the database.
+Database administrators use it to create the migration scripts.
+
+**Learn-dev MPD Diagram**:
+
+> TODO: 
+
+
+#### ERD Diagram
+
+> TODO: 
-The **Entity Relationships Diagram** (ERD)
-is available as an [SVG image](https://raw.githubusercontent.com/ebouchut/learn-dev/dev/docs/ERD.svg)
> [!NOTE]
> This diagram uses [Crow's foot notation](https://mermaid.js.org/syntax/entityRelationshipDiagram.html#relationship-syntax)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..41fdf99
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,61 @@
+# Ignore existing files with the same name as phony targets
+.PHONY: help diagrams mcd mld mpd ddl clean
+
+# Default make target used if none specified
+.DEFAULT_GOAL := help
+
+# Display the syntax with available targets
+help:
+ @echo "Available targets:"
+ @echo " make diagrams — generate MCD, MLD, and MPD"
+ @echo " make mcd — generate MCD"
+ @echo " make mld — generate MLD"
+ @echo " make mpd — generate MPD"
+ @echo " make ddl — regenerate DDL (SQL with Postgres database structure)"
+ @echo " make clean — remove generated diagrams"
+
+# Generate all database diagrams (MCD, MLD, MPD)
+diagrams: mcd mld mpd
+ @echo "All diagrams generated (MCD, MLD, MPD)"
+
+# Generate MCD from Mocodo source
+mcd:
+ @echo "Generating MCD..."
+ mocodo --input docs/database/mcd/learn-dev.mcd --output_dir docs/database/mcd --colors brewer+1
+ @echo "MCD generated in docs/database/mcd/"
+
+# Generate MLD (2 step process):
+# - transform MCD source into a MLD source: docs/database/mld/learn-dev_mld.mcd
+# - Render the MLD source
+mld:
+ @echo "Generating MLD..."
+ mocodo --input docs/database/mcd/learn-dev.mcd --output_dir docs/database/mld --transform mld diagram
+ rm -f docs/database/mld/learn-dev.*
+ mocodo --input docs/database/mld/learn-dev_mld.mcd --output_dir docs/database/mld --colors ocean
+ @echo "MLD generated in docs/database/mld/learn-dev_mld.svg"
+
+# Generate MPD from the PostgreSQL database
+mpd:
+ @echo "Generating MPD from PostgreSQL Database..."
+ @mkdir -p docs/database/mpd
+ @test -n "$(TBLS_DSN)" || (echo "TBLS_DSN is required (e.g., postgres://user:pass@host:5432/dbname)" >&2; exit 1)
+ tbls doc "$(TBLS_DSN)" docs/database/mpd --force
+ @echo "MPD generated in docs/database/mpd/"
+
+# Generate a SQL file to create the database structure (tables, associations)
+# (with Postgres DDL syntax)
+ddl:
+ @echo "Generating DDL (Postgres SQL syntax)..."
+ @mkdir -p docs/database/ddl
+ mocodo --input docs/database/mcd/learn-dev.mcd --output_dir docs/database/ddl -t postgres
+ @echo "DDL generated in docs/database/ddl/"
+
+# Clean up generated diagram files
+clean:
+ @echo "Cleaning up generated diagrams..."
+ rm -f docs/database/mcd/learn-dev.svg
+ rm -f docs/database/mcd/learn-dev_geo.json
+ rm -f docs/database/mld/*
+ rm -f docs/database/mpd/*
+ rm -f docs/database/ddl/*
+ @echo "Cleaned"
diff --git a/README.md b/README.md
index 070824a..978530a 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,45 @@ Install _Docker_ and _Docker Compose_:
```
- on [Windows and Linux](https://docs.docker.com/get-started/get-docker/)
+### Python Setup
+
+This is **optional** if you only need **to run the application**.
+
+This is necessary in order to regenerate the MERISE database diagrams
+(MCD, MLD and MPD) after any changes have been made to the database design.
+
+You will need to install *Python* and:
+- **`mocodo`**: a CLI tool to generate the MCD and MLD database diagrams
+ from a text-file description of the conceptual data model.
+- **`tbls`**: a CLI tool to reverse engineer the live database to generate the MPD.
+
+Here is the procedure:
+
+- [ ] Install Python
+ - Install Python on macOS
+ ```shell
+ brew install python@3.14
+ ```
+ - Install Python on other OSes:
+ https://docs.python-guide.org/en/latest/starting/installation/
+- [ ] Create a Python Virtual Environment:
+ ```shell
+ # cd to the folder where you cloned the repository
+ python3 -m venv venv # Do it once
+ source venv/bin/activate # Run this line each time you open a new shell/terminal/window/tab
+ ```
+- [ ] Install **[mocodo](https://laowantong.github.io/mocodo/doc/fr_refman.html#Installation-et-lancement-du-programme)**
+ ```shell
+ pip install 'mocodo[svg,clipboard]'
+ ```
+- [ ] Install **[tbls](https://github.com/k1LoW/tbls#install)**
+ ```shell
+ # On macOS
+ brew install tbls
+
+ # or any OS with Go installed
+ go install github.com/k1LoW/tbls@latest
+ ```
## Configuration
diff --git a/docs/database/mcd/learn-dev.mcd b/docs/database/mcd/learn-dev.mcd
new file mode 100644
index 0000000..1948f43
--- /dev/null
+++ b/docs/database/mcd/learn-dev.mcd
@@ -0,0 +1,28 @@
+% learn-dev MCD (Modele Conceptuel des Données).
+% This text file uses Mocodo-syntax to describe the MCD.
+%
+% See:
+% - GitHub Repository: https://github.com/laowantong/mocodo
+% - Syntax: https://laowantong.github.io/mocodo/doc/fr_refman.html#Syntaxe-de-description-d'un-MCD
+% Usage:
+% mocodo --input docs/database/mcd/learn-dev.mcd --output_dir docs/database/mcd --colors brewer+1
+
+:
+Email Token: token_id, token, expires_at, used_at
+Audit Log: log_id, action_type, entity_type, entity_id, description, ip_address, user_agent, was_successful, error_message, metadata
+:
+
+Reset Token: token_id, token, expires_at, used_at, ip_address
+Receives, 11 Email Token, 0N User
+Performs, 01 Audit Log, 0N User
+:
+
+Requests, 11 Reset Token, 0N User
+User: user_id, username, email, password, first_name, last_name, is_active, is_verified, is_locked, failed_login_attempts, last_login_at, password_changed_at
+Holds, 0N User, 0N Role : assigned_at, assigned_by
+Role: role_id, role_name, description, is_active
+
+:
+Owns, 11 Refresh Token, 0N User
+Refresh Token: token_id, token, expires_at, revoked_at, revoked_reason, ip_address, user_agent, last_used_at
+:
\ No newline at end of file
diff --git a/docs/database/mcd/learn-dev.svg b/docs/database/mcd/learn-dev.svg
new file mode 100644
index 0000000..066f1fb
--- /dev/null
+++ b/docs/database/mcd/learn-dev.svg
@@ -0,0 +1,197 @@
+
+
+
\ No newline at end of file
diff --git a/docs/database/mcd/learn-dev_geo.json b/docs/database/mcd/learn-dev_geo.json
new file mode 100644
index 0000000..7d256b0
--- /dev/null
+++ b/docs/database/mcd/learn-dev_geo.json
@@ -0,0 +1,43 @@
+{
+ "width": 551,
+ "height": 819,
+ "cx": [
+ [ "EMAIL_TOKEN", 230 ],
+ [ "AUDIT_LOG", 382 ],
+ [ "RESET_TOKEN", 73 ],
+ [ "RECEIVES", 230 ],
+ [ "PERFORMS", 382 ],
+ [ "REQUESTS", 73 ],
+ [ "USER", 230 ],
+ [ "HOLDS", 382 ],
+ [ "ROLE", 499 ],
+ [ "OWNS", 230 ],
+ [ "REFRESH_TOKEN", 382 ]
+ ],
+ "cy": [
+ [ "EMAIL_TOKEN", 115 ],
+ [ "AUDIT_LOG", 115 ],
+ [ "RESET_TOKEN", 274 ],
+ [ "RECEIVES", 274 ],
+ [ "PERFORMS", 274 ],
+ [ "REQUESTS", 485 ],
+ [ "USER", 485 ],
+ [ "HOLDS", 485 ],
+ [ "ROLE", 485 ],
+ [ "OWNS", 721 ],
+ [ "REFRESH_TOKEN", 721 ]
+ ],
+ "shift": [
+ [ "RECEIVES,EMAIL_TOKEN,0", 0 ],
+ [ "RECEIVES,USER,0", 0 ],
+ [ "PERFORMS,AUDIT_LOG,0", 0 ],
+ [ "PERFORMS,USER,0", 0 ],
+ [ "REQUESTS,RESET_TOKEN,0", 0 ],
+ [ "REQUESTS,USER,0", 0 ],
+ [ "HOLDS,USER,0", 0 ],
+ [ "HOLDS,ROLE,0", 0 ],
+ [ "OWNS,REFRESH_TOKEN,0", 0 ],
+ [ "OWNS,USER,0", 0 ]
+ ],
+ "ratio": []
+}
diff --git a/docs/database/mld/learn-dev_geo.json b/docs/database/mld/learn-dev_geo.json
new file mode 100644
index 0000000..7d256b0
--- /dev/null
+++ b/docs/database/mld/learn-dev_geo.json
@@ -0,0 +1,43 @@
+{
+ "width": 551,
+ "height": 819,
+ "cx": [
+ [ "EMAIL_TOKEN", 230 ],
+ [ "AUDIT_LOG", 382 ],
+ [ "RESET_TOKEN", 73 ],
+ [ "RECEIVES", 230 ],
+ [ "PERFORMS", 382 ],
+ [ "REQUESTS", 73 ],
+ [ "USER", 230 ],
+ [ "HOLDS", 382 ],
+ [ "ROLE", 499 ],
+ [ "OWNS", 230 ],
+ [ "REFRESH_TOKEN", 382 ]
+ ],
+ "cy": [
+ [ "EMAIL_TOKEN", 115 ],
+ [ "AUDIT_LOG", 115 ],
+ [ "RESET_TOKEN", 274 ],
+ [ "RECEIVES", 274 ],
+ [ "PERFORMS", 274 ],
+ [ "REQUESTS", 485 ],
+ [ "USER", 485 ],
+ [ "HOLDS", 485 ],
+ [ "ROLE", 485 ],
+ [ "OWNS", 721 ],
+ [ "REFRESH_TOKEN", 721 ]
+ ],
+ "shift": [
+ [ "RECEIVES,EMAIL_TOKEN,0", 0 ],
+ [ "RECEIVES,USER,0", 0 ],
+ [ "PERFORMS,AUDIT_LOG,0", 0 ],
+ [ "PERFORMS,USER,0", 0 ],
+ [ "REQUESTS,RESET_TOKEN,0", 0 ],
+ [ "REQUESTS,USER,0", 0 ],
+ [ "HOLDS,USER,0", 0 ],
+ [ "HOLDS,ROLE,0", 0 ],
+ [ "OWNS,REFRESH_TOKEN,0", 0 ],
+ [ "OWNS,USER,0", 0 ]
+ ],
+ "ratio": []
+}
diff --git a/docs/database/mld/learn-dev_mld.mcd b/docs/database/mld/learn-dev_mld.mcd
new file mode 100644
index 0000000..4b5d4b1
--- /dev/null
+++ b/docs/database/mld/learn-dev_mld.mcd
@@ -0,0 +1,25 @@
+%%mocodo
+:::
+Email Token: token_id, token, expires_at, used_at, #user_id > User > user_id
+:
+Audit Log: log_id, action_type, entity_type, entity_id, description, ip_address, user_agent, was_successful, error_message, metadata, #user_id > User > user_id
+:::
+
+
+:
+Reset Token: token_id, token, expires_at, used_at, ip_address, #user_id > User > user_id
+:::::::
+
+
+:::
+User: user_id, username, email, password, first_name, last_name, is_active, is_verified, is_locked, failed_login_attempts, last_login_at, password_changed_at
+:
+Holds: #user_id > User > user_id, _#role_id > Role > role_id, assigned_at, assigned_by
+:
+Role: role_id, role_name, description, is_active
+:
+
+
+:::::
+Refresh Token: token_id, token, expires_at, revoked_at, revoked_reason, ip_address, user_agent, last_used_at, #user_id > User > user_id
+:::
diff --git a/docs/database/mld/learn-dev_mld.md b/docs/database/mld/learn-dev_mld.md
new file mode 100644
index 0000000..375dbd9
--- /dev/null
+++ b/docs/database/mld/learn-dev_mld.md
@@ -0,0 +1,9 @@
+
+
+- **Audit Log** (log_id, action_type, entity_type, entity_id, description, ip_address, user_agent, was_successful, error_message, metadata, _#user_id_)
+- **Email Token** (token_id, token, expires_at, used_at, _#user_id_)
+- **Holds** (_#user_id_, _#role_id_, assigned_at, assigned_by)
+- **Refresh Token** (token_id, token, expires_at, revoked_at, revoked_reason, ip_address, user_agent, last_used_at, _#user_id_)
+- **Reset Token** (token_id, token, expires_at, used_at, ip_address, _#user_id_)
+- **Role** (role_id, role_name, description, is_active)
+- **User** (user_id, username, email, password, first_name, last_name, is_active, is_verified, is_locked, failed_login_attempts, last_login_at, password_changed_at)
diff --git a/docs/database/mld/learn-dev_mld.svg b/docs/database/mld/learn-dev_mld.svg
new file mode 100644
index 0000000..d9984d6
--- /dev/null
+++ b/docs/database/mld/learn-dev_mld.svg
@@ -0,0 +1,171 @@
+
+
+
\ No newline at end of file
diff --git a/docs/database/mld/learn-dev_mld_geo.json b/docs/database/mld/learn-dev_mld_geo.json
new file mode 100644
index 0000000..fc2fc81
--- /dev/null
+++ b/docs/database/mld/learn-dev_mld_geo.json
@@ -0,0 +1,24 @@
+{
+ "width": 772,
+ "height": 694,
+ "cx": [
+ [ "EMAIL_TOKEN", 302 ],
+ [ "AUDIT_LOG", 514 ],
+ [ "RESET_TOKEN", 102 ],
+ [ "USER", 302 ],
+ [ "HOLDS", 514 ],
+ [ "ROLE", 691 ],
+ [ "REFRESH_TOKEN", 514 ]
+ ],
+ "cy": [
+ [ "EMAIL_TOKEN", 124 ],
+ [ "AUDIT_LOG", 124 ],
+ [ "RESET_TOKEN", 263 ],
+ [ "USER", 410 ],
+ [ "HOLDS", 410 ],
+ [ "ROLE", 410 ],
+ [ "REFRESH_TOKEN", 587 ]
+ ],
+ "shift": [],
+ "ratio": []
+}