564 lines
13 KiB
Markdown
564 lines
13 KiB
Markdown
# Архитектура MVP: ERP для мастеров
|
||
|
||
## 🏗️ Общая архитектура
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "Frontend"
|
||
A[Angular PWA]
|
||
B[QR Scanner]
|
||
end
|
||
|
||
subgraph "Backend Services"
|
||
C[Go Core Service]
|
||
D[Python Document Service]
|
||
end
|
||
|
||
subgraph "Infrastructure"
|
||
E[PostgreSQL]
|
||
F[Redis Cache]
|
||
end
|
||
|
||
A <--> C
|
||
B --> A
|
||
C <--> E
|
||
C <--> D
|
||
D <--> F
|
||
|
||
style A fill:#ff9999
|
||
style C fill:#99ccff
|
||
style D fill:#99ff99
|
||
style E fill:#ffcc99
|
||
style F fill:#cc99ff
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ Технологический стек
|
||
|
||
### Backend (Go)
|
||
- **Framework:** Gin (легкий и быстрый)
|
||
- **Database:** PostgreSQL
|
||
- **Authentication:** JWT
|
||
- **Validation:** validator
|
||
- **Inter-service Communication:** gRPC + Protocol Buffers
|
||
- **API Documentation:** Swagger/OpenAPI
|
||
|
||
### Frontend (Angular PWA)
|
||
- **Framework:** Angular 17+
|
||
- **Build Tool:** Angular CLI
|
||
- **PWA:** @angular/service-worker
|
||
- **QR Scanner:** @zxing/ngx-scanner
|
||
- **UI:** Angular Material + Tailwind CSS
|
||
- **State Management:** NgRx (для сложной логики)
|
||
|
||
### Document Service (Python)
|
||
- **Framework:** FastAPI (быстрый, автоматическая документация)
|
||
- **PDF Generation:** reportlab + weasyprint
|
||
- **Office Documents:** python-docx, openpyxl
|
||
- **Templates:** Jinja2
|
||
- **Caching:** Redis
|
||
- **Inter-service Communication:** gRPC
|
||
|
||
### Infrastructure
|
||
- **Containerization:** Docker
|
||
- **Orchestration:** Docker Compose
|
||
- **Inter-service Communication:** gRPC + Protocol Buffers
|
||
- **API Gateway:** Traefik (опционально)
|
||
- **Security:** HTTPS, CORS, JWT
|
||
- **Monitoring:** Structured logging + Prometheus
|
||
|
||
---
|
||
|
||
## 📊 Структура базы данных
|
||
|
||
### ER-диаграмма
|
||
|
||
```mermaid
|
||
erDiagram
|
||
organizations {
|
||
uuid id PK
|
||
varchar name
|
||
varchar type
|
||
jsonb settings
|
||
timestamp created_at
|
||
}
|
||
|
||
users {
|
||
uuid id PK
|
||
uuid organization_id FK
|
||
varchar email
|
||
varchar role
|
||
timestamp created_at
|
||
}
|
||
|
||
storage_locations {
|
||
uuid id PK
|
||
uuid organization_id FK
|
||
uuid parent_id FK
|
||
varchar name
|
||
varchar address
|
||
varchar type
|
||
jsonb coordinates
|
||
varchar qr_code
|
||
timestamp created_at
|
||
}
|
||
|
||
items {
|
||
uuid id PK
|
||
uuid organization_id FK
|
||
varchar name
|
||
text description
|
||
varchar category
|
||
timestamp created_at
|
||
}
|
||
|
||
item_placements {
|
||
uuid id PK
|
||
uuid organization_id FK
|
||
uuid item_id FK
|
||
uuid location_id FK
|
||
integer quantity
|
||
timestamp created_at
|
||
}
|
||
|
||
organizations ||--o{ users : "has"
|
||
organizations ||--o{ storage_locations : "has"
|
||
organizations ||--o{ items : "has"
|
||
organizations ||--o{ item_placements : "has"
|
||
|
||
storage_locations ||--o{ storage_locations : "parent-child"
|
||
storage_locations ||--o{ item_placements : "contains"
|
||
|
||
items ||--o{ item_placements : "placed_in"
|
||
```
|
||
|
||
### Основные таблицы
|
||
|
||
```sql
|
||
-- Организации
|
||
CREATE TABLE organizations (
|
||
id UUID PRIMARY KEY,
|
||
name VARCHAR(255) NOT NULL,
|
||
type VARCHAR(100),
|
||
settings JSONB,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- Пользователи
|
||
CREATE TABLE users (
|
||
id UUID PRIMARY KEY,
|
||
organization_id UUID REFERENCES organizations(id),
|
||
email VARCHAR(255) UNIQUE NOT NULL,
|
||
role VARCHAR(50) DEFAULT 'user',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- Места хранения
|
||
CREATE TABLE storage_locations (
|
||
id UUID PRIMARY KEY,
|
||
organization_id UUID REFERENCES organizations(id),
|
||
parent_id UUID REFERENCES storage_locations(id),
|
||
name VARCHAR(255) NOT NULL,
|
||
address VARCHAR(100) NOT NULL,
|
||
type VARCHAR(50) NOT NULL,
|
||
coordinates JSONB,
|
||
qr_code VARCHAR(255),
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- Товары
|
||
CREATE TABLE items (
|
||
id UUID PRIMARY KEY,
|
||
organization_id UUID REFERENCES organizations(id),
|
||
name VARCHAR(255) NOT NULL,
|
||
description TEXT,
|
||
category VARCHAR(100),
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- Размещение товаров
|
||
CREATE TABLE item_placements (
|
||
id UUID PRIMARY KEY,
|
||
organization_id UUID REFERENCES organizations(id),
|
||
item_id UUID REFERENCES items(id),
|
||
location_id UUID REFERENCES storage_locations(id),
|
||
quantity INTEGER DEFAULT 1,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔌 API Endpoints
|
||
|
||
### Core Service (Go) - REST API
|
||
```
|
||
# Аутентификация
|
||
POST /api/auth/login
|
||
POST /api/auth/register
|
||
POST /api/auth/refresh
|
||
|
||
# Организации
|
||
GET /api/organizations/:id
|
||
PUT /api/organizations/:id
|
||
|
||
# Места хранения
|
||
GET /api/locations
|
||
POST /api/locations
|
||
GET /api/locations/:id
|
||
PUT /api/locations/:id
|
||
DELETE /api/locations/:id
|
||
|
||
# Товары
|
||
GET /api/items
|
||
POST /api/items
|
||
GET /api/items/:id
|
||
PUT /api/items/:id
|
||
DELETE /api/items/:id
|
||
|
||
# Операции
|
||
POST /api/operations/place-item
|
||
POST /api/operations/move-item
|
||
GET /api/operations/search
|
||
|
||
# Шаблоны
|
||
GET /api/templates
|
||
POST /api/templates/:id/apply
|
||
```
|
||
|
||
### Document Service (Python) - REST API
|
||
```
|
||
# Документы
|
||
POST /api/documents/generate-pdf
|
||
POST /api/documents/generate-excel
|
||
GET /api/documents/:id/status
|
||
GET /api/documents/:id/download
|
||
|
||
# Шаблоны документов
|
||
GET /api/templates
|
||
POST /api/templates
|
||
PUT /api/templates/:id
|
||
DELETE /api/templates/:id
|
||
```
|
||
|
||
## 🔄 Межсервисная коммуникация
|
||
|
||
### gRPC Services
|
||
|
||
#### Core Service → Document Service
|
||
```protobuf
|
||
service DocumentService {
|
||
rpc GenerateQRCode(QRCodeRequest) returns (QRCodeResponse);
|
||
rpc GenerateReport(ReportRequest) returns (ReportResponse);
|
||
rpc GetDocumentStatus(StatusRequest) returns (StatusResponse);
|
||
}
|
||
```
|
||
|
||
#### Document Service → Core Service
|
||
```protobuf
|
||
service CoreService {
|
||
rpc GetLocationData(LocationRequest) returns (LocationResponse);
|
||
rpc GetItemData(ItemRequest) returns (ItemResponse);
|
||
rpc ValidateTemplate(TemplateRequest) returns (TemplateResponse);
|
||
}
|
||
```
|
||
|
||
### События (Event-Driven)
|
||
```protobuf
|
||
message DocumentEvent {
|
||
string event_type; // "qr_generated", "report_ready"
|
||
string document_id;
|
||
string organization_id;
|
||
google.protobuf.Timestamp timestamp;
|
||
}
|
||
```
|
||
|
||
## 🔄 Диаграммы последовательности
|
||
|
||
### Генерация QR-кода
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant F as Frontend
|
||
participant C as Core Service
|
||
participant D as Document Service
|
||
participant R as Redis
|
||
|
||
F->>C: POST /api/locations/:id/qr-code
|
||
C->>D: gRPC GenerateQRCode()
|
||
D->>D: Generate QR code
|
||
D->>R: Cache document
|
||
D->>C: Return document URL
|
||
C->>F: Return QR code data
|
||
```
|
||
|
||
### Размещение товара
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as User
|
||
participant F as Frontend
|
||
participant C as Core Service
|
||
participant DB as Database
|
||
|
||
U->>F: Scan QR code
|
||
F->>F: Decode location ID
|
||
F->>C: GET /api/locations/:id
|
||
C->>DB: Query location
|
||
DB->>C: Return location data
|
||
C->>F: Return location info
|
||
F->>U: Show location details
|
||
|
||
U->>F: Select item & quantity
|
||
F->>C: POST /api/operations/place-item
|
||
C->>DB: Create placement
|
||
DB->>C: Confirm placement
|
||
C->>F: Return success
|
||
F->>U: Show confirmation
|
||
```
|
||
|
||
### Поиск товара
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as User
|
||
participant F as Frontend
|
||
participant C as Core Service
|
||
participant R as Redis
|
||
participant DB as Database
|
||
|
||
U->>F: Search query
|
||
F->>C: GET /api/operations/search?q=query
|
||
C->>R: Check cache
|
||
alt Cache hit
|
||
R->>C: Return cached results
|
||
else Cache miss
|
||
C->>DB: Search items & locations
|
||
DB->>C: Return results
|
||
C->>R: Cache results
|
||
end
|
||
C->>F: Return search results
|
||
F->>U: Display results
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Безопасность
|
||
|
||
### Аутентификация
|
||
- JWT токены с refresh механизмом
|
||
- Organization-scope на всех запросах
|
||
- Middleware для проверки прав доступа
|
||
|
||
### Валидация данных
|
||
- Входная валидация всех параметров
|
||
- SQL injection protection через prepared statements
|
||
- XSS protection в frontend
|
||
|
||
### HTTPS
|
||
- Обязательное использование HTTPS
|
||
- Secure cookies для JWT
|
||
- CORS настройки для PWA
|
||
|
||
---
|
||
|
||
## 📱 PWA Особенности
|
||
|
||
### Service Worker
|
||
- Кэширование статических ресурсов
|
||
- Offline fallback для базовых функций
|
||
- Background sync для операций
|
||
|
||
### QR Scanner
|
||
- Использование WebRTC для доступа к камере
|
||
- Real-time распознавание QR-кодов
|
||
- Fallback на ручной ввод
|
||
|
||
### Установка
|
||
- Manifest для установки как нативное приложение
|
||
- Splash screen и иконки
|
||
- Автоматические обновления
|
||
|
||
---
|
||
|
||
## 🚀 Развертывание
|
||
|
||
### Docker Compose
|
||
```yaml
|
||
version: '3.8'
|
||
services:
|
||
# Core Service (Go)
|
||
core-service:
|
||
build: ./core-service
|
||
ports:
|
||
- "8080:8080"
|
||
environment:
|
||
- DB_HOST=postgres
|
||
- JWT_SECRET=your-secret
|
||
- DOC_SERVICE_URL=http://doc-service:8000
|
||
depends_on:
|
||
- postgres
|
||
- redis
|
||
|
||
# Document Service (Python)
|
||
doc-service:
|
||
build: ./doc-service
|
||
ports:
|
||
- "8000:8000"
|
||
environment:
|
||
- REDIS_URL=redis://redis:6379
|
||
- CORE_SERVICE_URL=http://core-service:8080
|
||
depends_on:
|
||
- redis
|
||
|
||
# Frontend (Angular)
|
||
frontend:
|
||
build: ./frontend
|
||
ports:
|
||
- "3000:80"
|
||
depends_on:
|
||
- core-service
|
||
|
||
# Database
|
||
postgres:
|
||
image: postgres:15
|
||
environment:
|
||
- POSTGRES_DB=erp_mvp
|
||
- POSTGRES_USER=erp_user
|
||
- POSTGRES_PASSWORD=erp_pass
|
||
volumes:
|
||
- postgres_data:/var/lib/postgresql/data
|
||
|
||
# Cache
|
||
redis:
|
||
image: redis:7-alpine
|
||
ports:
|
||
- "6379:6379"
|
||
volumes:
|
||
- redis_data:/data
|
||
|
||
# API Gateway (опционально)
|
||
traefik:
|
||
image: traefik:v2.10
|
||
command:
|
||
- --api.insecure=true
|
||
- --providers.docker=true
|
||
ports:
|
||
- "80:80"
|
||
- "8081:8080"
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock
|
||
|
||
volumes:
|
||
postgres_data:
|
||
redis_data:
|
||
```
|
||
|
||
### Структура проекта
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[erp-mvp/] --> B[core-service/]
|
||
A --> C[doc-service/]
|
||
A --> D[frontend/]
|
||
A --> E[proto/]
|
||
A --> F[docker-compose.yml]
|
||
|
||
B --> B1[cmd/]
|
||
B --> B2[internal/]
|
||
B --> B3[pkg/]
|
||
B --> B4[proto/]
|
||
B --> B5[Dockerfile]
|
||
|
||
C --> C1[app/]
|
||
C --> C2[templates/]
|
||
C --> C3[proto/]
|
||
C --> C4[Dockerfile]
|
||
|
||
D --> D1[src/]
|
||
D --> D2[angular.json]
|
||
D --> D3[Dockerfile]
|
||
|
||
E --> E1[core.proto]
|
||
E --> E2[document.proto]
|
||
E --> E3[events.proto]
|
||
|
||
style A fill:#e1f5fe
|
||
style B fill:#f3e5f5
|
||
style C fill:#e8f5e8
|
||
style D fill:#fff3e0
|
||
style E fill:#fce4ec
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 Конкретные библиотеки и фреймворки
|
||
|
||
### Core Service (Go)
|
||
```go
|
||
// Основные зависимости
|
||
go.mod:
|
||
- github.com/gin-gonic/gin v1.9.1 // HTTP framework
|
||
- github.com/golang-jwt/jwt/v5 v5.0.0 // JWT authentication
|
||
- github.com/lib/pq v1.10.9 // PostgreSQL driver
|
||
- github.com/go-playground/validator/v10 // Validation
|
||
- google.golang.org/grpc v1.58.0 // gRPC client/server
|
||
- github.com/swaggo/gin-swagger v1.6.0 // API documentation
|
||
- github.com/redis/go-redis/v9 v9.2.1 // Redis client
|
||
```
|
||
|
||
### Document Service (Python)
|
||
```python
|
||
# requirements.txt
|
||
fastapi==0.104.1 # Web framework
|
||
uvicorn==0.24.0 # ASGI server
|
||
reportlab==4.0.4 # PDF generation
|
||
weasyprint==60.1 # HTML to PDF
|
||
python-docx==1.1.0 # Word documents
|
||
openpyxl==3.1.2 # Excel files
|
||
jinja2==3.1.2 # Templates
|
||
redis==5.0.1 # Redis client
|
||
grpcio==1.59.0 # gRPC
|
||
protobuf==4.24.4 # Protocol Buffers
|
||
pydantic==2.4.2 # Data validation
|
||
```
|
||
|
||
### Frontend (Angular)
|
||
```json
|
||
// package.json
|
||
{
|
||
"dependencies": {
|
||
"@angular/core": "^17.0.0",
|
||
"@angular/material": "^17.0.0",
|
||
"@angular/service-worker": "^17.0.0",
|
||
"@zxing/ngx-scanner": "^3.0.0",
|
||
"@ngrx/store": "^17.0.0",
|
||
"@ngrx/effects": "^17.0.0",
|
||
"tailwindcss": "^3.3.0",
|
||
"rxjs": "^7.8.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📊 Мониторинг
|
||
|
||
### Логирование
|
||
- **Go:** logrus или zerolog для structured logging
|
||
- **Python:** structlog для structured logging
|
||
- **Frontend:** Angular logging service
|
||
- Correlation ID для отслеживания запросов через все сервисы
|
||
|
||
### Метрики
|
||
- **Prometheus** для сбора метрик
|
||
- **Grafana** для визуализации
|
||
- Время отклика API по сервисам
|
||
- Количество ошибок и их типы
|
||
- Активные пользователи и операции
|
||
|
||
### Алерты
|
||
- Высокое время отклика (>500ms)
|
||
- Высокий процент ошибок (>5%)
|
||
- Недоступность сервисов
|
||
- Проблемы с генерацией документов
|