diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 030f659285c23967ecfe5172433777c9b5ad982f..02e0e700e3a3fef43d3527b6389771f3a9f9133d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,7 +4,7 @@ This document aims to specify how we currently work on this project, and how to
 
 ## General organisation
 
-To keep track of the past, present and future work, we use the gitlab repository as a source of trust for the progress of the project. All the bugs, *to do*, improvement ideas and discussions are developed in the [issues](https://forge.uclouvain.be/sbibauw/languagelab/-/issues).
+To keep track of the past, present and future work, we use the gitlab repository as a source of trust for the progress of the project. All the bugs, _to do_, improvement ideas and discussions are developed in the [issues](https://forge.uclouvain.be/sbibauw/languagelab/-/issues).
 
 The issues are categorised using tags. There are two types of tags. Gray tags are used to specify the kind of issues: UX, Studies, AI, topics, ... New kinds could be created at any time to reflect the progress and the targets of the project. Colored tags are used to specify the priority of an issue. Here are the different priorities:
 
@@ -12,7 +12,7 @@ The issues are categorised using tags. There are two types of tags. Gray tags ar
 - To do: New functionalities or improvements already discussed and validated.
 - Waiting: Issues where work has already started, but is waiting someone else's answer or opinion to continue.
 - To review: Developed functionalities and improvements waiting for a review.
-- Nice to have: Non-priority features or improvements, that would be *nice to have*.
+- Nice to have: Non-priority features or improvements, that would be _nice to have_.
 - Open for discussions: Features and improvements that still need more discussions before being started.
 - Won't: Rejected features and improvements.
 
@@ -20,7 +20,6 @@ To keep track of who is working on what, it's better to assign our-self an issue
 
 The different planned versions and the issues assigned to them are presented in the form of [milestones](https://forge.uclouvain.be/sbibauw/languagelab/-/milestones). The general idea is to finish a milestone before working on the next one.
 
-
 ## Getting started
 
 #### Requirements
@@ -31,11 +30,12 @@ The different planned versions and the issues assigned to them are presented in
 
 #### Configuration
 
-The application is configured using environment variables for both the frontend and the backend. The best way to specify them is through the `.env` file. 
+The application is configured using environment variables for both the frontend and the backend. The best way to specify them is through the `.env` file.
 
 Check `backend/app/config.py` and `frontend/src/lib/config.ts` for an extensive list of the environment variables in use and their default values.
 
 Here is a simple example:
+
 ```sh
 LANGUAGELAB_JWT_SECRET_KEY=abc
 LANGUAGELAB_JWT_REFRESH_SECRET_KEY=efg
@@ -44,6 +44,7 @@ LANGUAGELAB_ADMIN_PASSWORD=admin
 LANGUAGELAB_CALCOM_SECRET=hij
 ALLOWED_ORIGINS=*
 ```
+
 âš  Be sure to NEVER push the `.env` to the repo, and to use long and random keys for tests and deployment âš 
 
 #### Backend dependencies
@@ -69,6 +70,7 @@ pip install -r ../requirements.txt
 #### Pre-Commit hooks
 
 The CI run `npm run lint` and `black --check --verbose` on every commit, on every branch. To prevent a failing CI, there is a pre-commit hook ([docs](https://git-scm.com/book/ms/v2/Customizing-Git-Git-Hooks)). To use it, you can configure the local repository to use the hooks available directly on the repository:
+
 ```sh
 git config --local core.hooksPath .githooks
 ```
@@ -102,16 +104,20 @@ As alembic is backend-specific, you have to go into the `backend` folder for the
 :warning: Alembic versions work as a linked list. Each version refer it's previous and next version. To prevent having to tweak "weird" things, ensure you're up-to-date with any other version update. You could need to redo those steps if someone else merged a change in the meantime.
 
 To create a migration script, you can run
+
 ```sh
 alembic revision -m "<change message>"
 ```
+
 It will tell you the name of the new file, where you can implement the changes.
 
 In most cases, you should only need to change the functions:
- - `upgrade` contains all your changes
- - `downgrade` drop them. This is **deeply advised** to allow to rollback in case of issue, especially in production.
+
+- `upgrade` contains all your changes
+- `downgrade` drop them. This is **deeply advised** to allow to rollback in case of issue, especially in production.
 
 Here are the most useful alembic functions:
+
 ```python
 # Create a table
 op.create_table(
@@ -134,9 +140,11 @@ op.alter_column('account', 'id', new_column_name='uuid')
 ```
 
 To update to the latest version:
+
 ```sh
 alembic upgrade head
 ```
+
 :warning: You will also need to run that if someone else wrote a version. This is NOT automatic for the local environment.
 
 For more in depth information, check the [official documentation](https://alembic.sqlalchemy.org/en/latest/).
diff --git a/backend/alembic/README b/backend/alembic/README
index 98e4f9c44effe479ed38c66ba922e7bcc672916f..2500aa1bcf726a14c436070389837be3666ba96f 100644
--- a/backend/alembic/README
+++ b/backend/alembic/README
@@ -1 +1 @@
-Generic single-database configuration.
\ No newline at end of file
+Generic single-database configuration.
diff --git a/backend/app/crud/__init__.py b/backend/app/crud/__init__.py
index 1a280d17d74e2db5b9235f927249906d9d737760..b8a8c2a8b60dc83c89d65e489b6133a8930a4b86 100644
--- a/backend/app/crud/__init__.py
+++ b/backend/app/crud/__init__.py
@@ -9,10 +9,13 @@ from hashing import Hasher
 
 from crud.tests import *
 from crud.studies import *
+from crud.tasks import *
 
 
 def get_user(db: Session, user_id: int):
-    return db.query(models.User).filter(models.User.id == user_id).first()
+    user = db.query(models.User).filter(models.User.id == user_id).first()
+
+    return user
 
 
 def get_user_by_email(db: Session, email: str):
diff --git a/backend/app/crud/studies.py b/backend/app/crud/studies.py
index ce4923c55c3566c4a7ad3b2df2b4c87737ad012f..044f84ba26c366dd9c89a44bb8bd629d3e5f8168 100644
--- a/backend/app/crud/studies.py
+++ b/backend/app/crud/studies.py
@@ -254,3 +254,9 @@ def create_study_info(
     db.commit()
     db.refresh(db_study_info)
     return db_study_info
+
+
+def add_user_to_study(db: Session, study: models.Study, user: models.User):
+    study.users.append(user)
+    db.commit()
+    db.refresh(study)
diff --git a/backend/app/crud/tasks.py b/backend/app/crud/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..f487f1b86cedad49ab21d0589a9fd96d91ba3875
--- /dev/null
+++ b/backend/app/crud/tasks.py
@@ -0,0 +1,60 @@
+from sqlalchemy.orm import Session
+
+import models
+import schemas
+
+
+def get_tasks(db: Session, skip: int = 0):
+    return db.query(models.Task).offset(skip).all()
+
+
+def get_task(db: Session, task_id: int):
+    return db.query(models.Task).filter(models.Task.id == task_id).first()
+
+
+def create_task(db: Session, task: schemas.TaskCreate) -> models.Task:
+    db_task = models.Task(**task.model_dump())
+    db.add(db_task)
+    db.commit()
+    db.refresh(db_task)
+    return db_task
+
+
+def update_task(db: Session, task: schemas.TaskCreate, task_id: int) -> None:
+    db.query(models.Task).filter(models.Task.id == task_id).update(
+        {**task.model_dump(exclude_unset=True)}
+    )
+    db.commit()
+
+
+def delete_task(db: Session, task_id: int) -> None:
+    db.query(models.Task).filter(models.Task.id == task_id).delete()
+    db.commit()
+
+
+def create_task_status(
+    db: Session, task_status: schemas.TaskStatusCreate
+) -> models.TaskStatus:
+    db_task_status = models.TaskStatus(**task_status.model_dump())
+    db.add(db_task_status)
+    db.commit()
+    db.refresh(db_task_status)
+    return db_task_status
+
+
+def get_task_status_session(db: Session, session_id: int) -> models.TaskStatus | None:
+    return (
+        db.query(models.TaskStatus)
+        .filter(models.TaskStatus.session_id == session_id)
+        .order_by(models.TaskStatus.created_at.desc())
+        .first()
+    )
+
+
+def get_task_status_completed(db: Session, student_id: int) -> list[models.TaskStatus]:
+    return (
+        db.query(models.TaskStatus)
+        .filter(models.TaskStatus.student_id == student_id)
+        .filter(models.TaskStatus.status == "finish")
+        .all()
+    )
diff --git a/backend/app/main.py b/backend/app/main.py
index ac9c7b2918fa444aaa85a7fca0091552beb2b841..fec8ab0a205a0481b0613d7b703e0ff1aee429ae 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -28,6 +28,7 @@ import config
 from security import jwt_cookie, get_jwt_user
 from routes.tests import testRouter
 from routes.studies import studiesRouter
+from routes.tasks import taskRouter
 
 websocket_users = defaultdict(lambda: defaultdict(set))
 websocket_users_global = defaultdict(set)
@@ -128,6 +129,13 @@ def register(
 
     user = crud.create_user(db=db, user=user_data)
 
+    if register.study_id:
+        study = crud.get_study(db, register.study_id)
+        if study is None:
+            raise HTTPException(status_code=404, detail="Study not found")
+
+        crud.add_user_to_study(db, study, user)
+
     return user.id
 
 
@@ -1057,5 +1065,6 @@ v1Router.include_router(studyRouter)
 v1Router.include_router(websocketRouter)
 v1Router.include_router(testRouter)
 v1Router.include_router(studiesRouter)
+v1Router.include_router(taskRouter)
 apiRouter.include_router(v1Router)
 app.include_router(apiRouter)
diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py
index 131af45538f6e3c6e8ea62551bd1fee65989250a..206737aa04b7e86d0731a9197ee30c6be555b80e 100644
--- a/backend/app/models/__init__.py
+++ b/backend/app/models/__init__.py
@@ -18,6 +18,7 @@ from utils import datetime_aware
 
 from models.studies import *
 from models.tests import *
+from models.tasks import *
 
 
 class UserType(Enum):
diff --git a/backend/app/models/tasks.py b/backend/app/models/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..d36a8e1131f8a88a7d5209bb814d1622dac2cd47
--- /dev/null
+++ b/backend/app/models/tasks.py
@@ -0,0 +1,25 @@
+from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
+from utils import datetime_aware
+from database import Base
+
+
+class Task(Base):
+    __tablename__ = "tasks"
+
+    id = Column(Integer, primary_key=True, index=True)
+    level = Column(String, nullable=False)
+    shortTitle = Column(String, nullable=False)
+    instructions = Column(String, nullable=True)
+    learnerInstructions = Column(String, nullable=True)
+    examples = Column(String, nullable=False)
+
+
+class TaskStatus(Base):
+    __tablename__ = "task_status"
+    id = Column(Integer, primary_key=True, index=True)
+    task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False)
+    student_id = Column(Integer, ForeignKey("users.id"), nullable=False)
+    tutor_id = Column(Integer, ForeignKey("users.id"), nullable=False)
+    session_id = Column(Integer, ForeignKey("sessions.id"), nullable=False)
+    status = Column(String, nullable=False)
+    created_at = Column(DateTime, default=datetime_aware)
diff --git a/backend/app/routes/decorators.py b/backend/app/routes/decorators.py
index 6cd315b4f26303f90261d449ff3eff78334b1408..e7e944c893b2d48ce30db7b036ab3b6b8c848a8d 100644
--- a/backend/app/routes/decorators.py
+++ b/backend/app/routes/decorators.py
@@ -19,3 +19,18 @@ def require_admin(error: str):
         return wrapper
 
     return decorator
+
+
+def require_tutor(error: str):
+    def decorator(func: Callable):
+        def wrapper(*args, current_user: schemas.User, **kwargs):
+            if not check_user_level(current_user, schemas.UserType.TUTOR):
+                raise HTTPException(
+                    status_code=401,
+                    detail=error,
+                )
+            return func(*args, current_user=current_user, **kwargs)
+
+        return wrapper
+
+    return decorator
diff --git a/backend/app/routes/studies.py b/backend/app/routes/studies.py
index d4ce1f466dca0b03771aa8b917440fd2f46b9fc8..5e0b791320b82fe5fd24dae21aa29b9589c2fb5b 100644
--- a/backend/app/routes/studies.py
+++ b/backend/app/routes/studies.py
@@ -92,3 +92,27 @@ def create_study_info(
     db: Session = Depends(get_db),
 ):
     return crud.create_study_info(db, study_id, study_info)
+
+
+@studiesRouter.post("/{study_id}/users/{user_id}", status_code=status.HTTP_201_CREATED)
+def add_user_to_study(
+    study_id: int,
+    user_id: int,
+    current_user: schemas.User,
+    db: Session = Depends(get_db),
+):
+    if current_user.id != user_id and current_user.type != schemas.UserType.ADMIN:
+        raise HTTPException(
+            status_code=403,
+            detail="You do not have permission to add a user to this study.",
+        )
+
+    study = crud.get_study(db, study_id)
+    if study is None:
+        raise HTTPException(status_code=404, detail="Study not found")
+
+    user = crud.get_user(db, user_id)
+    if user is None:
+        raise HTTPException(status_code=404, detail="User not found")
+
+    crud.add_user_to_study(db, study, user)
diff --git a/backend/app/routes/tasks.py b/backend/app/routes/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..043143e826f563afc4ff790ccb3e187a1c185c7d
--- /dev/null
+++ b/backend/app/routes/tasks.py
@@ -0,0 +1,95 @@
+from fastapi import APIRouter, Depends, HTTPException, status
+from sqlalchemy.orm import Session
+
+import crud
+import schemas
+from database import get_db
+from routes.decorators import require_admin, require_tutor
+
+taskRouter = APIRouter(prefix="/tasks", tags=["Tasks"])
+
+
+@require_admin("You do not have permission to create a task.")
+@taskRouter.post("", status_code=status.HTTP_201_CREATED)
+def create_task(
+    task: schemas.TaskCreate,
+    db: Session = Depends(get_db),
+):
+    return crud.create_task(db, task).id
+
+
+@require_admin("You do not have permission to edit a task.")
+@taskRouter.put("/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
+def update_task(
+    task_id: int,
+    task: schemas.TaskCreate,
+    db: Session = Depends(get_db),
+):
+    return crud.update_task(db, task, task_id)
+
+
+@require_admin("You do not have permission to delete a task.")
+@taskRouter.delete("/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_task(
+    task_id: int,
+    db: Session = Depends(get_db),
+):
+    return crud.delete_task(db, task_id)
+
+
+@taskRouter.get("", response_model=list[schemas.Task])
+def get_tasks(
+    skip: int = 0,
+    db: Session = Depends(get_db),
+):
+    return crud.get_tasks(db, skip)
+
+
+@require_tutor("You do not have permission to create a task status.")
+@taskRouter.post("/status", status_code=status.HTTP_201_CREATED)
+def create_task_status(
+    task_status: schemas.TaskStatusCreate,
+    db: Session = Depends(get_db),
+):
+    return crud.create_task_status(db, task_status).id
+
+
+@taskRouter.get("/status/sessions/{session_id}", response_model=schemas.TaskStatus)
+def get_task_status_session(
+    session_id: int,
+    db: Session = Depends(get_db),
+):
+    task_status = crud.get_task_status_session(db, session_id)
+    if task_status is None:
+        raise HTTPException(
+            status_code=status.HTTP_404_NOT_FOUND, detail="Task status not found"
+        )
+    return task_status
+
+
+@taskRouter.get(
+    "/status/completed/students/{student_id}", response_model=list[schemas.TaskStatus]
+)
+def get_task_status_completed(
+    student_id: int,
+    db: Session = Depends(get_db),
+):
+    task_status = crud.get_task_status_completed(db, student_id)
+    if task_status is None:
+        raise HTTPException(
+            status_code=status.HTTP_404_NOT_FOUND, detail="Task status not found"
+        )
+    return task_status
+
+
+@taskRouter.get("/{task_id}", response_model=schemas.Task)
+def get_task(
+    task_id: int,
+    db: Session = Depends(get_db),
+):
+    task = crud.get_task(db, task_id)
+    if task is None:
+        raise HTTPException(
+            status_code=status.HTTP_404_NOT_FOUND, detail="Task not found"
+        )
+    return task
diff --git a/backend/app/routes/tests.py b/backend/app/routes/tests.py
index f310d546cfad88c57636aad32c2d14aaa6ac4c26..b19275d8bf53b4e849d942a7f720191bf3d896d5 100644
--- a/backend/app/routes/tests.py
+++ b/backend/app/routes/tests.py
@@ -1,6 +1,5 @@
 from fastapi import APIRouter, Depends, HTTPException, status
 from sqlalchemy.orm import Session
-from starlette.status import HTTP_200_OK
 
 import crud
 import schemas
diff --git a/backend/app/schemas/__init__.py b/backend/app/schemas/__init__.py
index f8dbff79fa40cb009ea682bec71c6882d439ab38..7affcd05d54f939700969e9fe9e00de67c05d520 100644
--- a/backend/app/schemas/__init__.py
+++ b/backend/app/schemas/__init__.py
@@ -3,6 +3,7 @@ from pydantic import BaseModel, NaiveDatetime
 from schemas.studies import *
 from schemas.tests import *
 from schemas.users import *
+from schemas.tasks import *
 
 
 class LoginData(BaseModel):
@@ -15,6 +16,7 @@ class RegisterData(BaseModel):
     password: str
     nickname: str
     is_tutor: bool
+    study_id: int | None = None
 
 
 class ContactCreate(BaseModel):
diff --git a/backend/app/schemas/tasks.py b/backend/app/schemas/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..71312f86ecc0651a54b09b5260b12aa599fc9196
--- /dev/null
+++ b/backend/app/schemas/tasks.py
@@ -0,0 +1,26 @@
+from pydantic import BaseModel, NaiveDatetime
+
+
+class TaskCreate(BaseModel):
+    level: str
+    shortTitle: str
+    instructions: str
+    learnerInstructions: str
+    examples: str
+
+
+class Task(TaskCreate):
+    id: int
+
+
+class TaskStatusCreate(BaseModel):
+    task_id: int
+    student_id: int
+    tutor_id: int
+    session_id: int
+    status: str
+    created_at: NaiveDatetime | None = None
+
+
+class TaskStatus(TaskStatusCreate):
+    id: int
diff --git a/backend/app/schemas/users.py b/backend/app/schemas/users.py
index ff07d5df38b7d8f29aa0ecbaf068250eb941e728..b48075f7cec48d0a83f6eb594602a510fa35907a 100644
--- a/backend/app/schemas/users.py
+++ b/backend/app/schemas/users.py
@@ -1,4 +1,4 @@
-from pydantic import BaseModel, NaiveDatetime
+from pydantic import BaseModel, NaiveDatetime, model_validator
 
 from models import UserType
 
@@ -21,6 +21,16 @@ class User(BaseModel):
     tutor_list: list[str] | None = []
     my_tutor: str | None = None
     my_slots: list[dict] | None = []
+    studies_id: list[int] = []
+
+    @model_validator(mode="before")
+    @classmethod
+    def add_studies_id(cls, data):
+        if hasattr(data, "__dict__"):
+            data.studies_id = []
+            if hasattr(data, "studies") and data.studies:
+                data.studies_id = [study.id for study in data.studies]
+        return data
 
     class Config:
         from_attributes = True
@@ -37,6 +47,7 @@ class User(BaseModel):
             "home_language": self.home_language,
             "target_language": self.target_language,
             "birthdate": self.birthdate.isoformat() if self.birthdate else None,
+            "studies_id": self.studies_id,
         }
 
 
diff --git a/docker-compose.yaml b/docker-compose.yaml
index f32cda31f1eff0d3ba1cfa9710c7502da3a5fd03..84e36ffde42df8fe7d7566346c08144a20bf3bb7 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -74,7 +74,7 @@ services:
       - ADMIN_EMAIL=${LANGUAGELAB_ADMIN_EMAIL}
       - ADMIN_PASSWORD=${LANGUAGELAB_ADMIN_PASSWORD}
       - CALCOM_SECRET=${LANGUAGELAB_CALCOM_SECRET}
-      - ALLOWED_ORIGINS=https://dev.languagelab.be,https://api.dev.languagelab.be
+      - ALLOWED_ORIGINS=*
     volumes:
       - /mnt/data/languagelab/backend:/data
       - /etc/timezone:/etc/timezone:ro
diff --git a/docs/cal.com.md b/docs/cal.com.md
index e77616c3a53ee2e70d0f1d6262a867bba27c20ca..e8d552606c17f20cdf1d9650a024ec3a2a9b3152 100644
--- a/docs/cal.com.md
+++ b/docs/cal.com.md
@@ -1,6 +1,7 @@
 LanguageLab utilise le site https://cal.com pour programmer les séances entre les tuteurs et les étudiants.
 
 Afin que l'intégration soit réussie, il est nécessaire de suivre les étapes suivantes:
- - Créer un compte sur https://cal.com.
- - Créer un nouveau type d'événement de 60 mins (https://app.cal.com/event-types -> [+ Nouveau]) avec un nom cohérent, par exemple `languagelab-tutorat`
- - Indiquer le lien de l'évenement dans https://languagelab.sipr.ucl.ac.be/tutor/timeslots. Example: `username/languagelab-tutorat`
+
+- Créer un compte sur https://cal.com.
+- Créer un nouveau type d'événement de 60 mins (https://app.cal.com/event-types -> [+ Nouveau]) avec un nom cohérent, par exemple `languagelab-tutorat`
+- Indiquer le lien de l'évenement dans https://languagelab.sipr.ucl.ac.be/tutor/timeslots. Example: `username/languagelab-tutorat`
diff --git a/frontend/src/lang/en.json b/frontend/src/lang/en.json
index 7c0efdc7e719ddcbf00639af6462083498e0d0d4..d3f6b7a090b33a383d22e42ae50f6000cf3a1a7a 100644
--- a/frontend/src/lang/en.json
+++ b/frontend/src/lang/en.json
@@ -5,7 +5,8 @@
 		"metadataWarning": "Please complete the post-registration form before using the application.",
 		"admin": {
 			"sessions": "Sessions",
-			"users": "Users"
+			"users": "Users",
+			"studies": "Studies"
 		},
 		"availability": "Availability",
 		"language": "Language",
@@ -148,7 +149,13 @@
 			"toggle": "Participants",
 			"title": "Study Title",
 			"OrganisationUni": "Organization/University",
-			"Address": "Address"
+			"Address": "Address",
+			"description": "Description",
+			"email": "E-mail",
+			"groups": "groups",
+			"questions": "questions",
+			"tests": "tests",
+			"users": "Users"
 		}
 	},
 	"button": {
@@ -165,7 +172,9 @@
 		"save": "Save",
 		"update": "Update",
 		"updated": "Updated!",
-		"continue": "Continue"
+		"continue": "Continue",
+		"delete": "DELETE",
+		"remove": "Withdraw"
 	},
 	"surveys": {
 		"complete": "Thank you for participating!",
@@ -299,20 +308,20 @@
 				"studyD": "Longitudinal study of foreign language tutoring",
 				"title": "Study information",
 				"university": "University",
-				"universityD": "Catholic University of Louvain (UCLouvain)"
+				"universityD": "Université catholique de Louvain (UCLouvain)"
 			},
 			"title": "Information document and informed consent"
 		},
-		"continue": "Aut sint sint et nihil aut. \nQuia nihil eos rerum neque exercitationem molestiae. \nAut ab accusantium consequatur rerum architecto voluptas. \nRepudiandae minima nemo vitae tempore. \nMolestiae rerum aliquid ut fugit eligendi. \nTempore eum id nobis sunt deleniti et non ducimus. \nMaiores perferendis non consequuntur neque nostrum. \nOdio itaque fugiat no. \nLaboriosam sint voluptatem aut placeat et perferendis. \nSed quam voluptatem necessitatibus quia dolorum. \nEius est nihil natus modi natus quisquam ut impedit. \nTempore enim autem laboriosam sequi ipsum quo. \n<bold class=\"font-bold\">Aut voluptatum debitis et aliquam vel rerum facere.</bold>",
 		"error": {
 			"emailRules": "Please enter a valid email address",
 			"emptyFields": "Please complete all fields",
 			"humanity": "Please confirm that you are not a robot",
 			"metadata": "Please check that you have completed all fields correctly",
-			"passwordRules": "Password must contain at least 8 characters"
+			"passwordRules": "Password must contain at least 8 characters",
+			"differentPasswords": "Passwords do not match",
+			"tutor": "Error when selecting the tutor. \nPlease try again."
 		},
 		"signup": "Register",
-		"start": "Aut sint sint et nihil aut. \nQuia nihil eos rerum neque exercitationem molestiae. \nAut ab accusantium consequatur rerum architecto voluptas. \nRepudiandae minima nemo vitae tempore. \nMolestiae rerum aliquid ut fugit eligendi. \nAlias ​​dolorum quia voluptatum veniam harum aut qui et. \nVoluptatibus adipisci il velit assumenda. \nAsperiores accusemus deserunt eveniet adipisci reprehenderit. \nDucimus placeat sit reprehenderit ea eos quam. \nUt facilis quia suscipit officiis odit unde temporibus error. \nNeque sapiente ut similique. \nEius ut sapiente maxime dolor est voluptatem eum. \nVeniam aut sit quo. \nQuibusdam sed numquam et rem. \nTempore eum id nobis sunt deleniti et non ducimus. \nMaiores perferendis non consequuntur neque nostrum. \nOdio itaque fugiat no. \nLaboriosam sint voluptatem aut placeat et perferendis. \nSed quam voluptatem necessitatibus quia dolorum. \nEius est nihil natus modi natus quisquam ut impedit. \nTempore enim autem laboriosam sequi ipsum quo. \n<bold class=\"font-bold\">Aut voluptatum debitis et aliquam vel rerum facere.</bold>",
 		"startButton": "To start",
 		"startFastButton": "Start using the app directly",
 		"tab": {
@@ -325,7 +334,8 @@
 			"information": "Information",
 			"signup": "Registration",
 			"start": "To start",
-			"ScheduleWith": "Schedule a meeting with"
+			"ScheduleWith": "Schedule a meeting with",
+			"test": "Tests"
 		},
 		"welcome": "Welcome to LanguageLab! Before you begin, please fill out the following information. This will allow us to get to know you better and tailor the experience to your needs.",
 		"homeLanguage": "First language",
@@ -339,7 +349,24 @@
 			"female": "A woman",
 			"other": "Other",
 			"na": "Prefer not to say"
-		}
+		},
+		"email": {
+			"note": "",
+			"ph": ""
+		},
+		"humans": "I'm not a robot",
+		"study": {
+			"placeholder": "",
+			"note": ""
+		},
+		"nickname": {
+			"note": "",
+			"ph": ""
+		},
+		"password": {
+			"note": ""
+		},
+		"continueButton": "Continue"
 	},
 	"session": {
 		"downloadAllFeedbacks": "Download all feedback",
@@ -384,10 +411,12 @@
 					"submit": "Error sending questionnaire",
 					"toggle": "Error activating or deactivating session"
 				},
-				"questions[0]": "How many hours of <b>course</b> in {lang} have you taken?",
-				"questions[1]": "How many hours have you <b>watched videos</b> in {lang} (films, series, Youtube...) or <b>listened to content</b> in {lang} (podcasts, radio \n, university courses, etc.)?",
-				"questions[2]": "How many hours have you <b>read texts</b> in {lang} (book, newspaper, comics, websites, etc.)?",
-				"questions[3]": "How many hours have you <b>spoken</b> in {lang} (discussions with friends, family, colleagues, etc.)?",
+				"questions": [
+					"How many hours of <b>courses</b> in {lang} have you taken?",
+					"How many hours have you <b>watched videos</b> in {lang} (films, series, Youtube...) or <b>listened to content</b> in {lang} (podcasts, radio, university courses...)?",
+					"How many hours have you <b>read texts</b> in {lang} (books, newspapers, comics, websites...)?",
+					"How many hours have you <b>spoken</b> in {lang} (discussions with friends, family, colleagues...)?"
+				],
 				"success": "Questionnaire sent, thank you!",
 				"title": "Weekly questionnaire"
 			}
