Подготовить безопасный production rollout

This commit is contained in:
Zuev
2026-07-29 23:13:17 +03:00
parent a78a93f2f0
commit 8bb7fe97eb
16 changed files with 494 additions and 324 deletions

View File

@@ -1,6 +1,27 @@
{
"generated_at": "2026-07-22T21:09:28.978295+00:00",
"generated_at": "2026-07-29T20:02:59.230356+00:00",
"nodes": {
"_gitea_workflows_docker_build_build_and_push_docker_images": {
"code_fingerprint": "80373e004c326a786715725be21ddb9214b6ff382a02cb829acad1bb9c9098f8",
"label": "Workflow сборки и публикации Docker-образов",
"last": "2026-07-29T19:59:04.551881+00:00",
"provenance": [
{
"date": "2026-07-29T19:59:04.551881+00:00",
"outcome": "useful",
"q": "новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше"
},
{
"date": "2026-07-29T19:26:44.188240+00:00",
"outcome": "useful",
"q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
}
],
"score": 1.999355769,
"source_file": ".gitea/workflows/docker-build.yaml",
"status": "preferred",
"uses": 2
},
"backend_src_main_java_com_magistr_app_config_auth_authorizationinterceptor_authorizationinterceptor": {
"code_fingerprint": "70b01b3fa22e058ee997250c52cc0affee54ab37aa5f8cc7eb74411487f1bbbf",
"label": "AuthorizationInterceptor",
@@ -22,7 +43,7 @@
"q": "Почему RequireRoles связывает множество контроллеров, моделей и сервисов как cross-community bridge?"
}
],
"score": 2.185520319,
"score": 1.861135007,
"source_file": "backend/src/main/java/com/magistr/app/config/auth/AuthorizationInterceptor.java",
"status": "preferred",
"uses": 3
@@ -38,7 +59,7 @@
"q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?"
}
],
"score": 0.776480146,
"score": 0.661231273,
"source_file": "backend/src/main/java/com/magistr/app/config/auth/JwtTokenService.java",
"status": "tentative",
"uses": 1
@@ -54,7 +75,7 @@
"q": "Почему RequireRoles связывает множество контроллеров, моделей и сервисов как cross-community bridge?"
}
],
"score": 0.653312094,
"score": 0.556344408,
"source_file": "backend/src/main/java/com/magistr/app/config/auth/RequireRoles.java",
"status": "tentative",
"uses": 1
@@ -70,7 +91,7 @@
"q": "Как безопасно обновлять tenant DataSource без потери рабочего подключения?"
}
],
"score": 0.794603611,
"score": 0.676664767,
"source_file": "backend/src/main/java/com/magistr/app/config/DataInitializer.java",
"status": "tentative",
"uses": 1
@@ -86,7 +107,7 @@
"q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'"
}
],
"score": 0.75572808,
"score": 0.643559327,
"source_file": "backend/src/main/java/com/magistr/app/config/tenant/ConfigMapUpdater.java",
"status": "tentative",
"uses": 1
@@ -102,7 +123,7 @@
"q": "Как безопасно заменить tenant DataSource без потери рабочего подключения?"
}
],
"score": 0.794468884,
"score": 0.676550037,
"source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantConfig.java",
"status": "tentative",
"uses": 1
@@ -128,7 +149,7 @@
"q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'"
}
],
"score": 2.344800575,
"score": 1.99677413,
"source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantConfigWatcher.java",
"status": "preferred",
"uses": 3
@@ -154,7 +175,7 @@
"q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?"
}
],
"score": 2.365552641,
"score": 2.014446076,
"source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantRoutingDataSource.java",
"status": "preferred",
"uses": 3
@@ -170,7 +191,7 @@
"q": "Почему в выборе аудитории показаны корпус и этаж?"
}
],
"score": 0.976851438,
"score": 0.831862505,
"source_file": "backend/src/main/java/com/magistr/app/controller/ClassroomController.java",
"status": "tentative",
"uses": 1
@@ -186,7 +207,7 @@
"q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?"
}
],
"score": 0.776480146,
"score": 0.661231273,
"source_file": "backend/src/main/java/com/magistr/app/controller/DatabaseController.java",
"status": "tentative",
"uses": 1
@@ -207,7 +228,7 @@
"q": "Как безопасно заменить tenant DataSource без потери рабочего подключения?"
}
],
"score": 1.589072495,
"score": 1.353214804,
"source_file": "backend/src/main/java/com/magistr/app/controller/DatabaseController.java",
"status": "preferred",
"uses": 2
@@ -223,7 +244,7 @@
"q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'"
}
],
"score": 0.75572808,
"score": 0.643559327,
"source_file": "backend/src/main/java/com/magistr/app/controller/GlobalExceptionHandler.java",
"status": "tentative",
"uses": 1
@@ -244,7 +265,7 @@
"q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?"
}
],
"score": 1.752429602,
"score": 1.492325672,
"source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleController.java",
"status": "preferred",
"uses": 2
@@ -260,7 +281,7 @@
"q": "Как безопасно валидировать и сохранять точечные изменения расписания?"
}
],
"score": 0.78890947,
"score": 0.671815777,
"source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleOverrideController.java",
"status": "tentative",
"uses": 1
@@ -281,11 +302,27 @@
"q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'"
}
],
"score": 1.549927354,
"score": 1.319879771,
"source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java",
"status": "preferred",
"uses": 2
},
"backend_src_main_java_com_magistr_app_model_academiccalendar_academiccalendar": {
"code_fingerprint": "5bdd7da771fe97443661a5bd06bed94f453ea036759c4de8c927ed68eb2b723d",
"label": "AcademicCalendar",
"last": "2026-07-22T21:09:57.015227+00:00",
"provenance": [
{
"date": "2026-07-22T21:09:57.015227+00:00",
"outcome": "useful",
"q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу"
}
],
"score": 0.851581632,
"source_file": "backend/src/main/java/com/magistr/app/model/AcademicCalendar.java",
"status": "tentative",
"uses": 1
},
"backend_src_main_java_com_magistr_app_model_classroom_classroom": {
"code_fingerprint": "5614d83b8b7e20fd2b76271b28a8ef11ffc137808ec2d7ed7cd23e42e0ab93ec",
"label": "Classroom",
@@ -297,11 +334,27 @@
"q": "Почему в выборе аудитории показаны корпус и этаж?"
}
],
"score": 0.976851438,
"score": 0.831862505,
"source_file": "backend/src/main/java/com/magistr/app/model/Classroom.java",
"status": "tentative",
"uses": 1
},
"backend_src_main_java_com_magistr_app_model_department_department": {
"code_fingerprint": "2948555ebc816c44c9f745ce199b0a908930bf6c82cb4a0bd46c23ffac42ea6a",
"label": "Department",
"last": "2026-07-22T21:09:57.015227+00:00",
"provenance": [
{
"date": "2026-07-22T21:09:57.015227+00:00",
"outcome": "useful",
"q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу"
}
],
"score": 0.851581632,
"source_file": "backend/src/main/java/com/magistr/app/model/Department.java",
"status": "tentative",
"uses": 1
},
"backend_src_main_java_com_magistr_app_model_schedulerule_schedulerule": {
"code_fingerprint": "692d61c1bfd5b46f5865174dde8cf2d962d2ccd124b5e4320e2ba8535bb29605",
"label": "ScheduleRule",
@@ -318,7 +371,7 @@
"q": "Корректны ли inferred-связи вокруг ScheduleRule?"
}
],
"score": 1.448240567,
"score": 1.23328582,
"source_file": "backend/src/main/java/com/magistr/app/model/ScheduleRule.java",
"status": "preferred",
"uses": 2
@@ -334,7 +387,7 @@
"q": "Какие связи затрагивает полная валидация правил расписания в исправлении №7?"
}
],
"score": 0.794199275,
"score": 0.676320444,
"source_file": "backend/src/main/java/com/magistr/app/model/ScheduleRuleSlot.java",
"status": "tentative",
"uses": 1
@@ -342,16 +395,37 @@
"backend_src_main_java_com_magistr_app_model_semester_semester": {
"code_fingerprint": "52546b552fff16ab841a63ea80fb806f6cc32edc0615ec53b3c002543d692f24",
"label": "Semester",
"last": "2026-07-21T19:52:13.631700+00:00",
"last": "2026-07-22T21:09:57.015227+00:00",
"provenance": [
{
"date": "2026-07-22T21:09:57.015227+00:00",
"outcome": "useful",
"q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу"
},
{
"date": "2026-07-21T19:52:13.631700+00:00",
"outcome": "useful",
"q": "в дополнительные фильры просмотра расписаний нужно добавить выбор семестра"
}
],
"score": 0.975949456,
"score": 1.682676032,
"source_file": "backend/src/main/java/com/magistr/app/model/Semester.java",
"status": "preferred",
"uses": 2
},
"backend_src_main_java_com_magistr_app_model_studentgroup_studentgroup": {
"code_fingerprint": "c4a022d9dd493adcfcf8bce3abd264e78d5539b45316d9e0aaef72f1b15091ac",
"label": "StudentGroup",
"last": "2026-07-22T21:09:57.015227+00:00",
"provenance": [
{
"date": "2026-07-22T21:09:57.015227+00:00",
"outcome": "useful",
"q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу"
}
],
"score": 0.851581632,
"source_file": "backend/src/main/java/com/magistr/app/model/StudentGroup.java",
"status": "tentative",
"uses": 1
},
@@ -366,7 +440,7 @@
"q": "Какие связи затрагивает полная валидация правил расписания в исправлении №7?"
}
],
"score": 0.794199275,
"score": 0.676320444,
"source_file": "backend/src/main/java/com/magistr/app/repository/SemesterRepository.java",
"status": "tentative",
"uses": 1
@@ -387,7 +461,7 @@
"q": "Как безопасно валидировать и сохранять точечные изменения расписания?"
}
],
"score": 1.764858926,
"score": 1.502910177,
"source_file": "backend/src/main/java/com/magistr/app/service/ScheduleQueryService.java",
"status": "preferred",
"uses": 2
@@ -403,7 +477,7 @@
"q": "Корректны ли inferred-связи вокруг ScheduleRule?"
}
],
"score": 0.654041293,
"score": 0.556965376,
"source_file": "backend/src/test/java/com/magistr/app/model/ScheduleRuleTest.java",
"status": "tentative",
"uses": 1
@@ -419,10 +493,95 @@
"q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?"
}
],
"score": 0.776480146,
"score": 0.661231273,
"source_file": "compose.yaml",
"status": "tentative",
"uses": 1
},
"compose_db_service": {
"code_fingerprint": "944ed05aa3bb66491e0622baa9659fc2db3115c79076325ebe243aeb84ca09f9",
"label": "PostgreSQL-сервис Docker Compose",
"last": "2026-07-29T19:59:04.551881+00:00",
"provenance": [
{
"date": "2026-07-29T19:59:04.551881+00:00",
"outcome": "useful",
"q": "новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше"
}
],
"score": 0.999937245,
"source_file": "compose.yaml",
"status": "tentative",
"uses": 1
},
"docs_database_flyway_migrations": {
"code_fingerprint": "2f5d4ce61ba0f5d8a9141f4ac33375dfc26a68e3bdccdc4269cf2a4f45a50176",
"label": "Flyway-миграции",
"last": "2026-07-29T19:26:44.188240+00:00",
"provenance": [
{
"date": "2026-07-29T19:26:44.188240+00:00",
"outcome": "useful",
"q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
}
],
"score": 0.999418524,
"source_file": "docs/DATABASE.md",
"status": "tentative",
"uses": 1
},
"docs_infrastructure_jwt_secret_policy": {
"code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1",
"label": "Политика JWT-секрета",
"last": "2026-07-29T19:26:44.188240+00:00",
"provenance": [
{
"date": "2026-07-29T19:26:44.188240+00:00",
"outcome": "useful",
"q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
}
],
"score": 0.999418524,
"source_file": "docs/INFRASTRUCTURE.md",
"status": "tentative",
"uses": 1
},
"docs_infrastructure_kubernetes_production": {
"code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1",
"label": "Production-инфраструктура Kubernetes",
"last": "2026-07-29T19:59:04.551881+00:00",
"provenance": [
{
"date": "2026-07-29T19:59:04.551881+00:00",
"outcome": "useful",
"q": "новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше"
},
{
"date": "2026-07-29T19:26:44.188240+00:00",
"outcome": "useful",
"q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
}
],
"score": 1.999355769,
"source_file": "docs/INFRASTRUCTURE.md",
"status": "preferred",
"uses": 2
},
"docs_infrastructure_tenants_configmap": {
"code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1",
"label": "Tenants ConfigMap",
"last": "2026-07-29T19:26:44.188240+00:00",
"provenance": [
{
"date": "2026-07-29T19:26:44.188240+00:00",
"outcome": "useful",
"q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
}
],
"score": 0.999418524,
"source_file": "docs/INFRASTRUCTURE.md",
"status": "tentative",
"uses": 1
}
},
"version": 1

