228 lines
5.8 KiB
Markdown
228 lines
5.8 KiB
Markdown
# Развертывание базы данных
|
||
|
||
Инструкция описывает минимальный порядок подготовки PostgreSQL-базы для `drill-cloud-v3`: создать базу, применить схему, зарегистрировать буровую и проверить ingest.
|
||
|
||
## Требования
|
||
|
||
- PostgreSQL с расширением TimescaleDB.
|
||
- Консольная утилита `psql`.
|
||
- Доступ к роли, которая может создавать БД, расширения и таблицы.
|
||
- Открытая интерактивная сессия `psql`.
|
||
|
||
Пример входа в `psql`:
|
||
|
||
```bash
|
||
psql -U postgres -W postgres
|
||
```
|
||
|
||
## 1. Создать базу
|
||
|
||
Если база уже создана, шаг можно пропустить.
|
||
|
||
Команды выполняются внутри `psql`:
|
||
|
||
```sql
|
||
SELECT current_database();
|
||
|
||
CREATE DATABASE "cloud-beta-dev";
|
||
|
||
\c cloud-beta-dev
|
||
|
||
SELECT current_database();
|
||
```
|
||
|
||
## 2. Применить базовую миграцию
|
||
|
||
Базовая схема лежит в:
|
||
|
||
```text
|
||
migrations/0000_cloud_beta_schema.sql
|
||
```
|
||
|
||
Она создает:
|
||
|
||
- `edge` - справочник буровых;
|
||
- `tag` - справочник тегов;
|
||
- `current` - последние значения тегов;
|
||
- `history` - история числовых значений;
|
||
- `camera` - видеопотоки буровых;
|
||
- индексы и первичные ключи;
|
||
- TimescaleDB hypertable для `history`.
|
||
|
||
Внутри `psql` применяем файл через `\i`:
|
||
|
||
```sql
|
||
\i 'C:/Users/myart/Drill/cloud/migrations/0000_cloud_beta_schema.sql'
|
||
```
|
||
|
||
Важно: внутри `psql` для Windows-путей используем `/`, а не `\`. Иначе `\Users` будет воспринято как psql-команда.
|
||
|
||
Проверка:
|
||
|
||
```sql
|
||
\dt public.*
|
||
|
||
SELECT hypertable_schema, hypertable_name
|
||
FROM timescaledb_information.hypertables;
|
||
```
|
||
|
||
Ожидаемо среди таблиц есть `edge`, `tag`, `current`, `history`, `camera`, а `history` отображается как hypertable.
|
||
|
||
## 3. Зарегистрировать буровую
|
||
|
||
Минимальная запись в `edge`:
|
||
|
||
```sql
|
||
INSERT INTO edge (id, name, parent_id)
|
||
VALUES ('edge-demo', 'Демо буровая', NULL)
|
||
ON CONFLICT (id)
|
||
DO UPDATE SET
|
||
name = EXCLUDED.name,
|
||
parent_id = EXCLUDED.parent_id;
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```sql
|
||
SELECT id, name, parent_id
|
||
FROM edge
|
||
ORDER BY name;
|
||
```
|
||
|
||
## 4. Зарегистрировать теги
|
||
|
||
Тег должен быть в таблице `tag`, если UI должен показывать русское имя, единицу измерения и метаданные.
|
||
|
||
Минимальный пример:
|
||
|
||
```sql
|
||
INSERT INTO tag (
|
||
id,
|
||
name,
|
||
min,
|
||
max,
|
||
comment,
|
||
unit_of_measurement,
|
||
precision,
|
||
tag_group
|
||
)
|
||
VALUES (
|
||
'BN1_10V_ControlVoltage_Fault',
|
||
'Ошибка контрольного напряжения 10В',
|
||
NULL,
|
||
NULL,
|
||
'',
|
||
'',
|
||
0,
|
||
'Электрика'
|
||
)
|
||
ON CONFLICT (id)
|
||
DO UPDATE SET
|
||
name = EXCLUDED.name,
|
||
min = EXCLUDED.min,
|
||
max = EXCLUDED.max,
|
||
comment = EXCLUDED.comment,
|
||
unit_of_measurement = EXCLUDED.unit_of_measurement,
|
||
precision = EXCLUDED.precision,
|
||
tag_group = EXCLUDED.tag_group;
|
||
```
|
||
|
||
Важно:
|
||
|
||
- `tag.id` должен совпадать с `tag`, который приходит в ingest.
|
||
- `tag.name` используется как основное имя в UI.
|
||
- `unit_of_measurement` отображается рядом со значением.
|
||
- `min` и `max` используются для статусов/границ, если они заданы.
|
||
|
||
## 5. Зарегистрировать камеры
|
||
|
||
Камеры хранятся в `camera`.
|
||
|
||
Пример:
|
||
|
||
```sql
|
||
INSERT INTO camera (edge, protocol, source)
|
||
VALUES ('edge-demo', 'wss', 'beta.video.drill.greact.ru/ws')
|
||
ON CONFLICT (edge, protocol, source) DO NOTHING;
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```sql
|
||
SELECT edge, protocol, source
|
||
FROM camera
|
||
ORDER BY edge, source;
|
||
```
|
||
|
||
## 6. Настроить backend
|
||
|
||
В `.env` backend-сервиса указать целевую БД:
|
||
|
||
```env
|
||
DATABASE_URL=postgresql://user:password@host:5432/cloud-beta-dev
|
||
INGEST_API_KEY=secret-key
|
||
PORT=3101
|
||
```
|
||
|
||
Запуск локально:
|
||
|
||
```bash
|
||
npm install
|
||
npm run start:dev
|
||
```
|
||
|
||
## 7. Smoke-test ingest
|
||
|
||
Отправить числовое значение:
|
||
|
||
```bash
|
||
curl -X POST "http://localhost:3101/api/ingest" \
|
||
-H "content-type: application/json" \
|
||
-H "x-api-key: secret-key" \
|
||
-d '{"edge":"edge-demo","tag":"BN1_10V_ControlVoltage_Fault","timestamp":"2026-07-06T10:00:00.000Z","value":0}'
|
||
```
|
||
|
||
Проверить `current`:
|
||
|
||
```bash
|
||
curl "http://localhost:3101/api/current?edge=edge-demo"
|
||
```
|
||
|
||
Проверить БД внутри `psql`:
|
||
|
||
```sql
|
||
SELECT edge, tag, value, "updatedAt"
|
||
FROM current
|
||
WHERE edge = 'edge-demo';
|
||
```
|
||
|
||
## 8. Поведение `NULL`
|
||
|
||
Ingest принимает явный `null`:
|
||
|
||
```json
|
||
{
|
||
"edge": "edge-demo",
|
||
"tag": "BN1_10V_ControlVoltage_Fault",
|
||
"timestamp": "2026-07-06T10:00:00.000Z",
|
||
"value": null
|
||
}
|
||
```
|
||
|
||
Правила:
|
||
|
||
- `current.value` обновляется в `NULL`;
|
||
- в `history` такая точка не пишется;
|
||
- на фронтенде current-виджет показывает `NULL` как `—`;
|
||
- `0` остается обычным числом и не считается `NULL`.
|
||
|
||
## 9. Короткая проверка после развертывания
|
||
|
||
```bash
|
||
curl "http://localhost:3101/api/health"
|
||
curl "http://localhost:3101/api/edge"
|
||
curl "http://localhost:3101/api/current?edge=edge-demo"
|
||
curl "http://localhost:3101/api/camera?edge=edge-demo"
|
||
```
|
||
|
||
Если эти запросы отвечают корректно, база готова для работы backend и UI. |