@@ -396,7 +425,9 @@
 	},
 	"tests": {
 		"sendResults": "Send",
-		"sendResultsDone": "Sent"
+		"sendResultsDone": "Sent",
+		"taskTests": "Language tests",
+		"typingTests": "Strike tests"
 	},
 	"timeslots": {
 		"availabilities": "Select your availability to filter available tutors",
@@ -438,6 +469,54 @@
 		"studyDescription": "Research Project (title and/or funding of the project this study is part of)",
 		"addressD": "Place Cardinal Mercier 14, 1348 Louvain-la-Neuve",
 		"contact": "Contact Person/Principal Investigator",
-		"email": "Email of PI/Contact Person"
+		"email": "Email of PI/Contact Person",
+		"addUserButton": "Add a participant",
+		"addUserError": "Error when adding the user",
+		"addUserSuccess": "User added to the study",
+		"andOr": "and/or",
+		"chatDuration": "Duration of sessions (in minutes)",
+		"complete": "Thank you for your participation!",
+		"consentParticipation": "If you agree to participate, you will be invited to participate in online tutorial sessions with a foreign language tutor. \nYou will also be invited to fulfill questionnaires before and after tutoring sessions. \nThe tutorial sessions will be recorded for subsequent analysis. We ask you to plan to carry out a minimum of 8 sessions of one hour of tutorial (therefore 8 hours in total), during a period of 1 to 3 months. \nYou can of course realize more if you wish. \nHowever, you can stop participating in the study at any time.",
+		"consentPrivacy": "The data collected (for example, transcriptions of conversations, test results, striking measures, information on participants such as age or gender) will be processed in a confidential and anonymous manner. \nThey will be kept after their full anonymization and can only be used for scientific or educational purposes. \nThey can possibly be shared with other researchers or teachers, but always in this strictly research or teaching framework.",
+		"consentRights": "Your participation in this study is voluntary. \nYou can decide not to participate in the study at any time without having to justify yourself. \nYou can also request that your data be deleted at any time. \nIf you have any questions or concerns about this study, you can contact the study manager.",
+		"consentStudyData": "Study information.",
+		"create": "Create a new study",
+		"createError": "Error when creating the study",
+		"createMissing": "Please fill all fields",
+		"createTitle": "Create a new study",
+		"created": "Successful study",
+		"deleteConfirm": "Are you sure you want to delete this study? \nThis action is irreversible.",
+		"editTitle": "Modification of the study",
+		"endDate": "End date",
+		"hasToLoggin": "Require that the participants be registered and connected to take the test",
+		"invalidEmail": "Invalide email address",
+		"nbSession": "Number of sessions",
+		"newUser": "New participant",
+		"noChanges": "No modification",
+		"removeUserConfirm": "Are you sure you want to withdraw this participant from the study?",
+		"removeUserError": "Error when the participant is deleted",
+		"removeUserSuccess": "Participant withdrawn from the study",
+		"score": {
+			"error": "Error when calculating the score",
+			"loading": "Calculation in progress ...",
+			"title": "Average result:"
+		},
+		"startDate": "Start date",
+		"study": "Study",
+		"tab": {
+			"code": "Code",
+			"end": "END",
+			"infos": "Information",
+			"study": "Study",
+			"tests": "Tests"
+		},
+		"typingTest": "Activate the typing test",
+		"typingTestDuration": "Duration (seconds)",
+		"typingTestInfoNote": "If no duration is provided the mode \"faster than possible\" will be activated.",
+		"typingTestRepetition": "Number of times to repeat",
+		"typingTestText": "Text",
+		"updateError": "Error when updating the study",
+		"updated": "Successful update study",
+		"userNotFound": "User not found"
 	}
 }
