# Детальный план разработки 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. **Мониторинг** - сбор метрик и обратной связи
