architect/arh/operations/MIGRATION_PLAN_PIM.md

ПЛАН МИГРАЦИИ: PIM в новую структуру платформы

Дата создания: 2025-12-22
Статус: DRAFT
Версия: 1.0.0


ПРИНЦИПЫ МИГРАЦИИ

✅ Что делаем:

  1. Создаем НОВУЮ структуру параллельно со старой
  2. Начинаем снизу вверх: L3-INFRA → L2-DATA → L0-ORG
  3. Документируем ВСЕ изменения перед внедрением
  4. Тестируем новую структуру не трогая старую
  5. Переключаемся только после полного тестирования

❌ Что НЕ делаем:


ТЕКУЩАЯ СТРУКТУРА (OLD)

$WORKSPACE/
└── projects/pirotehnika/          ← СТАРАЯ (НЕ ТРОГАЕМ!)
    ├── data/
    │   ├── nocodb/
    │   ├── connectors/pochta/
    │   └── scripts/
    ├── app/
    │   ├── mp1/
    │   ├── ozon/
    │   └── site/
    ├── business/
    └── infra/

Статус: ACTIVE - продолжает работать


ЦЕЛЕВАЯ СТРУКТУРА (NEW)

$WORKSPACE/
├── L3-INFRA/                      ← НОВОЕ (СОЗДАЕМ)
│   ├── database-engines/
│   │   └── postgresql-001/
│   ├── storage/
│   │   └── object/s3/hub/
│   └── compute/
│       └── containers/docker/
│
├── L2-DATA/                       ← НОВОЕ (СОЗДАЕМ)
│   ├── connections/
│   │   ├── bu-piro-db.yaml
│   │   ├── bu-piro-s3.yaml
│   │   └── platform-nocodb-db.yaml
│   ├── schemas/
│   │   └── pim/
│   ├── datasets/
│   │   └── products/
│   └── processors/
│       ├── price-parser/
│       └── 1c-sync/
│
├── L0-ORG/                        ← НОВОЕ (СОЗДАЕМ)
│   └── business-units/
│       └── pirotehnika/
│           ├── SPECIFICATION.md
│           ├── index.yaml
│           ├── services/
│           │   └── pim/
│           └── connections/
│
├── PLATFORM/                      ← НОВОЕ (СОЗДАЕМ)
│   └── applications/
│       └── nocodb/
│
└── projects/pirotehnika/          ← СТАРОЕ (ОСТАВЛЯЕМ!)
    └── ...                        ← Не трогаем до переключения

ЭТАПЫ МИГРАЦИИ

ЭТАП 0: Подготовка (СЕЙЧАС)

Цель: Спланировать и задокументировать

Задачи:
- [x] Инвентаризация данных
- [x] Анализ текущей структуры
- [ ] Создание плана миграции
- [ ] Обновление стандартов платформы

Документы:
- [x] DATA_INVENTORY_PIROTEHNIKA.md
- [x] PLATFORM_RESTRUCTURE_2025.md
- [x] RESOURCE_ALLOCATION.md
- [x] TERMINOLOGY_STANDARD.md
- [ ] MIGRATION_PLAN_PIM.md (этот документ)

Результат: План утвержден, можно начинать


ЭТАП 1: L3-INFRA (Физические ресурсы)

Цель: Описать существующую инфраструктуру

Создаем структуру:

mkdir -p $WORKSPACE/L3-INFRA/database-engines/postgresql-001
mkdir -p $WORKSPACE/L3-INFRA/storage/object/s3/hub
mkdir -p $WORKSPACE/L3-INFRA/compute/containers/docker
mkdir -p $WORKSPACE/L3-INFRA/network/domains

Создаем документы:

1.1. PostgreSQL Instance

Файл: L3-INFRA/database-engines/postgresql-001/index.yaml

name: postgresql-001
type: database_instance
engine: postgresql
version: "14"

location:
  server: dev-pro
  host: 91.218.142.168
  port: 5432

resources:
  cpu: shared
  memory: shared
  storage: shared

databases:
  - name: postgres
    default: true

schemas:
  - bu_piro              # Business Unit: pirotehnika
  - platform_nocodb      # Platform App: NocoDB

status: active
owner: platform

created: 2024-01-01

1.2. S3 Storage

Файл: L3-INFRA/storage/object/s3/hub/index.yaml

name: hub
type: s3_bucket
provider: beget

endpoint: https://s3.beget.com
bucket: hub