diff --git a/frontend/src/lang/es.json b/frontend/src/lang/es.json
index 69402c8b344b948dca4c1f353110edf28c6169c3..916c0db198141036c8d6545bfa28ba17a39b5be3 100644
--- a/frontend/src/lang/es.json
+++ b/frontend/src/lang/es.json
@@ -24,7 +24,7 @@
 	"chatbox": {
 		"deleteFeedback": "¿Estás seguro de que quieres eliminar estos comentarios? \nEsta acción es irreversible.",
 		"disabled": "Esta sesión sólo es visible para la memoria.",
-		"edited": "enmendado",
+		"edited": "modificado",
 		"history": "Histórico",
 		"placeholder": "Escribe tu mensaje aquí...",
 		"replyingTo": "En respuesta a:",
@@ -85,7 +85,10 @@
 	"login": {
 		"email": "Correo electrónico",
 		"login": "Acceso",
-		"noAccountLink": "Regístrate aquí"
+		"noAccountLink": "Regístrate aquí",
+		"noAccountText": "¿No hay cuenta todavía?",
+		"password": "Contraseña",
+		"title": "Conectar"
 	},
 	"register": {
 		"confirmPassword": "Confirmar Contraseña",
@@ -151,7 +154,9 @@
 			"emailRules": "Por favor, introduce una dirección de correo electrónico válida",
 			"emptyFields": "Por favor llene todos los campos",
 			"humanity": "Por favor confirma que no eres un robot.",
-			"metadata": "Verifique que haya llenado correctamente todos los campos"
+			"metadata": "Verifique que haya llenado correctamente todos los campos",
+			"passwordRules": "La contraseña debe contener al menos 8 caracteres",
+			"tutor": "Error al seleccionar el tutor. \nPor favor intente de nuevo."
 		},
 		"genders": {
 			"female": "una mujer",
@@ -165,16 +170,43 @@
 			"continue": "Continuar",
 			"information": "Información",
 			"signup": "Registro",
-			"start": "Para empezar"
+			"start": "Para empezar",
+			"availabilities": "Disponibilidad",
+			"availableSlots": "Ranuras disponibles:",
+			"study": "Estudiar",
+			"test": "Pruebas",
+			"timeslots": "Tutor"
 		},
 		"welcome": "¡Bienvenido a Languagelab! \nAntes de comenzar, complete la siguiente información. \nEsto nos permitirá conocerlo mejor y adaptar la experiencia a sus necesidades.",
-		"continue": "AUTS SINT y NIHIL AUT. \nQuia Nihil Eos Rerum Neque Exerciseem molestiae. \nAUT AB Accidentium consecuente Rerum Architecto Voluptas. \nRepudiandae Minima Nemo Vitae Tempore. \nMoletiae Rerum Aliquid Ut Fugit Eligendi. \nTempore Eum id nobis Sunt Deleniti y no Ducimus. \nMaiores Perferendis no acordado NOSTRUM. \nOdio Itaque Fugiat no. \nLabriosam Sint Voluptatem Aut Placeat y Perferendis. \nSed Quam Voluptatem Requiritatibus quia dolorum. \nEius es nihil natus modi natus quisquam ut impedit. \nTempore Enim Autem Laboriosam Sequi Ipsum quo. \n<Bold class = \"Font-Bold\"> Aut Voluptatum Debitis y Facera de Vel Rerum.",
 		"continueButton": "continuar con las pruebas",
 		"signup": "Registro",
-		"start": "AUTS SINT y NIHIL AUT. \nQuia Nihil Eos Rerum Neque Exerciseem molestiae. \nAUT AB Accidentium consecuente Rerum Architecto Voluptas. \nRepudiandae Minima Nemo Vitae Tempore. \nMoletiae Rerum Aliquid Ut Fugit Eligendi. \nAlias ​​dolorum quia voluptatum veniam harum auth y. \nVoluptatibus adipisci Ilo Velt Asumenda. \nAsperiores acumus deserunt desarrollo adipisci reprehenderit. \nDucimus Placat Sit Reverseit Ea Eos Quam. \nUT Facilis Quia Dégitiis Odit Unde temporibus Error. \nNeque Sapiente Ut similar. \nEius Ut Sapiente Maxime Dolor es Voluptatem Eum. \nVeniam Aut Quo. \nQuibusdam sed numquam y rem. \nTempore Eum id nobis Sunt Deleniti y no Ducimus. \nMaiores Perferendis no acordado NOSTRUM. \nOdio Itaque Fugiat no. \nLabriosam Sint Voluptatem Aut Placeat y Perferendis. \nSed Quam Voluptatem Requiritatibus quia dolorum. \nEius es nihil natus modi natus quisquam ut impedit. \nTempore Enim Autem Laboriosam Sequi Ipsum quo. \n<Bold class = \"Font-Bold\"> Aut Voluptatum Debitis y Facera de Vel Rerum.",
 		"startButton": "Para empezar",
 		"startFastButton": "Comience a usar la aplicación directamente",
-		"study": "Estudiar"
+		"study": "Estudiar",
+		"ScheduleWith": "Planificar una reunión con",
+		"addAvailability": "Agregar disponibilidad",
+		"confirm": "Confirmar",
+		"endTime": "Tiempo de finalización",
+
+		"noAvailabilities": "Sin disponibilidad proporcionada",
+		"noTutorsAvailable": "No hay tutor disponible actualmente",
+		"notAvailable": "No disponible",
+		"remove": "Borrar",
+		"role": "Role",
+		"roles": {
+			"learner": "Aprendiz",
+			"note": "Seleccione el papel que desea desempeñar en la aplicación",
+			"tutor": "Tutor"
+		},
+		"yourAvailabilities": "Tu disponibilidad",
+		"firstLanguage": "Idioma principal:",
+		"gender": "Eres...",
+		"scheduleMeeting": "Planificar una reunión",
+		"bio": "Biografía corta",
+		"selectWeekday": "Seleccione un día de la semana",
+		"startTime": "Hora de inicio",
+		"weekday": "Día de la semana",
+		"availabilities": "Disponibilidad"
 	},
 	"session": {
 		"downloadAllFeedbacks": "Descargar todos los comentarios",
@@ -219,23 +251,18 @@
 					"submit": "Error al enviar el cuestionario",
 					"toggle": "Error al activar o desactivar sesión"
 				},
-				"questions[0]": "¿Cuántas horas de <b> curso </b> {lang} has seguido?",
-				"questions[1]": "¿Cuántas horas ha visto videos </b> en {lang} (películas, series, youtube ...) o <b> escuchado contenido </b> en {lang} (podcasts, radio radio, cursos universitarios ... .)?",
-				"questions[2]": "¿Cuántas horas has <b>leído textos</b> en {lang} (libros, periódicos, cómics, sitios web, etc.)?",
-				"questions[3]": "¿Cuántas horas has <b>hablado</b> en {lang} (discusiones con amigos, familiares, colegas, etc.)?",
+				"questions": [
+					"¿Cuántas horas de <b>cursos</b> en {lang} has seguido?",
+					"¿Cuántas horas has <b>visto vídeos</b> en {lang} (películas, series, Youtube...) o <b>escuchado contenidos</b> en {lang} (podcasts, radio, cursos universitarios...)?",
+					"¿Cuántas horas has <b>leído textos</b> en {lang} (libros, periódicos, cómics, páginas web...)?",
+					"¿Cuántas horas has <b>hablado</b> en {lang} (conversaciones con amigos, familiares, compañeros...)?"
+				],
 				"success": "Cuestionario enviado, ¡gracias!",
 				"title": "Cuestionario semanal"
 			}
 		},
 		"noTopic": "No hay temas disponibles"
 	},