View File

@@ -0,0 +1,26 @@
---
type: "query"
date: "2026-07-29T19:26:44.188240+00:00"
question: "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?"
contributor: "graphify"
outcome: "useful"
source_nodes: ["Workflow сборки и публикации Docker-образов", "Production-инфраструктура Kubernetes", "Flyway-миграции", "Политика JWT-секрета", "Tenants ConfigMap"]
---
# Q: теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?
## Answer
Expanded from original query via vocab: [auth, cookie, database, docker, flyway, jwt, kubernetes, production, refresh, secret, secure, workflow]. Прямой push в main для первого rollout небезопасен: workflow меняет только image digests, а актуальные ../k8s манифесты находятся вне Git-корня и не применяются. В действующем кластере отсутствуют tenants-secret и otel-postgres-secret, а app-secret не содержит JWT_SECRET. Для консолидированной V1 нужно полностью пересоздать все tenant-БД, затем выполнить первый rollout вручную по digest через ../k8s/deploy.sh. Инструкция и ограничения rollback обновлены в STARTUP_GUIDE.md.
## Outcome
- Signal: useful
## Source Nodes
- Workflow сборки и публикации Docker-образов
- Production-инфраструктура Kubernetes
- Flyway-миграции
- Политика JWT-секрета
- Tenants ConfigMap

