Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# AGENTS.md — Standing Knowledge & Instructions

## 1. Project Purpose & Scope
**Task-Manager** is a task and project management web application built with Python and Flask. It allows users to organize tasks under project tabs, manage open/closed task statuses, rename projects and tasks, and interact through either a web browser interface or a RESTful JSON API documented via Swagger.

---

## 2. Verified Technology Stack
*(Source of truth: `pyproject.toml`, `task_manager/__init__.py`, `task_manager/app.py`)*

* **Language**: Python (`>=3.13` as declared in `pyproject.toml`)
* **Web Framework**: Flask 3.1.3
* **Database & ORM**: SQLite (`ctm.db`), Flask-SQLAlchemy 3.1.1, SQLAlchemy 2.0.41
* **API Documentation**: Flasgger 0.9.7.1 (Swagger UI at `/apidocs/`)
* **Frontend**: HTML5, Jinja2 3.1.6, Bootstrap 3.3.7 (CDN), jQuery 1.12.4 (CDN), custom UX script (`ux.js`)
* **Test Suite**: `pytest` 9.0.3, `pytest-cov` 6.2.1

---

## 3. Project Entry Points & Running
* **Development Server**: `python task_manager/app.py` or `make dev` (Runs Flask dev server on `http://localhost:5000`)
* **Production Server**: `make prod` (Runs Gunicorn server on `http://localhost:8000`)
* **Interactive API Documentation**: `http://localhost:5000/apidocs/`
* **Application Factory**: `task_manager/__init__.py:create_app()`

---

## 4. Test Execution & Quality Assurance
The project supports standard Python environment runners. When using `uv` in this sandbox environment:
* **Run All Tests**: `uv run pytest`
* **Run with Coverage**: `uv run pytest --cov=task_manager --cov-report=term-missing`
* **Code Formatting / Type Checks** (configured in `pyproject.toml`):
```bash
uv run black --check task_manager tests
uv run isort --check task_manager tests
uv run mypy task_manager
```

---

## 5. Architecture & Execution Flow

```
┌─────────────────────────┐
│ USER / HTTP CLIENT │
└────────────┬────────────┘
┌─────────────────┴─────────────────┐
│ │
▼ ▼
[ WEB UI REQUESTS ] [ REST API REQUESTS ]
e.g., GET /, POST /add e.g., GET /api/tasks,
GET /project/<slug> POST /api/tasks, PUT /api/...
│ │
└─────────────────┬─────────────────┘
[ Flask Blueprint Routes ]
(task_manager/routes.py)
┌───────────────────────────┴───────────────────────────┐
│ │
▼ ▼
[ Jinja2 View Renderer ] [ JSON Response ]
(task_manager/templates/index.html) (Flask jsonify)
│ │
└───────────────────────────┬───────────────────────────┘
[ SQLAlchemy ORM Models ]
(task_manager/models.py)
├── Projects (project_id, project_name, active, url_slug)
└── Tasks (task_id, project_id, task, status)
[ SQLite Database ]
(instance/ctm.db)
```

---

## 6. Repository Map

```
task-manager/
├── task_manager/
│ ├── __init__.py # Application factory (create_app) & DB initialization
│ ├── app.py # Main entrypoint with Flasgger Swagger initialization
│ ├── models.py # Database models (Projects, Tasks)
│ ├── routes.py # Web UI routes & REST API endpoints
│ ├── templates/
│ │ └── index.html # Jinja2 template for web interface
│ └── static/
│ └── js/
│ └── ux.js # Client-side JavaScript interactions
├── tests/
│ ├── conftest.py # Pytest fixtures (app, client, create_project, create_task)
│ ├── test_models.py # ORM Model unit tests
│ ├── test_routes.py # Web route integration tests
│ ├── test_api.py # Web API integration tests
│ └── test_rest.py # REST API unit tests
├── harness_learning/ # Exploration reports, implementation plans, and micro-contexts
├── pyproject.toml # Project metadata, dependencies, and tool settings
├── Makefile # Target commands (dev, prod, test, clean)
└── REST_README.md # REST API usage documentation
```

---

## 7. Development Conventions
1. **Preserve Existing Signatures**: Ensure function and model parameter lists retain backwards compatibility to prevent breaking callers and test fixtures.
2. **Explicit Form & JSON Fallbacks**: Route handlers processing `request.form` or `request.get_json()` must handle missing keys gracefully using fallbacks.
3. **ORM Model Methods**: Domain logic and slug generation belong directly on model classes in `models.py`.
4. **Clean Commits**: Commit messages should follow standard Git conventions (short subject line under 50 characters, blank line, clear body detailing reasoning).

---

## 8. What NOT To Do (Negative Constraints)
* **DO NOT** modify codebase files during exploration phases when only research or planning is requested.
* **DO NOT** write code without progressive exploration and context gathering first.
* **DO NOT** introduce heavy external dependencies (e.g. migration frameworks or custom enum libraries) when simple Python standard types suffice.
* **DO NOT** state claims as verified truth without citing inspected files or test output.

---

