diff --git a/backend/app/crud/tasks.py b/backend/app/crud/tasks.py
index 7877449104999f6f7071cfe7018a9218fa974960..e3dbd2a326ce328719aaba002bd78212856d6a71 100644
--- a/backend/app/crud/tasks.py
+++ b/backend/app/crud/tasks.py
@@ -30,3 +30,22 @@ def update_task(db: Session, task: schemas.TaskCreate, task_id: int) -> None:
 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()
+    )
diff --git a/backend/app/models/tasks.py b/backend/app/models/tasks.py
index c3f7a391aad9b8d66d408a73488459f0f10d1a1b..d36a8e1131f8a88a7d5209bb814d1622dac2cd47 100644
--- a/backend/app/models/tasks.py
+++ b/backend/app/models/tasks.py
@@ -15,11 +15,11 @@ class Task(Base):
 
 
 class TaskStatus(Base):
-    __tablename__ = "task_statuses"
+    __tablename__ = "task_status"
     id = Column(Integer, primary_key=True, index=True)
     task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False)
-    user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
-    status = Column(String, 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/tasks.py b/backend/app/routes/tasks.py
index 136eb833257bdd55ccd03f8af07f781a1ed281dc..68eede8c07c6c50e024e018371e4c7d02eff2fba 100644
--- a/backend/app/routes/tasks.py
+++ b/backend/app/routes/tasks.py
@@ -4,7 +4,7 @@ from sqlalchemy.orm import Session
 import crud
 import schemas
 from database import get_db
-from routes.decorators import require_admin
+from routes.decorators import require_admin, require_tutor
 
 taskRouter = APIRouter(prefix="/tasks", tags=["Tasks"])
 
@@ -45,6 +45,28 @@ def get_tasks(
     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("/{task_id}", response_model=schemas.Task)
 def get_task(
     task_id: int,
diff --git a/backend/app/schemas/tasks.py b/backend/app/schemas/tasks.py
index 524dcea453ee2a384ac5d6e04d471768d932785a..71312f86ecc0651a54b09b5260b12aa599fc9196 100644
--- a/backend/app/schemas/tasks.py
+++ b/backend/app/schemas/tasks.py
@@ -1,4 +1,4 @@
-from pydantic import BaseModel
+from pydantic import BaseModel, NaiveDatetime
 
 
 class TaskCreate(BaseModel):
@@ -11,3 +11,16 @@ class TaskCreate(BaseModel):
 
 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/frontend/src/lang/fr.json b/frontend/src/lang/fr.json
index cc5da60fdc709a805df8eb22b84f36e3ddc8934e..54bdee72414e8556a5189524d1dafa7f97b4eda4 100644
--- a/frontend/src/lang/fr.json
+++ b/frontend/src/lang/fr.json
@@ -407,7 +407,11 @@
 		"shortTitle": "Nom de la tâche (max 5 mots)",
 		"instructions": "Instructions le tuteur (peut être sur plusieurs lignes)",
 		"learnerInstructions": "Instructions pour l'apprenant (peut être sur plusieurs lignes)",
-		"examples": "Exemples (peut être sur plusieurs lignes)"
+		"examples": "Exemples (peut être sur plusieurs lignes)",
+		"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"
 	},
 	"button": {
 		"create": "Créer",
@@ -425,7 +429,9 @@
 		"updated": "Mis à jour !",
 		"delete": "Supprimer",
 		"remove": "Retirer",
-		"continue": "Continuer"
+		"continue": "Continuer",
+		"select": "Sélectionner",
+		"finish": "Terminer"
 	},
 	"utils": {
 		"month": {
@@ -510,7 +516,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/lib/api/tasks.ts b/frontend/src/lib/api/tasks.ts
index 614bd502edf0f45cca90e0899890f4b6e4abfbcd..a2ed536fd8f86a1bd6c4a6e7aeb87ef60fbd5f97 100644
--- a/frontend/src/lib/api/tasks.ts
+++ b/frontend/src/lib/api/tasks.ts
@@ -66,3 +66,34 @@ export async function deleteTaskAPI(fetch: fetchType, task_id: number): Promise<
 	});
 	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();
+}
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
index ce6129f86bb6f2eacae465f8d55a133476d12e2f..70804a96a6d6f1aad04fd807b69350bf0d2fc0de 100644
--- a/frontend/src/lib/types/tasks.ts
+++ b/frontend/src/lib/types/tasks.ts
@@ -69,3 +69,79 @@ export default class 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/routes/sessions/[id]/+page.svelte b/frontend/src/routes/sessions/[id]/+page.svelte
index a8bd4b6b4c44360b76312a8e207d1d33153fd89a..36ed70bbce0b0004a05995b38b11df8c165c22cd 100644
--- a/frontend/src/routes/sessions/[id]/+page.svelte
+++ b/frontend/src/routes/sessions/[id]/+page.svelte
@@ -3,11 +3,77 @@
 	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 } = 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;
+		}
+		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">
@@ -53,11 +119,61 @@
 		</div>
 
 		<h2 class="text-lg truncate font-semibold text-gray-700 text-center border-t pt-4 mt-4">
-			{$t('utils.words.topics')}
+			{$t('utils.words.tasks')}
 		</h2>
-		<p class="text-center truncate text-sm text-neutral-500 italic">
-			{$t('session.noTopic')}
-		</p>
+		{#if !taskInProgress || !currentTask}
+			<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}>{task.shortTitle}</option>
+								{/each}
+							</optgroup>
+						{/if}
+					{/each}
+				</select>
+			</div>
+			<button class="btn mt-2 w-full btn-primary" onclick={startTask}>
+				{$t('button.select')}
+			</button>
+		{:else}
+			<p class="mt-4 font-bold">
+				{$t('tasks.taskInProgress')}:
+			</p>
+			<p>
+				{currentTask.shortTitle}
+			</p>
+			{#if currentTask.instructions}
+				<p class="mt-2 font-bold">
+					{$t('utils.words.instructions')}:
+				</p>
+				<p>
+					{currentTask.instructions}
+				</p>
+			{/if}
+			<p class="mt-2 font-bold">
+				{$t('utils.words.examples')}:
+			</p>
+			<p>
+				{currentTask.examples}
+			</p>
+			<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('button.finish')}
+				</button>
+			</div>
+		{/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..08494fa31ac70d77b62e67b4e190657ba44d99de 100644
--- a/frontend/src/routes/sessions/[id]/+page.ts
+++ b/frontend/src/routes/sessions/[id]/+page.ts
@@ -1,5 +1,7 @@
 import { getSessionAPI } from '$lib/api/sessions';
+import { getTasksAPI, 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 +24,19 @@ 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;
+		}
+	}
+
+	return { session, jwt, tasks, currentTask };
 };