-	"signup": {
-		"signup": "",
-		"title": "",
-		"confirmPassword": "",
-		"email": "",
-		"language": ""
-	},
 	"studies": {
 		"addUserButton": "Agregar un participante",
 		"addUserError": "Error al agregar usuario",
@@ -258,7 +285,37 @@
 		"study": "Estudiar",
 		"updateError": "Error al actualizar el estudio",
 		"updated": "Estudio de actualización exitoso",
-		"userNotFound": "Usuario no encontrado"
+		"userNotFound": "Usuario no encontrado",
+		"addressD": "Place Cardinal Mercier 14, 1348 Louvain-La-Neuve",
+		"andOr": "y/o",
+		"complete": "¡Gracias por su participación!",
+		"consentParticipation": "Si acepta participar, se le invitará a participar en sesiones de tutoriales en línea con un tutor de idiomas extranjeros. \nTambién se le invitará a cumplir cuestionarios antes y después de las sesiones de tutoría. \nLas sesiones tutoriales se registrarán para el análisis posterior. \nPor supuesto, puede darse cuenta más si lo desea. \nSin embargo, puede dejar de participar en el estudio en cualquier momento.",
+		"consentPrivacy": "Los datos recopilados (por ejemplo, transcripciones de conversaciones, resultados de pruebas, medidas sorprendentes, información sobre participantes como la edad o el género) se procesarán de manera confidencial y anónima. \nSe mantendrán después de su anonimización completa y solo se pueden usar con fines científicos o educativos. \nPosiblemente puedan compartirse con otros investigadores o maestros, pero siempre en este marco estrictamente de investigación o enseñanza.",
+		"consentRights": "Su participación en este estudio es voluntaria. \nPuede decidir no participar en el estudio en ningún momento sin tener que justificarse. \nTambién puede solicitar que sus datos se eliminen en cualquier momento. \nSi tiene alguna pregunta o inquietud sobre este estudio, puede comunicarse con el gerente de estudio.",
+		"consentStudyData": "Información de estudio.",
+		"contact": "Persona de contacto/investigador principal",
+		"editTitle": "Modificación del estudio",
+		"email": "Pi Correo electrónico/persona de contacto",
+		"hasToLoggin": "Requiere que los participantes estén registrados y conectados para tomar la prueba",
+		"nbSession": "Número de sesiones",
+		"score": {
+			"error": "Error al calcular la puntuación",
+			"loading": "Cálculo en progreso ...",
+			"title": "Resultado promedio:"
+		},
+		"studyDescription": "Proyecto de investigación (título y/o financiamiento del proyecto en el que este estudio es parte)",
+		"tab": {
+			"code": "Código",
+			"end": "Fin",
+			"infos": "Información",
+			"study": "Estudiar",
+			"tests": "Pruebas"
+		},
+		"typingTest": "Activar la prueba de tipeo",
+		"typingTestDuration": "Duración (segundos)",
+		"typingTestInfoNote": "Si no se proporciona duración, se activará el modo \"más rápido de lo posible\".",
+		"typingTestRepetition": "Número de veces para repetir",
+		"typingTestText": "Texto"
 	},
 	"surveys": {
 		"birthYear": "¿Cuál es tu año de nacimiento?",
@@ -306,16 +363,19 @@
 	},
 	"tests": {
 		"sendResults": "Enviar",
-		"sendResultsDone": "Enviado"
+		"sendResultsDone": "Enviado",
+		"taskTests": "Pruebas de idiomas",
+		"typingTests": "Pruebas de huelga"
 	},
 	"timeslots": {
 		"availabilities": "Selecciona tu disponibilidad para filtrar los profesores disponibles",
 		"availableTutors": "Tutores disponibles",
 		"calcom": "Enlace a la reserva de calendario",
-		"calcomWarning": "CAL.com Enlace Invalidio",
-		"cesttime": "CE Hour (Bruselas)",
+		"calcomWarning": "Cal.com Enlace Invalidio",
+		"cesttime": "Hora CET (Bruselas)",
 		"noTutors": "No hay tutor disponible. \nPor favor seleccione otras disponibilidades.",
-		"setAvailabilities": "Selecciona tu disponibilidad"
+		"setAvailabilities": "Selecciona tu disponibilidad",
+		"availableSlots": "Ranuras disponibles"
 	},
 	"users": {
 		"actions": "Comportamiento",
@@ -420,7 +480,13 @@
 			"status": "Estado",
 			"title": "Título",
 			"topics": "Temas",
-			"users": "Usuarios"
+			"users": "Usuarios",
+			"Address": "Dirección",
+			"OrganisationUni": "Organización/universidad",
+			"groups": "grupos",
+			"questions": "preguntas",
+			"tests": "pruebas",
+			"toggle": "Participantes"
 		}
 	}
 }
diff --git a/frontend/src/lang/fr.json b/frontend/src/lang/fr.json
index 2f1cd665f8544170235379efa4881ba14a3c9dd2..331a6e4a8c466a18790bc85c0111d8f0f23c61b0 100644
--- a/frontend/src/lang/fr.json
+++ b/frontend/src/lang/fr.json
@@ -12,7 +12,8 @@
 		"admin": {
 			"users": "Utilisateurs",
 			"sessions": "Sessions",
-			"studies": "Études"
+			"studies": "Études",
+			"tasks": "Tâches"
 		}
 	},
 	"chatbox": {
@@ -246,14 +247,14 @@
 		"birthyear": "Année de naissance",
 		"birthyear.note": "En quelle année êtes-vous né·e ?",
 		"confirmTutor": "Confirmez-vous sélectionner \"{NAME}\" comme tuteur ?",
-		"continue": "Aut sint sint et nihil aut. Quia nihil eos rerum neque exercitationem molestiae. Aut ab accusantium consequatur rerum architecto voluptas. Repudiandae minima nemo vitae tempore. Molestiae rerum aliquid ut fugit eligendi. Tempore eum id nobis sunt deleniti et non ducimus. Maiores perferendis non consequuntur neque nostrum. Odio itaque fugiat non. Laboriosam sint voluptatem aut placeat et perferendis. Sed quam voluptatem necessitatibus quia dolorum. Eius est nihil natus modi natus quisquam ut impedit. Tempore enim autem laboriosam sequi ipsum quo. <bold class=\"font-bold\">Aut voluptatum debitis et aliquam vel rerum facere.</bold>",
+		"continue": "Continuer <!-- TODO: Remove this key -->",
 		"continueButton": "Continuer vers les tests",
 		"startFastButton": "Commencer directement à utiliser l'application",
-		"start": "Aut sint sint et nihil aut. Quia nihil eos rerum neque exercitationem molestiae. Aut ab accusantium consequatur rerum architecto voluptas. Repudiandae minima nemo vitae tempore. Molestiae rerum aliquid ut fugit eligendi. Alias dolorum quia voluptatum veniam harum aut qui et. Voluptatibus adipisci illo velit assumenda. Asperiores accusamus deserunt eveniet adipisci reprehenderit. Ducimus placeat sit reprehenderit ea eos quam. Ut facilis quia suscipit officiis odit unde temporibus error. Neque sapiente ut similique. Eius ut sapiente maxime dolor est voluptatem eum. Veniam aut sit quo. Quibusdam sed numquam et rem. Tempore eum id nobis sunt deleniti et non ducimus. Maiores perferendis non consequuntur neque nostrum. Odio itaque fugiat non. Laboriosam sint voluptatem aut placeat et perferendis. Sed quam voluptatem necessitatibus quia dolorum. Eius est nihil natus modi natus quisquam ut impedit. Tempore enim autem laboriosam sequi ipsum quo. <bold class=\"font-bold\">Aut voluptatum debitis et aliquam vel rerum facere.</bold>",
-		"startButton": "Commencer",
+		"start": "Continue",
 		"study": "Étude",
 		"study.note": "Nom de l'étude à laquelle vous participez",
-		"study.placeholder": "Nom de l'étude"
+		"study.placeholder": "Nom de l'étude",
+		"testText": "Vous allez passer un test de vocabulaire. Cliquez sur le bouton suivent pour commencer."
 	},
 	"timeslots": {
 		"cesttime": "Heure CET (Bruxelles)",
@@ -394,12 +395,29 @@
 			"title": "Résultat moyen: ",
 			"loading": "Calcul en cours...",
 			"error": "Erreur lors du calcul du score"
-		}
+		},
+		"backToHomePage": "Retour à la page d'accueil"
 	},
 	"tests": {
 		"taskTests": "Tests de langue",
 		"typingTests": "Tests de frappe"
 	},
+	"tasks": {
+		"title": "Nouvelle tâche cible",
+		"createTitle": "Créer une nouvelle tâche",
+		"editTitle": "Modifier la tâche",
+		"level": "Niveau CEFR",
+		"shortTitle": "Nom de la tâche (max 5 mots)",
+		"instructions": "Instructions pour le tuteur (plusieurs lignes si besoin)",
+		"learnerInstructions": "Instructions pour l'apprenant (plusieurs lignes si besoin)",
+		"examples": "Exemples (plusieurs lignes si besoin)",
+		"create": "Créer une nouvelle tâche",
+		"taskInProgress": "Tâche en cours",
+		"taskFinished": "Tâche terminée avec succès",
+		"statusFail": "Echec du changement de status de la tâche",
+		"startTask": "Commencer cette tâche",
+		"achieveTask": "Tâche achevée"
+	},
 	"button": {
 		"create": "Créer",
 		"submit": "Envoyer",
@@ -416,7 +434,9 @@
 		"updated": "Mis à jour !",
 		"delete": "Supprimer",
 		"remove": "Retirer",
-		"continue": "Continuer"
+		"continue": "Continuer",
+		"select": "Sélectionner",
+		"finish": "Terminer"
 	},
 	"utils": {
 		"month": {
@@ -501,7 +521,11 @@
 			"questions": "questions",
 			"tests": "tests",
 			"OrganisationUni": "Organisation/Université",
-			"Address": "Adresse"
+			"Address": "Adresse",
+			"all": "Tous",
+			"instructions": "Instructions",
+			"examples": "Exemples",
+			"tasks": "Tâches"
 		}
 	},
 	"inputs": {
diff --git a/frontend/src/lang/nl.json b/frontend/src/lang/nl.json
index 29c931f4f0fade07ee8fea4ed43fa6c6c6c346d3..32c76106a45aa61440c066795fb1f4063f24731a 100644
--- a/frontend/src/lang/nl.json
+++ b/frontend/src/lang/nl.json
@@ -8,7 +8,7 @@
 		"close": "Dichtbij",
 		"continue": "Doorgaan",
 		"create": "Creëren",
-		"delete": "VERWIJDEREN",
+		"delete": "Verwijderen",
 		"login": "Inloggen",
 		"next": "Volgende",
 		"remove": "Terugtrekken",
@@ -16,7 +16,7 @@
 		"sent": "Verstuurd !",
 		"start": "Om te beginnen",
 		"submit": "Versturen",
-		"thank-you": "BEDANKT !",
+		"thank-you": "Bedankt !",
 		"tryit": "Om te proberen",
 		"update": "Om bij te werken",
 		"updated": "Bijgewerkt!"
@@ -85,7 +85,10 @@
 	"login": {
 		"email": "E-mail",
 		"login": "Inloggen",
-		"noAccountLink": "Registreer hier"
+		"noAccountLink": "Registreer hier",
+		"noAccountText": "Nog geen account?",
+		"password": "Wachtwoord",
+		"title": "Verbinden"
 	},
 	"register": {
 		"confirm": "Bevestigen",
@@ -149,24 +152,17 @@
 			},
 			"title": "Informatiedocument en geïnformeerde toestemming"
 		},
-		"continue": "Auts Sint en Nihil Aut. \nQuia nihil eos rerum neque oefeningem molestiae. \nAut Ab Accidentium consequatur Rerum Architecto Voluptas. \nRefudiandae minima nemo vitae tempore. \nMoletiae Rerum aliquid UT Fugit eligendi. \nTempore Eum Id Nobis Sunt Deleniti en niet Ducimus. \nMaiRes Perferendis was niet overeengekomen Nostrum. \nOdio itaque Fugiat nr. \nLabriosam Sint Voluptatem Aut Placeat en Perferendis. \nSed quam voluptatem nodigatiBus quia dolorum. \nEius is Nihil Natus Modi Natus Quisquam Ut Impedit. \nTempore Enim Autem Laboriosam Sequi Ipsum quo. \n<Bold Class = \"Font-Bold\"> Aut Voluptatum Debitis en Aliquam Vel Rerum Facere.",
 		"continueButton": "Ga verder naar testen",
-		"email": {
-			"note": "",
-			"ph": ""
-		},
 		"error": {
 			"differentPasswords": "Wachtwoorden komen niet overeen",
 			"emailRules": "Voer een geldig e-mailadres in",
 			"emptyFields": "Vul alle velden in",
 			"humanity": "Bevestig dat u geen robot bent",
-			"metadata": "Controleer of u alle velden correct hebt gevuld"
-		},
-		"password": {
-			"note": ""
+			"metadata": "Controleer of u alle velden correct hebt gevuld",
+			"passwordRules": "Het wachtwoord moet minimaal 8 tekens bevatten",
+			"tutor": "Fout bij het selecteren van de tutor. \nProbeer het opnieuw."
 		},
 		"signup": "Register",
-		"start": "Auts Sint en Nihil Aut. \nQuia nihil eos rerum neque oefeningem molestiae. \nAut Ab Accidentium consequatur Rerum Architecto Voluptas. \nRefudiandae minima nemo vitae tempore. \nMoletiae Rerum aliquid UT Fugit eligendi. \nAlias ​​Dolorum Quia Voluptatum Veniam Harum Aut welke en. \nVoluptatibus adipisci illo velt Apportenda. \nAsperiores accumus deserunt ontwikkeling adipisci expreesit. \nDucimus placeat zit Reversereit ea eos quam. \nUt facilis quia dégitiis odit unde temporibus error. \nNeque Sapiente UT vergelijkbaar. \nEius ut sapiente maxime dolor is Voluptatem Eum. \nVeniam Aut Quo. \nQuibusdam sed Numquam en Rem. \nTempore Eum Id Nobis Sunt Deleniti en niet Ducimus. \nMaiRes Perferendis was niet overeengekomen Nostrum. \nOdio itaque Fugiat nr. \nLabriosam Sint Voluptatem Aut Placeat en Perferendis. \nSed quam voluptatem nodigatiBus quia dolorum. \nEius is Nihil Natus Modi Natus Quisquam Ut Impedit. \nTempore Enim Autem Laboriosam Sequi Ipsum quo. \n<Bold Class = \"Font-Bold\"> Aut Voluptatum Debitis en Aliquam Vel Rerum Facere.",
 		"startButton": "Om te beginnen",
 		"startFastButton": "Begin direct met het gebruiken van de app",
 		"tab": {
@@ -174,8 +170,28 @@
 			"information": "Informatie",
 			"signup": "Registratie",
 			"start": "Om te beginnen",
-			"study": "Studie"
-		}
+			"study": "Studie",
+			"ScheduleWith": "Plan een ontmoeting met",
+			"availabilities": "Beschikbaarheid",
+			"availableSlots": "Beschikbare slots:",
+			"consent": "Toestemming",
+			"test": "Tests"
+		},
+		"ScheduleWith": "Plan een ontmoeting met",
+		"addAvailability": "Voeg beschikbaarheid toe",
+		"endTime": "Eindtijd",
+		"linkNotAvailable": "Link niet beschikbaar",
+		"loadingTutors": "Tutors laden ...",
+		"nickname": {
+			"note": "",
+			"ph": ""
+		},
+		"noAvailabilities": "Geen beschikbaarheid verstrekt",
+		"noTutorsAvailable": "Er is momenteel geen tutor beschikbaar",
+		"notAvailable": "Niet beschikbaar",
+		"remove": "VERWIJDEREN",
+		"scheduleMeeting": "Plan een vergadering",
+		"yourAvailabilities": "Uw beschikbaarheid"
 	},
 	"session": {
 		"downloadAllFeedbacks": "Download alle feedbacks",
@@ -220,10 +236,246 @@
 					"submit": "Fout bij verzenden vragenlijst",
 					"toggle": "Fout bij het activeren of deactiveren van de sessie"
 				},
