🛠️ Технологический стек¶
📋 Обзор технологий¶
Система охраны труда построена на современном технологическом стеке, обеспечивающем высокую производительность, масштабируемость и безопасность.
🖥️ Frontend¶
React Ecosystem¶
- React 18.2+: современная библиотека для создания пользовательских интерфейсов
- TypeScript 5.0+: типизированный JavaScript для повышения надежности кода
- Vite 4.0+: быстрый инструмент сборки и разработки
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.0.0",
"vite": "^4.0.0"
}
}
UI Framework¶
- shadcn/ui: современная библиотека компонентов
- Tailwind CSS 3.0+: utility-first CSS фреймворк
- Radix UI: низкоуровневые компоненты для доступности
// Пример использования shadcn/ui компонента
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
const DocumentCard = ({ document }: { document: Document }) => (
<Card>
<CardHeader>
<CardTitle>{document.name}</CardTitle>
</CardHeader>
<CardContent>
<Button variant="outline">Скачать</Button>
</CardContent>
</Card>
)
State Management¶
- TanStack Query: управление серверным состоянием
- Zustand: легковесное управление клиентским состоянием
- React Hook Form: управление формами с валидацией
// Пример использования TanStack Query
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
const useDocuments = () => {
return useQuery({
queryKey: ['documents'],
queryFn: fetchDocuments,
staleTime: 5 * 60 * 1000, // 5 минут
})
}
const useCreateDocument = () => {
const queryClient = useQueryClient()
return useMutation({
mutationFn: createDocument,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['documents'] })
},
})
}
Routing & Navigation¶
- Wouter: легковесный роутер для React
- React Router: альтернативный роутер (опционально)
import { Route, useLocation } from 'wouter'
const App = () => (
<div>
<Route path="/" component={Dashboard} />
<Route path="/documents" component={Documents} />
<Route path="/documents/:id" component={DocumentDetail} />
</div>
)
🐍 Backend¶
Python Framework¶
- Python 3.11+: современная версия Python с улучшенной производительностью
- FastAPI 0.100+: высокопроизводительный веб-фреймворк
- Pydantic 2.0+: валидация данных и сериализация
# Пример FastAPI эндпоинта
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from typing import List
app = FastAPI(title="Safety API", version="1.0.0")
class DocumentCreate(BaseModel):
name: str
description: str | None = None
category: str
@app.post("/documents/", response_model=DocumentResponse)
async def create_document(
document: DocumentCreate,
current_user: User = Depends(get_current_active_user),
db: Session = Depends(get_db)
):
"""Создание нового документа"""
db_document = Document(**document.dict(), uploaded_by=current_user.id)
db.add(db_document)
db.commit()
db.refresh(db_document)
return db_document
Database & ORM¶
- PostgreSQL 14+: надежная реляционная база данных
- SQLAlchemy 2.0+: современный Python ORM
- Alembic: система миграций базы данных
# Пример модели SQLAlchemy
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
Base = declarative_base()
class User(Base):
__tablename__ = "safety_users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50), unique=True, index=True, nullable=False)
email = Column(String(100), unique=True, index=True, nullable=False)
full_name = Column(String(200), nullable=False)
password_hash = Column(String(255), nullable=False)
role = Column(String(20), default="user")
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
Authentication & Security¶
- JWT: JSON Web Tokens для аутентификации
- bcrypt: хеширование паролей
- python-jose: работа с JWT токенами
- passlib: библиотека для работы с паролями
# Пример аутентификации
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
🗄️ Database¶
PostgreSQL Features¶
- JSON/JSONB: хранение неструктурированных данных
- Full-text search: полнотекстовый поиск
- Indexing: оптимизированные индексы
- Partitioning: партиционирование больших таблиц
-- Пример использования JSONB
CREATE TABLE organizations (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
contacts JSONB,
additional_data JSONB
);
-- Создание индекса для JSONB
CREATE INDEX idx_organizations_contacts ON organizations USING GIN (contacts);
-- Запрос с использованием JSONB
SELECT * FROM organizations
WHERE contacts->>'email' = 'admin@example.com';
Database Optimization¶
- Connection pooling: переиспользование соединений
- Query optimization: оптимизация запросов
- Caching: кэширование результатов
- Monitoring: мониторинг производительности
📁 File Processing¶
Document Processing¶
- openpyxl: работа с Excel файлами
- python-docx: работа с Word документами
- PyPDF2: обработка PDF файлов
- python-magic: определение типов файлов
# Пример обработки Excel файла
import openpyxl
from openpyxl import load_workbook
def extract_excel_fields(file_path: str) -> dict:
"""Извлечение полей из Excel шаблона"""
workbook = load_workbook(file_path)
fields = {}
for sheet_name in workbook.sheetnames:
sheet = workbook[sheet_name]
sheet_fields = []
for row in sheet.iter_rows():
for cell in row:
if cell.value and isinstance(cell.value, str):
if '{' in cell.value and '}' in cell.value:
# Извлекаем поля в фигурных скобках
import re
matches = re.findall(r'\{([^}]+)\}', cell.value)
sheet_fields.extend(matches)
fields[sheet_name] = list(set(sheet_fields))
return fields
File Storage¶
- SFTP: безопасная передача файлов
- Local storage: локальное хранение
- File validation: проверка типов файлов
- Virus scanning: сканирование на вирусы
🔗 External Integrations¶
API Integrations¶
- httpx: асинхронные HTTP запросы
- requests: синхронные HTTP запросы
- FNS API: интеграция с налоговой службой
- SMTP: отправка email уведомлений
# Пример интеграции с FNS API
import httpx
from typing import Optional
class FNSService:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api-fns.ru/api"
async def get_organization_data(self, inn: str) -> Optional[dict]:
"""Получение данных организации из ФНС"""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.base_url}/egr",
params={"req": inn, "key": self.api_key}
)
if response.status_code == 200:
return response.json()
return None
Email Service¶
- aiosmtplib: асинхронная отправка email
- email-validator: валидация email адресов
- Jinja2: шаблонизация email сообщений
# Пример отправки email
import aiosmtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
async def send_email(to: str, subject: str, body: str):
"""Отправка email уведомления"""
message = MIMEMultipart()
message["From"] = SMTP_USER
message["To"] = to
message["Subject"] = subject
message.attach(MIMEText(body, "html"))
await aiosmtplib.send(
message,
hostname=SMTP_HOST,
port=SMTP_PORT,
username=SMTP_USER,
password=SMTP_PASSWORD,
use_tls=True
)
🚀 DevOps & Deployment¶
Containerization¶
- Docker: контейнеризация приложений
- Docker Compose: оркестрация для разработки
- Multi-stage builds: оптимизация образов
# Multi-stage Dockerfile
FROM node:18-alpine AS frontend-build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM python:3.11-slim AS backend-build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
FROM python:3.11-slim AS production
WORKDIR /app
COPY --from=backend-build /app .
COPY --from=frontend-build /app/dist ./static
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Monitoring & Logging¶
- Prometheus: сбор метрик
- Grafana: визуализация метрик
- ELK Stack: централизованное логирование
- Sentry: отслеживание ошибок
# Пример настройки логирования
import logging
import structlog
from pythonjsonlogger import jsonlogger
# Настройка структурированного логирования
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.stdlib.PositionalArgumentsFormatter(),
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.UnicodeDecoder(),
structlog.processors.JSONRenderer()
],
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
wrapper_class=structlog.stdlib.BoundLogger,
cache_logger_on_first_use=True,
)
CI/CD¶
- GitHub Actions: автоматизация сборки и развертывания
- Testing: pytest для backend, Jest для frontend
- Code Quality: black, flake8, mypy для Python
- Security: bandit для проверки безопасности
# GitHub Actions workflow
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Run tests
run: pytest tests/ --cov=app --cov-report=xml
- name: Code quality
run: |
black --check app/
flake8 app/
mypy app/
🔧 Development Tools¶
Code Quality¶
- Black: форматирование Python кода
- Flake8: линтинг Python кода
- MyPy: статическая типизация
- Pre-commit: хуки для Git
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
language_version: python3.11
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.3.0
hooks:
- id: mypy
additional_dependencies: [types-all]
Testing¶
- pytest: тестирование Python кода
- pytest-asyncio: тестирование асинхронного кода
- pytest-cov: покрытие кода тестами
- factory-boy: создание тестовых данных
# Пример теста
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import get_db
from tests.factories import UserFactory
client = TestClient(app)
@pytest.fixture
def test_user():
return UserFactory()
def test_create_document(test_user):
response = client.post(
"/documents/",
json={"name": "Test Document", "category": "safety"},
headers={"Authorization": f"Bearer {test_user.token}"}
)
assert response.status_code == 201
assert response.json()["name"] == "Test Document"
📊 Performance & Optimization¶
Caching¶
- Redis: кэширование данных
- Memcached: альтернативное кэширование
- Application cache: кэширование на уровне приложения
- CDN: кэширование статических ресурсов
Database Optimization¶
- Connection pooling: пул соединений с БД
- Query optimization: оптимизация SQL запросов
- Indexing strategy: стратегия индексирования
- Partitioning: партиционирование таблиц
Async Processing¶
- Celery: асинхронная обработка задач
- Redis: брокер сообщений
- Background tasks: фоновые задачи
- Queue management: управление очередями
Технологический стек выбран с учетом требований производительности, масштабируемости и современности разработки.