View File

@@ -0,0 +1,24 @@
---
type: "query"
date: "2026-07-29T19:59:04.551881+00:00"
question: "новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше"
contributor: "graphify"
outcome: "useful"
source_nodes: ["Workflow сборки и публикации Docker-образов", "Production-инфраструктура Kubernetes", "PostgreSQL-сервис Docker Compose"]
---
# Q: новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше
## Answer
Expanded from original query via vocab: [auth, database, flyway, jwt, kubernetes, postgres, production, secret, workflow]. Граф связал workflow сборки immutable Docker-образов, production-инфраструктуру Kubernetes и tenant PostgreSQL. Проверка исходников и кластера подтвердила: консолидированная V1 проходит на чистом PostgreSQL, push в main запускает image-only rollout, а новые манифесты ../k8s нужно применить вручную. До push необходимо создать JWT_SECRET в app-secret, tenants-secret и otel-postgres-secret; значения секретов не читались и не изменялись.
## Outcome
- Signal: useful
## Source Nodes
- Workflow сборки и публикации Docker-образов
- Production-инфраструктура Kubernetes
- PostgreSQL-сервис Docker Compose

View File

@@ -0,0 +1,25 @@
---
type: "query"
date: "2026-07-29T20:12:38.880629+00:00"
question: "сам можешь выполнить эти действия?"
contributor: "graphify"
outcome: "useful"
source_nodes: ["Workflow сборки и публикации Docker-образов", "Production-инфраструктура Kubernetes", "Job деплоя в Kubernetes", "Политика JWT-секрета"]
---
# Q: сам можешь выполнить эти действия?
## Answer
Expanded from original query via vocab: [workflow, production, kubernetes, secret, jwt, tenant, postgres, otel, gitea, main, registry, flyway]. Первый traversal по перегруженному main был нерелевантен; повторный запрос без main связал Workflow сборки и публикации Docker-образов, Production-инфраструктуру Kubernetes, Job деплоя в Kubernetes и Политику JWT-секрета. По отдельному разрешению старый backend масштабирован до 0, обе tenant-БД read-only проверены как пустые и имеющие CREATE, в app-secret добавлен новый JWT_SECRET без вывода значения, созданы переходные tenants-secret и otel-postgres-secret. Workflow изменён так, что push выполняет build/scan, а deploy разрешён только ручному workflow_dispatch. Server dry-run выявил immutable roleRef; внешний rbac.yaml исправлен новым именем backend-tenant-secret-binding, повторный dry-run прошёл.
## Outcome
- Signal: useful
## Source Nodes
- Workflow сборки и публикации Docker-образов
- Production-инфраструктура Kubernetes
- Job деплоя в Kubernetes
- Политика JWT-секрета

