Рефакторинг инфраструктуры и конфигурации проекта
- Перенесена структура 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:
3
src/core/__init__.py
Normal file
3
src/core/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ("celery_app",)
|
||||
49
src/core/api_v1_urls.py
Normal file
49
src/core/api_v1_urls.py
Normal 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
18
src/core/asgi.py
Normal 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
68
src/core/celery.py
Normal 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
57
src/core/urls.py
Normal 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
18
src/core/wsgi.py
Normal 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()
|
||||
Reference in New Issue
Block a user