-				"questions[0]": "Hoeveel uur <b>cursus</b> in het {lang} heeft u gevolgd?",
-				"questions[1]": "Hoeveel uur heb je video's bekeken </b> in {lang} (films, serie, youtube ...) of <b> luisterde naar inhoud </b> in {lang} (podcasts, radio -radio, universitaire cursussen .. .)?",
-				"questions[2]": "Hoeveel uur heeft u <b>teksten gelezen</b> in het {lang} (boek, krant, strips, websites, enz.)?"
+				"questions": [
+					"Hoeveel uur <b>cursussen</b> in {lang} heb je gevolgd?",
+					"Hoeveel uur heb je <b>video's</b> gekeken in {lang} (films, series, Youtube...) of <b>geluisterd naar inhoud</b> in {lang} (podcasts, radio, universitaire cursussen...)?",
+					"Hoeveel uur heb je <b>teksten</b> gelezen in {lang} (boeken, kranten, strips, websites...)?",
+					"Hoeveel uur heb je <b>gesproken</b> in {lang} (discussies met vrienden, familie, collega's...)?"
+				],
+				"success": "Vragenlijst verzonden, bedankt!",
+				"title": "Wekelijkse vragenlijst"
 			}
+		},
+		"noTopic": "Geen onderwerp beschikbaar"
+	},
+	"signup": {
+		"confirmPassword": "",
+		"email": ""
+	},
+	"studies": {
+		"addUserButton": "Voeg een deelnemer toe",
+		"addUserError": "Fout bij het toevoegen van de gebruiker",
+		"addUserSuccess": "Gebruiker toegevoegd aan de studie",
+		"addressD": "Plaats kardinaal Mercier 14, 1348 Louvain-la-neuve",
+		"andOr": "en/of",
+		"chatDuration": "Duur van sessies (in minuten)",
+		"complete": "Bedankt voor je deelname!",
+		"consentParticipation": "Als u ermee instemt om deel te nemen, wordt u uitgenodigd om deel te nemen aan online zelfstudiesessies met een tutor in vreemde talen. \nU wordt ook uitgenodigd om vragenlijsten voor en na tutoring -sessies uit te voeren. \nDe tutorialsessies worden opgenomen voor de latere analyse. \nJe kunt je natuurlijk meer realiseren als je dat wilt. \nU kunt echter op elk gewenst moment stoppen met deelname aan het onderzoek.",
+		"consentPrivacy": "De verzamelde gegevens (bijvoorbeeld transcripties van gesprekken, testresultaten, opvallende maatregelen, informatie over deelnemers zoals leeftijd of geslacht) zullen op een vertrouwelijke en anonieme manier worden verwerkt. \nZe zullen worden bewaard na hun volledige anonimisering en kunnen alleen worden gebruikt voor wetenschappelijke of educatieve doeleinden. \nZe kunnen mogelijk worden gedeeld met andere onderzoekers of leraren, maar altijd in dit strikt onderzoeks- of onderwijskader.",
+		"consentRights": "Uw deelname aan dit onderzoek is vrijwillig. U kunt besluiten om niet op elk gewenst moment deel te nemen aan het onderzoek zonder uzelf te rechtvaardigen. U kunt ook vragen om uw gegevens op elk gewenst moment te verwijderen. Als u vragen of zorgen over deze studie hebt, kunt u contact opnemen met de studiemanager.",
+		"consentStudyData": "Studie -informatie.",
+		"contact": "Contactpersoon/hoofdonderzoeker",
+		"create": "Creëer een nieuwe studie",
+		"createError": "Fout bij het maken van de studie",
+		"createMissing": "Vul alle velden in",
+		"createTitle": "Creëer een nieuwe studie",
+		"created": "Succesvolle studie",
+		"deleteConfirm": "Weet je zeker dat je deze studie wilt verwijderen? Deze actie is onomkeerbaar.",
+		"editTitle": "Aanpassing van de studie",
+		"email": "PI -e -mail/contactpersoon",
+		"endDate": "Einddatum",
+		"hasToLoggin": "Eisen dat de deelnemers worden geregistreerd en verbonden om de test af te leggen",
+		"invalidEmail": "Invalide e -mailadres",
+		"nbSession": "Aantal sessies",
+		"newUser": "Nieuwe deelnemer",
+		"noChanges": "Geen aanpassing",
+		"removeUserConfirm": "Weet u zeker dat u deze deelnemer uit de studie wilt opnemen?",
+		"removeUserError": "Fout wanneer de deelnemer wordt verwijderd",
+		"removeUserSuccess": "Deelnemer teruggetrokken uit het onderzoek",
+		"score": {
+			"error": "Fout bij het berekenen van de score",
+			"loading": "Rekening in uitvoering ...",
+			"title": "Gemiddeld resultaat:"
+		},
+		"startDate": "Startdatum",
+		"study": "Studie",
+		"studyDescription": "Onderzoeksproject (titel en/of financiering van het project waarin deze studie deel uitmaakt)",
+		"tab": {
+			"code": "Code",
+			"end": "Einde",
+			"infos": "Informatie",
+			"study": "Studie",
+			"tests": "Tests"
+		},
+		"typingTest": "Activeer de typetest",
+		"typingTestDuration": "Duur (seconden)",
+		"typingTestInfoNote": "Als er geen duur wordt verstrekt, wordt de modus \"sneller dan mogelijk\" geactiveerd.",
+		"typingTestRepetition": "Aantal keren om te herhalen",
+		"typingTestText": "Tekst",
+		"updateError": "Fout bij het bijwerken van de studie",
+		"updated": "Succesvolle updatestudie",
+		"userNotFound": "Gebruiker niet gevonden"
+	},
+	"surveys": {
+		"birthYear": "Wat is uw geboortejaar?",
+		"code": "Uw code:",
+		"codeIndication": "De instructeur moet u een persoonlijke code hebben gegeven.",
+		"complete": "Bedankt voor je deelname!",
+		"consent": {
+			"intro": "U wordt uitgenodigd om deel te nemen aan een wetenschappelijk onderzoek om vocabulaire tests te ontwerpen, valideren en toepassen.",
+			"ok": "Ik ga ermee akkoord om deel te nemen aan het onderzoek zoals hierboven beschreven.",
+			"participation": "Wat betreft uw deelname?",
+			"participationD": "Als u ermee instemt deel te nemen, hoeft u deze vragenlijst alleen maar te beantwoorden en mogelijk een andere test, indien aangegeven door de persoon die de test beheert.",
+			"privacy": "Hoe worden uw gegevens verwerkt en bewaard?",
+			"privacyD": "De verzamelde gegevens (uw antwoorden op de verschillende vragen) worden op een vertrouwelijke en anonieme manier verwerkt. \nZe zullen worden bewaard na hun volledige anonimisering en kunnen alleen worden gebruikt voor wetenschappelijke of educatieve doeleinden. \nZe kunnen mogelijk worden gedeeld met andere onderzoekers of leraren, maar altijd in dit strikt onderzoeks- of onderwijskader.",
+			"rights": "Wat zijn uw rechten? Vrijwillige deelname en mogelijke terugtrekking",
+			"rightsD": "Uw deelname aan dit onderzoek is vrijwillig. \nU kunt besluiten om niet op elk gewenst moment deel te nemen aan het onderzoek zonder uzelf te rechtvaardigen. \nU kunt ook vragen om uw gegevens op elk gewenst moment te verwijderen. \nAls u vragen of zorgen over deze studie hebt, kunt u contact opnemen met de studiemanager, Serge Bibauw, op het volgende adres:",
+			"title": "Informatie over geïnformeerde studie- en toestemming"
+		},
+		"education": {
+			"Bachelor": "Vrijgezel",
+			"Master": "Meester of hoger diploma",
+			"NoEducation": "Geen",
+			"NonUni": "Superieure niet -academisch",
+			"PrimarySchool": "Basisschool",
+			"SecondarySchool": "Middelbare school",
+			"title": "Wat is het hoogste kwaliteit, diploma of studieniveau dat je hebt?"
+		},
+		"example": "Voorbeeld",
+		"gender": "Wat voor soort identificeer je?",
+		"genders": {
+			"female": "Een vrouw",
+			"male": "Een man",
+			"na": "Ik geef er de voorkeur aan om niet te antwoorden",
+			"other": "Ander"
+		},
+		"homeLanguage": "Eerste taal",
+		"introduction": "Dit is een vragenlijst.",
+		"invalidCode": "Ongeldige code",
+		"invalidEmail": "Invalide e -mailadres",
+		"loginEmail": "Gebruik een e-mailadres",
+		"loginUser": "Maak verbinding via een gebruikersaccount",
+		"loginWarning": "Om uw voortgang te onthouden, moet u worden geverifieerd om toegang te krijgen tot deze vragenlijst. \nAls u een gebruikersaccount heeft, maakt u verbinding. \nAnders kunt u <a class = \"link\" href = \"/register\"> register </a> of doorgaan met een e -mailadres.",
+		"otherLanguage": "Is er een andere taal waarin u relatief vloeiend bent?",
+		"otherLanguageNote": "(Als u vloeiend bent in meerdere andere talen, buiten uw doeltaal en uw eerste taal, selecteer dan degene die het dichtst bij uw doeltaal staat of dat lijkt u het meest te helpen bij het leren van uw doeltaal.)",
+		"score": "Score:"
+	},
+	"tests": {
+		"sendResults": "",
+		"sendResultsDone": "",
+		"taskTests": "Taaltests",
+		"typingTests": "Strike -tests"
+	},
+	"timeslots": {
+		"availabilities": "Selecteer uw beschikbaarheid om de beschikbare docenten te filteren",
+		"availableSlots": "Beschikbare slots",
+		"availableTutors": "Beschikbare docenten",
+		"calcom": "Link naar agenda -boeking",
+		"calcomWarning": "Cal.com Link Invalide",
+		"cesttime": "CET Tijd (Brussel)",
+		"noTutors": "Geen tutor beschikbaar. \nSelecteer andere beschikbaarheid.",
+		"setAvailabilities": "Selecteer uw beschikbaarheid"
+	},
+	"users": {
+		"actions": "Acties",
+		"availability": "Beschikbaarheid",
+		"category": "Categorie",
+		"email": "E-mail",
+		"gender": "Geslacht",
+		"genders": {
+			"female": "Vrouwen",
+			"male": "Man",
+			"na": "Ik geef er de voorkeur aan om niet te antwoorden",
+			"other": "Ander"
+		},
+		"isActive": "Actief",
+		"nickname": "Naam",
+		"type": {
+			"0": "Admin",
+			"1": "Tutor",
+			"2": "Leerling",
+			"admin": "Admin",
+			"admins": "Admin(s)",
+			"student": "Leerling",
+			"students": "Leerling(en)",
+			"tutor": "Tutor",
+			"tutors": "Tutor(en)"
+		}
+	},
+	"utils": {
+		"bool": {
+			"false": "Nee",
+			"true": "Ja"
+		},
+		"days": {
+			"0": "Maandag",
+			"1": "Dinsdag",
+			"2": "Woensdag",
+			"3": "Donderdag",
+			"4": "Vrijdag",
+			"5": "Zaterdag",
+			"6": "Zondag",
+			"friday": "Vrijdag",
+			"monday": "Maandag",
+			"saturday": "Zaterdag",
+			"sunday": "Zondag",
+			"thursday": "Donderdag",
+			"tuesday": "Dinsdag",
+			"wednesday": "Woensdag"
+		},
+		"language": {
+			"en": "Engels",
+			"eng": "Engels",
+			"fr": "Frans",
+			"fra": "Frans"
+		},
+		"month": {
+			"april": "april",
+			"august": "augustus",
+			"december": "december",
+			"february": "februari",
+			"january": "januari",
+			"july": "juli",
+			"june": "juni",
+			"march": "maart",
+			"may": "mei",
+			"november": "november",
+			"october": "oktober",
+			"september": "september"
+		},
+		"past": {
+			"day": "Er is {n, meervoud, één {",
+			"hour": "Er is {n, meervoud, één {",
+			"justNow": "Minder dan een uur geleden",
+			"month": "Er is {n, meervoud, één {",
+			"today": "Vandaag",
+			"year": "Er is {n, meervoud, één {",
+			"yesterday": "Gisteren"
+		},
+		"shortMonth": {
+			"april": "apr.",
+			"august": "aug.",
+			"december": "dec.",
+			"february": "feb.",
+			"january": "jan.",
+			"july": "jul.",
+			"june": "jun.",
+			"march": "maa.",
+			"may": "mei",
+			"november": "nov.",
+			"october": "okt.",
+			"september": "sep."
+		},
+		"words": {
+			"Address": "Adres",
+			"OrganisationUni": "Organisatie/universiteit",
+			"actions": "Acties",
+			"date": "Datum",
+			"description": "Beschrijving",
+			"email": "E-mail",
+			"finished": "Afgerond",
+			"groups": "groepen",
+			"inProgress": "In uitvoering",
+			"messages": "Berichten",
+			"participants": "Deelnemers",
+			"programed": "Geprogrammeerd",
+			"questions": "vragen",
+			"status": "Status",
+			"tests": "tests",
+			"title": "Studietitel",
+			"toggle": "Deelnemers",
+			"topics": "Onderwerpen",
+			"users": "Gebruikers"
 		}
 	}
 }