paths:
  - /business-units/pirotehnika/
  - /platform/applications/nocodb/

credentials:
  vault_path: /L3-INFRA/storage/object/s3/hub

status: active
owner: platform

1.3. Docker Container Runtime

Файл: L3-INFRA/compute/containers/docker/index.yaml

name: docker
type: container_runtime
engine: docker
version: "24.0"

location:
  server: dev-pro
  host: 91.218.142.168

containers:
  nocodb:
    image: nocodb/nocodb:latest
    port: 8085
    status: running

  mp1:
    image: mp1:latest
    port: 8504
    status: running

status: active
owner: platform

Задачи:
- [ ] Создать структуру папок L3-INFRA
- [ ] Создать index.yaml для PostgreSQL
- [ ] Создать index.yaml для S3
- [ ] Создать index.yaml для Docker
- [ ] Задокументировать все физические ресурсы

Результат: Физические ресурсы описаны в L3-INFRA


ЭТАП 2: L2-DATA (Коннекторы и схемы)

Цель: Создать абстракцию над данными

2.1. Connections (Коннекторы)

Создаем структуру:

mkdir -p $WORKSPACE/L2-DATA/connections
mkdir -p $WORKSPACE/L2-DATA/schemas/pim
mkdir -p $WORKSPACE/L2-DATA/datasets/products
mkdir -p $WORKSPACE/L2-DATA/processors/price-parser
mkdir -p $WORKSPACE/L2-DATA/processors/1c-sync

Создаем коннекторы:

2.1.1. Connection: bu-piro-db

Файл: L2-DATA/connections/bu-piro-db.yaml

name: bu-piro-db
type: database_connection
description: "PostgreSQL connection для бизнес-единицы pirotehnika"

target:
  instance: /L3-INFRA/database-engines/postgresql-001
  database: postgres
  schema: bu_piro

credentials:
  vault_path: /business-units/pirotehnika/db
  user: bu_piro_rw
  # password: from vault

tables:
  # PIM tables
  pim:
    - pim_products
    - pim_brands
    - pim_categories
    - pim_attributes
    - pim_prices
    - pim_suppliers
    - pim_cost_rules
    - pim_sku_mappings
    - pim_bundle_items
    - pim_catalog

  # OZON tables
  ozon:
    - OZON_Products
    - OZON_Orders
    - OZON_OrderItems
    - OZON_Transactions
    - OZON_Analytics_Stocks

  # Other tables
  products:
    - Products

  orders:
    - Order
    - OrderItem

  reference:
    - Suppliers
    - Brands
    - Categories
    - Channel
    - Effects
    - Attributes

permissions:
  read: true
  write: true
  create: true
  drop: false

status: active
created: 2025-12-22
2.1.2. Connection: platform-nocodb-db

Файл: L2-DATA/connections/platform-nocodb-db.yaml

name: platform-nocodb-db
type: database_connection
description: "PostgreSQL connection для NocoDB приложения"

target:
  instance: /L3-INFRA/database-engines/postgresql-001
  database: postgres
  schema: platform_nocodb

credentials:
  vault_path: /platform/applications/nocodb/db
  user: platform_nocodb_rw

tables:
  - nc_*  # NocoDB system tables

permissions:
  read: true
  write: true
  create: true
  drop: true  # NocoDB управляет своими таблицами

status: active
owner: /PLATFORM/applications/nocodb
2.1.3. Connection: bu-piro-s3

Файл: L2-DATA/connections/bu-piro-s3.yaml

name: bu-piro-s3
type: s3_connection
description: "S3 storage для pirotehnika"

target:
  storage: /L3-INFRA/storage/object/s3/hub
  bucket: hub
  path: /business-units/pirotehnika/

credentials:
  vault_path: /business-units/pirotehnika/s3
  access_key: from_vault
  secret_key: from_vault

paths:
  prices: /business-units/pirotehnika/prices/
  images: /business-units/pirotehnika/images/
  exports: /business-units/pirotehnika/exports/
  archive: /business-units/pirotehnika/archive/

status: active

2.2. Schemas (Схемы данных)

Файл: L2-DATA/schemas/pim/tables.yaml

schema: bu_piro
prefix: pim_

