diff --git a/README.md b/README.md index 33db948..2ff933f 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ aiogram is a modern and fully asynchronous framework for Telegram bot developmen ### [Redis](https://redis.io/) -Redis is an in-memory data structure store often used as a database, cache, and message broker. It supports various data structures and offers high performance for read and write operations, making it suitable for caching and real-time analytics. Very popular and has big community for today. In project used as fsm for aiogram (to avoid data loss on restart), caches (current_date, mlscores, clicks, views) for backend and as broker for Celery. +Redis is an in-memory data structure store often used as a database, cache, and message broker. It supports various data structures and offers high performance for read and write operations, making it suitable for caching and real-time analytics. Very popular and has big community for today. In project used as fsm for aiogram (to avoid data loss on restart), caches (mlscores, clicks, views) for backend and as broker for Celery. ### [Postgres](https://www.postgresql.org/) @@ -268,7 +268,7 @@ Default login: `admin` Default password: `proooooood` -Analytics dashboard when deployed with default docker compose: [localhost:13243/d/adnova-statistics/statistics](http://localhost:13243/d/adnova-statisticss/statistics). You can enter advertiser id and get detailed advertiser statistics and also detailed statistics for each advertiser's campaign. +Analytics dashboard when deployed with default docker compose: [localhost:13243/d/adnova-advertiser-statistics](http://localhost:13243/d/adnova-advertiser-statistics/statistics). You can enter advertiser id and get detailed advertiser statistics and also detailed statistics for each advertiser's campaign. Demonstration: diff --git a/services/backend/Dockerfile b/services/backend/Dockerfile index b55f660..8e95eb9 100644 --- a/services/backend/Dockerfile +++ b/services/backend/Dockerfile @@ -1,7 +1,7 @@ # Stage 1: Install dependencies -FROM docker.io/python:3.11-alpine3.20 AS builder +FROM docker.io/python:3.13-alpine3.22 AS builder -COPY --from=ghcr.io/astral-sh/uv:0.4.30 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app @@ -17,7 +17,7 @@ RUN uv sync --no-dev --no-install-project --no-cache # Stage 2: Start the application -FROM docker.io/python:3.11-alpine3.20 +FROM docker.io/python:3.13-alpine3.22 WORKDIR /app @@ -39,4 +39,4 @@ EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --start-interval=2s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:8080/health?format=json || exit 1 -CMD gunicorn config.wsgi --workers=8 -b 0.0.0.0:8080 --access-logfile - --error-logfile - +CMD [ "gunicorn", "config.wsgi", "--workers=8", "-b", "0.0.0.0:8080", "--access-logfile", "-", "--error-logfile", "-" ] diff --git a/services/backend/Dockerfile.staticfiles b/services/backend/Dockerfile.staticfiles index 5150bf5..b291c86 100644 --- a/services/backend/Dockerfile.staticfiles +++ b/services/backend/Dockerfile.staticfiles @@ -1,7 +1,7 @@ # Stage 1: Install dependencies and compile staticfiles -FROM docker.io/python:3.11-alpine3.20 AS builder +FROM docker.io/python:3.13-alpine3.22 AS builder -COPY --from=ghcr.io/astral-sh/uv:0.4.30 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app @@ -17,11 +17,12 @@ RUN uv sync --no-dev --no-install-project --no-cache COPY . . -RUN uv run python manage.py collectstatic --noinput +RUN uv run --no-dev python manage.py collectstatic --noinput + # Stage 2: Start nginx and serve staticfiles -FROM docker.io/nginx:latest +FROM docker.io/nginx:1.29-alpine-slim COPY --from=builder /app/static /usr/share/nginx/html -CMD ["nginx", "-g", "daemon off;"] +CMD [ "nginx", "-g", "daemon off;" ] diff --git a/services/backend/README.md b/services/backend/README.md index 3b48e87..9019de0 100644 --- a/services/backend/README.md +++ b/services/backend/README.md @@ -4,9 +4,9 @@ Ensure you have the following installed on your system: -- [Python](https://www.python.org/) (>=3.10,<3.12) -- [uv](https://docs.astral.sh/uv/) -- [Docker](https://www.docker.com/) (for containerized setup) +- [Python](https://www.python.org/) (>=3.10,<3.14) +- [uv](https://docs.astral.sh/uv/) (latest version recommended) +- [Docker](https://www.docker.com/) (for containerized setup, latest version recommended) ## Basic setup diff --git a/services/backend/pyproject.toml b/services/backend/pyproject.toml index 5ee2ff5..14b0da1 100644 --- a/services/backend/pyproject.toml +++ b/services/backend/pyproject.toml @@ -1,38 +1,38 @@ [project] -name = "adnova-backend" -version = "0.1.0" -readme = "README.md" -requires-python = ">=3.10,<3.12" dependencies = [ - "celery>=5.4.0", - "colorlog>=6.9.0", - "django-cors-headers>=4.6.0", - "django-environ>=0.11.2", - "django-extensions>=3.2.3", - "django-guid>=3.5.0", - "django-health-check>=3.18.3", - "django-minio-storage>=0.5.7", - "django-ninja>=1.3.0", - "django-stubs-ext>=5.1.3", - "gunicorn>=23.0.0", - "httpx>=0.28.1", - "pillow>=11.1.0", - "psycopg2-binary>=2.9.10", - "pydantic>=2.10.5", - "pyjwt>=2.10.1", - "python-json-logger>=3.2.1", - "pytz>=2024.2", - "redis>=5.2.1", - "yandex-cloud-ml-sdk>=0.3.1", + "celery>=5.5.0,<6.0.0", + "colorlog>=6.9.0,<7.0.0", + "django-cors-headers>=4.7.0,<5.0.0", + "django-environ>=0.12.0,<1.0.0", + "django-extensions>=4.1.0,<5.0.0", + "django-guid>=3.5.1,<4.0.0", + "django-health-check>=3.18.3,<4.0.0", + "django-minio-storage>=0.5.7,<0.6.0", + "django-ninja>=1.3.0,<2.0.0", + "django-stubs-ext>=5.1.3,<6.0.0", + "gunicorn>=23.0.0,<24.0.0", + "httpx>=0.28.1,<0.29.0", + "pillow>=11.1.0,<12.0.0", + "psycopg2-binary>=2.9.10,<3.0.0", + "pydantic>=2.10.5,<3.0.0", + "pyjwt>=2.10.1,<3.0.0", + "python-json-logger>=3.2.1,<4.0.0", + "pytz>=2024.2,<2025.0", + "redis>=6.2.0,<7.0.0", + "yandex-cloud-ml-sdk>=0.3.1,<0.4.0", ] +name = "adnova-backend" +readme = "README.md" +requires-python = ">=3.10,<3.14" +version = "0.1.0" [dependency-groups] dev = [ - "coverage>=7.6.12", - "django-debug-toolbar>=4.4.6", - "django-stubs[compatible-mypy]>=5.1.3", - "mypy>=1.15.0", - "ruff>=0.9.3", + "coverage", + "django-debug-toolbar>=5.2,<5.3", + "django-stubs[compatible-mypy]", + "mypy", + "ruff", ] [tool.ruff] @@ -66,7 +66,7 @@ extend-include = [] fix = false fix-only = false force-exclude = true -include = ["*.py", "*.pyi", "*.ipynb", "**/pyproject.toml"] +include = ["**/pyproject.toml", "*.ipynb", "*.py", "*.pyi"] indent-width = 4 line-length = 79 namespace-packages = [] @@ -81,20 +81,20 @@ unsafe-fixes = false [tool.ruff.analyze] detect-string-imports = true -direction = "Dependencies" -exclude = [] -include-dependencies = {} -preview = false +direction = "Dependencies" +exclude = [] +include-dependencies = {} +preview = false [tool.ruff.format] -docstring-code-format = true +docstring-code-format = true docstring-code-line-length = 79 -exclude = [] -indent-style = "space" -line-ending = "lf" -preview = false -quote-style = "double" -skip-magic-trailing-comma = false +exclude = [] +indent-style = "space" +line-ending = "lf" +preview = false +quote-style = "double" +skip-magic-trailing-comma = false [tool.ruff.lint] allowed-confusables = ["ℹ"] @@ -109,26 +109,26 @@ extend-unsafe-fixes = [] external = [] fixable = ["ALL"] ignore = [ - "ARG", - "D", - "ANN401", - "COM812", - "DJ001", - "DJ007", - "FBT001", - "FBT002", - "N813", - "PLR2004", - "PT009", - "PT027", - "RUF001", - "S311", + "ANN401", + "ARG", + "COM812", + "D", + "DJ001", + "DJ007", + "FBT001", + "FBT002", + "N813", + "PLR2004", + "PT009", + "PT027", + "RUF001", + "S311", ] logger-objects = [] per-file-ignores = {} preview = false select = ["ALL"] -task-tags = ["TODO", "FIXME", "HACK", "WORKOUT"] +task-tags = ["FIXME", "HACK", "TODO", "WORKOUT"] typing-modules = [] unfixable = [] @@ -136,26 +136,26 @@ unfixable = [] max-args = 6 [tool.mypy] -plugins = ["mypy_django_plugin.main"] ignore_missing_imports = true -strict = false -show_error_context = false -no_implicit_optional = false +no_implicit_optional = false +plugins = ["mypy_django_plugin.main"] +show_error_context = false +strict = false [tool.django-stubs] django_settings_module = "config.settings" -strict_settings = false +strict_settings = false [tool.coverage.run] omit = [ - "manage.py", - "config/wsgi.py", - "config/asgi.py", - "config/urls.py", - "config/settings.py", - "config/handlers.py", - "config/errors.py", - "integrations/yandexai/*" + "config/asgi.py", + "config/errors.py", + "config/handlers.py", + "config/settings.py", + "config/urls.py", + "config/wsgi.py", + "integrations/yandexai/*", + "manage.py", ] [tool.coverage.report] diff --git a/services/telegram_bot/Dockerfile b/services/telegram_bot/Dockerfile index 4f90ebf..56c80e5 100644 --- a/services/telegram_bot/Dockerfile +++ b/services/telegram_bot/Dockerfile @@ -1,7 +1,7 @@ # Stage 1: Install dependencies -FROM docker.io/python:3.11-alpine3.20 AS builder +FROM docker.io/python:3.13-alpine3.22 AS builder -COPY --from=ghcr.io/astral-sh/uv:0.4.30 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app @@ -17,7 +17,7 @@ RUN uv sync --no-dev --no-install-project --no-cache # Stage 2: Start the application -FROM docker.io/python:3.11-alpine3.20 +FROM docker.io/python:3.13-alpine3.22 WORKDIR /app @@ -34,4 +34,4 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONOPTIMIZE=2 \ PATH="/opt/venv/bin:$PATH" -CMD python main.py +CMD [ "python", "main.py" ] diff --git a/services/telegram_bot/README.md b/services/telegram_bot/README.md index 9dbab70..956c5a3 100644 --- a/services/telegram_bot/README.md +++ b/services/telegram_bot/README.md @@ -4,9 +4,9 @@ Ensure you have the following installed on your system: -- [Python](https://www.python.org/) (>=3.10,<3.12) -- [uv](https://docs.astral.sh/uv/) -- [Docker](https://www.docker.com/) (for containerized setup) +- [Python](https://www.python.org/) (>=3.10,<3.14) +- [uv](https://docs.astral.sh/uv/) (latest version recommended) +- [Docker](https://www.docker.com/) (for containerized setup, latest version recommended) ## Basic setup diff --git a/services/telegram_bot/pyproject.toml b/services/telegram_bot/pyproject.toml index afbc664..33e0bed 100644 --- a/services/telegram_bot/pyproject.toml +++ b/services/telegram_bot/pyproject.toml @@ -1,22 +1,19 @@ [project] -name = "adnova-telegram_bot" -version = "0.1.0" -readme = "README.md" -requires-python = ">=3.10,<3.12" dependencies = [ - "aiogram-dialog>=2.3.1", - "aiogram>=3.17.0", - "cachetools>=5.5.1", - "httpx>=0.28.1", - "openapi-python-client>=0.23.1", - "python-dotenv>=1.0.1", - "redis>=5.2.1", + "aiogram-dialog>=2.4.0,<3.0.0", + "aiogram>=3.17.0,<4.0.0", + "cachetools>=5.0.0,<6.0.0", + "httpx>=0.28.0,<0.29.0", + "python-dotenv>=1.1.0,<2.0.0", + "redis>=6.2.0,<7.0.0", ] +name = "adnova-telegram_bot" +readme = "README.md" +requires-python = ">=3.10,<3.14" +version = "0.1.0" [dependency-groups] -dev = [ - "ruff>=0.9.6", -] +dev = ["ruff"] [tool.ruff] builtins = [] @@ -49,7 +46,7 @@ extend-include = [] fix = false fix-only = false force-exclude = true -include = ["*.py", "*.pyi", "*.ipynb", "**/pyproject.toml"] +include = ["**/pyproject.toml", "*.ipynb", "*.py", "*.pyi"] indent-width = 4 line-length = 79 namespace-packages = [] @@ -64,20 +61,20 @@ unsafe-fixes = false [tool.ruff.analyze] detect-string-imports = true -direction = "Dependencies" -exclude = [] -include-dependencies = {} -preview = false +direction = "Dependencies" +exclude = [] +include-dependencies = {} +preview = false [tool.ruff.format] -docstring-code-format = true +docstring-code-format = true docstring-code-line-length = 79 -exclude = [] -indent-style = "space" -line-ending = "lf" -preview = false -quote-style = "double" -skip-magic-trailing-comma = false +exclude = [] +indent-style = "space" +line-ending = "lf" +preview = false +quote-style = "double" +skip-magic-trailing-comma = false [tool.ruff.lint] allowed-confusables = ["ℹ"] @@ -92,23 +89,23 @@ extend-unsafe-fixes = [] external = [] fixable = ["ALL"] ignore = [ - "ARG", - "D", - "ANN401", - "COM812", - "DJ001", - "FBT001", - "FBT002", - "N813", - "PLR2004", - "RUF001", - "TC002", + "ANN401", + "ARG", + "COM812", + "D", + "DJ001", + "FBT001", + "FBT002", + "N813", + "PLR2004", + "RUF001", + "TC002", ] logger-objects = [] per-file-ignores = {} preview = false select = ["ALL"] -task-tags = ["TODO", "FIXME", "HACK", "WORKOUT"] +task-tags = ["FIXME", "HACK", "TODO", "WORKOUT"] typing-modules = [] unfixable = [] diff --git a/tests/README.md b/tests/README.md index 319b65f..a3e2c7f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ # AdNova Tests -There is `unit` and `e2e` tests available, unit tests are placed all around `backend` service folder and `e2e` tests placed [here](./e2e/). +There is `unit` and `e2e` tests available, `unit` tests are placed all around `backend` service folder and `e2e` tests placed [here](./e2e/). ## Running unit tests diff --git a/tests/e2e/README.md b/tests/e2e/README.md index d05845e..555f918 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -4,10 +4,10 @@ Ensure you have the following installed on your system: -- [Python](https://www.python.org/) (>=3.10,<3.12) -- [uv](https://docs.astral.sh/uv/) -- [Docker](https://www.docker.com/) -- [Docker compose](https://docs.docker.com/compose/) (latest versions) +- [Python](https://www.python.org/) (>=3.10,<3.14) +- [uv](https://docs.astral.sh/uv/) (latest version recommended) +- [Docker](https://www.docker.com/) (latest version recommended) +- [Docker compose](https://docs.docker.com/compose/) (latest version recommended) ## Warning diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index 2e81273..2bd55ca 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -1,18 +1,12 @@ [project] -name = "adnova-e2e-tests" -version = "0.1.0" -readme = "README.md" -requires-python = ">=3.10,<3.12" -dependencies = [ - "httpx>=0.28.1", - "pytest>=8.3.4", - "python-dotenv>=1.0.1", -] +dependencies = ["httpx>=0.28.1", "pytest>=8.3.4", "python-dotenv>=1.0.1"] +name = "adnova-tests-e2e" +readme = "README.md" +requires-python = ">=3.10,<3.14" +version = "0.1.0" [dependency-groups] -dev = [ - "ruff>=0.9.6", -] +dev = ["ruff"] [tool.ruff] builtins = [] @@ -45,7 +39,7 @@ extend-include = [] fix = false fix-only = false force-exclude = true -include = ["*.py", "*.pyi", "*.ipynb", "**/pyproject.toml"] +include = ["**/pyproject.toml", "*.ipynb", "*.py", "*.pyi"] indent-width = 4 line-length = 79 namespace-packages = [] @@ -60,50 +54,41 @@ unsafe-fixes = false [tool.ruff.analyze] detect-string-imports = true -direction = "Dependencies" -exclude = [] -include-dependencies = {} -preview = false +direction = "Dependencies" +exclude = [] +include-dependencies = {} +preview = false [tool.ruff.format] -docstring-code-format = true +docstring-code-format = true docstring-code-line-length = 79 -exclude = [] -indent-style = "space" -line-ending = "lf" -preview = false -quote-style = "double" -skip-magic-trailing-comma = false +exclude = [] +indent-style = "space" +line-ending = "lf" +preview = false +quote-style = "double" +skip-magic-trailing-comma = false [tool.ruff.lint] -allowed-confusables = ["ℹ"] -dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" -exclude = ["tests.py"] -explicit-preview-rules = false -extend-fixable = [] +allowed-confusables = ["ℹ"] +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" +exclude = ["tests.py"] +explicit-preview-rules = false +extend-fixable = [] extend-per-file-ignores = {} -extend-safe-fixes = [] -extend-select = [] -extend-unsafe-fixes = [] -external = [] -fixable = ["ALL"] -ignore = [ - "ARG", - "D", - "ANN401", - "COM812", - "FBT001", - "FBT002", - "N813", - "S101", -] -logger-objects = [] -per-file-ignores = {} -preview = false -select = ["ALL"] -task-tags = ["TODO", "FIXME", "HACK", "WORKOUT"] -typing-modules = [] -unfixable = [] +extend-safe-fixes = [] +extend-select = [] +extend-unsafe-fixes = [] +external = [] +fixable = ["ALL"] +ignore = ["ANN401", "ARG", "COM812", "D", "FBT001", "FBT002", "N813", "S101"] +logger-objects = [] +per-file-ignores = {} +preview = false +select = ["ALL"] +task-tags = ["FIXME", "HACK", "TODO", "WORKOUT"] +typing-modules = [] +unfixable = [] [tool.ruff.lint.pylint] max-args = 6