Рефакторинг инфраструктуры и конфигурации проекта
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Successful in 1m52s
CI/CD Pipeline / Run Tests (push) Failing after 2m2s
CI/CD Pipeline / Build & Push Images (push) Has been skipped

- Перенесена структура Django-конфига в src/core и src/settings

- Унифицирована Docker-сборка и docker-compose для dev/prod

- Добавлены startup-checks (DB/Redis) и обновлены env-шаблоны

- Расширена OpenAPI-документация и ответы API

- Удалены устаревшие deploy/requirements/служебные скрипты

- Обновлены CI/CD, README и тесты
This commit is contained in:
2026-02-18 13:25:01 +01:00
parent 0f4af561de
commit d5d184537f
71 changed files with 1253 additions and 2318 deletions

3
src/core/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
from .celery import app as celery_app
__all__ = ("celery_app",)

49
src/core/api_v1_urls.py Normal file
View File

@@ -0,0 +1,49 @@
"""
API v1 URL configuration.
Все API эндпоинты версионированы под /api/v1/
Структура:
- /api/v1/users/ - Аутентификация и пользователи
- /api/v1/jobs/ - Фоновые задачи
- /api/v1/minpromtorg/ - Минпромторг (сертификаты, производители)
- /api/v1/proverki/ - Единый реестр проверок
- /api/v1/zakupki/ - Государственные закупки
- /api/v1/fns/ - ФНС (бухгалтерская отчетность)
- /api/v1/system/ - Системные (логи, прокси) - только для админов
"""
from apps.core.views import BackgroundJobListView, BackgroundJobStatusView
from apps.parsers.urls import (
fns_urlpatterns,
minpromtorg_urlpatterns,
proverki_urlpatterns,
system_urlpatterns,
zakupki_urlpatterns,
)
from django.urls import include, path
app_name = "api_v1"
# Фоновые задачи
jobs_urlpatterns = [
path("", BackgroundJobListView.as_view(), name="job-list"),
path("<str:task_id>/", BackgroundJobStatusView.as_view(), name="job-status"),
]
urlpatterns = [
# Аутентификация и пользователи
path("users/", include("apps.user.urls")),
# Фоновые задачи
path("jobs/", include((jobs_urlpatterns, "jobs"))),
# Парсеры - Минпромторг
path("minpromtorg/", include((minpromtorg_urlpatterns, "minpromtorg"))),
# Парсеры - Единый реестр проверок
path("proverki/", include((proverki_urlpatterns, "proverki"))),
# Парсеры - Государственные закупки
path("zakupki/", include((zakupki_urlpatterns, "zakupki"))),
# Парсеры - ФНС бухгалтерская отчетность
path("fns/", include((fns_urlpatterns, "fns"))),
# Системные (только админы)
path("system/", include((system_urlpatterns, "system"))),
]

18
src/core/asgi.py Normal file
View File

@@ -0,0 +1,18 @@
"""
ASGI config for the project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from apps.core.startup_checks import run_startup_checks
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.production")
run_startup_checks(component="asgi")
application = get_asgi_application()

68
src/core/celery.py Normal file
View File

@@ -0,0 +1,68 @@
"""
Celery configuration for the project.
This module contains Celery configuration and task registration.
"""
import os
import sys
from apps.core.startup_checks import run_startup_checks
from celery import Celery
# Set the Django settings module for the 'celery' program.
if "DJANGO_SETTINGS_MODULE" not in os.environ:
raise RuntimeError(
"DJANGO_SETTINGS_MODULE is not set. "
"Export it explicitly before starting Celery "
"(e.g., settings.production or settings.dev)."
)
def _is_celery_runtime() -> bool:
"""True when current process is an actual Celery runtime command."""
argv = " ".join(sys.argv).lower()
return "celery" in argv and (
" worker" in argv or " beat" in argv or " flower" in argv
)
if _is_celery_runtime():
run_startup_checks(component="celery")
app = Celery("project")
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object("django.conf:settings", namespace="CELERY")
# Load task modules from all registered Django apps.
app.autodiscover_tasks()
# Configure Celery Beat schedule
app.conf.beat_schedule = {
# Парсинг сертификатов промышленного производства - каждый день в 3:00
"parse-industrial-production-daily": {
"task": "apps.parsers.tasks.parse_industrial_production",
"schedule": 86400.0, # Every 24 hours
},
# Парсинг реестра производителей - каждый день в 4:00
"parse-manufactures-daily": {
"task": "apps.parsers.tasks.parse_manufactures",
"schedule": 86400.0, # Every 24 hours
},
# Сканирование папки FNS - каждые 5 минут
"scan-fns-directory": {
"task": "apps.parsers.tasks.scan_fns_directory",
"schedule": 300.0, # Every 5 minutes
},
}
app.conf.timezone = "Europe/Moscow"
@app.task(bind=True)
def debug_task(self):
print(f"Request: {self.request!r}")

57
src/core/urls.py Normal file
View File

@@ -0,0 +1,57 @@
"""
URL Configuration for the project.
The `urlpatterns` list routes URLs to views.
"""
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions
# Swagger schema view
schema_view = get_schema_view(
openapi.Info(
title="Mostovik API",
default_version="v1",
description="""
## API документация для проекта Mostovik
### Авторизация
Для доступа к защищённым эндпоинтам используйте JWT токен:
1. Получите токен через `POST /api/v1/users/login/`
2. Добавьте заголовок: `Authorization: Bearer <access_token>`
### Обновление токена
Используйте `POST /api/v1/users/token/refresh/` с refresh токеном.
### Парсеры
API предоставляет только чтение данных (GET, GET list).
Добавление и удаление записей происходит через парсеры и админку.
""",
contact=openapi.Contact(email="contact@mostovik.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path(
"",
schema_view.with_ui("swagger", cache_timeout=0),
name="schema-swagger-ui",
),
path("admin/", admin.site.urls),
path("health/", include("apps.core.urls")),
path("api/v1/", include("core.api_v1_urls", namespace="api_v1")),
path("auth/", include("rest_framework.urls")),
]
# Serve media files in development
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

18
src/core/wsgi.py Normal file
View File

@@ -0,0 +1,18 @@
"""
WSGI config for the project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
"""
import os
from apps.core.startup_checks import run_startup_checks
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.dev")
run_startup_checks(component="wsgi")
application = get_wsgi_application()