From 725d4c4474b5904ab688e9c5956ece25909be0d6 Mon Sep 17 00:00:00 2001 From: Andrey Epifantsev Date: Wed, 27 Aug 2025 14:34:14 +0400 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=BB=D0=B0=D0=BD=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20Core=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D0=B2=D0=B8=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core-service/.cursor/plan.md | 504 +++++++++++++++++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 core-service/.cursor/plan.md diff --git a/core-service/.cursor/plan.md b/core-service/.cursor/plan.md new file mode 100644 index 0000000..bc5ffb9 --- /dev/null +++ b/core-service/.cursor/plan.md @@ -0,0 +1,504 @@ +# Детальный план разработки Core Service + +## 🎯 Цель +Реализация Core Service для ERP MVP с упрощённой архитектурой: Go + PostgreSQL + REST API без gRPC, Redis и Document Service. + +## 📋 Общие принципы +- **REST API** вместо gRPC +- **PostgreSQL** как единственная БД (без Redis) +- **JWT аутентификация** с organization-scope +- **Структурированное логирование** (без Prometheus на MVP) +- **Валидация данных** на всех уровнях + +--- + +## 🚀 Этап 1: Фундамент (Недели 1-2) + +### Шаг 1.1: Очистка и настройка проекта +- [ ] Удалить зависимости: `grpc`, `redis`, `prometheus` +- [ ] Обновить `go.mod` - оставить только необходимые пакеты +- [ ] Настроить структуру проекта согласно Go standards +- [ ] Добавить `.env` для конфигурации + +**Файлы для изменения:** +``` +go.mod - удалить grpc, redis, prometheus +cmd/main.go - убрать redis, grpc клиенты +internal/config/config.go - упростить конфигурацию +``` + +### Шаг 1.2: Базовая конфигурация +- [ ] Создать `internal/config/config.go` с упрощённой структурой +- [ ] Добавить поддержку `.env` файлов +- [ ] Настроить логирование через logrus +- [ ] Добавить health check endpoint + +**Структура конфигурации:** +```go +type Config struct { + Server ServerConfig + Database DatabaseConfig + JWT JWTConfig +} + +type ServerConfig struct { + Port string + Host string +} + +type DatabaseConfig struct { + Host string + Port string + User string + Password string + DBName string + SSLMode string +} + +type JWTConfig struct { + Secret string + TTL time.Duration +} +``` + +### Шаг 1.3: Подключение к базе данных +- [ ] Создать `internal/database/connection.go` +- [ ] Настроить подключение к PostgreSQL +- [ ] Добавить миграции через `golang-migrate` +- [ ] Создать базовые таблицы + +**Структура БД (упрощённая):** +```sql +-- organizations +CREATE TABLE organizations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(255) NOT NULL, + type VARCHAR(100), + settings JSONB, + created_at TIMESTAMP DEFAULT NOW() +); + +-- users +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID REFERENCES organizations(id), + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + role VARCHAR(50) DEFAULT 'user', + created_at TIMESTAMP DEFAULT NOW() +); + +-- storage_locations +CREATE TABLE storage_locations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + 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, + created_at TIMESTAMP DEFAULT NOW() +); + +-- items +CREATE TABLE items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID REFERENCES organizations(id), + name VARCHAR(255) NOT NULL, + description TEXT, + category VARCHAR(100), + created_at TIMESTAMP DEFAULT NOW() +); + +-- item_placements +CREATE TABLE item_placements ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + 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() +); +``` + +### Шаг 1.4: Базовые модели +- [ ] Создать `internal/models/` с основными структурами +- [ ] Добавить валидацию через `validator` +- [ ] Реализовать JSON теги для API + +**Основные модели:** +```go +// internal/models/organization.go +type Organization struct { + ID uuid.UUID `json:"id" db:"id"` + Name string `json:"name" validate:"required"` + Type string `json:"type"` + Settings JSON `json:"settings"` + CreatedAt time.Time `json:"created_at" db:"created_at"` +} + +// internal/models/user.go +type User struct { + ID uuid.UUID `json:"id" db:"id"` + OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"` + Email string `json:"email" validate:"required,email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at" db:"created_at"` +} + +// internal/models/storage_location.go +type StorageLocation struct { + ID uuid.UUID `json:"id" db:"id"` + OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"` + ParentID *uuid.UUID `json:"parent_id,omitempty" db:"parent_id"` + Name string `json:"name" validate:"required"` + Address string `json:"address" validate:"required"` + Type string `json:"type" validate:"required"` + Coordinates JSON `json:"coordinates"` + CreatedAt time.Time `json:"created_at" db:"created_at"` +} + +// internal/models/item.go +type Item struct { + ID uuid.UUID `json:"id" db:"id"` + OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"` + Name string `json:"name" validate:"required"` + Description string `json:"description"` + Category string `json:"category"` + CreatedAt time.Time `json:"created_at" db:"created_at"` +} + +// internal/models/item_placement.go +type ItemPlacement struct { + ID uuid.UUID `json:"id" db:"id"` + OrganizationID uuid.UUID `json:"organization_id" db:"organization_id"` + ItemID uuid.UUID `json:"item_id" db:"item_id"` + LocationID uuid.UUID `json:"location_id" db:"location_id"` + Quantity int `json:"quantity" validate:"min=1"` + CreatedAt time.Time `json:"created_at" db:"created_at"` +} +``` + +--- + +## 🔐 Этап 2: Аутентификация (Неделя 2) + +### Шаг 2.1: JWT аутентификация +- [ ] Создать `internal/auth/jwt.go` +- [ ] Реализовать генерацию и валидацию JWT токенов +- [ ] Добавить organization-scope в токены +- [ ] Создать middleware для проверки аутентификации + +**JWT структура:** +```go +type Claims struct { + UserID uuid.UUID `json:"user_id"` + OrganizationID uuid.UUID `json:"organization_id"` + Email string `json:"email"` + Role string `json:"role"` + jwt.RegisteredClaims +} +``` + +### Шаг 2.2: Хеширование паролей +- [ ] Создать `internal/auth/password.go` +- [ ] Использовать bcrypt для хеширования +- [ ] Добавить функции проверки паролей + +### Шаг 2.3: API endpoints для аутентификации +- [ ] `POST /api/auth/register` - регистрация организации и пользователя +- [ ] `POST /api/auth/login` - вход в систему +- [ ] `POST /api/auth/refresh` - обновление токена (опционально) + +**Структура запросов:** +```go +type RegisterRequest struct { + OrganizationName string `json:"organization_name" validate:"required"` + UserEmail string `json:"user_email" validate:"required,email"` + UserPassword string `json:"user_password" validate:"required,min=8"` + OrganizationType string `json:"organization_type"` +} + +type LoginRequest struct { + Email string `json:"email" validate:"required,email"` + Password string `json:"password" validate:"required"` +} +``` + +--- + +## 🏗️ Этап 3: API структура (Неделя 3) + +### Шаг 3.1: Базовые handlers +- [ ] Создать `internal/api/handlers/` с базовыми структурами +- [ ] Реализовать middleware для CORS, логирования, аутентификации +- [ ] Добавить обработку ошибок + +**Структура handlers:** +``` +internal/api/ +├── handlers/ +│ ├── auth.go +│ ├── organizations.go +│ ├── locations.go +│ ├── items.go +│ └── operations.go +├── middleware/ +│ ├── auth.go +│ ├── cors.go +│ ├── logging.go +│ └── error_handler.go +└── server.go +``` + +### Шаг 3.2: Repository pattern +- [ ] Создать `internal/repository/` для работы с БД +- [ ] Реализовать CRUD операции для всех сущностей +- [ ] Добавить organization-scope фильтрацию + +**Основные репозитории:** +```go +// internal/repository/organizations.go +type OrganizationRepository interface { + Create(ctx context.Context, org *models.Organization) error + GetByID(ctx context.Context, id uuid.UUID) (*models.Organization, error) + Update(ctx context.Context, org *models.Organization) error +} + +// internal/repository/users.go +type UserRepository interface { + Create(ctx context.Context, user *models.User, password string) error + GetByEmail(ctx context.Context, email string) (*models.User, error) + GetByID(ctx context.Context, id uuid.UUID) (*models.User, error) +} + +// internal/repository/locations.go +type LocationRepository interface { + Create(ctx context.Context, location *models.StorageLocation) error + GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.StorageLocation, error) + GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) + Update(ctx context.Context, location *models.StorageLocation) error + Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error +} + +// internal/repository/items.go +type ItemRepository interface { + Create(ctx context.Context, item *models.Item) error + GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.Item, error) + GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) + Search(ctx context.Context, orgID uuid.UUID, query string) ([]*models.Item, error) + Update(ctx context.Context, item *models.Item) error + Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error +} +``` + +### Шаг 3.3: Service layer +- [ ] Создать `internal/service/` для бизнес-логики +- [ ] Реализовать валидацию и обработку данных +- [ ] Добавить транзакции для сложных операций + +--- + +## 📍 Этап 4: Шаблоны помещений (Неделя 4) + +### Шаг 4.1: Система шаблонов +- [ ] Создать `internal/templates/` для шаблонов помещений +- [ ] Реализовать 3 базовых шаблона: Гараж, Мастерская, Склад +- [ ] Добавить генерацию адресов мест + +**Шаблоны:** +```go +type Template struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Zones []Zone `json:"zones"` + AddressRules []AddressRule `json:"address_rules"` +} + +type Zone struct { + Name string `json:"name"` + Type string `json:"type"` // "cabinet", "floor", "table" + Rows int `json:"rows"` + Columns int `json:"columns"` + Position Position `json:"position"` +} + +type AddressRule struct { + ZoneType string `json:"zone_type"` + Prefix string `json:"prefix"` + Format string `json:"format"` // "Ш{zone}-П{row}-Я{col}" +} +``` + +### Шаг 4.2: API для шаблонов +- [ ] `GET /api/templates` - список доступных шаблонов +- [ ] `POST /api/templates/:id/apply` - применение шаблона к организации +- [ ] Генерация мест хранения из шаблона + +### Шаг 4.3: Адресация мест +- [ ] Реализовать систему адресации (Ш1-П2-Я3, З1-У2) +- [ ] Автоматическая генерация адресов при создании мест +- [ ] Валидация уникальности адресов в рамках организации + +--- + +## 🔍 Этап 5: Операции (Неделя 5) + +### Шаг 5.1: Размещение товаров +- [ ] `POST /api/operations/place-item` - размещение товара +- [ ] Валидация доступности места +- [ ] Обновление статуса места +- [ ] Логирование операций + +**Структура запроса:** +```go +type PlaceItemRequest struct { + ItemID uuid.UUID `json:"item_id" validate:"required"` + LocationID uuid.UUID `json:"location_id" validate:"required"` + Quantity int `json:"quantity" validate:"required,min=1"` +} +``` + +### Шаг 5.2: Поиск товаров +- [ ] `GET /api/operations/search` - поиск по названию, адресу, категории +- [ ] Оптимизация запросов через индексы +- [ ] Пагинация результатов + +**Параметры поиска:** +```go +type SearchRequest struct { + Query string `form:"q"` + Category string `form:"category"` + Address string `form:"address"` + Page int `form:"page,default=1"` + PageSize int `form:"page_size,default=20"` +} +``` + +### Шаг 5.3: Перемещение товаров +- [ ] `POST /api/operations/move-item` - перемещение между местами +- [ ] Валидация наличия товара в исходном месте +- [ ] Атомарность операции через транзакции + +--- + +## 🧪 Этап 6: Тестирование и полировка (Неделя 6) + +### Шаг 6.1: Unit тесты +- [ ] Тесты для всех репозиториев +- [ ] Тесты для сервисов +- [ ] Тесты для handlers +- [ ] Покрытие кода > 80% + +### Шаг 6.2: Интеграционные тесты +- [ ] Тесты API endpoints +- [ ] Тесты с реальной БД +- [ ] Тесты аутентификации + +### Шаг 6.3: Производительность +- [ ] Оптимизация SQL запросов +- [ ] Добавление индексов +- [ ] Тестирование под нагрузкой +- [ ] Мониторинг медленных запросов + +### Шаг 6.4: Документация API +- [ ] Swagger/OpenAPI документация +- [ ] Примеры запросов и ответов +- [ ] Описание ошибок + +--- + +## 📊 Критерии готовности + +### Функциональные критерии +- [ ] Все CRUD операции работают для items, locations +- [ ] Аутентификация с organization-scope +- [ ] Шаблоны помещений генерируют структуру +- [ ] Операции размещения/поиска/перемещения работают +- [ ] API отвечает на все запросы + +### Технические критерии +- [ ] Время отклика API ≤ 200мс +- [ ] Покрытие тестами > 80% +- [ ] Все endpoints документированы +- [ ] Логирование работает корректно +- [ ] Graceful shutdown реализован + +### Безопасность +- [ ] JWT токены валидируются +- [ ] Organization-scope на всех данных +- [ ] Валидация входных данных +- [ ] SQL injection protection + +--- + +## 🚨 Риски и митигация + +### Высокий риск +- **Производительность БД при большом количестве данных** + - Митигация: Индексы, пагинация, мониторинг запросов + +### Средний риск +- **JWT токены без refresh механизма** + - Митигация: Короткий TTL, возможность перелогина + +### Низкий риск +- **Отсутствие кэширования** + - Митигация: Оптимизация SQL, индексы + +--- + +## 📁 Структура проекта (финальная) + +``` +app/core-service/ +├── cmd/ +│ └── main.go +├── internal/ +│ ├── api/ +│ │ ├── handlers/ +│ │ ├── middleware/ +│ │ └── server.go +│ ├── auth/ +│ │ ├── jwt.go +│ │ └── password.go +│ ├── config/ +│ │ └── config.go +│ ├── database/ +│ │ ├── connection.go +│ │ └── migrations/ +│ ├── models/ +│ │ ├── organization.go +│ │ ├── user.go +│ │ ├── storage_location.go +│ │ ├── item.go +│ │ └── item_placement.go +│ ├── repository/ +│ │ ├── organizations.go +│ │ ├── users.go +│ │ ├── locations.go +│ │ └── items.go +│ ├── service/ +│ │ ├── auth_service.go +│ │ ├── location_service.go +│ │ └── item_service.go +│ └── templates/ +│ ├── templates.go +│ └── address_rules.go +├── migrations/ +├── tests/ +├── go.mod +├── go.sum +├── Dockerfile +└── .env.example +``` + +--- + +## 🎯 Следующие шаги после Core Service + +1. **Frontend разработка** - Angular PWA с QR сканером +2. **Интеграция** - тестирование API с фронтендом +3. **Пилот** - тестирование с реальными пользователями +4. **Мониторинг** - сбор метрик и обратной связи