tables:
  pim_products:
    description: "Товары с ценами и брендами"
    primary_key: article
    fields:
      article:
        type: varchar(50)
        nullable: false
        description: "Артикул товара"

      name:
        type: varchar(500)
        description: "Название товара"

      brand_id:
        type: integer
        references: Brands.id
        description: "ID бренда"

      supplier_id:
        type: integer
        references: Suppliers.id
        description: "ID поставщика"

      category_id:
        type: integer
        references: Categories.id
        description: "ID категории"

      base_price:
        type: decimal(10,2)
        description: "Базовая цена (из прайса)"

      cost_price:
        type: decimal(10,2)
        description: "Себестоимость  учетом скидки)"

      sku:
        type: varchar(100)
        description: "SKU для маркетплейсов"

      status:
        type: varchar(20)
        default: active
        description: "active, archived, deleted"

      created_at:
        type: timestamp
        default: now()

      updated_at:
        type: timestamp
        default: now()

    indexes:
      - [brand_id]
      - [supplier_id]
      - [category_id]
      - [sku]
      - [status]

  pim_cost_rules:
    description: "Правила расчета себестоимости (скидки по брендам)"
    primary_key: id
    fields:
      id:
        type: serial

      brand_id:
        type: integer
        references: Brands.id

      discount_percent:
        type: decimal(5,2)
        description: "Процент скидки (50.00 = 50%)"

      active:
        type: boolean
        default: true

  # ... другие таблицы

Файл: L2-DATA/schemas/pim/relations.yaml

relations:
  pim_products:
    belongs_to:
      - table: Brands
        foreign_key: brand_id
        name: brand

      - table: Suppliers
        foreign_key: supplier_id
        name: supplier

      - table: Categories
        foreign_key: category_id
        name: category

    has_many:
      - table: pim_sku_mappings
        foreign_key: article
        name: sku_mappings

2.3. Processors (Обработчики)

Файл: L2-DATA/processors/price-parser/index.yaml

name: price-parser
type: etl_processor
description: "Парсинг прайсов Excel поставщиков"

input:
  type: file
  formats: [xlsx, csv]
  source: /L2-DATA/connections/bu-piro-s3
  path: /business-units/pirotehnika/prices/

output:
  type: database
  connection: /L2-DATA/connections/bu-piro-db
  tables:
    - PriceList
    - PriceListItem
    - pim_products

logic:
  - step: read_excel
    description: "Читаем Excel файл"

  - step: normalize
    description: "Нормализуем данные"
    rules:
      - trim_whitespace
      - convert_price_format
      - validate_article

  - step: apply_discounts
    description: "Применяем скидки из pim_cost_rules"
    formula: "cost_price = base_price * (1 - discount_percent/100)"

  - step: upsert
    description: "Обновляем или создаем записи"
    on_conflict: article
    action: update

schedule:
  type: manual
  # or: cron: "0 2 * * *"  # Ежедневно в 2:00

status: active

Задачи ЭТАПА 2:
- [ ] Создать структуру L2-DATA
- [ ] Создать connections (bu-piro-db, platform-nocodb-db, bu-piro-s3)
- [ ] Создать schemas/pim/ (tables.yaml, relations.yaml)
- [ ] Создать processors/ (price-parser, 1c-sync)
- [ ] Задокументировать все коннекторы

Результат: Данные описаны в L2-DATA, готовы к использованию


ЭТАП 3: L0-ORG (Бизнес-единица и сервис PIM)

Цель: Создать бизнес-единицу pirotehnika и сервис PIM

3.1. Business Unit

Создаем структуру:

mkdir -p $WORKSPACE/L0-ORG/business-units/pirotehnika
mkdir -p $WORKSPACE/L0-ORG/business-units/pirotehnika/services/pim
mkdir -p $WORKSPACE/L0-ORG/business-units/pirotehnika/connections
mkdir -p $WORKSPACE/L0-ORG/business-units/pirotehnika/channels

Файл: L0-ORG/business-units/pirotehnika/index.yaml

name: "Пиротехника"
code: piro
type: business_unit

description: "Продажа фейерверков и пиротехники"

resources:
  database:
    connection: /L2-DATA/connections/bu-piro-db
    schema: bu_piro

  storage:
    connection: /L2-DATA/connections/bu-piro-s3
    path: /business-units/pirotehnika/

  credentials:
    vault_path: /business-units/pirotehnika/

services:
  - pim
  - analytics
  - integration-hub

channels:
  - retail
  - wholesale
  - marketplaces

status: active
created: 2024-01-01

Файл: L0-ORG/business-units/pirotehnika/SPECIFICATION.md

# СПЕЦИФИКАЦИЯ: Бизнес-единица Пиротехника

