ваше сообщение коммита

This commit is contained in:
2025-11-26 21:59:51 +03:00
parent 6d158c3952
commit 25c6ccc5d0
8 changed files with 221 additions and 23 deletions

12
.gitignore vendored
View File

@@ -202,4 +202,14 @@ backend/test_*.js
# Environment specific files
backend/.env.local
backend/.env.production
backend/.env.production
# Server management scripts - may contain sensitive information
scripts/clean-server.sh
scripts/export-template-for-release.sh
# Docker data and release archives - не коммитить в Git!
docker-data/
dle-template.tar.gz
dle-template.tar.gz.part-*
dle-template.tar.gz.join.sh

View File

@@ -36,7 +36,8 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup.s
The script automatically downloads the latest artifacts from the release and deploys `docker-data`.
### 📦 Releases and artifacts
- [Release v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — contains an archive split into parts (`dle-template.tar.gz.part-*`) that is installed together with the script.
- [Release v1.0.1](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.1) (Latest) — contains the complete application template with Docker images, volumes, and encryption key. Archive is split into parts (`dle-template.tar.gz.part-*`) for easy download.
- [Release v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — previous version.
### Running the application
```bash

View File

@@ -36,7 +36,8 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup.s
Скрипт автоматически скачивает последние артефакты из релиза и разворачивает `docker-data`.
### 📦 Релизы и артефакты
- [Релиз v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — содержит архив, разбитый на части (`dle-template.tar.gz.part-*`), который устанавливается вместе со скриптом.
- [Релиз v1.0.1](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.1) (Latest) — содержит полный шаблон приложения с Docker образами, томами и ключом шифрования. Архив разделен на части (`dle-template.tar.gz.part-*`) для удобства загрузки.
- [Релиз v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — предыдущая версия.
### Запуск приложения
```bash

View File

@@ -88,6 +88,24 @@ router.get('/okved', async (req, res, next) => {
});
}
// Сортировка кодов ОКВЭД по коду (правильная числовая сортировка для каждой части)
codes.sort((a, b) => {
// Разбиваем коды на части для правильной сортировки
const partsA = a.code.split('.').map(p => parseInt(p, 10));
const partsB = b.code.split('.').map(p => parseInt(p, 10));
// Сравниваем части по порядку численно
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const partA = partsA[i] !== undefined ? partsA[i] : 0;
const partB = partsB[i] !== undefined ? partsB[i] : 0;
if (partA !== partB) {
return partA - partB;
}
}
return 0;
});
// Ограничиваем количество результатов для производительности
const limit = parseInt(req.query.limit) || 2000; // Увеличили лимит для полного списка
codes = codes.slice(0, limit);

View File

