2. Créer l'entité Todo
Objectif: utiliser la CLI pour créer le fichier minimal, puis écrire le modèle métier et ses tests.

Depuis la racine du projet:
Répondre au prompt:
| Text Only |
|---|
| Entité — utilisez le singulier (ex : Recipe, recipe_step, MealPlan)
Nom de l'entité: Todo
|
La CLI crée:
| Text Only |
|---|
| src/todo_list_service/domain/models/todo.py
|
Le fichier initial est volontairement exécutable sans import inutilisé :
| Python |
|---|
| from __future__ import annotations
from arclith.domain.models.entity import Entity
# Guides:
# - Arclith entity tutorial: https://github.com/karned-rekipe/arclith/blob/main/docs/tutorials/todo-list/02-create-entity.md
# - Arclith architecture: https://github.com/karned-rekipe/arclith/blob/main/arclith/docs/architecture.md
# - Pydantic models: https://docs.pydantic.dev/latest/concepts/models/
# - Pydantic fields: https://docs.pydantic.dev/latest/concepts/fields/
# - Pydantic validators: https://docs.pydantic.dev/latest/concepts/validators/
class Todo(Entity):
"""TODO: define the business fields and invariants for this entity.
Arclith Entity already provides uuid, audit fields, soft-delete fields,
and optimistic versioning.
"""
# Example:
# title: str = Field(min_length=1, max_length=140)
pass
|
Field n'est pas importé tant que l'exemple reste commenté. L'ajouter depuis
pydantic au moment de déclarer les vrais champs.
Modifier src/todo_list_service/domain/models/todo.py:
| Python |
|---|
| from __future__ import annotations
from datetime import date, datetime
from enum import StrEnum
from arclith.domain.models.entity import Entity
from pydantic import Field, field_validator, model_validator
class TodoStatus(StrEnum):
TODO = "todo"
WIP = "wip"
DONE = "done"
class Todo(Entity):
title: str = Field(min_length=1, max_length=140)
description: str = Field(default="", max_length=4000)
due_date: date
completed_at: datetime | None = None
status: TodoStatus = TodoStatus.TODO
@field_validator("title")
@classmethod
def normalize_title(cls, value: str) -> str:
normalized = value.strip()
if not normalized:
raise ValueError("title ne peut pas etre vide")
return normalized
@field_validator("description")
@classmethod
def normalize_description(cls, value: str) -> str:
return value.strip()
@model_validator(mode="after")
def validate_completion(self) -> "Todo":
if self.status == TodoStatus.DONE and self.completed_at is None:
raise ValueError("completed_at est requis quand status=done")
if self.status != TodoStatus.DONE and self.completed_at is not None:
raise ValueError("completed_at doit rester vide tant que la todo n'est pas done")
return self
|
Commentaires importants:
Todo hérite de Entity, donc Arclith fournit déjà uuid, created_at, updated_at,
deleted_at et version;
TodoStatus est une enum de chaîne pour produire des valeurs JSON lisibles;
- les invariants métier restent dans le domaine, pas dans FastAPI, MCP ou LangGraph.
Tester
Créer tests/test_todo_entity.py:
| Python |
|---|
| from datetime import date, datetime, timezone
import pytest
from pydantic import ValidationError
from todo_list_service.domain.models.todo import Todo, TodoStatus
def test_create_todo_with_required_fields() -> None:
todo = Todo(title=" Preparer la revue ", due_date=date(2026, 8, 31))
assert todo.title == "Preparer la revue"
assert todo.description == ""
assert todo.status == TodoStatus.TODO
assert todo.completed_at is None
def test_done_requires_completed_at() -> None:
with pytest.raises(ValidationError):
Todo(title="Publier", due_date=date(2026, 8, 31), status=TodoStatus.DONE)
def test_completed_at_is_rejected_before_done() -> None:
with pytest.raises(ValidationError):
Todo(
title="Publier",
due_date=date(2026, 8, 31),
completed_at=datetime.now(timezone.utc),
status=TodoStatus.WIP,
)
|
Lancer:
| Bash |
|---|
| uv run python -m pytest tests/test_todo_entity.py
|
Voie rapide
| Bash |
|---|
| arclith-cli add-entity Todo
|
Étape suivante: créer les use cases.