**Тип:** Business Unit
**Код:** piro
**Статус:** Active

## ЧТО (What)

Продажа фейерверков и пиротехники через разные каналы:
- Розница (B2C) - сайт pirotehnika.spb.ru
- Опт (B2B) - прямые продажи
- Маркетплейсы (OZON, WB, Яндекс.Маркет)

## КТО (Who)

**Роли:**
- Владелец: ИП Кондуров
- Менеджер: Кондуров Н.
- Операторы: 2 человека

## КАК (How)

**Процессы:**
1. Закупка у поставщиков
2. Хранение на складе
3. Размещение на площадках
4. Прием заказов
5. Отправка
6. Учет и аналитика

## ЧЕМ (With what)

**Ресурсы:**
- База данных: PostgreSQL схема bu_piro
- Хранилище: S3 /business-units/pirotehnika/
- Сервисы: PIM, Analytics, Integration Hub

## КОГДА (When)

**Сезонность:**
- Высокий сезон: октябрь-январь
- Низкий сезон: февраль-сентябрь

## ГДЕ (Where)

**Локации:**
- Склад: Санкт-Петербург
- Офис: удаленно
- Инфраструктура: @dev-pro, @beget

## ПОЧЕМУ (Why)

**Цели:**
- Автоматизация учета товаров
- Унификация работы с маркетплейсами
- Снижение операционных затрат
- Повышение маржинальности

## СКОЛЬКО (How much)

**Метрики:**
- Товаров в каталоге: ~4,600
- Заказов в месяц: ~100-150
- Средний чек: 3,000 руб
- Оборот в месяц: ~300,000 руб

## ЗАЧЕМ (What for)

**Результаты:**
- Единая система управления товарами
- Автоматическая синхронизация с площадками
- Прозрачная аналитика продаж
- Оптимизация закупок

3.2. Service: PIM

Файл: L0-ORG/business-units/pirotehnika/services/pim/index.yaml

name: pim
full_name: "Product Information Management"
type: business_unit_service

description: "Управление информацией о товарах"

owner:
  business_unit: pirotehnika

resources:
  database:
    connection: /L2-DATA/connections/bu-piro-db
    schema: bu_piro
    prefix: pim_

    tables:
      - pim_products
      - pim_brands
      - pim_categories
      - pim_attributes
      - pim_prices
      - pim_suppliers
      - pim_cost_rules
      - pim_sku_mappings
      - pim_bundle_items
      - pim_catalog

  storage:
    connection: /L2-DATA/connections/bu-piro-s3
    path: /business-units/pirotehnika/services/pim/

uses_platform_apps:
  - name: nocodb
    app: /PLATFORM/applications/nocodb
    workspace: piro-pim

uses_processors:
  - /L2-DATA/processors/price-parser
  - /L2-DATA/processors/1c-sync

provides:
  api:
    type: internal
    consumers:
      - /L0-ORG/business-units/pirotehnika/services/analytics
      - /L0-ORG/business-units/pirotehnika/channels/retail

  cli:
    commands:
      - pim import-price
      - pim export-products
      - pim sync-1c
      - pim update-cost-rules

status: active

Структура сервиса PIM:

services/pim/
├── index.yaml                      Метаданные сервиса
├── SPECIFICATION.md                Спецификация (7 вопросов)

├── database/                       Схемы БД
   ├── schema.sql                 DDL таблиц
   ├── functions.sql              PostgreSQL функции
   └── views.sql                  Views

├── core/                           Бизнес-логика
   ├── products.py                CRUD товаров
   ├── prices.py                  Управление ценами
   ├── categories.py              Категории
   └── suppliers.py               Поставщики

├── integrations/                   Интеграции
   ├── 1c/
      ├── sync.py
      └── config.yaml
   ├── nocodb/
      └── workspace.yaml
   └── ozon/
       └── sync.py

├── cli/                            CLI функции
   ├── __init__.py
   ├── import_price.py            pim import-price
   ├── export_products.py         pim export
   └── sync_1c.py                 pim sync-1c

└── config/
    ├── suppliers.yaml             Конфигурация поставщиков
    └── cost_rules.yaml            Правила ценообразования

Задачи ЭТАПА 3:
- [ ] Создать структуру L0-ORG/business-units/pirotehnika
- [ ] Создать index.yaml бизнес-единицы
- [ ] Создать SPECIFICATION.md бизнес-единицы
- [ ] Создать структуру services/pim/
- [ ] Создать index.yaml сервиса PIM
- [ ] Создать database/ (schema.sql)
- [ ] Создать core/ (products.py, prices.py)
- [ ] Создать cli/ (import_price.py)