@@ -91,7 +91,7 @@ async function runMigrations() {
}
// Извлекаем только UP SQL
const sqlToExecute = fileContent.substring(upSqlStartIndex, upSqlEndIndex).trim();
let sqlToExecute = fileContent.substring(upSqlStartIndex, upSqlEndIndex).trim();
if (!sqlToExecute) {
logger.warn(`Migration file ${file} has no executable UP SQL content. Skipping.`);
@@ -99,6 +99,38 @@ async function runMigrations() {
}
logger.info(`Executing UP migration from ${file}...`);
// Выделяем CREATE EXTENSION команды, которые должны выполняться вне транзакции
const extensionRegex = /CREATE\s+EXTENSION\s+IF\s+NOT\s+EXISTS\s+\w+;?/gi;
const extensionCommands = [];
sqlToExecute = sqlToExecute.replace(extensionRegex, (match) => {
extensionCommands.push(match.replace(/;?\s*$/, ''));
return ''; // Удаляем из основного SQL
});
// Выполняем CREATE EXTENSION команды вне транзакции
for (const extCmd of extensionCommands) {
try {
await pool.query(extCmd);
logger.info(`Extension command executed: ${extCmd}`);
} catch (error) {
// Игнорируем ошибку, если расширение уже установлено
if (!error.message.includes('already exists')) {
logger.warn(`Warning executing extension command: ${error.message}`);
}
}
}
// Очищаем оставшийся SQL от пустых строк
sqlToExecute = sqlToExecute.trim();
// Если после удаления CREATE EXTENSION остался только пустой SQL, пропускаем транзакцию
if (!sqlToExecute) {
await pool.query('INSERT INTO migrations (name) VALUES ($1)', [file]);
logger.info(`Migration ${file} executed successfully (extension only)`);
continue;
}
await pool.query('BEGIN');
try {
// Создаем функцию для получения ключа шифрования

View File

@@ -1320,6 +1320,24 @@ const fetchOkvedCodes = async (level, parentCode, optionsRef, loadingRef) => {
);
}
// Сортировка кодов ОКВЭД по коду (правильная числовая сортировка для каждой части)
filteredCodes.sort((a, b) => {
// Разбиваем коды на части для правильной сортировки
const partsA = a.code.split('.').map(p => parseInt(p, 10));
const partsB = b.code.split('.').map(p => parseInt(p, 10));
// Сравниваем части по порядку численно
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const partA = partsA[i] !== undefined ? partsA[i] : 0;
const partB = partsB[i] !== undefined ? partsB[i] : 0;
if (partA !== partB) {
return partA - partB;
}
}
return 0;
});
optionsRef.value = filteredCodes.map(code => ({
value: code.code,
text: `${code.code} - ${code.title}`

View File

@@ -23,12 +23,34 @@ fi
ENCRYPTION_KEY=$(cat ./ssl/keys/full_db_encryption.key)
# Создаем роли Read-Only и Editor
# Используем DO блок для безопасной вставки с проверкой уникальности name_encrypted
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
INSERT INTO roles (id, name_encrypted) VALUES
(1, encrypt_text('readonly', '$ENCRYPTION_KEY')),
(2, encrypt_text('editor', '$ENCRYPTION_KEY'))
ON CONFLICT (id) DO UPDATE SET
name_encrypted = EXCLUDED.name_encrypted;"
DO \$\$
DECLARE
readonly_id INTEGER;
editor_id INTEGER;
BEGIN
-- Проверяем и создаем/обновляем роль readonly
SELECT id INTO readonly_id FROM roles WHERE decrypt_text(name_encrypted, get_encryption_key()) = 'readonly' LIMIT 1;
IF readonly_id IS NULL THEN
-- Если роли нет, пытаемся вставить с id=1, если занято - используем следующий доступный
BEGIN
INSERT INTO roles (id, name_encrypted) VALUES (1, encrypt_text('readonly', get_encryption_key()));
EXCEPTION WHEN unique_violation THEN
INSERT INTO roles (name_encrypted) VALUES (encrypt_text('readonly', get_encryption_key()));
END;
END IF;
-- Проверяем и создаем/обновляем роль editor
SELECT id INTO editor_id FROM roles WHERE decrypt_text(name_encrypted, get_encryption_key()) = 'editor' LIMIT 1;
IF editor_id IS NULL THEN
BEGIN
INSERT INTO roles (id, name_encrypted) VALUES (2, encrypt_text('editor', get_encryption_key()));
EXCEPTION WHEN unique_violation THEN
INSERT INTO roles (name_encrypted) VALUES (encrypt_text('editor', get_encryption_key()));
END;
END IF;
END \$\$;"
# Заполняем справочную таблицу is_rag_source
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
@@ -38,17 +60,87 @@ INSERT INTO is_rag_source (id, name_encrypted) VALUES
ON CONFLICT (id) DO UPDATE SET
name_encrypted = EXCLUDED.name_encrypted;"
# Заполняем RPC провайдеры с проверкой дубликатов
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
VALUES
(encrypt_text('sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://1rpc.io/sepolia', '$ENCRYPTION_KEY'), 11155111),
(encrypt_text('arbitrum-sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://sepolia-rollup.arbitrum.io/rpc', '$ENCRYPTION_KEY'), 421614),
(encrypt_text('base-sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://sepolia.base.org', '$ENCRYPTION_KEY'), 84532)
ON CONFLICT DO NOTHING;"
DO \$\$
BEGIN
-- Sepolia
IF NOT EXISTS (
SELECT 1 FROM rpc_providers
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'sepolia'
AND chain_id = 11155111
) THEN
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
VALUES (encrypt_text('sepolia', get_encryption_key()), encrypt_text('https://1rpc.io/sepolia', get_encryption_key()), 11155111);
END IF;
-- Arbitrum Sepolia
IF NOT EXISTS (
SELECT 1 FROM rpc_providers
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'arbitrum-sepolia'
AND chain_id = 421614
) THEN
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
VALUES (encrypt_text('arbitrum-sepolia', get_encryption_key()), encrypt_text('https://sepolia-rollup.arbitrum.io/rpc', get_encryption_key()), 421614);
END IF;
-- Base Sepolia
IF NOT EXISTS (
SELECT 1 FROM rpc_providers
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'base-sepolia'
AND chain_id = 84532
) THEN
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
VALUES (encrypt_text('base-sepolia', get_encryption_key()), encrypt_text('https://sepolia.base.org', get_encryption_key()), 84532);
END IF;
END \$\$;"
# Заполняем токены аутентификации с проверкой дубликатов
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
VALUES
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1),
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('arbitrum-sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1),
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('base-sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1)
ON CONFLICT DO NOTHING;"
DO \$\$
BEGIN
-- Sepolia token
IF NOT EXISTS (
SELECT 1 FROM auth_tokens
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'sepolia'
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
) THEN
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
VALUES (
encrypt_text('DLE', get_encryption_key()),
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
encrypt_text('sepolia', get_encryption_key()),
1.000000000000000000, 1, 1
);
END IF;
-- Arbitrum Sepolia token
IF NOT EXISTS (
SELECT 1 FROM auth_tokens
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'arbitrum-sepolia'
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
) THEN
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
VALUES (
encrypt_text('DLE', get_encryption_key()),
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
encrypt_text('arbitrum-sepolia', get_encryption_key()),
1.000000000000000000, 1, 1
);
END IF;
-- Base Sepolia token
IF NOT EXISTS (
SELECT 1 FROM auth_tokens
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'base-sepolia'
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
) THEN
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
VALUES (
encrypt_text('DLE', get_encryption_key()),
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
encrypt_text('base-sepolia', get_encryption_key()),
1.000000000000000000, 1, 1
);
END IF;
END \$\$;"

View File

@@ -24,14 +24,13 @@ print_red() {
echo -e "\e[31m$1\e[0m"
}
ARCHIVE_VERSION="v1.0.0"
ARCHIVE_VERSION="v1.0.1"
ARCHIVE_BASE_URL="https://github.com/VC-HB3-Accelerator/DLE/releases/download/${ARCHIVE_VERSION}"
ARCHIVE_PARTS=(
"dle-template.tar.gz.part-aa"
"dle-template.tar.gz.part-ab"
"dle-template.tar.gz.part-ac"
"dle-template.tar.gz.part-ad"
"dle-template.tar.gz.part-ae"
)
# Проверка curl
@@ -263,6 +262,30 @@ import_volumes() {
print_green "✅ Все тома импортированы"
}
# Копирование ключа шифрования из архива
copy_encryption_key() {
print_blue "🔐 Копирование ключа шифрования..."
# Проверяем наличие ключа в архиве
if [ -f "docker-data/ssl/keys/full_db_encryption.key" ]; then
# Создаем директорию для ключа
mkdir -p ssl/keys
# Копируем ключ
cp docker-data/ssl/keys/full_db_encryption.key ssl/keys/full_db_encryption.key
chmod 600 ssl/keys/full_db_encryption.key
print_green "✅ Ключ шифрования скопирован из архива"
print_yellow "⚠️ Примечание: Это дефолтный ключ, замените его на свой!"
else
print_yellow "⚠️ Ключ шифрования не найден в архиве"
print_blue "Создайте новый ключ или он будет создан автоматически"
# Создаем директорию для ключа на всякий случай
mkdir -p ssl/keys
fi
}
# Запуск приложения
start_application() {
print_blue "🚀 Запуск приложения..."
@@ -314,6 +337,9 @@ main() {
create_volumes
import_volumes
# Копирование ключа шифрования
copy_encryption_key
# Запуск
start_application
check_status