This single-page application allows you to create and manage tasks, organize them into projects, schedule recurrences, and track upcoming items.
The backend and frontend communicate primarily via a REST API. When you interact with the app, it synchronizes your actions with a PostgreSQL database. Backend is powered by Python/Django and Django REST Framework. Frontend is powered by Vue. Routing is implemented using Vue Router. When a URL is accessed via the browser, the backend returns only the data required for the current tab, while other tabs are lazy-loaded along with their respective data. Resource collections are stored in global stores powered by Pinia. Each frontend view loads the collections it needs and performs necessary transformations, such as joins, sorting, and filtering. HTTP requests are made using Axios. The frontend is built and served using Vite and uses Vue 3 Composition API, single-file components, TypeScript and Tailwind CSS. Periodic tasks are generated using a custom Django command and Cron. Delayed tasks are handled using Celery, with Redis serving as a message broker.
Clone the repository:
git clone https://github.com/AlexxSurin/task-manager.git
cd task-managerUse this command to get the project up and running completely inside Docker:
docker compose upThe app should now be available at http://127.0.0.1:8000/
Django admin: http://127.0.0.1:8000/admin/ (username: admin, password: admin)
You can change the source code right in the working directory you started the app from — Docker containers are using files from that directory. Django server will automatically reload if you change Python files, and Vite is watching the frontend files with hot reloading in the browser.
You may also want to the change the TIME_ZONE in settings.py according to your time zone
for the app to use your local current time.
From now on, you can quickly stop and restart the app using the following commands:
docker compose stopdocker compose startDependencies are cached inside Docker, so if you alter the dependency lists, you will need to
rebuild images with --build flag:
docker compose up --buildTo stop all containers and remove everything created during installation (containers, images, and volumes):
docker compose down -v --remove-orphans --rmi all- Python 3.10+
- Node 22+
- PostgreSQL 14+
Create and activate a python virtual environment:
python -m venv .venv
source .venv/bin/activateInstall backend dependencies:
pip install -r requirements.txtEnsure PostgreSQL is running and listening on port 5432, then open its interactive terminal:
psql -h localhost -p 5432 -U postgresCreate a new user and database for this project by running the following queries:
CREATE USER task_manager WITH PASSWORD 'password';
CREATE DATABASE task_manager;
ALTER DATABASE task_manager OWNER TO task_manager;
GRANT ALL PRIVILEGES ON DATABASE task_manager TO task_manager;You can exit the psql terminal using \q or by typing exit.
If you used different credentials, make sure they are correctly specified in settings.py
(DATABASES = ...)
Apply database migrations:
python manage.py migrateCreate an admin user to be able to access Django admin:
python manage.py createsuperuserUsername: admin
Email address: admin@example.com
Password: **********
Password (again): *********
Superuser created successfully.Django admin should be available at http://127.0.0.1:8000/admin/ once you start the server.
You can import some demo data into the database, if you want:
psql -h localhost -U task_manager -d task_manager -f docker/demo_data.sqlInstall frontend dependencies:
npm installStart serving the frontend:
npm run serveStart serving the backend:
python manage.py runserver 127.0.0.1:8000The app should be available at http://127.0.0.1:8000/
Build using the following command (the files will be emitted to frontend/dist/):
npm run buildSet USE_BUILT_MEDIA = True in settings.py to test it.
npm run type-checkmypySome tasks can be marked as periodic and recur on specified days of the week.
To generate new periodic tasks automatically at midnight, add the following job to Cron:
0 0 * * * /path-to-project/.venv/bin/python /path-to-project/manage.py generate_periodic_tasks
To test it manually, add periodic recurrence rules via the Django admin
(http://127.0.0.1:8000/admin/todo/periodicrecurrence/add/), then change the cron job to run every
minute (*/1 * * * *) or run the command manually:
python manage.py generate_periodic_tasks...and look for the generated tasks in Django admin (http://localhost:8000/admin/todo/task/) or in the app.
Delayed tasks are generated precisely after the specified delay using Celery. If you mark a task as completed and it has a delayed recurrence rule, a Celery job will be added to the queue. Redis handles the task queue.
In order for such jobs to run on your machine, first install Redis and make sure it is listening on
port 6379 (or edit CELERY_BROKER_URL accordingly). The easiest way to do this is using Docker:
docker run -d --name redis -p 6379:6379 redis:7.4.4-alpineYou can start and stop this container later using the following commands:
docker start redis
docker stop redisFinally, start a Celery worker:
celery -A backend worker --loglevel=infoSince the minimum delay is 1 day, to test it quickly in a local environment, look for the
generate_delayed_task.apply_async() call in the code, temporarily change countdown argument to
some lower number of seconds and watch the output in the terminal session in which you started a
Celery worker.
Note that if you change the code of any Celery task, you need to restart the worker for those changes to take effect.
Each collection has the following API endpoint pattern:
| Method | Endpoint | Description |
|---|---|---|
| GET | /{api_endpoint}/ | Retrieve all resources from the collection |
| POST | /{api_endpoint}/ | Create a new resource in the collection. Returns the created resource |
| GET | /{api_endpoint}/{id}/ | Retrieve a single resource by its ID |
| PUT | /{api_endpoint}/{id}/ | Replace an entire resource. Returns the replacing resource |
| PATCH | /{api_endpoint}/{id}/ | Partially update a resource. Returns the updated resource |
| DELETE | /{api_endpoint}/{id}/ | Delete a resource |
API endpoint: /api/todo/projects/
DELETE request also deletes related tasks.
| Field | Type | Access | Description |
|---|---|---|---|
| id | number | read-only | Project ID |
| title | string | writable, optional | Task title. Max length: 200. Default: New project |
| expanded | boolean | writable, optional | Whether the project is expanded in UI. Default: true |
API endpoint: /api/todo/tasks/
DELETE request also deletes related periodic and delayed recurrences.
| Field | Type | Access | Description |
|---|---|---|---|
| id | number | read-only | Task ID |
| title | string | writable, optional | Task title. Max length: 200. Default: New task |
| description | string | writable, optional | Task description. Default: empty string |
| dueDate | string | writable, optional | The due date for the task. Format: YYYY-MM-DD. Default: tomorrow |
| overdue | boolean | read-only | Whether the task is overdue |
| priority | integer | writable, optional | Task priority. A number from 1 (highest) to 3 (lowest). Default: 3 |
| completed | boolean | writable, optional | Whether the task is completed. Default: false |
| completedAt | string | read-only | Date and time of completion. Returned only for completed tasks. Format: ISO 8601 |
API endpoint: /api/todo/recurrences/periodic/
POST request also deletes a delayed recurrence for the task, if it has one.
| Field | Type | Access | Description |
|---|---|---|---|
| id | number | read-only | Periodic recurrence ID |
| schedule | number[] | writable, optional | Days of the week on which the task should recur. Array containing numbers in the range 0-6 representing Mon-Sun respectively. Should contain at least 1 such number. Default: [0] |
| task | number | writable, required | ID of the recurring task |
API endpoint: /api/todo/recurrences/delayed/
POST request also deletes a periodic recurrence for the task, if it has one.
| Field | Type | Access | Description |
|---|---|---|---|
| id | number | read-only | Delayed recurrence ID |
| delayDays | number | writable, optional | Delay in days. Default: 1 |
| task | number | writable, required | ID of the recurring task |
API endpoint: GET /api/about/
| Field | Type | Access | Description |
|---|---|---|---|
| adminUrl | string | read-only | Django admin's URL |
