# Детальный план разработки 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: Очистка и настройка проекта - [x] Удалить зависимости: `grpc`, `redis`, `prometheus` - [x] Обновить `go.mod` - оставить только необходимые пакеты - [x] Настроить структуру проекта согласно Go standards - [x] Добавить `.env` для конфигурации **Файлы для изменения:** ``` go.mod - удалить grpc, redis, prometheus ✅ cmd/main.go - убрать redis, grpc клиенты ✅ internal/config/config.go - упростить конфигурацию ✅ ``` ### Шаг 1.2: Базовая конфигурация - [x] Создать `internal/config/config.go` с упрощённой структурой - [x] Добавить поддержку `.env` файлов - [x] Настроить логирование через logrus - [x] Добавить 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: Подключение к базе данных - [x] Создать `internal/database/connection.go` - [x] Настроить подключение к PostgreSQL - [x] Добавить миграции через `golang-migrate` - [x] Создать базовые таблицы **Структура БД (упрощённая):** ```sql -- organizations CREATE TABLE organizations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(255) NOT NULL, type VARCHAR(100), settings JSONB, created_at TIMESTAMP DEFAULT NOW() ); -- users CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, 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 uuid_generate_v4(), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, parent_id UUID REFERENCES storage_locations(id) ON DELETE CASCADE, 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 uuid_generate_v4(), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, 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 uuid_generate_v4(), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, item_id UUID REFERENCES items(id) ON DELETE CASCADE, location_id UUID REFERENCES storage_locations(id) ON DELETE CASCADE, quantity INTEGER DEFAULT 1, created_at TIMESTAMP DEFAULT NOW() ); ``` ### Шаг 1.4: Базовые модели - [x] Создать `internal/models/` с основными структурами - [x] Добавить валидацию через `validator` - [x] Реализовать 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"` PasswordHash string `json:"-" db:"password_hash"` 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 аутентификация ✅ - [x] Создать `internal/auth/jwt.go` - [x] Реализовать генерацию и валидацию JWT токенов - [x] Добавить organization-scope в токены - [x] Создать 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: Хеширование паролей ✅ - [x] Создать `internal/auth/password.go` - [x] Использовать bcrypt для хеширования - [x] Добавить функции проверки паролей ### Шаг 2.3: API endpoints для аутентификации ✅ - [x] `POST /api/auth/register` - регистрация организации и пользователя - [x] `POST /api/auth/login` - вход в систему - [x] `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"` } ``` **Результаты тестирования:** - ✅ Регистрация: `POST /api/auth/register` - 201 Created - ✅ Вход: `POST /api/auth/login` - 200 OK - ✅ Middleware: JWT токены проходят валидацию - ✅ JSON поля: исправлена конвертация в PostgreSQL ``` --- ## 🏗️ Этап 3: API структура (Неделя 3) ✅ ЗАВЕРШЁН ### Шаг 3.1: Repository pattern ✅ - [x] Создать `internal/repository/` для работы с БД - [x] Реализовать CRUD операции для всех сущностей - [x] Добавить organization-scope фильтрацию **Структура 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: Service layer ✅ - [x] Создать `internal/service/` с бизнес-логикой - [x] Реализовать сервисы для всех сущностей - [x] Добавить валидацию и логирование **Основные сервисы:** ```go // internal/service/location_service.go type LocationService interface { CreateLocation(ctx context.Context, orgID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) GetLocation(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.StorageLocation, error) GetLocations(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) UpdateLocation(ctx context.Context, id uuid.UUID, orgID uuid.UUID, req *models.CreateLocationRequest) (*models.StorageLocation, error) DeleteLocation(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error } // internal/service/item_service.go type ItemService interface { CreateItem(ctx context.Context, orgID uuid.UUID, req *models.CreateItemRequest) (*models.Item, error) GetItem(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.Item, error) GetItems(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) UpdateItem(ctx context.Context, id uuid.UUID, orgID uuid.UUID, req *models.CreateItemRequest) (*models.Item, error) DeleteItem(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error SearchItems(ctx context.Context, orgID uuid.UUID, query string, category string) ([]*models.Item, error) } // internal/service/operations_service.go type OperationsService interface { PlaceItem(ctx context.Context, orgID uuid.UUID, req *models.PlaceItemRequest) (*models.ItemPlacement, error) MoveItem(ctx context.Context, placementID uuid.UUID, newLocationID uuid.UUID, orgID uuid.UUID) error GetItemPlacements(ctx context.Context, itemID uuid.UUID, orgID uuid.UUID) ([]*models.ItemPlacement, error) GetLocationPlacements(ctx context.Context, locationID uuid.UUID, orgID uuid.UUID) ([]*models.ItemPlacement, error) Search(ctx context.Context, orgID uuid.UUID, req *models.SearchRequest) (*models.SearchResponse, error) } ``` ### Шаг 3.3: HTTP Handlers ✅ - [x] Создать `internal/api/handlers/` с базовыми структурами - [x] Реализовать handlers для всех API endpoints - [x] Добавить валидацию запросов **Результаты этапа 3:** - ✅ Созданы репозитории для locations, items, operations - ✅ Реализованы сервисы с бизнес-логикой - ✅ Созданы HTTP handlers для всех API endpoints - ✅ Добавлена функция GetClaims в middleware - ✅ Organization-scope фильтрация во всех операциях - ✅ Поддержка JSON полей в PostgreSQL - ✅ Валидация всех входящих запросов ``` --- ## 📍 Этап 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. **Мониторинг** - сбор метрик и обратной связи