From 5d1ed489fc4bd3cbacb80b81c5c7d1600bff73b0 Mon Sep 17 00:00:00 2001 From: psiri0514-cyber Date: Mon, 9 Feb 2026 21:50:46 -0500 Subject: [PATCH 1/2] Update README and add task management API spec --- README.md | 57 +++++++++- SPECS/task-management-api.md | 40 +++++++ app.py | 119 +++++++++++++++++++++ requirements.txt | 4 + test_app.py | 196 +++++++++++++++++++++++++++++++++++ 5 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 SPECS/task-management-api.md create mode 100644 app.py create mode 100644 requirements.txt create mode 100644 test_app.py diff --git a/README.md b/README.md index 494f1c75..344254c7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Candidate Assessment: Spec-Driven Development With Codegen Tools -This assessment evaluates how you use modern code generation tools (for example `5.2-Codex`, `Claude`, `Copilot`, and similar) to design, build, and test a software application using a spec-driven development pattern. You may build a frontend, a backend, or both. +This assessment evaluates how you use modern code generation tools to design, build, and test a software application using a spec-driven development pattern. You may build a frontend, a backend, or both. ## Goals - Build a working application with at least one meaningful feature. @@ -41,3 +41,58 @@ Your solution should include at least one real workflow, for example: - When you are complete, put up a Pull Request against this repository with your changes. - A short summary of your approach and tools used in your PR submission - Any additional information or approach that helped you. + +--- + +# Task Management API + +This is a simple REST API for managing tasks. You can create, read, update, and delete tasks. It's built with Python and Flask. + +## Setup + +Make sure you have Python installed, then run: + +```bash +pip install -r requirements.txt +``` + +## Running the App + +Start the server: + +```bash +python app.py +``` + +The API runs on `http://localhost:5000` + +## API Endpoints + +- `GET /` - Check if API is running +- `POST /api/tasks` - Create a new task +- `GET /api/tasks` - Get all tasks +- `GET /api/tasks/{id}` - Get one task +- `PUT /api/tasks/{id}` - Update a task +- `DELETE /api/tasks/{id}` - Delete a task + +## Example + +Create a task: +```bash +curl -X POST http://localhost:5000/api/tasks \ + -H "Content-Type: application/json" \ + -d '{"title": "My task", "description": "Do something"}' +``` + +## Running Tests + +Run all tests: + +```bash +pytest +``` + +## Notes + +- Tasks are stored in memory and will be lost when you restart the server +- All responses are in JSON format diff --git a/SPECS/task-management-api.md b/SPECS/task-management-api.md new file mode 100644 index 00000000..15013ab3 --- /dev/null +++ b/SPECS/task-management-api.md @@ -0,0 +1,40 @@ +# Feature Spec: Task Management API + +## Goal +- Build a RESTful backend API for managing tasks +- Provide CRUD operations (Create, Read, Update, Delete) for tasks +- Include data persistence (in-memory storage) +- Create a comprehensive test suite + +## Scope +- In: + - REST API endpoints for task management + - Task model with id, title, description, status, and created_at fields + - In-memory data storage + - Test suite with unit and integration tests + - API documentation +- Out: + - Frontend UI + - Database persistence (using in-memory storage instead) + - Authentication/Authorization + - Advanced features like filtering, pagination + +## Requirements +- API must be built using Python and Flask framework +- All endpoints must return JSON responses +- Tasks should have: id (auto-generated), title (required), description (optional), status (default: "pending"), created_at (timestamp) +- API should handle errors gracefully with appropriate HTTP status codes +- Tests must cover all endpoints and edge cases +- Application must run locally with simple setup + +## Acceptance Criteria +- [ ] POST /api/tasks - Create a new task +- [ ] GET /api/tasks - List all tasks +- [ ] GET /api/tasks/{id} - Get a specific task by ID +- [ ] PUT /api/tasks/{id} - Update a task by ID +- [ ] DELETE /api/tasks/{id} - Delete a task by ID +- [ ] All endpoints return appropriate HTTP status codes (200, 201, 404, 400) +- [ ] Test suite covers all endpoints with success and error cases +- [ ] Application can be run with simple command (e.g., `python app.py` or `flask run`) +- [ ] README includes setup and run instructions +- [ ] Tests can be run with a simple command (e.g., `pytest`) diff --git a/app.py b/app.py new file mode 100644 index 00000000..8174eb1c --- /dev/null +++ b/app.py @@ -0,0 +1,119 @@ +from flask import Flask, request, jsonify +from flask_cors import CORS +from datetime import datetime +import uuid + +app = Flask(__name__) +CORS(app) + +tasks = [] + + +class Task: + # Initialize task with title, optional description and status + def __init__(self, title, description=None, status="pending"): + self.id = str(uuid.uuid4()) + self.title = title + self.description = description or "" + self.status = status + self.created_at = datetime.utcnow().isoformat() + + # Convert task object to dictionary + def to_dict(self): + return { + "id": self.id, + "title": self.title, + "description": self.description, + "status": self.status, + "created_at": self.created_at + } + + # Update task fields from provided data + def update(self, data): + if "title" in data: + self.title = data["title"] + if "description" in data: + self.description = data["description"] + if "status" in data: + self.status = data["status"] + + +# Find and return task by ID +def find_task_by_id(task_id): + for task in tasks: + if task.id == task_id: + return task + return None + + +# Create a new task +@app.route("/api/tasks", methods=["POST"]) +def create_task(): + data = request.get_json() + + if not data or "title" not in data: + return jsonify({"error": "Title is required"}), 400 + + task = Task( + title=data["title"], + description=data.get("description"), + status=data.get("status", "pending") + ) + tasks.append(task) + + return jsonify(task.to_dict()), 201 + + +# Get all tasks +@app.route("/api/tasks", methods=["GET"]) +def list_tasks(): + return jsonify([task.to_dict() for task in tasks]), 200 + + +# Get a specific task by ID +@app.route("/api/tasks/", methods=["GET"]) +def get_task(task_id): + task = find_task_by_id(task_id) + + if not task: + return jsonify({"error": "Task not found"}), 404 + + return jsonify(task.to_dict()), 200 + + +# Update a task by ID +@app.route("/api/tasks/", methods=["PUT"]) +def update_task(task_id): + task = find_task_by_id(task_id) + + if not task: + return jsonify({"error": "Task not found"}), 404 + + data = request.get_json() + if not data: + return jsonify({"error": "No data provided"}), 400 + + task.update(data) + return jsonify(task.to_dict()), 200 + + +# Delete a task by ID +@app.route("/api/tasks/", methods=["DELETE"]) +def delete_task(task_id): + task = find_task_by_id(task_id) + + if not task: + return jsonify({"error": "Task not found"}), 404 + + tasks.remove(task) + return jsonify({"message": "Task deleted successfully"}), 200 + + +# Health check endpoint +@app.route("/", methods=["GET"]) +def health_check(): + return jsonify({"status": "ok", "message": "Task Management API is running"}), 200 + + +if __name__ == "__main__": + app.run(debug=True, host="0.0.0.0", port=5000) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..b402f7c5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Flask==3.0.0 +pytest==7.4.3 +pytest-flask==1.3.0 +flask-cors==4.0.0 diff --git a/test_app.py b/test_app.py new file mode 100644 index 00000000..32a833e9 --- /dev/null +++ b/test_app.py @@ -0,0 +1,196 @@ +import pytest +from app import app, tasks, Task + + +@pytest.fixture +def client(): + app.config["TESTING"] = True + with app.test_client() as client: + tasks.clear() + yield client + + +def test_health_check(client): + response = client.get("/") + assert response.status_code == 200 + data = response.get_json() + assert data["status"] == "ok" + + +def test_create_task_success(client): + response = client.post( + "/api/tasks", + json={"title": "Test Task", "description": "This is a test"} + ) + assert response.status_code == 201 + data = response.get_json() + assert data["title"] == "Test Task" + assert data["description"] == "This is a test" + assert data["status"] == "pending" + assert "id" in data + assert "created_at" in data + + +def test_create_task_with_status(client): + response = client.post( + "/api/tasks", + json={"title": "Completed Task", "status": "completed"} + ) + assert response.status_code == 201 + data = response.get_json() + assert data["status"] == "completed" + + +def test_create_task_missing_title(client): + response = client.post( + "/api/tasks", + json={"description": "No title"} + ) + assert response.status_code == 400 + data = response.get_json() + assert "error" in data + + +def test_create_task_empty_json(client): + response = client.post("/api/tasks", json={}) + assert response.status_code == 400 + + +def test_list_tasks_empty(client): + response = client.get("/api/tasks") + assert response.status_code == 200 + data = response.get_json() + assert data == [] + + +def test_list_tasks_with_data(client): + client.post("/api/tasks", json={"title": "Task 1"}) + client.post("/api/tasks", json={"title": "Task 2"}) + + response = client.get("/api/tasks") + assert response.status_code == 200 + data = response.get_json() + assert len(data) == 2 + assert data[0]["title"] == "Task 1" + assert data[1]["title"] == "Task 2" + + +def test_get_task_success(client): + create_response = client.post( + "/api/tasks", + json={"title": "Get Me", "description": "Find this task"} + ) + task_id = create_response.get_json()["id"] + + response = client.get(f"/api/tasks/{task_id}") + assert response.status_code == 200 + data = response.get_json() + assert data["title"] == "Get Me" + assert data["description"] == "Find this task" + assert data["id"] == task_id + + +def test_get_task_not_found(client): + response = client.get("/api/tasks/non-existent-id") + assert response.status_code == 404 + data = response.get_json() + assert "error" in data + + +def test_update_task_success(client): + create_response = client.post( + "/api/tasks", + json={"title": "Original Title", "status": "pending"} + ) + task_id = create_response.get_json()["id"] + + response = client.put( + f"/api/tasks/{task_id}", + json={"title": "Updated Title", "status": "completed", "description": "New description"} + ) + assert response.status_code == 200 + data = response.get_json() + assert data["title"] == "Updated Title" + assert data["status"] == "completed" + assert data["description"] == "New description" + + +def test_update_task_partial(client): + create_response = client.post( + "/api/tasks", + json={"title": "Original", "description": "Original desc"} + ) + task_id = create_response.get_json()["id"] + + response = client.put( + f"/api/tasks/{task_id}", + json={"title": "New Title"} + ) + assert response.status_code == 200 + data = response.get_json() + assert data["title"] == "New Title" + assert data["description"] == "Original desc" + + +def test_update_task_not_found(client): + response = client.put( + "/api/tasks/non-existent-id", + json={"title": "Updated"} + ) + assert response.status_code == 404 + + +def test_update_task_no_data(client): + create_response = client.post("/api/tasks", json={"title": "Test"}) + task_id = create_response.get_json()["id"] + + response = client.put(f"/api/tasks/{task_id}", json={}) + assert response.status_code == 400 + + +def test_delete_task_success(client): + create_response = client.post("/api/tasks", json={"title": "To Delete"}) + task_id = create_response.get_json()["id"] + + response = client.delete(f"/api/tasks/{task_id}") + assert response.status_code == 200 + data = response.get_json() + assert "message" in data + + get_response = client.get(f"/api/tasks/{task_id}") + assert get_response.status_code == 404 + + +def test_delete_task_not_found(client): + response = client.delete("/api/tasks/non-existent-id") + assert response.status_code == 404 + + +def test_full_workflow(client): + task1_response = client.post("/api/tasks", json={"title": "Workflow Task 1"}) + task2_response = client.post("/api/tasks", json={"title": "Workflow Task 2"}) + + task1_id = task1_response.get_json()["id"] + task2_id = task2_response.get_json()["id"] + + list_response = client.get("/api/tasks") + assert list_response.status_code == 200 + assert len(list_response.get_json()) == 2 + + get_response = client.get(f"/api/tasks/{task1_id}") + assert get_response.status_code == 200 + assert get_response.get_json()["title"] == "Workflow Task 1" + + update_response = client.put( + f"/api/tasks/{task1_id}", + json={"status": "completed"} + ) + assert update_response.status_code == 200 + assert update_response.get_json()["status"] == "completed" + + delete_response = client.delete(f"/api/tasks/{task1_id}") + assert delete_response.status_code == 200 + + list_response = client.get("/api/tasks") + assert len(list_response.get_json()) == 1 + assert list_response.get_json()[0]["id"] == task2_id From 80fab75168c95cc03e3e09347920cb03aad4ea35 Mon Sep 17 00:00:00 2001 From: lakshmipoojitha0207-creator Date: Tue, 10 Feb 2026 19:16:16 -0500 Subject: [PATCH 2/2] Push complete task management implementation --- .gitignore | 1 + README.md | 62 +++++---- __pycache__/app.cpython-311.pyc | Bin 0 -> 7649 bytes .../test_app.cpython-311-pytest-8.2.1.pyc | Bin 0 -> 37196 bytes app.py | 125 ++++++++++-------- cd | 0 git | 0 7 files changed, 110 insertions(+), 78 deletions(-) create mode 100644 __pycache__/app.cpython-311.pyc create mode 100644 __pycache__/test_app.cpython-311-pytest-8.2.1.pyc create mode 100644 cd create mode 100644 git diff --git a/.gitignore b/.gitignore index e69de29b..464beeeb 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +notepad .gitignore \ No newline at end of file diff --git a/README.md b/README.md index 344254c7..8cbbd493 100644 --- a/README.md +++ b/README.md @@ -3,54 +3,55 @@ This assessment evaluates how you use modern code generation tools to design, build, and test a software application using a spec-driven development pattern. You may build a frontend, a backend, or both. ## Goals -- Build a working application with at least one meaningful feature. + +- Build a working application with at least one feature. - Create a testing framework to validate the application. - Demonstrate effective use of code generation tools to accelerate delivery. -- Show clear, maintainable engineering practices. ## Deliverables + - Application source code in this repository. - A test suite and test harness that can be run locally. - Documentation that explains how to run the app and the tests. ## Scope Options -Pick one: + +Pick one of the following: + - Frontend-only application. - Backend-only application. - Full-stack application. -Your solution should include at least one real workflow, for example: -- Create and view a resource. -- Search or filter data. -- Persist data in memory or storage. - ## Rules -- You must use a code generation tool (for example `5.2-Codex`, `Claude`, or similar). You can use multiple tools. + +- You must use a code generation tool (for example Codex, Claude, or similar). You can use multiple tools. - You must build the application and a testing framework for it. - The application and tests must run locally. - Do not include secrets or credentials in this repository. ## Evaluation Criteria + - Working product: Does the app do what it claims? - Test coverage: Do tests cover key workflows and edge cases? - Engineering quality: Clarity, structure, and maintainability. - Use of codegen: How effectively you used tools to accelerate work. - Documentation: Clear setup and run instructions. -## What to Submit +## Submission Criteria + - When you are complete, put up a Pull Request against this repository with your changes. -- A short summary of your approach and tools used in your PR submission -- Any additional information or approach that helped you. +- Include a short summary of your approach and tools used in your PR submission. +- Include any additional information or approach that helped you. --- # Task Management API -This is a simple REST API for managing tasks. You can create, read, update, and delete tasks. It's built with Python and Flask. +REST API for managing tasks: create, read, update, and delete. Implemented in Python with Flask. ## Setup -Make sure you have Python installed, then run: +Requires Python 3. Install dependencies: ```bash pip install -r requirements.txt @@ -64,35 +65,44 @@ Start the server: python app.py ``` -The API runs on `http://localhost:5000` +The API is available at `http://localhost:5000`. ## API Endpoints -- `GET /` - Check if API is running -- `POST /api/tasks` - Create a new task -- `GET /api/tasks` - Get all tasks -- `GET /api/tasks/{id}` - Get one task -- `PUT /api/tasks/{id}` - Update a task -- `DELETE /api/tasks/{id}` - Delete a task +| Method | Path | Description | +|--------|------|-------------| +| GET | `/` | Health check; returns status and message. | +| POST | `/api/tasks` | Create a task. Body must include `title`; `description` and `status` are optional. | +| GET | `/api/tasks` | List all tasks. | +| GET | `/api/tasks/{id}` | Get a single task by ID. | +| PUT | `/api/tasks/{id}` | Update a task. Body may include `title`, `description`, `status`. | +| DELETE | `/api/tasks/{id}` | Delete a task by ID. | -## Example +## Example Request Create a task: + ```bash curl -X POST http://localhost:5000/api/tasks \ -H "Content-Type: application/json" \ - -d '{"title": "My task", "description": "Do something"}' + -d "{\"title\": \"My task\", \"description\": \"Do something\"}" ``` ## Running Tests -Run all tests: +Run the full test suite: ```bash pytest ``` +For verbose output: + +```bash +pytest -v +``` + ## Notes -- Tasks are stored in memory and will be lost when you restart the server -- All responses are in JSON format +- Tasks are stored in memory only; data is lost when the server stops. +- All request and response bodies are JSON. diff --git a/__pycache__/app.cpython-311.pyc b/__pycache__/app.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8f0372065158b266e4d281db2de4e23a4e26b71e GIT binary patch literal 7649 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", methods=["GET"]) def get_task(task_id): - task = find_task_by_id(task_id) - - if not task: + entry = tasks.get(task_id) + if entry is None: return jsonify({"error": "Task not found"}), 404 - - return jsonify(task.to_dict()), 200 + return jsonify(entry), 200 -# Update a task by ID @app.route("/api/tasks/", methods=["PUT"]) def update_task(task_id): - task = find_task_by_id(task_id) - - if not task: + entry = tasks.get(task_id) + if entry is None: return jsonify({"error": "Task not found"}), 404 - - data = request.get_json() - if not data: + body = request.get_json() + if not body: return jsonify({"error": "No data provided"}), 400 - - task.update(data) - return jsonify(task.to_dict()), 200 + _patch(entry, body) + return jsonify(entry), 200 -# Delete a task by ID @app.route("/api/tasks/", methods=["DELETE"]) def delete_task(task_id): - task = find_task_by_id(task_id) - - if not task: + entry = tasks.get(task_id) + if entry is None: return jsonify({"error": "Task not found"}), 404 - - tasks.remove(task) + tasks.drop(entry) return jsonify({"message": "Task deleted successfully"}), 200 -# Health check endpoint @app.route("/", methods=["GET"]) def health_check(): return jsonify({"status": "ok", "message": "Task Management API is running"}), 200 diff --git a/cd b/cd new file mode 100644 index 00000000..e69de29b diff --git a/git b/git new file mode 100644 index 00000000..e69de29b