Результат: Сервис PIM создан в новой структуре


ЭТАП 4: PLATFORM (Платформенные приложения)

Цель: Описать NocoDB как платформенное приложение

Создаем структуру:

mkdir -p $WORKSPACE/PLATFORM/applications/nocodb

Файл: PLATFORM/applications/nocodb/index.yaml

name: nocodb
type: platform_application
version: "0.200.0"

description: "Low-code database platform"

resources:
  database:
    connection: /L2-DATA/connections/platform-nocodb-db
    schema: platform_nocodb

  storage:
    connection: /L2-DATA/connections/bu-piro-s3
    path: /platform/applications/nocodb/

  compute:
    container: platform-nocodb-prod
    runtime: /L3-INFRA/compute/containers/docker
    ports:
      - 8085

workspaces:
  piro-pim:
    owner: /L0-ORG/business-units/pirotehnika/services/pim
    base_id: pt7k98pv0fwi1el

used_by:
  - /L0-ORG/business-units/pirotehnika/services/pim

status: active

Задачи:
- [ ] Создать PLATFORM/applications/nocodb/
- [ ] Создать index.yaml
- [ ] Задокументировать workspaces

Результат: NocoDB описан как платформенное приложение


ЭТАП 5: Тестирование параллельно

Цель: Убедиться что новая структура работает

Задачи:
- [ ] Запустить CLI команды из новой структуры
- [ ] Проверить подключение к БД через новые connections
- [ ] Проверить чтение/запись данных
- [ ] Сравнить результаты со старой структурой

Критерии успеха:
- ✅ CLI команды работают
- ✅ Данные читаются/пишутся корректно
- ✅ Нет конфликтов со старой структурой
- ✅ Производительность не ухудшилась

Результат: Новая структура работает корректно


ЭТАП 6: Переключение и cleanup

Цель: Переключиться на новую структуру

Задачи:
- [ ] Обновить пути в коде
- [ ] Обновить environment variables
- [ ] Обновить документацию
- [ ] Переместить старую структуру в archive/
- [ ] Создать CHANGELOG

Результат: Платформа работает на новой структуре


ЖУРНАЛ ИЗМЕНЕНИЙ

Изменение 1: Создание L3-INFRA

Дата: TBD
Статус: Pending

Что создаем:
- [ ] $WORKSPACE/L3-INFRA/
- [ ] database-engines/postgresql-001/index.yaml
- [ ] storage/object/s3/hub/index.yaml
- [ ] compute/containers/docker/index.yaml

Зачем: Описать физические ресурсы платформы

Риски: Нет (только документация)


Изменение 2: Создание L2-DATA

Дата: TBD
Статус: Pending

Что создаем:
- [ ] $WORKSPACE/L2-DATA/
- [ ] connections/bu-piro-db.yaml
- [ ] connections/bu-piro-s3.yaml
- [ ] schemas/pim/tables.yaml
- [ ] processors/price-parser/

Зачем: Абстракция над данными

Риски: Нет (параллельно со старой структурой)


Изменение 3: Создание L0-ORG

Дата: TBD
Статус: Pending

Что создаем:
- [ ] $WORKSPACE/L0-ORG/business-units/pirotehnika/
- [ ] services/pim/

Зачем: Новая структура бизнес-единицы

Риски: Нет (параллельно со старой структурой)


ЧЕКЛИСТ БЕЗОПАСНОСТИ

Перед каждым изменением проверяем:


ROLLBACK ПЛАН

Если что-то пошло не так:

  1. Остановить использование новой структуры
  2. Вернуться к старой структуре projects/pirotehnika/
  3. Проанализировать проблему
  4. Исправить в новой структуре
  5. Протестировать заново

Старая структура НЕ удаляется до полного успеха миграции!


СТАТУС ВЫПОЛНЕНИЯ

Этап Статус Прогресс Дата
0. Подготовка In Progress 80% 2025-12-22
1. L3-INFRA Pending 0% -
2. L2-DATA Pending 0% -
3. L0-ORG Pending 0% -
4. PLATFORM Pending 0% -
5. Тестирование Pending 0% -
6. Переключение Pending 0% -

Следующий шаг: Обсудить и утвердить план, начать с ЭТАПА 1 (L3-INFRA)