diff --git a/frontend/src/lib/api/tasks.ts b/frontend/src/lib/api/tasks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0f99fe8fb7fde256d131f7ebbc35fd5732159b10
--- /dev/null
+++ b/frontend/src/lib/api/tasks.ts
@@ -0,0 +1,108 @@
+import type { fetchType } from '$lib/utils/types';
+
+export async function createTaskAPI(
+	fetch: fetchType,
+	level: string,
+	shortTitle: string,
+	instructions: string,
+	learnerInstructions: string,
+	examples: string
+): Promise<number | undefined> {
+	const response = await fetch(`/api/tasks`, {
+		method: 'POST',
+		headers: { 'Content-Type': 'application/json' },
+		body: JSON.stringify({
+			level,
+			shortTitle,
+			instructions,
+			learnerInstructions,
+			examples
+		})
+	});
+
+	if (!response.ok) return;
+
+	return parseInt(await response.text());
+}
+
+export async function getTasksAPI(fetch: fetchType) {
+	const response = await fetch('/api/tasks');
+	if (!response.ok) return null;
+	return await response.json();
+}
+
+export async function getTaskAPI(fetch: fetchType, task_id: number) {
+	const response = await fetch(`/api/tasks/${task_id}`);
+	if (!response.ok) return null;
+	return await response.json();
+}
+
+export async function updateTaskAPI(
+	fetch: fetchType,
+	task_id: number,
+	level: string,
+	shortTitle: string,
+	instructions: string,
+	learnerInstructions: string,
+	examples: string
+): Promise<boolean> {
+	const response = await fetch(`/api/tasks/${task_id}`, {
+		method: 'PUT',
+		headers: { 'Content-Type': 'application/json' },
+		body: JSON.stringify({
+			level,
+			shortTitle,
+			instructions,
+			learnerInstructions,
+			examples
+		})
+	});
+	return response.ok;
+}
+
+export async function deleteTaskAPI(fetch: fetchType, task_id: number): Promise<boolean> {
+	const response = await fetch(`/api/tasks/${task_id}`, {
+		method: 'DELETE'
+	});
+	return response.ok;
+}
+
+export async function sendTaskStatusAPI(
+	fetch: fetchType,
+	status: string,
+	student_id: number,
+	tutor_id: number,
+	task_id: number,
+	session_id: number
+): Promise<boolean> {
+	const response = await fetch(`/api/tasks/status`, {
+		method: 'POST',
+		headers: { 'Content-Type': 'application/json' },
+		body: JSON.stringify({
+			status,
+			task_id,
+			student_id,
+			tutor_id,
+			session_id
+		})
+	});
+	return response.ok;
+}
+
+export async function getTaskStatusFromSessionAPI(
+	fetch: fetchType,
+	session_id: number
+): Promise<any> {
+	const response = await fetch(`/api/tasks/status/sessions/${session_id}`);
+	if (!response.ok) return null;
+	return await response.json();
+}
+
+export async function getTaskStatusCompletedFromStudentAPI(
+	fetch: fetchType,
+	student_id: number
+): Promise<any> {
+	const response = await fetch(`/api/tasks/status/completed/students/${student_id}`);
+	if (!response.ok) return null;
+	return await response.json();
+}
diff --git a/frontend/src/lib/components/studies/StudyForm.svelte b/frontend/src/lib/components/studies/StudyForm.svelte
index 9cd142beacab75f6f6a645bf5936573211a0f82c..4ecba1e3e2d1e417632e2ba64d27bb5655e7c9d2 100644
--- a/frontend/src/lib/components/studies/StudyForm.svelte
+++ b/frontend/src/lib/components/studies/StudyForm.svelte
@@ -16,7 +16,6 @@
 		study = $bindable(),
 		possibleTests,
 		mode,
-		data,
 		form
 	}: {
 		study: Study | null;
diff --git a/frontend/src/lib/services/i18n.ts b/frontend/src/lib/services/i18n.ts
index f5e350b0c5275e541f19b33437769056a054b68b..d2b9e850bd204fa966976ad9d6f49b0d775487c2 100644
--- a/frontend/src/lib/services/i18n.ts
+++ b/frontend/src/lib/services/i18n.ts
@@ -13,10 +13,20 @@ const config: Config = {
 			key: '',
 			loader: async () => (await import('../../lang/en.json')).default
 		},
+		{
+			locale: 'es',
+			key: '',
+			loader: async () => (await import('../../lang/es.json')).default
+		},
 		{
 			locale: 'fr',
 			key: '',
 			loader: async () => (await import('../../lang/fr.json')).default
+		},
+		{
+			locale: 'nl',
+			key: '',
+			loader: async () => (await import('../../lang/nl.json')).default
 		}
 	],
 	fallbackLocale: 'fr'
diff --git a/frontend/src/lib/types/session.ts b/frontend/src/lib/types/session.ts
index 254dce9feba8477403447640ed980c6ecc23f72b..7a93aca4f37d449fef1f2e5f478e9ab77f5566f0 100644
--- a/frontend/src/lib/types/session.ts
+++ b/frontend/src/lib/types/session.ts
@@ -125,6 +125,10 @@ export default class Session {
 		return this._length;
 	}
 
