type: standard
aspect: structure
title: "Управление кодом: Library"
version: 1.0.0
date: 2026-02-19
status: active
Версия: 2.1.0
Дата: 2025-12-20
Статус: ОБЯЗАТЕЛЬНО
ОДИН РАЗ НАПИСАТЬ → МНОГО РАЗ ИСПОЛЬЗОВАТЬ
Перед написанием кода — проверь library/ и system/.
┌─────────────────────────────────────────────────────────────┐
│ УРОВЕНЬ 1: ПЛАТФОРМА (для всех проектов) │
│ library/connectors/ API/Data/Device коннекторы │
│ library/functions/ Парсеры, форматтеры, валидаторы │
│ library/internal/ Утилиты (хелперы) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ УРОВЕНЬ 2: ПРОЕКТ (только для данного проекта) │
│ project/lib/ Проектные библиотеки │
│ project/data/config/ Конфигурации для платформы │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ УРОВЕНЬ 3: ПРИЛОЖЕНИЕ (конкретный сервис) │
│ project/app/X/ Бизнес-логика приложения │
└─────────────────────────────────────────────────────────────┘
| Вопрос | library/ | project/lib/ |
|---|---|---|
| Для кого? | Все проекты | Один проект |
| Что это? | Готовый код (коннекторы, функции) | Проектный код |
| Примеры | ozon-connector, xlsx-parser | jf_importer |
| Зависит от данных проекта? | Нет | Да |
library/ projects/X/lib/
├── connectors/ ├── pim/
│ ├── api/ │ └── ndb_client.py
│ │ ├── ozon/ ├── importers/
│ │ └── telegram/ │ └── jf_importer.py
│ ├── data/ └── utils/
│ │ ├── postgres/ └── sku_parser.py
│ │ └── nocodb/
│ └── device/
│ └── printer/
├── functions/
│ ├── parsers/
│ │ └── xlsx/
│ └── formatters/
└── internal/
└── some-lib/
Код использует внешний API/БД/устройство?
├── ДА → library/connectors/
│
└── НЕТ → Это функция обработки данных?
├── ДА → library/functions/
│
└── НЕТ → Код переиспользуется внутри проекта?
├── ДА → project/lib/
│
└── НЕТ → project/app/X/ (inline)
library/
├── index.yaml ← Каталог компонентов
├── sandbox/ ← DEV: сырой код (v0.x.x)
├── internal/ ← PROD: наш код (v1.0.0+)
└── external/ ← PROD: внешний код (vendor)
| Папка | Статус | Версия | Использование |
|---|---|---|---|
| sandbox | dev | 0.x.x | Только разработка |
| internal | prod | ≥1.0.0 | Все проекты |
| external | prod | — | Все проекты |
┌─────────────────────────────────────────────────────────────┐
│ SANDBOX (v0.x.x) │
│ │
│ • Новый код │
│ • Разработка и тестирование │
│ • Эксперименты │
│ • НЕ для production │
└────────────────────────┬────────────────────────────────────┘
│
│ Тесты пройдены
│ Документация готова
│ Версия → 1.0.0
▼
┌─────────────────────────────────────────────────────────────┐
│ INTERNAL (v1.0.0+) │
│ │
│ • Проверенный стабильный код │
│ • Полная документация │
│ • Для всех проектов │
│ • Обратная совместимость обязательна │
└─────────────────────────────────────────────────────────────┘
1. Получил задачу
↓
2. Проверь library/
├── Есть в internal/external? → Используй
├── Есть в sandbox? → Оцени, помоги доработать
└── Нет? → Создай в sandbox/
↓
3. Используй в проекте
# PROD — безопасно для production
from library.internal.filemanager import FileManager
from library.external.some_github_lib import Helper
# DEV — только для разработки!
from library.sandbox.new_parser import Parser # НЕ для prod!
# КОННЕКТОРЫ — из system/, НЕ из library/!
from system.connectors.marketplaces.ozon import OzonClient
from system.connectors.delivery.pochta import PochtaClient
| Ситуация | Действие |
|---|---|
| pip/npm пакет, используем as-is | НЕ копируем, указываем в requirements |
| Код которого нет в pip | Копируем в external/ |
| Модифицируем внешний код | Копируем + MODS.md |
library/external/some-lib/
├── README.md ← Что, как использовать
├── ORIGIN.md ← Откуда: URL, версия, лицензия
├── MODS.md ← Наши изменения (если есть)
└── src/
ВАЖНО: API-клиенты (ozon, pochta, telegram) — это НЕ external!
Они в library/connectors/api/. External — только чужой utility-код.
# Источник
- **URL:** https://github.com/example/lib
- **Версия:** 1.2.3
- **Дата копирования:** 2025-12-20
- **Лицензия:** MIT
## Зачем взяли
[причина]
# Модификации
## 2025-12-20 — Описание изменения
**Файл:** src/client.py:45
**Причина:** [зачем]
**Изменение:** [что сделали]
sandbox/my-component/
├── README.md ← Что делает, как использовать
├── tests/ ← Тесты
└── src/ ← Код
internal/my-component/
├── README.md ← Что, как использовать, примеры
├── HISTORY.md ← Откуда появился, история изменений
├── tests/
└── src/
# История
## Происхождение
- **Появился в:** projects/pirotehnika
- **Дата:** 2025-11-01
- **Перенесён в library:** 2025-12-20
## Версии
- v1.0.0 (2025-12-20) — Первый релиз
MAJOR.MINOR.PATCH
MAJOR — несовместимые изменения
MINOR — новая функциональность (совместимо)
PATCH — исправления багов
| Папка | Версия |
|---|---|
| sandbox | 0.x.x (всё может меняться) |
| internal | ≥1.0.0 (обратная совместимость) |
Код, который переиспользуется внутри одного проекта, но не универсален для платформы.
projects/pirotehnika/
├── lib/ ← Проектные библиотеки
│ ├── __init__.py
│ │
│ ├── pim/ Работа с PIM
│ │ ├── __init__.py
│ │ ├── ndb_client.py Обёртка над library/connectors/data/nocodb
│ │ └── base_importer.py Базовый класс импортеров
│ │
│ ├── importers/ Импортеры поставщиков
│ │ ├── __init__.py
│ │ ├── jf_importer.py
│ │ ├── maxsem_importer.py
│ │ └── piroff_importer.py
│ │
│ └── utils/ Проектные утилиты
│ ├── __init__.py
│ └── sku_parser.py
│
├── data/
│ └── config/ Конфигурации
│ ├── nocodb.yaml
│ └── suppliers.yaml
│
└── app/
└── mp1/ Использует lib/
└── solution/
└── scripts/
| Критерий | project/lib/ | library/ |
|---|---|---|
| Использует данные проекта | ✅ Да | ❌ Нет |
| Специфичная бизнес-логика | ✅ Да | ❌ Нет |
| Переиспользуется в проекте | ✅ Да | ✅ Да |
| Переиспользуется между проектами | ❌ Нет | ✅ Да |
# projects/pirotehnika/lib/pim/ndb_client.py
"""Проектная обёртка над library/connectors/data/nocodb"""
from library.connectors.data.nocodb import NocoDBConnector, NocoDBCredentials
# Проектные таблицы
TABLES = {
"Product": "tbl_abc123",
"Order": "tbl_def456",
"Supplier": "tbl_ghi789",
}
class PIMClient:
"""NocoDB клиент для PIM pirotehnika"""
def __init__(self, config_path: str = "data/config/nocodb.yaml"):
# Загружаем проектный конфиг
config = load_config(config_path)
# Используем платформенный коннектор
self.connector = NocoDBConnector(
NocoDBCredentials(**config)
)
def get_products(self):
return self.connector.list(TABLES["Product"])
# projects/pirotehnika/app/mp1/solution/scripts/sync.py
# Импорт из проектной библиотеки
from lib.pim.ndb_client import PIMClient
from lib.importers.jf_importer import JFImporter
# Использование
client = PIMClient()
products = client.get_products()
Если код из project/lib/ становится универсальным:
1. Код работает в проекте (project/lib/)
↓
2. Другой проект хочет использовать
↓
3. Выделяем универсальную часть
↓
4. Переносим в library/sandbox/
↓
5. Тестируем в обоих проектах
↓
6. Переводим в library/internal/
{component}/
├── README.md ← Документация
├── index.yaml ← Метаданные (опционально)
├── tests/
│ └── test_*.py
└── src/
├── __init__.py
└── *.py
name: filemanager
version: "1.0.0"
description: "Файловый менеджер для DATASPACE"
dependencies:
- requests
- pathlib
author: "@user"
components:
sandbox:
new-parser:
version: "0.3.0"
description: "Новый парсер"
path: "sandbox/new-parser/"
internal:
filemanager:
version: "1.0.0"
description: "Файловый менеджер"
path: "internal/filemanager/"
external:
pochta-api:
version: "1.0.0"
origin: "https://..."
path: "external/pochta-api/"
ПРАВИЛО: В git НЕ должно быть симлинков (symbolic links).
❌ Windows — требуют админских прав, часто превращаются в текстовые файлы
❌ Git clone — могут стать текстовыми файлами со ссылкой вместо реального линка
❌ Кросс-платформенность — разное поведение на Linux/Mac/Windows
❌ CI/CD — ломаются при сборке в контейнерах
✅ Обёртки-скрипты (wrapper scripts):
#!/usr/bin/env python3
"""
create_value_object.py - Обёртка для create_entity.py
"""
import sys, subprocess
from pathlib import Path
script_dir = Path(__file__).parent
create_entity = script_dir / "create_entity.py"
# Добавить параметры и запустить
args = [sys.executable, str(create_entity), "--type", "value-object"] + sys.argv[1:]
sys.exit(subprocess.call(args))
✅ Копии файлов — если файл маленький (<1KB)
✅ Import/require — если это код:
# Вместо симлинка library/connectors/api/onec → 1c
# Используем импорт или реальную папку
# Проверить всю платформу (кроме node_modules и venv)
find $WORKSPACE -type l \
-not -path "*/node_modules/*" \
-not -path "*/venv/*" \
-not -path "*/.venv/*" \
-ls
# Проверить что в git
git ls-files -s | grep "^120000"
# 1. Удалить из git (но оставить файл локально)
git rm --cached path/to/symlink
# 2. Заменить на обёртку или копию
# 3. Закоммитить изменения
git add path/to/wrapper.py
git commit -m "replace symlink with wrapper script"
✅ Можно оставить симлинки (но НЕ коммитить в git):
- Локальные удобства навигации ($WORKSPACE/pirotehnika → projects/pirotehnika)
- Создаются автоматически (node_modules/.bin/, venv/bin/)
Добавить в .gitignore:
# Symlinks (не коммитим)
/lideravto
/pirotehnika
/seller1
*.old/
library/sandbox/{name}/src/tests/library/index.yamllibrary/internal/library/index.yamllibrary/external/{name}/library/index.yaml# projects/pirotehnika/data/index.yaml
links:
uses:
- path: "library/internal/filemanager"
what: "Файловый менеджер"
- path: "library/internal/price-parser"
what: "Парсер прайсов"
# Коннекторы — из library/
- path: "library/connectors/api/pochta"
what: "API Почты России"
Версия: 3.0.0