feat(db): перевести хранилище с SQLite на PostgreSQL
Docker images / prepare-release (push) Successful in 12s
Docker images / backend-test (push) Successful in 4m9s
Docker images / frontend-image (push) Successful in 4m28s
Docker images / updater-image (push) Successful in 58s
Docker images / backend-image (push) Successful in 2m49s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s

При старте backend накатывает схему PostgreSQL 18 и, если база пустая, один раз импортирует mikrotik.db с тома. Повторный старт не копирует данные. Бэкап в UI идёт через pg_dump.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-08 01:36:48 +07:00
co-authored by Cursor
parent 0e5fb065e2
commit ec43591a99
128 changed files with 4304 additions and 3639 deletions
+1 -1
View File
@@ -2846,7 +2846,7 @@ export default function AlertsPage() {
</CollapsibleTrigger>
<CollapsibleContent className="px-3 pb-3 text-[11px] text-muted-foreground leading-relaxed space-y-2 border-t border-border/60 pt-2">
<p>
Движок читает последние сэмплы из SQLite (uptime ресурсы, REST-пинг, пробы, GRE/BGP). Условие
Движок читает последние сэмплы из PostgreSQL (uptime ресурсы, REST-пинг, пробы, GRE/BGP). Условие
срабатывает только если цепочка состояний совпадает с текстом правила.
</p>
<ul className="list-disc pl-4 space-y-1.5">
+3 -3
View File
@@ -220,7 +220,7 @@ function SnapshotTables({ snap }: { snap: SchedulerRunSnapshot }) {
</Alert>
) : null}
<p className="text-xs text-muted-foreground">
Запись в SQLite на{" "}
Запись в PostgreSQL на{" "}
<span className="font-mono tabular-nums">{new Date(g.sampledAt).toLocaleString("ru-RU")}</span>
{" "} строки GRE и BGP для движка оповещений.
</p>
@@ -347,7 +347,7 @@ function SnapshotTables({ snap }: { snap: SchedulerRunSnapshot }) {
<p className="text-xs text-muted-foreground">
Снимок на{" "}
<span className="font-mono tabular-nums">{new Date(a.sampledAt).toLocaleString("ru-RU")}</span>
. Данные для правил берутся из SQLite после джоб сбора (трафик, uptime, REST, GRE+BGP и т.д.).
. Данные для правил берутся из PostgreSQL после джоб сбора (трафик, uptime, REST, GRE+BGP и т.д.).
</p>
<dl className="grid grid-cols-2 sm:grid-cols-4 gap-3 text-xs">
<div>
@@ -1215,7 +1215,7 @@ export default function DataCollectionPage() {
<OpsPanel
title="Журнал прогонов"
description="SQLite `scheduler_runs` — до 80 записей; раскройте строку для полей и текста ошибки."
description="Таблица `scheduler_runs` — до 80 записей; раскройте строку для полей и текста ошибки."
headerRight={
<div className="flex items-center gap-2 shrink-0">
<label className="text-xs text-muted-foreground whitespace-nowrap" htmlFor="run-filter">
+8 -8
View File
@@ -88,7 +88,7 @@ function DatabaseRestoreConfirm({
</AlertDialogMedia>
<AlertDialogTitle>Восстановить базу приложения?</AlertDialogTitle>
<AlertDialogDescription>
Файл: {filename}. Текущие данные SQLite на бекенде будут полностью заменены.
Файл: {filename}. Текущие данные PostgreSQL на бекенде будут полностью заменены.
Рекомендуется сначала скачать актуальный бэкап.
</AlertDialogDescription>
</AlertDialogHeader>
@@ -435,7 +435,7 @@ export default function SettingsPage() {
<OpsPanel
title="База данных приложения"
description="Резервная копия SQLite бекенда и сброс таблиц NetFlow. На время операции планировщик и коллектор IPFIX приостанавливаются. Preview: https://reui.io/preview/base/settings-16"
description="Резервная копия PostgreSQL (pg_dump custom) и сброс таблиц NetFlow. На время операции планировщик и коллектор IPFIX приостанавливаются. Preview: https://reui.io/preview/base/settings-16"
contentClassName="divide-y px-5"
>
{!systemDbAvailable && (
@@ -446,7 +446,7 @@ export default function SettingsPage() {
)}
<SettingRow
label="Скачать бэкап"
description="Консистентная копия файла mikrotik.db"
description="Консистентный дамп PostgreSQL (pg_dump -Fc)"
>
<Button
variant="outline"
@@ -461,7 +461,7 @@ export default function SettingsPage() {
</SettingRow>
<SettingRow
label="Восстановить из файла"
description="Полностью заменяет текущую базу SQLite"
description="Полностью заменяет текущую базу PostgreSQL (pg_restore)"
>
<div className="flex flex-col items-end gap-2">
<Button
@@ -481,7 +481,7 @@ export default function SettingsPage() {
</SettingRow>
<SettingRow
label="Сбросить данные NetFlow"
description="Удалит сессии и агрегаты из SQLite, затем VACUUM. Ключи WG и пиры не трогает"
description="Удалит сессии и агрегаты NetFlow в PostgreSQL. Ключи WG и пиры не трогает"
>
<Button
variant="destructive"
@@ -563,7 +563,7 @@ export default function SettingsPage() {
>
access.md
</a>
. URL и ключ хранятся в SQLite на сервере бекенда (
. URL и ключ хранятся в PostgreSQL на сервере бекенда (
<code className="font-mono bg-muted px-1 rounded">evobgp_settings</code>
). Каталог {" "}
<code className="font-mono bg-muted px-1 rounded">GET /v1/router-lists/catalog</code> через прокси.
@@ -937,8 +937,8 @@ export default function SettingsPage() {
open={dbRestoreDialogOpen}
onOpenChange={setDbRestoreDialogOpen}
title="Восстановление базы данных"
description="Выберите файл SQLite (.db) — текущая база будет полностью заменена"
accept=".db,.sqlite,.sqlite3,application/octet-stream"
description="Выберите файл pg_dump custom (.dump) — текущая база будет полностью заменена"
accept=".dump,.backup,application/octet-stream"
onImport={async (files) => {
const file = files[0]
if (!file) return