{"id":31548528,"url":"https://github.com/gokhanmeteerturk/task_tracker","last_synced_at":"2025-10-04T16:37:10.742Z","repository":{"id":299930295,"uuid":"1004657723","full_name":"gokhanmeteerturk/task_tracker","owner":"gokhanmeteerturk","description":"Dockerized FastAPI Task Tracker with hexagonal architecture","archived":false,"fork":false,"pushed_at":"2025-06-19T01:38:28.000Z","size":50,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T02:33:33.734Z","etag":null,"topics":["alembic","docker","fastapi","hexagonal-architecture","python","sqlalchemy"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gokhanmeteerturk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-19T01:31:24.000Z","updated_at":"2025-06-19T01:38:31.000Z","dependencies_parsed_at":"2025-06-19T02:33:35.146Z","dependency_job_id":"d2d531f6-8c30-48f9-bfd1-9373cca4e93b","html_url":"https://github.com/gokhanmeteerturk/task_tracker","commit_stats":null,"previous_names":["gokhanmeteerturk/task_tracker"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gokhanmeteerturk/task_tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokhanmeteerturk%2Ftask_tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokhanmeteerturk%2Ftask_tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokhanmeteerturk%2Ftask_tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokhanmeteerturk%2Ftask_tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gokhanmeteerturk","download_url":"https://codeload.github.com/gokhanmeteerturk/task_tracker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokhanmeteerturk%2Ftask_tracker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278343083,"owners_count":25971399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alembic","docker","fastapi","hexagonal-architecture","python","sqlalchemy"],"created_at":"2025-10-04T16:36:56.470Z","updated_at":"2025-10-04T16:37:10.716Z","avatar_url":"https://github.com/gokhanmeteerturk.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dockerized FastAPI Task Tracker: A Hexagonal Architecture-Powered Task \u0026 Goal Management System\n\nThis project presents a task and goal tracking system that is extremely flexible. Start scheduling recurring tasks or goals with adaptive deadline distributions, and replace manual tasks with automated scripts only when you have the time.\n\nIt uses **FastAPI** and the principles of **Hexagonal Architecture (Ports and Adapters)** and **Domain-Driven Design (DDD)** to stay extremely adaptable when used with external dependencies.\n\nYou can write a simple adapter for **Model Context Protocol** and let LLMs perform tasks. Or implement browser automation with Selenium by writing a new strategy adapter. Its core purpose is to serve as a highly maintainable and extensible backend service for task and goal management.\n\nBy using a **State pattern** for task status transitions and flexible **SchedulingPolicy**, the system is designed for adaptability and future enhancements.\n\n## Table of Contents\n\n1.  [Features](#features)\n2.  [Architectural Highlights](#architectural-highlights)\n    * [Hexagonal Architecture (Ports \u0026 Adapters)](#hexagonal-architecture-ports--adapters)\n    * Domain-Driven Design (DDD)\n    * State Pattern for Task Status\n3.  [Technology Stack](#technology-stack)\n4.  [Local Development (Dockerized / Uvicorn)](#local-development-dockerized--uvicorn)\n5.  [Deploying to Cloud (Amazon Web Services)](#deploying-to-cloud-amazon-web-services)\n6.  [Endpoints](#endpoints)\n7.  [Testing](#testing)\n\n## 1. Features\n\n* **Goal Management:** Define and track recurring goals with flexible scheduling policies (e.g., fixed intervals, deadline-driven distributions).\n* **Automated Task Generation:** Automatically generates concrete tasks based on defined goals and their scheduling policies.\n* **Task Lifecycle Management:** Comprehensive status tracking for tasks (Waiting, InProgress, Completed, Failed, Skipped) with controlled transitions.\n* **Audit Logging:** Detailed logs for all task status changes, ensuring traceability and accountability.\n* **Pluggable Strategies:** Supports various strategies for performing and checking tasks (e.g., browser automation(planned), custom scripts, manual prompts).\n* **Platform \u0026 Account Abstraction:** Manages tasks across different external platforms and associated user accounts.\n\n## 2. Architectural Highlights\n\n### Hexagonal Architecture (Ports \u0026 Adapters)\n\nProject applies the Hexagonal Architecture, making sure the core domain remains independent of external concerns.\n\n* **Domain Core:** python models `Platform`, `Account`, `Goal`, `Task`, `TaskLog`, value objects (e.g., `SchedulingPolicy`), and `Domain Services`. defines the business rules and logic.\n* **Ports (Interfaces):** Defined as `Protocol`s in Python. Examples: `ITaskRepository`, `IGoalRepository`, `IScheduler`, `IStrategyFactory`, `ILogger`.\n* **Adapters:** Concrete implementations of the ports, including:\n    * **Persistence Adapters:** SQLAlchemy for data storage.\n    * **Scheduler Adapters:** APScheduler for task scheduling (for now).\n    * **Perform/Check Strategy Adapters:** `ScriptRunner` for executing scripts, and manual prompt for user interaction.\n    * **UI Adapters:** FastAPI serves as the primary web interface, exposing the application's use cases.\n\n## 3. Technology Stack\n\n* **Backend Framework:** FastAPI\n* **Asynchronous Web Server:** Uvicorn\n* **Database:** Sqlite (Planned: PostgreSQL) (via SQLAlchemy ORM and alembic for migrations)\n* **Dependency Management:** `pip` / `requirements.txt`\n* **Containerization:** Docker\n* **Cloud Deployment:** Amazon Web Services (AWS)\n\n## 4. Local Development (Dockerized / Uvicorn)\nFor uvicorn, running the application is as simple as using `python main.py`. But you need to first create a virtual environment, install the dependencies, and run the migrations with alembic.\n\nFor docker, run the following command:\n```bash\ndocker-compose build\ndocker-compose up\n```\nYour database will persist in the db folder on your host.\n\nFor all future changes to the models use below commands (for docker enter container's bash and run the command there):\n\n```\nalembic revision --autogenerate -m \"new message\"\nalembic upgrade head\n```\n\n## 5. Deploying to Cloud (Amazon Web Services)\n\n### 1.**Build and Push Your Docker Image to Amazon Web Services ECR**\n\n1.  **Create an ECR Repository**\n    In AWS Console, go to ECR (Elastic Container Registry) and create a new repository (e.g. `task-tracker` ).\n\n2.  **Authenticate Docker to ECR**\n```bash\naws ecr get-login-password --region \u003cyour-region\u003e | docker login --username AWS --password-stdin \u003cyour-account-id\u003e.dkr.ecr.\u003cyour-region\u003e.amazonaws.com\n```\n\n3.  **Build and Push Docker Image**\n```bash\ndocker build -t task-tracker .\ndocker tag task-tracker:latest \u003cyour-account-id\u003e.dkr.ecr.\u003cyour-region\u003e.amazonaws.com/task-tracker:latest\ndocker push \u003cyour-account-id\u003e.dkr.ecr.\u003cyour-region\u003e.amazonaws.com/task-tracker:latest\n```\n\n### 2.**Deploy to AWS**\n\n#### Option 1: ECS\nCreate a new ECS cluster, create task definition using the ECR image, set up a service to run the container. Create an EFS volume and mount to /app/db\n\n#### Option 2: EC2\nLaunch an EC2 instance. Pull your image if you created it, or just pull your repo and build\u0026run a container:\n```bash\naws ecr get-login-password --region YOUR_REGION | \\\ndocker login --username AWS --password-stdin YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com\ndocker pull YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/YOUR_IMAGE_NAME:tag\ndocker run -d -p 8000:8000 YOUR_IMAGE_NAME\n```\n\nAnd use nginx for reverse proxy. Conf example:\n```nginx\nserver {\n    listen 80; # or use 443 after ssl setup\n    server_name mywebsite.com;\n\n    location / {\n        proxy_pass http://localhost:8000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n```\n\n## 6. Endpoints\n\n### **Dashboard**\n\n| Method                     | Path                            | Description                                                | Parameters (Path/Form)                                       |\n| :------------------------- | :------------------------------ | :--------------------------------------------------------- | :----------------------------------------------------------- |\n| GET (Returns HTMLResponse)  | /                               | Displays the main dashboard with an overview of platforms. | None                                                         |\n| POST (Returns JSONResponse) | /services/{service\\_name}/start | Starts a specified service.                                | service\\_name: string (path)Returns: {\"status\": \"started\"} or {\"error\": \"Service not found\"} |\n| GET (Returns HTMLResponse)  | /all-tasks                      | Displays a list of all tasks.                              | None                                                         |\n\n\n### **Goals**\n\n| Method                         | Path                     | Description                                                  | Parameters (Path/Form)                                       |\n| :----------------------------- | :----------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |\n| GET (Returns HTMLResponse)      | /goals                   | Displays a list of all created goals.                        | None                                                         |\n| GET (Returns HTMLResponse)      | /goals/add               | Displays the form for adding a new goal.                     | None                                                         |\n| POST (Returns RedirectResponse) | /goals/add               | Handles the submission of the \"add goal\" form, creating a new goal. | Form data: platform\\_id (integer), description (string), start\\_date (date), policy\\_type (string), interval\\_days (integer, optional), deadline\\_date (date, optional), total\\_occurrences (integer, optional), freeze\\_on\\_miss (boolean), account\\_ids (list of integers, optional), task\\_distribution\\_strategy (string), catchup\\_strategy (string), execution\\_strategy (string), execution\\_script\\_content (string), execution\\_script\\_env\\_vars (string, KEY=VALUE\\\\nKEY2=VALUE2 format to be parsed into dict) |\n| GET (Returns HTMLResponse)      | /goals/{goal\\_id}/edit   | Displays the form to edit an existing goal, pre-filled with its data. | goal\\_id: integer (path)                                     |\n| POST (Returns RedirectResponse) | /goals/{goal\\_id}/edit   | Handles the submission of the \"edit goal\" form, updating an existing goal. | goal\\_id: integer (path)Form data: same as /goals/add plus check\\_strategy (string), check\\_script\\_content (string), check\\_script\\_env\\_vars (string, KEY=VALUE\\\\nKEY2=VALUE2 format to be parsed into dict) |\n| POST (Returns RedirectResponse) | /goals/{goal\\_id}/delete | Handles the deletion of a goal.                              | goal\\_id: integer (path)                                     |\n\n\n### **Platforms \u0026 Accounts**\n\n| Method                         | Path                                   | Description                                                  | Parameters (Path/Form)                                       |\n| :----------------------------- | :------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |\n| GET (Returns HTMLResponse)      | /platforms                             | Displays a list of all managed platforms.                    | None                                                         |\n| POST (Returns RedirectResponse) | /platforms/add                         | Adds a new platform.                                         | Form data: name: string (required), config: string (optional, default \"{}\") |\n| GET (Returns HTMLResponse)      | /platforms/{platform\\_id}/accounts     | Displays a list of accounts associated with a specific platform. | platform\\_id: integer (path)                                 |\n| POST (Returns RedirectResponse) | /platforms/{platform\\_id}/accounts/add | Adds a new account to a specified platform.                  | platform\\_id: integer (path)Form data: username: string (required), notes: string (optional) |\n| POST (Returns RedirectResponse) | /accounts/{account\\_id}/delete         | Deletes an account.                                          | account\\_id: integer (path)Form data: platform\\_id: integer (required) |\n| GET (Returns HTMLResponse)      | /platforms/{platform\\_id}/edit         | Displays the form to edit an existing platform.              | platform\\_id: integer (path)                                 |\n| POST (Returns RedirectResponse) | /platforms/{platform\\_id}/edit         | Handles the submission of the \"edit platform\" form, updating an existing platform. | platform\\_id: integer (path)Form data: name: string (required), config: string (optional, default \"{}\") |\n\n\n### **Tasks**\n\n| Method                         | Path                            | Description                                                  | Parameters (Path/Form)                                       |\n| :----------------------------- | :------------------------------ | :----------------------------------------------------------- | :----------------------------------------------------------- |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/run-execution | Schedules the execution script for a task to run in the background. | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\") |\n| POST (Returns RedirectResponse) | /tasks/generate-due             | Triggers the generation of new tasks based on due goals in the background. | Form data: redirect\\_url: string (optional, default \"/all-tasks\") |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/run-check     | Schedules the check script for a task to run in the background. | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\") |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/skip          | Marks a task as skipped.                                     | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\"), notes: string (optional) |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/complete      | Marks a task as complete.                                    | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\"), notes: string (optional) |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/start         | Marks a task as in progress.                                 | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\") |\n| POST (Returns RedirectResponse) | /tasks/{task\\_id}/fail          | Marks a task as failed.                                      | task\\_id: integer (path)Form data: redirect\\_url: string (optional, default \"/all-tasks\"), notes: string (optional) |\n| GET (Returns HTMLResponse)      | /tasks/{task\\_id}/logs          | Displays the logs for a specific task.                       | task\\_id: integer (path)                                     |\n\n\n*Content to be filled with API endpoint documentation (e.g., `/goals/`, `/tasks/`, `/tasks/{task_id}/complete`, etc.).*\n\n## 7. Testing\n\n*Work in progress.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgokhanmeteerturk%2Ftask_tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgokhanmeteerturk%2Ftask_tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgokhanmeteerturk%2Ftask_tracker/lists"}