View File

@@ -1,30 +1,39 @@
# Lessons
_Auto-generated by `graphify reflect` from 11 session memories in graphify-out/memory/. Deterministic; no LLM. Use for orientation — verify before relying, and revisit dead ends if the code has changed since._
_Auto-generated by `graphify reflect` from 14 session memories in graphify-out/memory/. Deterministic; no LLM. Use for orientation — verify before relying, and revisit dead ends if the code has changed since._
## Summary
- 10 useful · 1 dead ends · 0 corrected · 0 unmarked
- 13 useful · 1 dead ends · 0 corrected · 0 unmarked
## Lessons
**Preferred sources** — corroborated by ≥2 useful results; start here.
- `ScheduleGeneratorService` (3× useful)
- `TenantRoutingDataSource` (3× useful)
- `Production-инфраструктура Kubernetes` (2× useful)
- `Workflow сборки и публикации Docker-образов` (2× useful)
- `TenantConfigWatcher` (3× useful)
- `AuthorizationInterceptor` (3× useful)
- `Semester` (2× useful)
- `ScheduleQueryService` (2× useful)
- `ScheduleController.java` (2× useful)
- `DatabaseController` (2× useful)
- `ScheduleGeneratorService` (2× useful)
- `ScheduleRuleAdminController` (2× useful)
- `ScheduleRule` (2× useful)
**Tentative** — useful in fewer than 2 results; verify before relying.
- `PostgreSQL-сервис Docker Compose` (1× useful)
- `Flyway-миграции` (1× useful)
- `Tenants ConfigMap` (1× useful)
- `Политика JWT-секрета` (1× useful)
- `AcademicCalendar` (1× useful)
- `Department` (1× useful)
- `StudentGroup` (1× useful)
- `Classroom` (1× useful)
- `ClassroomController.java` (1× useful)
- `Semester` (1× useful)
- `DataInitializer` (1× useful)
- `TenantConfig` (1× useful)
- `ScheduleRuleSlot` (1× useful)