## 9. Verification Instructions
Before declaring any task complete, perform three levels of verification:
1. **Behavioral Verification**: Confirm that the implemented requirement actually works end-to-end as intended in runtime execution, not merely that automated tests exist.
2. **Regression & Test Verification**: Execute `uv run pytest` to verify that relevant unit and integration tests pass and no regressions were introduced.
3. **Repository State Verification**: Run `git status` to confirm that only intended files were modified or created.
99 changes: 99 additions & 0 deletions harness_learning/due_date_spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Specification: Task Due Dates Feature

## 1. Overview & Purpose
This specification defines the requirement for adding an **optional Due Date** field to tasks in the Task-Manager application. When specified, the due date is displayed directly in front of the task description in `DD/MM` format. If the due date has passed, the due date label turns **red**. Tasks created without a due date (and all pre-existing tasks in the database) default to showing `"Unassigned"`.

---

## 2. Core Requirements & Scope Boundaries

### Included Features:
1. **Optional Due Date Input**: User can optionally select or enter a due date during task creation via Web UI or REST API.
2. **Display Format**: Rendered in `DD/MM` format (e.g. `25/12`) directly in front of the status checkbox / task action icons.
3. **Unassigned Fallback**: Tasks without a due date display `"Unassigned"`. All existing records in the database inherit `"Unassigned"`.
4. **Overdue Highlighting**: If the current date exceeds the task's due date, the due date text/badge renders in **red** (e.g., Bootstrap CSS `text-danger` or `label-danger`).
5. **REST API & Swagger Integration**: `due_date` field exposed in GET, POST, and PUT API responses/payloads.

### Explicit Negative Constraints (Out of Scope):
* **NO Reminders**: Do NOT build email, push, or popup reminder functionality.
* **NO Notifications**: Do NOT send background notifications or queue system messages.
* **NO Recurring Schedules**: Do NOT build recurring due date logic or calendar sync integrations.

---

## 3. Interfaces & Data Contracts

### A. Database Schema (`task_manager/models.py`)
* **New Column**: `due_date = db.Column(db.String(10), default="Unassigned")`
* **Model Constructor**:
```python
def __init__(self, project_id, task, status=True, priority="Medium", due_date="Unassigned"):
self.project_id = project_id
self.task = task
self.status = status
self.priority = priority
self.due_date = due_date if due_date else "Unassigned"
```

### B. Web Interface (`task_manager/templates/index.html` & `routes.py`)
1. **Creation Form**:
* Add optional date input field in task form:
`<input type="date" id="due_date" name="due_date" class="form-control" placeholder="Due Date (DD/MM)">`
2. **Task Table Display**:
* Position: Rendered just before the status check icon / column in `index.html`.
* Template Logic:
```jinja2
{% if task.due_date and task.due_date != "Unassigned" and is_overdue(task.due_date) %}
<span class="text-danger font-weight-bold">{{ task.due_date }}</span>
{% else %}
<span>{{ task.due_date }}</span>
{% endif %}
```

### C. REST API Contracts (`task_manager/routes.py`)
1. **`GET /api/tasks` & `GET /api/tasks/<id>`**:
* Response payload key: `"due_date": "25/12"` or `"due_date": "Unassigned"`.
2. **`POST /api/tasks`**:
* Optional JSON property: `"due_date": "25/12"`. If omitted or null, defaults to `"Unassigned"`.
3. **`PUT /api/tasks/<id>`**:
* Optional JSON property: `"due_date": "25/12"`. Updates task due date if provided.

---

## 4. Blast Radius Analysis & Risk Mitigation

| Component | Blast Radius Risk | Mitigation Strategy |
| :--- | :--- | :--- |
| **`Tasks.__init__` Constructor** | **High**: Adding `due_date` as a required parameter breaks all existing model instantiations in routes and unit test fixtures. | Make `due_date="Unassigned"` an optional keyword argument with default value. |
| **Database Backward Compatibility** | **High**: Existing rows in `ctm.db` will have `NULL` or missing `due_date` values. | Python property getter / helper method treats `None` or missing value as `"Unassigned"`. |
| **Date Parsing Mismatch** | **Medium**: Users or API clients submitting dates in `YYYY-MM-DD` vs `DD/MM` formats. | Standardize formatting logic helper `format_due_date()` in Python to format valid dates to `DD/MM` and fall back safely to `"Unassigned"`. |
| **Overdue Comparison** | **Medium**: Date comparison logic failing across month boundaries or leap years. | Parse `DD/MM` with current year context using Python `datetime` for overdue comparison (`task_date < today`). |

---

## 5. Verification & Test Strategy

To verify feature correctness without regressions:

