Files
task_flow/README.md

365 lines
5.4 KiB
Markdown

# 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
```json
{
"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
```
### One-command run (recommended)
```
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
---