Gogs 3 hete
szülő
commit
a0cdb65c22
1 módosított fájl, 742 hozzáadás és 14 törlés
  1. 742 14
      README.md

+ 742 - 14
README.md

@@ -12,6 +12,737 @@
 **GIT репозитарий:** https://gogs.osvoj.ru/oleg/s5l.ru-crm
 **Текущая версия промта** https://gogs.osvoj.ru/oleg/s5l.ru-crm/raw/master/README.md
 
+## 🛠 ТЕХНИЧЕСКИЙ СТЕК
+- **Шаблонизатор:** Pug с Vue компонентами
+- **Стилизация:** Stylus + CSS переменные + BEM методология
+- **Логика:** CoffeeScript + Vue.js 3 (runtime)
+- **Маршрутизация:** Vue Router
+- **База данных:** PouchDB (клиент) + CouchDB (сервер)
+- **Анимации:** CSS transitions/transforms + Vue transitions
+
+
+## 📁 СТРУКТУРА ПРОЕКТА
+
+### 🏗️ АРХИТЕКТУРА ФАЙЛОВ
+```
+app/
+├── index.pug                 # Главный layout
+├── index.coffee              # Инициализация Vue и роутера
+├── index.styl                # Глобальные стили и CSS переменные
+├── config.coffee             # Конфигурация приложения
+├── types/                    # Интерфейсы данных
+│   ├── data.coffee
+│   ├── events.coffee
+│   └── api.coffee
+├── services/                 # Бизнес-логика
+│   ├── DomainService.coffee
+│   ├── ProductService.coffee
+│   ├── ImportService.coffee
+│   └── CategoryService.coffee
+├── utils/                    # Утилиты
+│   └── pouch.coffee          # PouchDB сервис
+├── design/                   # Дизайн-документы CouchDB
+│   ├── admin.coffee
+│   └── site.coffee
+├── components/               # Переиспользуемые компоненты
+│   ├── UI/
+│   │   ├── Button/
+│   │   ├── Modal/
+│   │   └── Notification/
+│   ├── Domain/
+│   │   ├── ProductCard/
+│   │   ├── CategoryMenu/
+│   │   └── CartWidget/
+│   └── Admin/
+│       ├── DataTable/
+│       └── FileUpload/
+└── pages/                    # Страницы приложения
+    ├── Home/                 # Главная страница
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    ├── Catalog/              # Каталог товаров
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    ├── Product/              # Страница товара
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    ├── Cart/                 # Корзина
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    ├── Blog/                 # Блог
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    ├── Article/              # Статья блога
+    │   ├── index.pug
+    │   ├── index.coffee
+    │   └── index.styl
+    └── Admin/                # Админ-панель
+        ├── index.pug
+        ├── index.coffee
+        ├── index.styl
+        ├── Dashboard/        # Дашборд
+        ├── Products/         # Управление товарами
+        │   ├── index.pug
+        │   ├── index.coffee
+        │   ├── index.styl
+        │   └── Import/       # Импорт товаров
+        │       ├── index.pug
+        │       ├── index.coffee
+        │       └── index.styl
+        ├── Categories/       # Управление категориями
+        ├── Blog/             # Управление блогом
+        ├── Slider/           # Управление слайдами
+        ├── Clients/          # Управление клиентами
+        ├── Orders/           # Управление заказами
+        ├── Routes/           # Управление маршрутами
+        └── Settings/         # Настройки системы
+```
+## 💻 ПРИМЕРЫ КОДА
+
+### 🎨 СИСТЕМА СТИЛЕЙ
+
+**app/index.styl**
+здесь храняться базовые стили темы. которые используются во всех остальных стилевых файлах.
+отдельно его подключать в них не нужно, он глобально доступен.
+
+```stylus
+// CSS переменные вместо rgba функций
+:root
+  // Основные цвета
+  --color-primary: #2c5aa0
+  --color-secondary: #6c757d
+  --color-success: #28a745
+  --color-danger: #dc3545
+  --color-warning: #ffc107
+  --color-light: #f8f9fa
+  --color-dark: #343a40
+  
+  // Прозрачные варианты
+  --color-primary-10: #2c5aa01a
+  --color-primary-20: #2c5aa033
+  --color-primary-50: #2c5aa080
+  --color-dark-10: #343a401a
+  --color-dark-50: #343a4080
+  --color-light-10: #f8f9fa1a
+  --color-light-50: #f8f9fa80
+  
+  // Тени
+  --shadow-sm: 0 1px 2px var(--color-dark-10)
+  --shadow-md: 0 4px 6px var(--color-dark-10)
+  --shadow-lg: 0 10px 15px var(--color-dark-10)
+  
+  // Прочие переменные
+  --border-radius: 8px
+  --transition: all 0.3s ease
+
+// Базовые стили
+.app
+  min-height: 100vh
+  transition: var(--transition)
+  background: var(--color-light)
+  color: var(--color-dark)
+
+  &.theme-dark
+    background: var(--color-dark)
+    color: var(--color-light)
+
+.header
+  display: flex
+  align-items: center
+  padding: 1rem 2rem
+  background: var(--color-light)
+  box-shadow: var(--shadow-sm)
+  border-bottom: 1px solid var(--color-primary-10)
+  
+  .theme-dark &
+    background: var(--color-dark)
+    box-shadow: var(--shadow-md)
+
+// Адаптивность
+@media (max-width: 768px)
+  .header
+    padding: 1rem
+    flex-direction: column
+    gap: 1rem
+```
+
+**app/index.pug**
+```pug
+div(class="app" :class="{'theme-dark': theme === 'dark'}")
+  header(class="header")
+    nav(class="header-nav")
+      div(class="header-nav-block")
+        div(class="header-nav--name") {{ currentDomainSettings?.companyName || companyName }}
+        div(class="header-nav--menu")
+          multilevelmenu(:domains="availableDomains" :current-domain="currentDomain")
+          themetoggle(:theme="theme" @theme-changed="toggleTheme")
+          languagetoggle(:languages="languages" :current-language="currentLanguage" @language-changed="setLanguage")
+          cartwidget(:items="cartItems" @update-cart="updateCart")
+  
+  main(class="main-content")
+    router-view(v-slot="{ Component, route }")
+      transition(name="page-slide" mode="out-in")
+        component(
+          :is="Component"
+          :key="route.fullPath"
+          :domain-settings="currentDomainSettings"
+          :language="currentLanguage"
+        )
+  
+  notification-container(:notifications="notifications")
+```
+
+**app/index.coffee**
+```coffee
+# Загрузка конфигурации
+config = require 'app/config'
+DataTypes = require 'app/types/data'
+EventTypes = require 'app/types/events'
+
+# Инициализация глобальных переменных
+globalThis.renderFns = require 'pug.json'
+globalThis.stylFns = require 'styl.json'
+
+# Глобальная инициализация debug
+globalThis.debug = require 'debug'
+globalThis.log = debug.log
+
+# Сервисы
+PouchDBService = require 'app/utils/pouch'
+DomainService = require 'app/services/DomainService'
+
+# Мета-теги
+document.head.insertAdjacentHTML 'beforeend', '<meta charset="UTF-8">'
+document.head.insertAdjacentHTML 'beforeend', '<meta name="viewport" content="width=device-width, initial-scale=1.0">'
+document.head.insertAdjacentHTML 'beforeend', '<style type="text/css">' + stylFns['app/index.styl'] + '</style>'
+
+# Главное приложение Vue
+app = Vue.createApp({
+  data: ->
+    {
+      theme: localStorage.getItem('theme') or 'light'
+      companyName: 'Браер-Колор'
+      loading: false
+      currentDomain: window.location.hostname
+      currentDomainSettings: null
+      availableDomains: []
+      languages: config.languages
+      currentLanguage: localStorage.getItem('language') or config.defaultLanguage
+      user: null
+      cartItems: []
+      notifications: []
+    }
+  
+  computed:
+    isAdmin: -> @user?.role == 'admin'
+    domainConfig: -> 
+      DomainService.getDomainConfig(@currentDomain)
+  
+  methods:
+    toggleTheme: ->
+      @theme = if @theme == 'light' then 'dark' else 'light'
+      localStorage.setItem 'theme', @theme
+      document.documentElement.classList.toggle 'dark'
+      @$emit EventTypes.THEME_CHANGED, @theme
+    
+    setLanguage: (lang) ->
+      if @languages.includes lang
+        @currentLanguage = lang
+        localStorage.setItem 'language', @lang
+        @$emit EventTypes.LANGUAGE_CHANGED, lang
+    
+    loadDomainData: ->
+      DomainService.loadDomainSettings(@currentDomain)
+        .then (settings) =>
+          @currentDomainSettings = settings
+          document.title = settings?.companyName or @companyName
+          log 'Настройки домена загружены', settings
+        .catch (error) =>
+          log 'Настройки домена не найдены, используются значения по умолчанию'
+          @currentDomainSettings = new DataTypes.DomainSettings()
+    
+    updateCart: (items) ->
+      @cartItems = items
+      localStorage.setItem 'cart', JSON.stringify(items)
+    
+    showNotification: (message, type = 'success') ->
+      notification = { id: Date.now(), message, type, visible: true }
+      @notifications.push notification
+      setTimeout (=>
+        notification.visible = false
+        setTimeout (=>
+          @notifications = @notifications.filter (n) -> n.id != notification.id
+        ), 300
+      ), 5000
+  
+  async mounted: ->
+    # Инициализация темы
+    if @theme == 'dark'
+      document.documentElement.classList.add 'dark'
+    
+    # Инициализация сервисов
+    try
+      await PouchDBService.init()
+      log 'PouchDB инициализирован'
+      
+      await DomainService.init()
+      @availableDomains = DomainService.getAvailableDomains()
+      
+      await @loadDomainData()
+    catch error
+      log 'Ошибка инициализации:', error
+    
+    # Загрузка пользователя и корзины
+    @loadUserData()
+    @loadCartData()
+  
+  loadUserData: ->
+    userData = localStorage.getItem 'user'
+    if userData
+      try
+        @user = JSON.parse userData
+      catch
+        @user = null
+  
+  loadCartData: ->
+    cartData = localStorage.getItem 'cart'
+    if cartData
+      try
+        @cartItems = JSON.parse cartData
+      catch
+        @cartItems = []
+
+  render: (new Function '_ctx', '_cache', renderFns['app/index.pug'])()
+})
+
+# Глобальная обработка ошибок
+app.config.errorHandler = (err, vm, info) ->
+  log 'Vue ошибка:', err, info
+
+app.mount('body')
+```
+
+## 🚨 КРИТИЧЕСКИЕ ПРАВИЛА РАЗРАБОТКИ
+
+### ❌ **ЗАПРЕЩЕНО:**
+
+1. **Использование rgba() функций в стилях**
+   ```stylus
+   // ❌ НЕПРАВИЛЬНО
+   background: rgba(44, 90, 160, 0.1)
+   
+   // ✅ ПРАВИЛЬНО  
+   background: var(--color-primary-10)
+   ```
+
+2. **Прямое использование console.log**
+   ```coffee
+   # ❌ НЕПРАВИЛЬНО
+   console.log 'Ошибка'
+   
+   # ✅ ПРАВИЛЬНО
+   log 'Ошибка'
+   ```
+
+3. **Многострочные атрибуты в Pug**
+   ```pug
+   // ❌ НЕПРАВИЛЬНО
+   div(
+     class="class"
+     data-attr="value"
+   )
+   
+   // ✅ ПРАВИЛЬНО
+   div(class="class" data-attr="value")
+   ```
+
+4. **@import в стилях компонентов**
+   ```stylus
+   // ❌ НЕПРАВИЛЬНО
+   @import '../../index.styl'
+   
+   // ✅ ПРАВИЛЬНО
+   .my-component
+     background: var(--color-primary-10)
+   ```
+
+5. **JavaScript операторы в CoffeeScript**
+   ```coffee
+   # ❌ НЕПРАВИЛЬНО
+   if user && user.role
+   condition ? 'yes' : 'no'
+   
+   # ✅ ПРАВИЛЬНО
+   if user and user.role
+   if condition then 'yes' else 'no'
+   ```
+
+6. **HTML/HEAD/BODY теги в компонентах**
+   ```pug
+   // ❌ НЕПРАВИЛЬНО
+   html
+     body
+       div.app
+   
+   // ✅ ПРАВИЛЬНО
+   div(class="app")
+   ```
+
+7. **Объявление debug в компонентах**
+   ```coffee
+   # ❌ НЕПРАВИЛЬНО
+   debug = require 'debug'
+   log = debug.log
+   
+   # ✅ ПРАВИЛЬНО - debug глобальный
+   log 'Сообщение'
+   ```
+
+### ✅ **ОБЯЗАТЕЛЬНО:**
+
+1. **Полные листинги файлов** - всегда приводи все три файла компонента
+2. **Адаптивная верстка** - mobile-first для всех компонентов
+3. **BEM методология** - `block__element--modifier`
+4. **CSS переменные** - только через var(--variable-name)
+5. **Обработка ошибок** - try/catch для всех асинхронных операций
+6. **Валидация данных** - проверка обязательных полей
+7. **Прогресс операций** - индикаторы для длительных процессов
+8. **Мультиязычность** - все тексты из настроек домена
+9. **Использование глобального debug** - только `log 'сообщение'`
+
+## 🗂️ СТРУКТУРА ДАННЫХ
+
+### 📊 ТИПЫ ДОКУМЕНТОВ
+
+**app/types/data.coffee**
+```coffee
+class DomainEntity
+  constructor: ->
+    @_id = ''
+    @type = ''
+    @domains = []
+    @createdAt = new Date().toISOString()
+    @updatedAt = new Date().toISOString()
+    @active = true
+
+class Product extends DomainEntity
+  constructor: ->
+    super()
+    @type = 'product'
+    @name = ''
+    @sku = ''
+    @price = 0
+    @oldPrice = null
+    @category = ''
+    @brand = ''
+    @description = ''
+    @attributes = {}
+    @images = []
+    @richContent = null
+    @inStock = true
+    @weight = 0
+    @volume = 0
+
+class Category extends DomainEntity
+  constructor: ->
+    super()
+    @type = 'category'
+    @name = ''
+    @slug = ''
+    @parent = null
+    @order = 0
+    @image = ''
+    @description = ''
+
+class HeroSlide extends DomainEntity
+  constructor: ->
+    super()
+    @type = 'hero_slide'
+    @title = ''
+    @subtitle = ''
+    @image = ''
+    @buttonText = 'В каталог'
+    @buttonLink = '/catalog'
+    @order = 0
+
+class DomainSettings extends DomainEntity
+  constructor: ->
+    super()
+    @type = 'domain_settings'
+    @domain = ''
+    @companyName = ''
+    @languages = ['ru']
+    @theme = 'light'
+    @contacts = {}
+    @seo = {}
+    @social = {}
+
+module.exports = {Product, Category, HeroSlide, DomainSettings, DomainEntity}
+```
+
+## 🔧 СЕРВИСЫ И УТИЛИТЫ
+
+### 🗃️ POUCHDB СЕРВИС
+
+**app/utils/pouch.coffee**
+```coffee
+class PouchDBService
+  constructor: (options = {}) ->
+    {@localDbName, @remoteDbUrl, @userFilter, @appVersion} = options
+    @localDb = null
+    @remoteDb = null
+    @initialized = false
+
+  init: ->
+    return Promise.resolve() if @initialized
+    
+    try
+      @localDb = new PouchDB(@localDbName or 'braer_color_cache')
+      await @ensureRemoteDatabase()
+      await @loadDesignDocs()
+      await @ensureDesignDocs()
+      
+      # Настройка селективной синхронизации
+      PouchDB.sync(@remoteDb, @localDb, {
+        live: true,
+        retry: true,
+        filter: (doc) => @shouldSyncDocument(doc)
+      })
+      
+      @initialized = true
+      return Promise.resolve()
+    catch error
+      log 'Ошибка инициализации PouchDB:', error
+      return Promise.reject(error)
+
+  getDocument: (docId) ->
+    @ensureInit()
+    
+    try
+      return await @localDb.get(docId)
+    catch localError
+      if localError.status == 404
+        try
+          doc = await @remoteDb.get(docId)
+          await @localDb.put(doc)
+          return doc
+        catch remoteError
+          throw remoteError
+      else
+        throw localError
+
+  saveToRemote: (doc) ->
+    @ensureInit()
+    
+    try
+      existingDoc = await @remoteDb.get(doc._id)
+      doc._rev = existingDoc._rev
+      return await @remoteDb.put(doc)
+    catch error
+      if error.status == 404
+        return await @remoteDb.put(doc)
+      else
+        throw error
+
+  shouldSyncDocument: (doc) ->
+    if doc.type in ['product', 'category', 'settings', 'hero_slide', 'blog_article', 'route']
+      return true
+    if doc.type in ['order', 'user_data', 'cart']
+      return doc.userId == @userFilter?.userId
+    return false
+
+module.exports = new PouchDBService({
+  localDbName: 'braer_color_cache'
+  remoteDbUrl: 'http://localhost:5984/braer_color_shop'
+  userFilter: { userId: 'current_user_id' }
+  appVersion: '1.0.0'
+})
+```
+
+### 📦 СЕРВИС ИМПОРТА ТОВАРОВ
+
+
+Важно: при полной реализации используй пример csv файла, При этом учти что количество полей в документе может меняться. выдели из них основные, остальные загружай по факту как свойства товара.
+Индивидуальное сохранение товаров
+Каждый товар сохраняется как отдельный документ в PouchDB
+Используется стабильный _id на основе артикула: product:#{sku}
+Автоматическое обновление существующих товаров при повторном импорте
+Улучшенная обработка изображений
+Загрузка основного и дополнительных изображений как attachments
+Формат ссылок: /d/braer_color_shop/{doc_id}/{filename}
+Все фото из csv должны быть загружены как attachment в документ товара
+Объеденяй товары в группы по полю из csv файла, в списке товаров выводи главное изображение.
+в редакторе нужно иметь возможность управлять всеми данными товара. некоторые атрибуты иметь возможность отметить как скрытые, по из названи. (нужно упаравление атрибутами в категории)
+Прогресс импорта
+Визуальный индикатор прогресса обработки
+Отслеживание количества обработанных товаров
+Детальная статистика по завершении импорта
+Обработка Rich-контента
+Преобразование JSON в Markdown для описаний товаров
+Сохранение оригинальной структуры для возможного редактирования
+Создать редактор товаров
+
+Создание объектов катигорий при появлении новых значений в поле "Тип*", сделать редактор категорий, с возможностью загрузки фото
+При обработке csv загружай изображения в базу данных как attachment, также сохраняй ричконтент преобразовывая в markdown, и выводи его в качестве описания товара при его наличии.
+формат ссылок на attachment файлы "/d/[ИМЯ БД]/[id doc]/[имя файла]"
+Важно: каждый товар должен быть привязан к домену/доменам (может одновременно быть доступен на разных доменах), тоже касается статей блога.
+
+
+
+**app/services/ImportService.coffee**
+```coffee
+{ Product, Category } = require 'app/types/data'
+
+class ImportService
+  constructor: ->
+    @batchSize = 50
+    @maxImages = 5
+  
+  transformProductData: (csvRow, index, domain) ->
+    product = new Product()
+    
+    product._id = "product:#{csvRow['Артикул*']}"
+    product.name = csvRow['Название товара']
+    product.sku = csvRow['Артикул*']
+    product.price = parseFloat(csvRow['Цена, руб.*'].replace(',', '.')) or 0
+    product.oldPrice = if csvRow['Цена до скидки, руб.'] then parseFloat(csvRow['Цена до скидки, руб.'].replace(',', '.')) else null
+    product.brand = csvRow['Бренд*']
+    product.category = csvRow['Тип*']
+    product.domains = [domain]
+    
+    product.images = @processImages(csvRow, product._id)
+    
+    if csvRow['Rich-контент JSON']
+      try
+        product.richContent = @jsonToMarkdown(JSON.parse(csvRow['Rich-контент JSON']))
+      catch error
+        log 'Ошибка парсинга rich-контента:', error
+    
+    product.attributes = @extractAttributes(csvRow)
+    
+    return product
+  
+  processImages: (csvRow, docId) ->
+    images = []
+    
+    if csvRow['Ссылка на главное фото*']
+      images.push {
+        url: csvRow['Ссылка на главное фото*']
+        type: 'main'
+        order: 0
+      }
+    
+    if csvRow['Ссылки на дополнительные фото']
+      additionalImages = csvRow['Ссылки на дополнительные фото'].split('\n').slice(0, @maxImages)
+      additionalImages.forEach (imgUrl, index) ->
+        if imgUrl.trim()
+          images.push {
+            url: imgUrl.trim()
+            type: 'additional'
+            order: index + 1
+          }
+    
+    return images
+  
+  jsonToMarkdown: (richContent) ->
+    markdown = ''
+    
+    if richContent?.content
+      richContent.content.forEach (block) ->
+        if block.widgetName == 'raTextBlock' and block.text?.items
+          block.text.items.forEach (item) ->
+            if item.type == 'text' and item.content
+              markdown += item.content + '\n\n'
+            else if item.type == 'br'
+              markdown += '\n'
+    
+    return markdown.trim()
+  
+  extractAttributes: (csvRow) ->
+    attributes = {}
+    
+    technicalFields = [
+      'Вес в упаковке, г*', 'Ширина упаковки, мм*', 'Высота упаковки, мм*', 
+      'Длина упаковки, мм*', 'Объем, л', 'Время высыхания, часов', 'Расход, л/м2',
+      'Макс. температура эксплуатации, С°', 'Количество компонентов'
+    ]
+    
+    technicalFields.forEach (field) ->
+      if csvRow[field]
+        attributes[field] = csvRow[field]
+    
+    categoryFields = [
+      'Вид краски', 'Назначение грунтовки', 'Материал основания', 'Основа краски',
+      'Способ нанесения', 'Назначение', 'Тип помещения', 'Возможность колеровки'
+    ]
+    
+    categoryFields.forEach (field) ->
+      if csvRow[field]
+        attributes[field] = csvRow[field]
+    
+    return attributes
+  
+  importFromCSV: (file, domain, onProgress) ->
+    return new Promise (resolve, reject) =>
+      reader = new FileReader()
+      
+      reader.onload = (e) =>
+        try
+          results = Papa.parse(e.target.result, {
+            header: true
+            delimiter: ';'
+            skipEmptyLines: true
+            encoding: 'UTF-8'
+          })
+          
+          validProducts = results.data.filter (row) => 
+            row and row['Артикул*'] and row['Название товара'] and row['Цена, руб.*']
+          
+          this.processProductsInBatches(validProducts, domain, onProgress)
+            .then(resolve)
+            .catch(reject)
+          
+        catch error
+          reject(new Error("Ошибка парсинга CSV: #{error.message}"))
+      
+      reader.onerror = -> reject(new Error('Ошибка чтения файла'))
+      reader.readAsText(file, 'UTF-8')
+  
+  processProductsInBatches: (products, domain, onProgress) ->
+    batches = []
+    for i in [0...products.length] by @batchSize
+      batches.push(products.slice(i, i + @batchSize))
+    
+    processed = 0
+    total = products.length
+    
+    processBatch = (batch) =>
+      transformedProducts = batch.map (product, index) =>
+        @transformProductData(product, processed + index, domain)
+      
+      return PouchDBService.bulkDocs(transformedProducts)
+        .then (results) =>
+          processed += batch.length
+          if onProgress
+            onProgress({
+              processed: processed
+              total: total
+              percentage: Math.round((processed / total) * 100)
+            })
+          return results
+    
+    return batches.reduce (promise, batch) =>
+      promise.then -> processBatch(batch)
+    , Promise.resolve()
+
+module.exports = new ImportService()
+```
+
 ## 📊 ОБРАЗЕЦ CSV ФАЙЛА ДЛЯ ИМПОРТА
 
 ### 📝 СПЕЦИФИКАЦИЯ CSV
