Files
Zimin A.N. bcfb07f547 docs: split integrator guide (Diplodoc) vs internal docs + add build-docs CI
Чёткое разделение audiences:
- docs/ — consumer-facing only, Diplodoc-built. Public contract для
  интеграторов (Альтум, BI, third-party).
- docs-internal/ — operator runbooks, status snapshots, legacy tech pages.
  НЕ в Diplodoc build, НЕ публикуются.

Изменения:
- Move docs/{ops,status,tech} → docs-internal/{ops,status,tech}
- docs/toc.yaml: убраны секции Operations, Архитектура (legacy), Status
- docs/index.md: убран tab "оператор / on-call", focus на integrators
- docs/README.md: rewritten — scope только integrator guide, editorial
  guidelines (no leak internal architecture, stable API contract)
- .yfm: убран явный ignore status/* (теперь не нужно — папка переехала)
- docs-internal/README.md: index для внутренней документации с rationale
  разделения

Scrubbing implementation details из Diplodoc страниц:
- events.md: убраны Strimzi/cluster.142 references, OutboxPoller детали,
  internal alert names (OrdinisOutboxLagHigh, OrdinisOutboxDLQNonEmpty),
  metric names (nsi_outbox_*). Заменены на consumer-observable contract.
- webhooks.md: убраны metric names (nsi_webhook_ssrf_rejected_total),
  alert table (OrdinisWebhookHighFailureRate и т.д.). Retry policy
  переписана на user-side perspective.
- errors.md: убран alert name OrdinisReadApiErrorBudgetBurnFast, Tempo
  endpoint URL, internal connection details.
- x-references.md: OrphanReferenceScanner → general "Ordinis периодически
  детектирует". Убраны metric/alert names. Cascade roadmap без link на
  internal design doc.
- auth.md: убран file path ScopeContext.java.
- bundle-cuod.md: убран Maven module path.
- caching.md: cascade design link заменён на text reference.

CI:
- .gitlab-ci.yml: новый job build-docs (stage: build) — Node 20 alpine,
  pnpm install --frozen-lockfile + pnpm build, artifact docs/_dist на
  неделю. Triggers: auto на docs/**, либо manual web. Готов к follow-up
  pages-deploy job когда host решён.
- Новый pattern .docs-changes для rules.

Build verified clean: 13 HTML pages, 6.9M, no broken links/refs.
2026-05-07 23:27:03 +03:00

126 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Runbook: Liquibase миграции БД
**Источник правды:** `ordinis-migrations/src/main/resources/db/changelog/`
- `master.xml` — список включённых changelog'ов в порядке применения.
- `changes/00NN-*.xml` — конкретные изменения (CREATE TABLE, ADD COLUMN и т.д.).
Миграции применяются **автоматически** при старте `ordinis-app` через
`spring.liquibase` (Spring Boot starter). Если миграция падает — pod
не стартует, остальные pods тоже не поднимутся (read-api/projection-writer
имеют startup-зависимость от схемы БД).
## 1. Просмотр applied миграций
```bash
export KUBECONFIG=/tmp/kubeconfig-161
PG_PASS=$(kubectl get secret -n ordinis-staging ordinis-postgres-app \
-o jsonpath='{.data.password}' | base64 -d)
kubectl exec -n ordinis-staging ordinis-postgres-1 -c postgres -- \
env PGPASSWORD="$PG_PASS" psql -h localhost -U ordinis_app -d ordinis -c \
"SELECT id, author, dateexecuted, exectype FROM databasechangelog ORDER BY orderexecuted;"
```
Колонка `exectype`:
- `EXECUTED` — миграция применена успешно
- `FAILED` — упала (pod не должен стартовать в этом случае)
- `MARK_RAN` — пропущена через preCondition
- `RERAN` — была применена повторно (manual)
## 2. Добавление новой миграции
1. Создать `ordinis-migrations/src/main/resources/db/changelog/changes/00NN-<topic>.xml`.
- Номер строго следующий (последний +1).
- Author = `ordinis`.
- Idempotent: использовать `<preConditions onFail="MARK_RAN">` для добавлений.
2. Зарегистрировать в `master.xml` через `<include file="changes/00NN-*.xml"/>`.
3. Тестировать локально на dev-Postgres:
```bash
docker run -d --rm --name ord-pg -e POSTGRES_PASSWORD=dev \
-p 5432:5432 postgres:18
mvn -pl ordinis-migrations -am liquibase:update \
-Dliquibase.url=jdbc:postgresql://localhost:5432/postgres \
-Dliquibase.username=postgres -Dliquibase.password=dev
```
4. Commit + push. CI пересобирает app image, deploy применяет новые миграции
при следующем старте pod'а.
## 3. Откат миграции
⚠️ **Liquibase rollback требует `<rollback>` блок в changeset**. Без него
автоматический откат невозможен — только manual SQL.
### Если changeset имеет `<rollback>`
```bash
# Через kubectl exec на pod где есть mvn — обычно нет, проще локально:
mvn -pl ordinis-migrations -am liquibase:rollback \
-Dliquibase.url=jdbc:postgresql://192.168.100.161:5432/ordinis \
-Dliquibase.username=ordinis_app \
-Dliquibase.password=$PG_PASS \
-Dliquibase.rollbackCount=1
```
### Manual SQL (если rollback не задан)
1. Прочитать changeset XML — посмотреть какие изменения сделаны.
2. Написать обратные SQL (DROP TABLE, ALTER TABLE DROP COLUMN и т.д.).
3. Удалить запись из `databasechangelog`:
```sql
DELETE FROM databasechangelog WHERE id = '00NN-1-some-id' AND author = 'ordinis';
```
4. После этого Liquibase при следующем старте либо переприменит миграцию
(если она всё ещё в master.xml), либо считает её не-применённой.
## 4. Failed migration recovery
Сценарий: миграция упала, pod в CrashLoopBackOff.
### A) Миграция частично применилась
Liquibase помечает changeset как FAILED в `databasechangelog`. Чтобы
повторить:
```sql
DELETE FROM databasechangelog WHERE id = '00NN-1-broken' AND exectype = 'FAILED';
```
После этого pod рестарт → Liquibase снова попытается. Если миграция всё ещё
broken, исправить XML (или применённый частично state в БД), пересобрать
image, redeploy.
### B) Миграция полностью применилась но с ошибкой в данных
Например column добавлена с NOT NULL без default. Manual SQL:
```sql
ALTER TABLE my_table ALTER COLUMN broken_col DROP NOT NULL;
-- либо UPDATE my_table SET broken_col = 'default' WHERE broken_col IS NULL;
```
И исправить XML на `defaultValueComputed=...` для следующих deployments.
## 5. Текущий список миграций (на 2026-05-05)
| ID | Назначение |
|---|---|
| 0001-extensions.xml | PostGIS, btree_gist (для tstzrange exclusion) |
| 0002-dictionary-definitions.xml | Таблица `dictionary_definitions` |
| 0003-dictionary-records.xml | Таблица `dictionary_records` + tstzrange exclusion |
| 0004-audit-log.xml | Таблица `audit_log` |
| 0005-outbox-events.xml | Таблица `outbox_events` + partial index |
| 0006-idempotency-keys.xml | Таблица `idempotency_keys` |
| 0007-add-version-columns.xml | JPA optimistic lock columns |
| 0008-fix-scope-check-uppercase.xml | Чек на scope в верхнем регистре |
| 0009-fix-records-scope-check.xml | Чек consistency dictionary↔record scope |
| 0010-envers-tables.xml | Hibernate Envers (revinfo, *_aud) |
| 0011-outbox-dlq.xml | DLQ column + partial indexes |
## 6. Эскалация
| Проблема | Действие |
|---|---|
| Migration на staging упала, pod не стартует | DELETE FAILED row + fix XML + redeploy. См. §4A. |
| Migration on prod упала | **СТОП**. Не делать manual fix без apply tech lead. Возможно нужен rollback всего deployment. |
| `databasechangelog` lock застрял (другая миграция параллельно) | `DELETE FROM databasechangelog_lock WHERE id=1; INSERT INTO databasechangelog_lock VALUES (1, false, NULL, NULL);` |
| Postgres недоступен | См. CNPG cluster status: `kubectl get cluster -n ordinis-staging` |