+	get student(): User | null {
+		return this._users.find((u) => u.type === 2) ?? null;
+	}
+
 	usersList(maxLength = 30): string {
 		const users = this._users
 			.filter((u) => u.id != this._user?.id)
diff --git a/frontend/src/lib/types/tasks.ts b/frontend/src/lib/types/tasks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..70804a96a6d6f1aad04fd807b69350bf0d2fc0de
--- /dev/null
+++ b/frontend/src/lib/types/tasks.ts
@@ -0,0 +1,147 @@
+import { toastAlert } from '$lib/utils/toasts';
+
+export default class Task {
+	private _id: number;
+	private _level: string;
+	private _shortTitle: string;
+	private _instructions: string;
+	private _learnerInstructions: string;
+	private _examples: string;
+
+	constructor(
+		id: number,
+		level: string,
+		shortTitle: string,
+		instructions: string,
+		learnerInstructions: string,
+		examples: string
+	) {
+		this._id = id;
+		this._level = level;
+		this._shortTitle = shortTitle;
+		this._instructions = instructions;
+		this._learnerInstructions = learnerInstructions;
+		this._examples = examples;
+	}
+
+	get id(): number {
+		return this._id;
+	}
+	get level(): string {
+		return this._level;
+	}
+	get shortTitle(): string {
+		return this._shortTitle;
+	}
+	get instructions(): string {
+		return this._instructions;
+	}
+	get learnerInstructions(): string {
+		return this._learnerInstructions;
+	}
+	get examples(): string {
+		return this._examples;
+	}
+
+	static parse(data: any): Task | null {
+		if (data === null) {
+			toastAlert('Failed to parse tasks data');
+			return null;
+		}
+
+		return new Task(
+			data.id,
+			data.level,
+			data.shortTitle,
+			data.instructions,
+			data.learnerInstructions,
+			data.examples
+		);
+	}
+
+	static parseAll(data: any): Task[] {
+		if (data === null) {
+			toastAlert('Failed to parse tasks data');
+			return [];
+		}
+		return data
+			.map((task: any) => Task.parse(task))
+			.filter((task: Task | null): task is Task => task !== null);
+	}
+}
+
+// some IDs not resolved because they are not used in the front-end
+export class TaskStatus {
+	private _id: number;
+	private _task_id: number;
+	private _student_id: number;
+	private _tutor_id: number;
+	private _session_id: number;
+	private _status: string;
+
+	constructor(
+		id: number,
+		task_id: number,
+		student_id: number,
+		tutor_id: number,
+		session_id: number,
+		status: string
+	) {
+		this._id = id;
+		this._task_id = task_id;
+		this._student_id = student_id;
+		this._tutor_id = tutor_id;
+		this._session_id = session_id;
+		this._status = status;
+	}
+
+	get id(): number {
+		return this._id;
+	}
+
+	get task_id(): number {
+		return this._task_id;
+	}
+
+	get status(): string {
+		return this._status;
+	}
+
+	get student_id(): number {
+		return this.student_id;
+	}
+
+	get tutor_id(): number {
+		return this.tutor_id;
+	}
+
+	get session_id(): number {
+		return this.session_id;
+	}
+
+	static parse(data: any): TaskStatus | null {
+		if (data === null) {
+			toastAlert('Failed to parse task status data');
+			return null;
+		}
+
+		return new TaskStatus(
+			data.id,
+			data.task_id,
+			data.student_id,
+			data.tutor_id,
+			data.session_id,
+			data.status
+		);
+	}
+
+	static parseAll(data: any): TaskStatus[] {
+		if (data === null) {
+			toastAlert('Failed to parse task status data');
+			return [];
+		}
+		return data
+			.map((taskStatus: any) => TaskStatus.parse(taskStatus))
+			.filter((taskStatus: TaskStatus | null): taskStatus is TaskStatus => taskStatus !== null);
+	}
+}
diff --git a/frontend/src/lib/types/user.ts b/frontend/src/lib/types/user.ts
index b1acf04ec6dda0e0b07676c98a78f9713994b444..906d98667918f45fd8a268b76446186c84d30baf 100644
--- a/frontend/src/lib/types/user.ts
+++ b/frontend/src/lib/types/user.ts
@@ -32,7 +32,7 @@ export default class User {
 	private _gender: string | null;
 	private _bio: string | null;
 	private _calcom_link: string | null;
-	private _study_id: number | null;
+	private _studies_id: number[];
 	private _last_survey: Date | null;
 	private _tutor_list: string[];
 	private _my_tutor: string | null;
@@ -54,7 +54,7 @@ export default class User {
 		birthdate: Date | null,
 		gender: string | null,
 		calcom_link: string | null,
-		study_id: number | null,
+		studies_id: number[] | null,
 		last_survey: Date | null,
 		tutor_list: string[] = [],
 		my_tutor: string | null = null,
@@ -73,7 +73,7 @@ export default class User {
 		this._birthdate = birthdate;
 		this._gender = gender;
 		this._calcom_link = calcom_link;
-		this._study_id = study_id;
+		this._studies_id = studies_id || [];
 		this._last_survey = last_survey;
 		this._tutor_list = tutor_list;
 		this._my_tutor = my_tutor;
@@ -142,8 +142,8 @@ export default class User {
 		return this._calcom_link;
 	}
 
-	get study_id(): number | null {
-		return this._study_id;
+	get studies_id(): number[] {
+		return this._studies_id;
 	}
 
 	get last_survey(): Date | null {
@@ -214,7 +214,7 @@ export default class User {
 			birthdate: this.birthdate,
 			gender: this.gender,
 			calcom_link: this.calcom_link,
-			study_id: this.study_id,
+			studies_id: this.studies_id,
 			last_survey: this.last_survey,
 			tutor_list: this._tutor_list,
 			my_tutor: this.my_tutor,
@@ -237,7 +237,7 @@ export default class User {
 			if (data.birthdate) this._birthdate = data.birthdate;
 			if (data.gender) this._gender = data.gender;
 			if (data.calcum_link) this._calcom_link = data.calcom_link;
-			if (data.study_id) this._study_id = data.study_id;
+			if (data.studies_id) this._studies_id = data.studies_id;
 			if (data.last_survey) this._last_survey = data.last_survey;
 			if (data.tutor_list) this._tutor_list = data.tutor_list;
 			if (data.my_tutor) this._my_tutor = data.my_tutor;
@@ -355,7 +355,7 @@ export default class User {
 			json.birthdate,
 			json.gender,
 			json.calcom_link,
-			json.study_id,
+			json.studies_id,
 			json.last_survey === null ? null : parseToLocalDate(json.last_survey),
 			json.tutor_list || [],
 			json.my_tutor,
diff --git a/frontend/src/lib/utils/security.ts b/frontend/src/lib/utils/security.ts
index 9d8bb0848f395da91a0346892433d4e36617ffca..734f5f63242709d53e11e916b0b1e222e2837c2f 100644
--- a/frontend/src/lib/utils/security.ts
+++ b/frontend/src/lib/utils/security.ts
@@ -28,12 +28,7 @@ export function validateEmail(email: unknown): email is string {
 }
 
 export function validateUsername(username: unknown): username is string {
-	return (
-		typeof username === 'string' &&
-		username.length >= 3 &&
-		username.length <= 31 &&
-		/^[a-z0-9_-]+$/.test(username)
-	);
+	return typeof username === 'string' && username.length >= 3 && username.length <= 31;
 }
 
 export function validatePassword(password: unknown): password is string {
diff --git a/frontend/src/routes/Header.svelte b/frontend/src/routes/Header.svelte
index 876faf2f741150f97c9aaa4e5e0bb02f82717092..dbb172773b765caaeaec429c1998c2ce5b2e6bfa 100644
--- a/frontend/src/routes/Header.svelte
+++ b/frontend/src/routes/Header.svelte
@@ -93,6 +93,11 @@
 										{$t('header.admin.studies')}
 									</a>
 								</li>
+								<li>
+									<a data-sveltekit-reload href="/admin/tasks">
+										{$t('header.admin.tasks')}
+									</a>
+								</li>
 							</ul>
 						</details>
 					</li>
diff --git a/frontend/src/routes/admin/tasks/+page.svelte b/frontend/src/routes/admin/tasks/+page.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..d503e175ea5c28f0d8c8ee775eba2b906bfb1698
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/+page.svelte
@@ -0,0 +1,39 @@
+<script lang="ts">
+	import { t } from '$lib/services/i18n';
+	import type { PageData } from './$types';
+	import Task from '$lib/types/tasks';
+
+	const { data }: { data: PageData } = $props();
+
+	let tasks: Task[] = $state(data.tasks);
+</script>
+
+<h1 class="text-xl font-bold m-5 text-center">
+	{$t('header.admin.tasks')}
+</h1>
+
+<table class="table max-w-5xl mx-auto text-center">
+	<thead>
+		<tr>
+			<th>#</th>
+			<th>{$t('tasks.level')}</th>
+			<th>{$t('tasks.shortTitle')}</th>
+		</tr>
+	</thead>
+	<tbody>
+		{#each tasks as task (task.id)}
+			<tr
+				class="hover:bg-gray-100 hover:cursor-pointer"
+				onclick={() => (window.location.href = `/admin/tasks/${task.id}`)}
+			>
+				<td>{task.id}</td>
+				<td>{task.level}</td>
+				<td>{task.shortTitle}</td>
+			</tr>
+		{/each}
+	</tbody>
+</table>
+
+<div class="mt-8 w-[64rem] mx-auto">
+	<a class="button" href="/admin/tasks/new">{$t('tasks.create')}</a>
+</div>
diff --git a/frontend/src/routes/admin/tasks/+page.ts b/frontend/src/routes/admin/tasks/+page.ts
new file mode 100644
index 0000000000000000000000000000000000000000..732612b1e902bf254b14aa93f792d86cfa0ace1e
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/+page.ts
@@ -0,0 +1,11 @@
+import { getTasksAPI } from '$lib/api/tasks';
+import Task from '$lib/types/tasks';
+import { type Load } from '@sveltejs/kit';
+
+export const load: Load = async ({ fetch }) => {
+	const tasks = Task.parseAll(await getTasksAPI(fetch));
+
+	return {
+		tasks
+	};
+};
diff --git a/frontend/src/routes/admin/tasks/TaskForm.svelte b/frontend/src/routes/admin/tasks/TaskForm.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..42c0fb295579e0109f86340d197ef76d8da4ad39
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/TaskForm.svelte
@@ -0,0 +1,101 @@
+<script lang="ts">
+	import { deleteTaskAPI } from '$lib/api/tasks';
+	import { t } from '$lib/services/i18n';
+	import type { Task } from '$lib/types/tasks';
+	import autosize from 'svelte-autosize';
+	import { ShoppingBag } from 'svelte-hero-icons';
+
+	let { form, task }: { form: FormData; task: Task | null } = $props();
+
+	async function deleteTask() {
+		if (!task) return;
+		await deleteTaskAPI(fetch, task.id);
+		document.location.href = '/admin/tasks';
+	}
+</script>
+
+<div class="mx-auto w-full max-w-5xl px-4">
+	<h2 class="text-xl font-bold m-5 text-center">
+		{$t(task === null ? 'tasks.createTitle' : 'tasks.editTitle')}
+	</h2>
+
+	{#if form?.message}
+		<div class="alert alert-error shadow-lg mb-4">
+			{form?.message}
+		</div>
+	{/if}
+
+	<form method="post">
+		<label class="label" for="level">{$t('tasks.level')} *</label>
+		<select
+			class="select select-bordered w-full"
+			id="level"
+			name="level"
+			required
+			value={task?.level}
+		>
+			<option value="A1">A1</option>
+			<option value="A2">A2</option>
+			<option value="B1">B1</option>
+			<option value="B2">B2</option>
+			<option value="C1">C1</option>
+		</select>
+
+		<label class="label" for="shortTitle">{$t('tasks.shortTitle')} *</label>
+		<input
+			class="input w-full"
+			type="text"
+			id="shortTitle"
+			name="shortTitle"
+			required
+			value={task?.shortTitle}
+		/>
+
+		<label class="label" for="instructions">{$t('tasks.instructions')}</label>
+		<textarea
+			use:autosize
+			class="input w-full"
+			id="instructions"
+			name="instructions"
+			value={task?.instructions}
+		></textarea>
+
+		<label class="label" for="learnerInstructions">{$t('tasks.learnerInstructions')}</label>
+		<textarea
+			use:autosize
+			class="input w-full"
+			id="learnerInstructions"
+			name="learnerInstructions"
+			value={task?.learnerInstructions}
+		></textarea>
+
+		<label class="label" for="examples">{$t('tasks.examples')} *</label>
+		<textarea
+			use:autosize
+			class="input w-full"
+			id="examples"
+			name="examples"
+			required
+			value={task?.examples}
+		></textarea>
+
+		<div class="mt-4 mb-6">
+			<input type="hidden" name="id" value={task ? task.id : ''} />
+			<button type="submit" class="button">
+				{$t(task === null ? 'button.create' : 'button.update')}
+			</button>
+			<a class="btn btn-outline float-end ml-2" href="/admin/tasks">
+				{$t('button.cancel')}
+			</a>
+			{#if task}
+				<button
+					type="button"
+					class="btn btn-error btn-outline float-end"
+					onclick={() => confirm($t('tasks.deleteConfirm')) && deleteTask()}
+				>
+					{$t('button.delete')}
+				</button>
+			{/if}
+		</div>
+	</form>
+</div>
diff --git a/frontend/src/routes/admin/tasks/[id]/+page.server.ts b/frontend/src/routes/admin/tasks/[id]/+page.server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ea11ed7010df5467a0ef6635c4220f319f1cb23
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/[id]/+page.server.ts
@@ -0,0 +1,49 @@
+import { updateTaskAPI } from '$lib/api/tasks';
+import { redirect, type Actions } from '@sveltejs/kit';
+
+export const actions: Actions = {
+	default: async ({ request, fetch }) => {
+		const formData = await request.formData();
+
+		const idStr = formData.get('id')?.toString();
+		const level = formData.get('level')?.toString();
+		const shortTitle = formData.get('shortTitle')?.toString();
+
+		const instructions = formData.get('instructions')?.toString() || '';
+
+		const learnerInstructions = formData.get('learnerInstructions')?.toString() || '';
+
+		const examples = formData.get('examples')?.toString();
+
+		if (!level || !shortTitle || !examples || !idStr) {
+			return {
+				message: 'Invalid request: Missing required fields'
+			};
+		}
+
+		const id = parseInt(idStr, 10);
+		if (isNaN(id)) {
+			return {
+				message: 'Invalid request: Invalid task ID'
+			};
+		}
+
+		const ok = await updateTaskAPI(
+			fetch,
+			id,
+			level,
+			shortTitle,
+			instructions,
+			learnerInstructions,
+			examples
+		);
+
+		if (!ok) {
+			return {
+				message: 'Invalid request: Failed to update task'
+			};
+		}
+
+		return redirect(303, `/admin/tasks`);
+	}
+};
diff --git a/frontend/src/routes/admin/tasks/[id]/+page.svelte b/frontend/src/routes/admin/tasks/[id]/+page.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..08c2e686a3f917cf16f8339c4a21f0462cd461bd
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/[id]/+page.svelte
@@ -0,0 +1,8 @@
+<script lang="ts">
+	import type { PageData } from './$types';
+	import TaskForm from '../TaskForm.svelte';
+
+	let { form, data }: { form: FormData; data: PageData } = $props();
+</script>
+
+<TaskForm {form} task={data.task} />
diff --git a/frontend/src/routes/admin/tasks/[id]/+page.ts b/frontend/src/routes/admin/tasks/[id]/+page.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d05028075f04922cf32e5f12ea4f8586062e936c
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/[id]/+page.ts
@@ -0,0 +1,20 @@
+import { getTaskAPI } from '$lib/api/tasks';
+import Task from '$lib/types/tasks';
+import { error, type Load } from '@sveltejs/kit';
+
+export const load: Load = async ({ fetch, params }) => {
+	const idStr = params.id;
+	if (!idStr) {
+		return error(400, 'Invalid request: Missing task ID');
+	}
+	const id = parseInt(idStr, 10);
+
+	const task = Task.parse(await getTaskAPI(fetch, id));
+	if (!task) {
+		return error(404, 'Task not found');
+	}
+
+	return {
+		task
+	};
+};
diff --git a/frontend/src/routes/admin/tasks/new/+page.server.ts b/frontend/src/routes/admin/tasks/new/+page.server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..263ac17c3fb9723fc38e621f4742dfbdfed30ad4
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/new/+page.server.ts
@@ -0,0 +1,40 @@
+import { createTaskAPI } from '$lib/api/tasks';
+import { redirect, type Actions } from '@sveltejs/kit';
+
+export const actions: Actions = {
+	default: async ({ request, fetch }) => {
+		const formData = await request.formData();
+
+		const level = formData.get('level')?.toString();
+		const shortTitle = formData.get('shortTitle')?.toString();
+
+		const instructions = formData.get('instructions')?.toString() || '';
+
+		const learnerInstructions = formData.get('learnerInstructions')?.toString() || '';
+
+		const examples = formData.get('examples')?.toString();
+
+		if (!level || !shortTitle || !examples) {
+			return {
+				message: 'Invalid request: Missing required fields'
+			};
+		}
+
+		const id = await createTaskAPI(
+			fetch,
+			level,
+			shortTitle,
+			instructions,
+			learnerInstructions,
+			examples
+		);
+
+		if (id === undefined) {
+			return {
+				message: 'Invalid request: Failed to create task'
+			};
+		}
+
+		return redirect(303, `/admin/tasks`);
+	}
+};
diff --git a/frontend/src/routes/admin/tasks/new/+page.svelte b/frontend/src/routes/admin/tasks/new/+page.svelte
new file mode 100644
index 0000000000000000000000000000000000000000..2998be34552faff8ff983a2ee7f161c6df9684d1
--- /dev/null
+++ b/frontend/src/routes/admin/tasks/new/+page.svelte
@@ -0,0 +1,7 @@
+<script lang="ts">
+	import TaskForm from '../TaskForm.svelte';
+
+	let { form }: { form: FormData } = $props();
+</script>
+
+<TaskForm {form} task={null} />
diff --git a/frontend/src/routes/register/[[studyId]]/+page.server.ts b/frontend/src/routes/register/[[studyId]]/+page.server.ts
index 1e911c77c118a89e3f897fe4fab837d2c0c5e7c6..d2354f635b09abb7975c2432be0b817a079ecdcd 100644
--- a/frontend/src/routes/register/[[studyId]]/+page.server.ts
+++ b/frontend/src/routes/register/[[studyId]]/+page.server.ts
@@ -1,14 +1,16 @@
 import { addUserToStudyAPI } from '$lib/api/studies';
-import { patchUserAPI, getUsersAPI } from '$lib/api/users';
+import { patchUserAPI } from '$lib/api/users';
 import { formatToUTCDate } from '$lib/utils/date';
 import { validateEmail, validatePassword, validateUsername } from '$lib/utils/security';
 import { redirect, type Actions } from '@sveltejs/kit';
 
 export const actions: Actions = {
-	register: async ({ request, fetch, params }) => {
+	register: async ({ request, fetch, params, url }) => {
 		const formData = await request.formData();
-		const studyId = params.studyId;
-		if (!studyId) return { message: 'Invalid request' };
+		const study_idStr = params.studyId;
+		if (!study_idStr) return { message: 'Invalid request' };
+		const study_id = parseInt(study_idStr);
+		if (isNaN(study_id)) return { message: 'Invalid request' };
 
 		const email = formData.get('email');
 		const nickname = formData.get('nickname');
@@ -33,7 +35,7 @@ export const actions: Actions = {
 				'Content-Type': 'application/json'
 			},
 			method: 'POST',
-			body: JSON.stringify({ email, nickname, password, is_tutor })
+			body: JSON.stringify({ email, nickname, password, is_tutor, study_id })
 		});
 
 		if (response.status === 400) return { message: 'User already exists' };
@@ -53,7 +55,11 @@ export const actions: Actions = {
 		if (response.status === 422) return { message: 'Invalid request' };
 		if (!response.ok) return { message: 'Unknown error occurred' };
 
-		return redirect(303, `/register/${studyId}`);
+		if (url.searchParams.has('role')) {
+			return redirect(303, `/register/${study_id}?role=${url.searchParams.get('role')}`);
+		}
+
+		return redirect(303, `/register/${study_id}`);
 	},
 	data: async ({ request, fetch, locals }) => {
 		if (!locals.user) {
@@ -66,7 +72,6 @@ export const actions: Actions = {
 		const targetLanguage = formData.get('targetLanguage');
 		const birthyear = formData.get('birthyear');
 		const gender = formData.get('gender');
-		const study = formData.get('study');
 		const bio = formData.get('bio');
 		let my_tutor = formData.get('myTutor');
 
@@ -86,7 +91,7 @@ export const actions: Actions = {
 				return { message: 'Invalid request' };
 			}
 
-			const response = await patchUserAPI(fetch, locals.user.id, {
+			let response = await patchUserAPI(fetch, locals.user.id, {
 				home_language: homeLanguage,
 				target_language: targetLanguage,
 				gender,
@@ -95,7 +100,7 @@ export const actions: Actions = {
 			});
 			if (!response) return { message: 'Unknown error occurred' };
 
-			redirect(303, '/register');
+			redirect(303, `/register/`);
 		} else if (locals.user.type == 1) {
 			if (!homeLanguage || !birthyear || !gender || !bio) {
 				return { message: 'Invalid request' };
@@ -116,7 +121,7 @@ export const actions: Actions = {
 				bio
 			});
 			if (!response) return { message: 'Unknown error occurred' };
-			redirect(303, '/register');
+			redirect(303, `/register/`);
 		}
 	}
 };
diff --git a/frontend/src/routes/register/[[studyId]]/+page.svelte b/frontend/src/routes/register/[[studyId]]/+page.svelte
index 84b646af6a0f51dd17fb79dd2aa6a4cbc1105802..b1c4344cc3e2e9034e78c0ac522a42a6c36ffe05 100644
--- a/frontend/src/routes/register/[[studyId]]/+page.svelte
+++ b/frontend/src/routes/register/[[studyId]]/+page.svelte
@@ -4,14 +4,12 @@
 	import { displayDate } from '$lib/utils/date';
 	import { t } from '$lib/services/i18n';
 	import { Icon, Envelope, Key, UserCircle } from 'svelte-hero-icons';
-	import Typingtest from '$lib/components/tests/typingtest.svelte';
-	import { browser } from '$app/environment';
 	import type { PageData } from './$types';
 	import Consent from '$lib/components/surveys/consent.svelte';
 	import type Study from '$lib/types/study';
 
 	let { data, form }: { data: PageData; form: FormData } = $props();
-	let study: Study | undefined = $state(data.study);
+	let study: Study | undefined | null = $state(data.study);
 	let studies: Study[] | undefined = $state(data.studies);
 	let user = $state(data.user);
 	let message = $state('');
@@ -21,7 +19,6 @@
 	let tutors = $state(data.tutors || []);
 	let isLoading = $state(false);
 	let selectedTutorEmail = $state('');
-	let is_tutor = $state(false);
 	const MAX_BIO_LENGTH = 100;
 	let remainingCharacters = $state(MAX_BIO_LENGTH);
 	let bio = $state('');
@@ -71,13 +68,6 @@
 		})()
 	);
 
-	let study_id: number | null = (() => {
-		if (!browser) return null;
-		let study_id_str = new URLSearchParams(window.location.search).get('study');
-		if (!study_id_str) return null;
-		return parseInt(study_id_str) || null;
-	})();
-
 	async function handleTutorSelection(tutor: any) {
 		selectedTutorEmail = tutor.email;
 		selectedTutor = tutor;
@@ -243,7 +233,7 @@
 			<a
 				class="button mt-8"
 				class:btn-disabled={!selectedStudy}
-				href="/register/{selectedStudy?.id}"
+				href="/register/{selectedStudy?.id}?role={data.role}"
 				data-sveltekit-reload
 			>
 				{$t('button.continue')}
@@ -328,15 +318,9 @@
 						/>
 					</div>
 				</label>
-				<div class="form-control">
-					<label for="role" class="label">
-						<span class="label-text">{$t('register.role')}</span>
-					</label>
-					<select class="select select-bordered" id="role" name="role" bind:value={is_tutor}>
-						<option value="2">{$t('register.roles.learner')}</option>
-						<option value="1">{$t('register.roles.tutor')}</option>
-					</select>
-				</div>
+				<select hidden id="role" name="role">
+					<option value={data.role === 'tutor' ? 1 : 2}></option>
+				</select>
 				<div class="form-control">
 					<button class="button mt-2">{$t('register.signup')}</button>
 				</div>
@@ -612,25 +596,16 @@
 		</div>
 	{:else if current_step == 7}
 		<div class="text-center">
-			<p class="text-center">
-				{@html $t('register.continue')}
-			</p>
-			<button class="button mt-4 w-full" onclick={() => (current_step = 6)}>
+			<p>{$t('register.testText')}</p>
+			<a class="button mt-4 w-full" href="/studies/{study?.id || user?.studies_id[0]}">
 				{$t('register.continueButton')}
-			</button>
-			<button class="button mt-4 w-full" onclick={() => (document.location.href = '/')}>
-				{$t('register.startFastButton')}
-			</button>
+			</a>
+			<!-- <button class="button mt-4 w-full" onclick={() => (document.location.href = '/')}> -->
+			<!-- 	{$t('register.startFastButton')} -->
+			<!-- </button> -->
 		</div>
-	{:else if current_step == 8}
-		{#if user}
-			<Typingtest onFinish={() => current_step++} {user} />
-		{/if}
-	{:else if current_step == 9}
+	{:else if current_step == 8}{:else if current_step == 9}
 		<div class="text-center">
-			<p class="text-center">
-				{@html $t('register.start')}
-			</p>
 			<button class="button mt-4 m-auto" onclick={() => (document.location.href = '/')}>
 				{$t('register.startButton')}
 			</button>
diff --git a/frontend/src/routes/register/[[studyId]]/+page.ts b/frontend/src/routes/register/[[studyId]]/+page.ts
index 9f2b5121e4b5fe14bef56b66afbbda8fecd0d225..b8209365de0fb398701352cb24b0745c3f304afc 100644
--- a/frontend/src/routes/register/[[studyId]]/+page.ts
+++ b/frontend/src/routes/register/[[studyId]]/+page.ts
@@ -3,8 +3,9 @@ import { getUsersAPI } from '$lib/api/users';
 import Study from '$lib/types/study';
 import type { Load } from '@sveltejs/kit';
 
-export const load: Load = async ({ parent, fetch, params }) => {
+export const load: Load = async ({ parent, fetch, params, url }) => {
 	const { user } = await parent();
+	console.log(user);
 
 	const sStudyId: string | undefined = params.studyId;
 	let study = null;
@@ -13,16 +14,31 @@ export const load: Load = async ({ parent, fetch, params }) => {
 		if (studyId) {
 			study = Study.parse(await getStudyAPI(fetch, studyId));
 		}
+	} else if (user) {
+		const studyId = user.studies_id[0];
+		if (studyId) {
+			study = Study.parse(await getStudyAPI(fetch, studyId));
+		}
 	}
 
 	const studies = Study.parseAll(await getStudiesAPI(fetch));
 
 	const users = await getUsersAPI(fetch);
 	const tutors = users.filter((user) => user.type === 1);
+
+	let role = 'learner';
+	if (url.searchParams.has('role')) {
+		const roleParam = url.searchParams.get('role');
+		if (roleParam && roleParam === 'tutor') {
+			role = 'tutor';
+		}
+	}
+
 	return {
 		studyError: !study,
 		study,
 		studies,
-		tutors
+		tutors,
+		role
 	};
 };
diff --git a/frontend/src/routes/sessions/[id]/+page.svelte b/frontend/src/routes/sessions/[id]/+page.svelte
index a8bd4b6b4c44360b76312a8e207d1d33153fd89a..84a9de893c0588ef56ee4f5b4b7ec73c948e7f27 100644
--- a/frontend/src/routes/sessions/[id]/+page.svelte
+++ b/frontend/src/routes/sessions/[id]/+page.svelte
@@ -3,11 +3,79 @@
 	import type { PageData } from './$types.js';
 	import WeeklySurvey from './WeeklySurvey.svelte';
 	import Chatbox from './Chatbox.svelte';
+	import type Task from '$lib/types/tasks';
+	import { toastAlert, toastSuccess } from '$lib/utils/toasts';
+	import { sendTaskStatusAPI } from '$lib/api/tasks';
 
 	let { data }: { data: PageData } = $props();
 	let user = data.user!;
-	let { session, jwt } = data;
+	let { session, jwt, tasks, completedTasks } = data;
 	let { onlineUsers } = session;
+
+	let level = $state('all');
+	let currentTask: Task | null = $state(data.currentTask);
+	let taskInProgress: boolean = $state(data.currentTask !== null);
+
+	let availableLevels = new Set(tasks.map((task: Task) => task.level));
+
+	async function startTask() {
+		const student = session.student;
+		if (!student || !currentTask) return;
+		const ok = await sendTaskStatusAPI(
+			fetch,
+			'start',
+			student.id,
+			user.id,
+			currentTask.id,
+			session.id
+		);
+		if (!ok) {
+			toastAlert($t('tasks.statusFail'));
+			return;
+		}
+		taskInProgress = true;
+	}
+
+	async function cancelTask() {
+		const student = session.student;
+		if (!student || !currentTask) return;
+		const ok = await sendTaskStatusAPI(
+			fetch,
+			'cancel',
+			student.id,
+			user.id,
+			currentTask.id,
+			session.id
+		);
+		if (!ok) {
+			toastAlert($t('tasks.statusFail'));
+			return;
+		}
+		taskInProgress = false;
+		currentTask = null;
+	}
+
+	async function finishTask() {
+		const student = session.student;
+		if (!student || !currentTask) return;
+		const ok = await sendTaskStatusAPI(
+			fetch,
+			'finish',
+			student.id,
+			user.id,
+			currentTask.id,
+			session.id
+		);
+		if (!ok) {
+			toastAlert($t('tasks.statusFail'));
+			return;
+		}
+		completedTasks.push(currentTask);
+
+		taskInProgress = false;
+		currentTask = null;
+		toastSuccess($t('tasks.taskFinished'));
+	}
 </script>
 
 <div class="h-full flex flex-col lg:flex-row pt-2 lg:pt-0 bg-gray-50 relative">
@@ -52,12 +120,71 @@
 			{/each}
 		</div>
 
-		<h2 class="text-lg truncate font-semibold text-gray-700 text-center border-t pt-4 mt-4">
-			{$t('utils.words.topics')}
-		</h2>
-		<p class="text-center truncate text-sm text-neutral-500 italic">
-			{$t('session.noTopic')}
-		</p>
+		{#if !taskInProgress || !currentTask}
+			{#if user.is_tutor}
+				<h2 class="text-lg truncate font-semibold text-gray-700 text-center border-t pt-4 mt-4">
+					🎯 {$t('tasks.title')}
+				</h2>
+				<div class="flex gap-2">
+					<select class="select select-bordered w-32" bind:value={level}>
+						<option value="all">{$t('utils.words.all')}</option>
+						{#each availableLevels as l}
+							<option value={l}>{l}</option>
+						{/each}
+					</select>
+					<select class="select select-bordered flex-1 overflow-hidden" bind:value={currentTask}>
+						{#each availableLevels as l}
+							{#if level === 'all' || l === level}
+								<optgroup label={l}>
+									{#each tasks.filter((task: Task) => task.level === l) as task (task.id)}
+										<option value={task}>
+											{#if completedTasks.includes(task)}
+												✓
+											{/if}
+											{task.shortTitle}
+										</option>
+									{/each}
+								</optgroup>
+							{/if}
+						{/each}
+					</select>
+				</div>
+				<button class="btn mt-2 w-full btn-primary" onclick={startTask}>
+					{$t('tasks.startTask')}
+				</button>
+			{/if}
+		{:else}
+			<p class="mt-4 font-bold">
+				🎯 {$t('tasks.taskInProgress')}:
+			</p>
+			<p>
+				{currentTask.shortTitle}
+			</p>
+			{#if user.is_tutor}
+				{#if currentTask.instructions}
+					<p>
+						{currentTask.instructions}
+					</p>
+				{/if}
+				{#if currentTask.examples}
+					<p class="mt-2 text-sm">
+						{currentTask.examples}
+					</p>
+				{/if}
+				<div class="flex gap-2 mt-4">
+					<button class="btn flex-grow" onclick={cancelTask}>
+						🔙 {$t('button.cancel')}
+					</button>
+					<button class="btn btn-primary flex-grow" onclick={finishTask}>
+						✔️ {$t('tasks.achieveTask')}
+					</button>
+				</div>
+			{:else if currentTask.learnerInstructions}
+				<p>
+					{currentTask.learnerInstructions}
+				</p>
+			{/if}
+		{/if}
 	</div>
 
 	<div class="flex flex-row flex-grow col-span-5">
diff --git a/frontend/src/routes/sessions/[id]/+page.ts b/frontend/src/routes/sessions/[id]/+page.ts
index 251ba545835504f12d817b4ff4eee7d6bfb406df..fd99a73f44317e601b6c480201547230452774f8 100644
--- a/frontend/src/routes/sessions/[id]/+page.ts
+++ b/frontend/src/routes/sessions/[id]/+page.ts
@@ -1,5 +1,11 @@
 import { getSessionAPI } from '$lib/api/sessions';
+import {
+	getTasksAPI,
+	getTaskStatusCompletedFromStudentAPI,
+	getTaskStatusFromSessionAPI
+} from '$lib/api/tasks';
 import Session from '$lib/types/session';
+import Task, { TaskStatus } from '$lib/types/tasks';
 import { error, type Load } from '@sveltejs/kit';
 
 export const load: Load = async ({ params, fetch, data }) => {
@@ -22,5 +28,34 @@ export const load: Load = async ({ params, fetch, data }) => {
 
 	await session.loadMessages(fetch);
 
-	return { session, jwt };
+	const tasksRaw = await getTasksAPI(fetch);
+	const tasks = Task.parseAll(tasksRaw);
+
+	let currentTask: Task | null = null;
+
+	const sessionTaskStatusRaw = await getTaskStatusFromSessionAPI(fetch, nid);
+	if (sessionTaskStatusRaw) {
+		const sessionTaskStatus = TaskStatus.parse(sessionTaskStatusRaw);
+		if (sessionTaskStatus && sessionTaskStatus.status == 'start') {
+			const task = tasks.find((task) => task.id === sessionTaskStatus.task_id);
+			if (task) currentTask = task;
+		}
+	}
+
+	let completedTasks: Task[] = [];
+
+	if (session.student) {
+		const completedTasksStatusRaw = await getTaskStatusCompletedFromStudentAPI(
+			fetch,
+			session.student.id
+		);
+		if (completedTasksStatusRaw) {
+			const completedTasksStatus = TaskStatus.parseAll(completedTasksStatusRaw);
+			completedTasks = completedTasksStatus
+				.map((taskStatus) => tasks.find((task) => task.id === taskStatus.task_id))
+				.filter((task) => task !== undefined) as Task[];
+		}
+	}
+
+	return { session, jwt, tasks, currentTask, completedTasks };
 };
diff --git a/frontend/src/routes/studies/[[id]]/+page.svelte b/frontend/src/routes/studies/[[id]]/+page.svelte
index 358954930a8a5e2eebebdc4906cf7e764e181d88..3bf196147168d49eb831195492a7fa7fcca6e556 100644
--- a/frontend/src/routes/studies/[[id]]/+page.svelte
+++ b/frontend/src/routes/studies/[[id]]/+page.svelte
@@ -161,16 +161,16 @@
 					</div>
 				{/if}
 			{/key}
+			<!-- {:else if current_step == study.tests.length + 2} -->
+			<!-- 	<div class="flex flex-col h-full"> -->
+			<!-- 		<EndQuestions study_id={study.id} {rid} onFinish={() => current_step++} /> -->
+			<!-- 	</div> -->
 		{:else if current_step == study.tests.length + 2}
-			<div class="flex flex-col h-full">
-				<EndQuestions study_id={study.id} {rid} onFinish={() => current_step++} />
-			</div>
-		{:else if current_step == study.tests.length + 3}
 			<div class="flex flex-col h-full">
 				<div class="flex-grow text-center mt-16">
 					<span>{$t('studies.complete')}</span>
 
-					<div class="mt-4">
+					<div class="my-4">
 						{$t('studies.score.title')}
 						{#await getTestEntriesScoreAPI(fetch, rid)}
 							{$t('studies.score.loading')}
@@ -182,6 +182,9 @@
 							{/if}
 						{/await}
 					</div>
+
+					<!-- TODO: Only if registration was required -->
+					<a class="btn btn-primary" href="/">{$t('studies.backToHomePage')}</a>
 				</div>
 
 				<dl class="text-sm">