@@ -123,13 +854,7 @@ importFromCSV: (file, domain, onProgress) ->
     
     reader.readAsText(file, 'UTF-8')
 ```
-## 🛠 ТЕХНИЧЕСКИЙ СТЕК
-- **Шаблонизатор:** Pug с Vue компонентами
-- **Стилизация:** Stylus + CSS переменные + BEM методология
-- **Логика:** CoffeeScript + Vue.js 3 (runtime + compiler)
-- **Маршрутизация:** Vue Router
-- **База данных:** PouchDB (клиент) + CouchDB (сервер)
-- **Анимации:** CSS transitions/transforms + Vue transitions
+
 
 ## 🚨 КРИТИЧЕСКИЕ ПРАВИЛА РАЗРАБОТКИ
 
@@ -212,28 +937,31 @@ importFromCSV: (file, domain, onProgress) ->
    - Темная/светлая темы
 
 
-1. **Система импорта товаров** ⚠️ ПРИОРИТЕТ
+5. **Система импорта товаров**
    - Компонент загрузки CSV файлов
    - Парсинг и валидация данных
    - Пакетная обработка товаров
    - Создание категорий на лету
+   
+    5.1. Завершить компонент импорта товаров
+    5.2. Реализовать редактор категорий
+    5.3. Создать компонент управления слайдами
+    5.4. Разработать главную страницу магазина
+
 
-2. **Админ-панель**
+6. **Админ-панель**
    - Управление товарами
    - Система прогресса операций
    - Обработка ошибок импорта
 
-1. Завершить компонент импорта товаров
-2. Реализовать редактор категорий
-3. Создать компонент управления слайдами
-4. Разработать главную страницу магазина
+
 
 
 ### 🔄 В РАБОТЕ СЕЙЧАС
 
 отвечай на русском Анализировать реализованный код, по git репозитарию https://gogs.osvoj.ru/oleg/s5l.ru-crm.git Проверяй промт и изменения в нём по адресу https://gogs.osvoj.ru/oleg/s5l.ru-crm/raw/master/README.md
 
-1. **Базовая архитектура**
+1. **Базовая архитектура**  ⚠️ ПРИОРИТЕТ
    - Напиши базовые файлы системы
    - Система роутинга
    - Глобальная конфигурация