1. **Model Tests (`tests/test_models.py`)**:
* Verify default `due_date` is `"Unassigned"`.
* Verify explicit `due_date` storing (e.g. `"15/08"`).
2. **Web Route & Overdue Styling Tests (`tests/test_routes.py`)**:
* Verify task creation with and without `due_date`.
* **Mandatory Test**: Verify that if a due date has passed (e.g., yesterday's date formatted as `DD/MM`), the rendered HTML contains the `text-danger` class or red styling indicator.
3. **REST API Tests (`tests/test_rest.py`)**:
* Verify `GET /api/tasks` returns `"due_date"` field for all records.
* Verify `POST /api/tasks` accepts `"due_date"`.
* Verify `PUT /api/tasks/<id>` updates `"due_date"`.

---

## 6. Acceptance Criteria (Definition of Done)

* **AC 1**: Tasks created without a due date show `"Unassigned"`.
* **AC 2**: Pre-existing tasks in the database display `"Unassigned"`.
* **AC 3**: Due dates display in `DD/MM` format positioned before the status check icon.
* **AC 4**: When a task due date is in the past, it renders in **red** text/style on the UI.
* **AC 5**: REST API GET, POST, and PUT endpoints support `"due_date"`.
* **AC 6**: Automated test asserts that overdue tasks render with red styling indicator.
* **AC 7**: Zero reminders, notifications, or extraneous features are added.
83 changes: 83 additions & 0 deletions harness_learning/exploration_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Exploration Report: Task Priority Feature

## 1. Boundary & Exploration Scope Constraint
* **Boundary Rule**: Source code (`task_manager/`, `tests/`) was strictly preserved without modification during exploration.
* **Artifact Scope**: This document in `harness_learning/` is generated specifically to capture exploration findings and structural dependencies as requested.

---

## 2. Observed Repository Facts vs Inferences vs Proposed Assumptions

### A. Observed Repository Facts (Grounded in Code Inspection)
1. **`task_manager/models.py`**:
* `Tasks` table schema currently has columns: `task_id` (Integer, Primary Key), `project_id` (Integer, ForeignKey), `task` (Text), `status` (Boolean, default False).
* `Tasks.__init__(self, project_id, task, status=True)` initializes these attributes.
2. **`task_manager/routes.py`**:
* `/add` (`POST`) retrieves `task = request.form.get("task")`, `project = request.form.get("project")`, `status = bool(int(request.form.get("status")))`.
* `/api/tasks` (`GET`) serializes tasks into dictionaries with keys `id`, `project_id`, `task`, `status`.
* `/api/tasks` (`POST`) accepts `project_id`, `task`, `status` from JSON payload.
* `/api/tasks/<id>` (`PUT`) updates `task` and `status` from JSON payload.
3. **`conftest.py`**:
* `create_task` fixture calls `Tasks(project_id=project.project_id, task=task_desc, status=status)`.

### B. Inferences (Derived Architectural Relationships)
1. Adding a new attribute to `Tasks` requires synchronized updates across ORM model attributes, form parsing, JSON serialization/deserialization, and test fixtures.
2. Form handlers use `request.form.get()` which defaults to `None` if a form parameter is missing; API endpoints use `request.get_json()` which requires dict key checking.

### C. Proposed Implementation Assumptions (Future Design Choices)
1. Task priority will be stored as a string field (`"Low"`, `"Medium"`, `"High"`) with a default value of `"Medium"`.
2. All existing tasks and legacy API requests without explicit priority will automatically default to `"Medium"`.

---

## 3. Structural Dependency Relationships vs Runtime Execution Flow

### A. Structural Dependency Relationships
* **`task_manager/models.py:Tasks`**
└── Dependent on: `db.Model` (SQLAlchemy)
* **`task_manager/routes.py`**
├── Dependent on: `task_manager/models.py:Tasks`
├── Dependent on: `task_manager/models.py:Projects`
└── Dependent on: `task_manager/templates/index.html`
* **`tests/conftest.py`**
└── Dependent on: `task_manager/models.py:Tasks`
* **`tests/test_routes.py`, `tests/test_api.py`, `tests/test_rest.py`**
└── Dependent on: `conftest.py` fixtures and `routes.py` endpoints

### B. Runtime Execution Flow for Task Operations

```
[ Web UI Form Submission ] [ REST API JSON Request ]
POST /add POST /api/tasks
│ │
▼ ▼
Extract form fields Extract JSON fields
(task, project, status) (project_id, task, status)
│ │
└───────────────────────┬────────────────────────┘
Instantiate Tasks Model
Tasks(project_id, task, status)
SQLAlchemy DB Session Commit
db.session.add() & db.session.commit()
┌───────────────────────┴────────────────────────┐
│ │
▼ ▼
Redirect to / (Render index.html) Return 201 Created JSON Payload
```

---

## 4. Grounding Verification Matrix

| Claim in Exploration Report | Inspected File & Line Evidence | Verification Status |
| :--- | :--- | :--- |
| `Tasks` model has `task_id`, `project_id`, `task`, `status` | `task_manager/models.py` (lines 28-34) | **Grounded** |
| `/add` route handles task creation via form data | `task_manager/routes.py` (lines 43-85) | **Grounded** |
| `/api/tasks` GET endpoint serializes task fields | `task_manager/routes.py` (lines 191-213) | **Grounded** |
| `create_task` test fixture instantiates `Tasks` | `conftest.py` (lines 38-46) | **Grounded** |
| Working tree is clean and 55 pytest tests pass | Terminal command `uv run pytest` output | **Grounded** |
Loading