feat(taskflow): add core task API, storage persistence, csv export, stats page, and test coverage
This commit is contained in:
8
app/domain/__init__.py
Normal file
8
app/domain/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from app.domain.tasks import InvalidTransitionError, complete_task, start_task
|
||||
|
||||
__all__ = [
|
||||
"InvalidTransitionError",
|
||||
"start_task",
|
||||
"complete_task",
|
||||
]
|
||||
|
||||
60
app/domain/tasks.py
Normal file
60
app/domain/tasks.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, UTC
|
||||
|
||||
from app.storage.models import StoredTask
|
||||
|
||||
|
||||
class InvalidTransitionError(Exception):
|
||||
"""Raised when task workflow transition is invalid."""
|
||||
|
||||
|
||||
def start_task(task: StoredTask) -> StoredTask:
|
||||
"""
|
||||
Transition task from backlog → in_progress.
|
||||
|
||||
Rules:
|
||||
- Idempotent: if already started, do not change started_at
|
||||
- Cannot start a task that is already done
|
||||
"""
|
||||
# already done → invalid
|
||||
if task.done_at is not None:
|
||||
raise InvalidTransitionError("invalid_transaction")
|
||||
|
||||
# already started → idempotent (no change)
|
||||
if task.started_at is not None:
|
||||
return task
|
||||
|
||||
return StoredTask(
|
||||
id=task.id,
|
||||
title=task.title,
|
||||
created_at=task.created_at,
|
||||
started_at=datetime.now(UTC),
|
||||
done_at=task.done_at,
|
||||
)
|
||||
|
||||
|
||||
def complete_task(task: StoredTask) -> StoredTask:
|
||||
"""
|
||||
Transition task from in_progress → done.
|
||||
|
||||
Rules:
|
||||
- Allowed only if task is started
|
||||
- Idempotent: if already done, do not change done_at
|
||||
"""
|
||||
# not started → invalid
|
||||
if task.started_at is None:
|
||||
raise InvalidTransitionError("invalid_transaction")
|
||||
|
||||
# already done → idempotent
|
||||
if task.done_at is not None:
|
||||
return task
|
||||
|
||||
return StoredTask(
|
||||
id=task.id,
|
||||
title=task.title,
|
||||
created_at=task.created_at,
|
||||
started_at=task.started_at,
|
||||
done_at=datetime.now(UTC),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user