TaskFlow (Local Task Tracker)

Minimalistic local task tracker implementing a simple workflow:

Backlog → In Progress → Done

The service exposes a clean HTTP API, provides workflow metrics, persists state to disk, and includes a lightweight HTML dashboard.


Tech Stack

  • Python 3.14
  • FastAPI 0.135
  • Pydantic v2
  • Pytest
  • Docker (local runtime)

Features

  • CRUD operations for tasks
  • Workflow transitions with validation:
    • backlog → in_progress → done
  • Idempotent start operation
  • Metrics:
    • Lead Time
    • Cycle Time
  • CSV export with injection protection
  • Persistent storage (data/tasks.json)
  • HTML dashboard (/stats)
  • Lightweight dashboard data loading via internal /ui_data/* routes
  • Atomic file writes with corruption recovery

Project Structure

.
├── app/        # Application code
│   ├── api/    # Transport layer (FastAPI routers)
│   ├── domain/ # Business logic
│   └── storage/# Persistence layer
├── data/       # Persistent storage (tasks.json)
├── tests/      # Test suite
└── Dockerfile

Architecture

The project follows a layered architecture:

1. Transport Layer

  • FastAPI routers
  • Request/response validation (Pydantic)
  • HTTP error mapping

2. Domain Layer

  • Business rules
  • Workflow transitions
  • Metrics calculation

3. Storage Layer

  • File-based persistence
  • Atomic writes (tmp + rename)
  • Corruption recovery (backup + reset)

Domain Model

Task

{
  "id": "uuid",
  "title": "string (max 100)",
  "created_at": "datetime (UTC ISO-8601)",
  "started_at": "datetime | null",
  "done_at": "datetime | null"
}

Status Derivation

Status is not stored explicitly:

  • backlog → started_at == null
  • in_progress → started_at != null && done_at == null
  • done → done_at != null

API Endpoints

Tasks

List tasks

GET /api/tasks

Query params:

  • limit (default: 100)
  • status (optional: backlog | in_progress | done)
  • search (optional substring match)

Get task by ID

GET /api/tasks/{id}

Create task

POST /api/tasks

Update task

PATCH /api/tasks/{id}

Delete task

DELETE /api/tasks/{id}

Workflow Actions

Start task

POST /api/tasks/{id}/start

Rules:

  • Idempotent (multiple calls do not change started_at)
  • Valid only if task is in backlog

Complete task

POST /api/tasks/{id}/done

Rules:

  • Allowed only from in_progress
  • Enforces workflow integrity

Export

GET /api/tasks/export
  • Returns text/csv
  • Includes header row
  • Protects against CSV injection (=, +, -, @)

Stats

GET /stats

HTML page:

  • Top block:

    • Selected task details:
      • Title
      • Status
      • Created datetime
      • Start datetime
      • Done datetime
      • Cycle time
  • Bottom:

    • Kanban board:
      • Backlog
      • In Progress
      • Done

Implementation notes:

  • /stats returns a lightweight HTML shell
  • Task lists are loaded separately from an internal UI endpoint
  • Selected task details are loaded on demand when a card is selected
  • Full task payloads are not embedded into the HTML for every card

Internal UI Data Routes

These routes are used only by the HTML dashboard and are intentionally hidden from Swagger / OpenAPI.

Board data

GET /ui_data/stats/board

Returns lightweight task list items grouped by status:

  • backlog_tasks
  • in_progress_tasks
  • done_tasks

Each list item contains only:

  • id
  • title
  • status
  • display_date_label
  • display_date_value

Task details

GET /ui_data/tasks/{id}

Returns the full details needed for the selected-task panel:

  • id
  • title
  • status
  • created_at
  • started_at
  • done_at
  • cycle_time

Error Format

All errors follow unified format:

{
  "error": "invalid_*",
  "message": "human readable description"
}

Examples:

  • invalid_id
  • invalid_payload
  • invalid_transition
  • invalid_transaction

HTTP codes:

  • 2xx — success
  • 4xx — client errors (validation, transitions)

Data Persistence

  • File: data/tasks.json
  • Writes are atomic:
    1. Write to temp file
    2. Rename

Corruption Handling

If JSON is invalid:

  • Backup corrupted file
  • Reset to empty state
  • Service continues running

Metrics

  • Lead Time = done_at - created_at
  • Cycle Time = done_at - started_at

Average values are computed across completed tasks.


Testing Requirements

Test suite must cover:

  1. CRUD operations and filters
  2. Workflow transitions:
    • valid transitions → 2xx
    • invalid → 409 invalid_transaction
  3. Metrics correctness
  4. CSV export:
    • text/csv
    • correct header
  5. Persistence between restarts
  6. Performance:
    • typical requests ≤ 100 ms

Running with Docker

Build and run

docker build -t taskflow .
docker run -p 8000:8000 -v $(pwd)/data:/app/data taskflow
docker compose up --build

Conventions

  • All timestamps are UTC (ISO-8601)
  • Validation via Pydantic v2
  • Strict API contracts
  • No implicit state mutations
  • Idempotent operations where required

Goal

The project is considered complete when:

  • The service runs in Docker with a single command
  • All tests pass
  • State persists across restarts
  • API behaves according to specification

Description
No description provided
Readme 101 KiB
Languages
Python 85.3%
HTML 13.9%
Dockerfile 0.8%