diff --git a/apps/sso-core/docker-entrypoint.sh b/apps/sso-core/docker-entrypoint.sh index 67d0678..81ec6fd 100644 --- a/apps/sso-core/docker-entrypoint.sh +++ b/apps/sso-core/docker-entrypoint.sh @@ -1,13 +1,22 @@ #!/bin/sh set -e -echo "[sso-core] Применение схемы БД (Prisma)..." +echo "[sso-core] Применение схемы БД (Prisma migrate deploy → db push)..." attempt=0 max_attempts=30 +apply_prisma_schema() { + if npm --workspace @lendry/sso-core run prisma:migrate-deploy; then + echo "[sso-core] Миграции Prisma применены (migrate deploy)" + return 0 + fi + echo "[sso-core] migrate deploy не выполнен — пробуем db push..." + npm --workspace @lendry/sso-core run prisma:push +} + while [ "$attempt" -lt "$max_attempts" ]; do attempt=$((attempt + 1)) - if npm --workspace @lendry/sso-core run prisma:push; then + if apply_prisma_schema; then echo "[sso-core] Схема БД синхронизирована" break fi diff --git a/apps/sso-core/package.json b/apps/sso-core/package.json index b52fbdb..102e72a 100644 --- a/apps/sso-core/package.json +++ b/apps/sso-core/package.json @@ -10,6 +10,7 @@ "prisma:format": "prisma format --schema prisma/schema.prisma", "prisma:generate": "prisma generate --schema prisma/schema.prisma", "prisma:push": "prisma db push --schema prisma/schema.prisma --accept-data-loss", + "prisma:migrate-deploy": "prisma migrate deploy --schema prisma/schema.prisma", "proto:generate": "node scripts/generate-proto-types.mjs" }, "dependencies": { diff --git a/apps/sso-core/prisma/migrations/20260701120000_add_user_activity_log/migration.sql b/apps/sso-core/prisma/migrations/20260701120000_add_user_activity_log/migration.sql new file mode 100644 index 0000000..416c13b --- /dev/null +++ b/apps/sso-core/prisma/migrations/20260701120000_add_user_activity_log/migration.sql @@ -0,0 +1,34 @@ +-- CreateTable +CREATE TABLE IF NOT EXISTS "UserActivityLog" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "action" TEXT NOT NULL, + "title" TEXT NOT NULL, + "detail" TEXT, + "entityType" TEXT, + "entityId" TEXT, + "ipAddress" TEXT, + "userAgent" TEXT, + "actorId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "UserActivityLog_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "UserActivityLog_userId_createdAt_idx" ON "UserActivityLog"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "UserActivityLog_userId_action_idx" ON "UserActivityLog"("userId", "action"); + +-- AddForeignKey +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'UserActivityLog_userId_fkey' + ) THEN + ALTER TABLE "UserActivityLog" + ADD CONSTRAINT "UserActivityLog_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + END IF; +END $$; diff --git a/apps/sso-core/prisma/migrations/migration_lock.toml b/apps/sso-core/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..99e4f20 --- /dev/null +++ b/apps/sso-core/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" diff --git a/install.sh b/install.sh index 8a471aa..f063b87 100644 --- a/install.sh +++ b/install.sh @@ -10,7 +10,7 @@ set -euo pipefail -SCRIPT_VERSION="2.5.0" +SCRIPT_VERSION="2.6.0" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$ROOT_DIR" @@ -75,6 +75,7 @@ ${BOLD}Lendry ID v${SCRIPT_VERSION}${NC} — установка и управл ./install.sh --configure-domains Изменить домены / Nginx / SSL ./install.sh --renew-ssl Обновить сертификаты (Let's Encrypt / custom / selfsigned) ./install.sh --restart Перезапуск контейнеров + ./install.sh --migrate-rebuild Миграции Prisma + пересборка стека (после git pull) ./install.sh --docker-prune Только очистка Docker (без пересборки) ./install.sh --fix-proxy Исправить 502: host Nginx + порты 3000/3002/3003 ./install.sh --fix-all Комплексное исправление: 502, прокси, порты, Nginx @@ -157,6 +158,7 @@ parse_args() { --configure-domains) ACTION="configure-domains"; shift ;; --renew-ssl) ACTION="renew-ssl"; shift ;; --restart) ACTION="restart"; shift ;; + --migrate-rebuild) ACTION="migrate-rebuild"; shift ;; --docker-prune) ACTION="docker-prune"; shift ;; --skip-docker-prune) SKIP_DOCKER_PRUNE=1; shift ;; --docker-prune-aggressive) DOCKER_PRUNE_AGGRESSIVE=1; shift ;; @@ -1462,6 +1464,87 @@ action_reset_db() { save_infra_secrets } +# Prisma migrate deploy (fallback db push) — без перезапуска всего стека. +run_prisma_migrations() { + [[ -f .env ]] || fail "Файл .env не найден" + load_env + prepare_compose_stack + build_compose_stack_cmd + + if ! docker_cmd "${COMPOSE_STACK_CMD[@]}" ps --status running postgres 2>/dev/null | grep -q postgres; then + warn "PostgreSQL не запущен — поднимаем..." + compose_build_and_up postgres + fi + wait_for_service postgres 90 + verify_postgres_auth || true + + log "Сборка образа sso-core для миграций..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" build sso-core + + local migrate_script + migrate_script='set -e +if npm --workspace @lendry/sso-core run prisma:migrate-deploy; then + echo "[install] Prisma migrate deploy: OK" +else + echo "[install] migrate deploy не выполнен — fallback db push" + npm --workspace @lendry/sso-core run prisma:push +fi' + + if docker_cmd inspect --format='{{.State.Running}}' lendry-id-sso-core 2>/dev/null | grep -q true; then + log "Применение миграций через контейнер lendry-id-sso-core..." + docker_cmd exec lendry-id-sso-core sh -c "$migrate_script" || fail "Не удалось применить миграции Prisma" + else + log "Применение миграций через одноразовый контейнер sso-core..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" run --rm --no-deps --entrypoint sh sso-core -c "$migrate_script" \ + || fail "Не удалось применить миграции Prisma" + fi + + ok "Миграции Prisma применены" +} + +# После обновления кода: миграции БД + пересборка backend/frontend. +action_migrate_rebuild() { + [[ -f .env ]] || fail "Файл .env не найден — сначала выполните ./install.sh --install" + load_env + prepare_compose_stack + + echo "" + echo -e "${BOLD}Миграция БД и пересборка стека${NC}" + echo " (Prisma migrate deploy, sso-core, api-gateway, frontend, docs, media-ws)" + echo "" + + log "Шаг 1/4: PostgreSQL и инфраструктура..." + compose_build_and_up postgres redis rabbitmq minio + wait_for_service postgres 90 + verify_postgres_auth + + log "Шаг 2/4: Миграции Prisma..." + run_prisma_migrations + + log "Шаг 3/4: Пересборка backend и frontend..." + compose_build_and_up ldap-auth sso-core + wait_for_service sso-core 120 + compose_build_and_up api-gateway + wait_for_service api-gateway 90 + wait_for_api_grpc_ready 60 || warn "gRPC api-gateway → sso-core не готов" + compose_build_and_up frontend docs media-ws + wait_for_service frontend 90 + wait_for_service docs 60 + + log "Шаг 4/4: Nginx и проверка..." + refresh_host_nginx_configs || true + sync_nginx_after_api_gateway_restart || true + sync_nginx_after_edge_restart || true + reload_docker_nginx || true + diagnose_common_issues || true + + ok "Миграция и пересборка завершены" + echo "" + echo " После git pull используйте этот пункт или: ./install.sh --migrate-rebuild --yes" + echo "" + show_status +} + persist_domain_env() { write_env_secrets_if_missing @@ -3479,6 +3562,7 @@ print_summary() { echo "" print_intranet_hint echo -e " ${BOLD}Управление:${NC} ./install.sh" + echo -e " ${BOLD}После git pull:${NC} ./install.sh --migrate-rebuild" echo -e " ${BOLD}Смена доменов:${NC} ./install.sh --configure-domains" echo -e " ${BOLD}Логи:${NC} docker compose logs -f api-gateway nginx" echo -e " ${BOLD}Очистка Docker:${NC} ./install.sh --docker-prune" @@ -4071,15 +4155,19 @@ action_fix_all_errors() { echo " (502 Bad Gateway, /idp-api, Docker Nginx lendry-id-nginx, порты upstream)" echo "" - log "Шаг 1/6: диагностика..." + log "Шаг 1/7: диагностика..." diagnose_common_issues || true - log "Шаг 2/6: Docker Nginx — остановка system nginx, освобождение 80/443..." + log "Шаг 2/7: Docker Nginx — остановка system nginx, освобождение 80/443..." ensure_docker_nginx_mode_for_fix_all write_compose_override ensure_split_domain_public_urls - log "Шаг 3/6: пересборка ldap-auth → sso-core → api-gateway..." + log "Шаг 3/7: миграции PostgreSQL (Prisma)..." + compose_build_and_up postgres 2>/dev/null || true + run_prisma_migrations || warn "Миграции Prisma не применены — sso-core попробует при старте" + + log "Шаг 4/7: пересборка ldap-auth → sso-core → api-gateway..." compose_build_and_up ldap-auth wait_for_service "ldap-auth" 90 compose_build_and_up sso-core @@ -4089,7 +4177,7 @@ action_fix_all_errors() { wait_for_api_grpc_ready 90 || compose_build_and_up api-gateway sync_nginx_after_api_gateway_restart - log "Шаг 4/6: пересборка frontend (same-origin /idp-api), docs, media-ws..." + log "Шаг 5/7: пересборка frontend (same-origin /idp-api), docs, media-ws..." compose_build_and_up frontend docs media-ws wait_for_service "frontend" 90 wait_for_service "docs" 60 @@ -4097,7 +4185,7 @@ action_fix_all_errors() { baked_api="$(docker_cmd exec lendry-id-frontend printenv NEXT_PUBLIC_API_URL 2>/dev/null || true)" log "frontend NEXT_PUBLIC_API_URL=${baked_api:-не задан} (браузер SPA использует /idp-api на SSO)" - log "Шаг 5/6: Docker Nginx — конфиги в ./nginx/conf.d и контейнер lendry-id-nginx..." + log "Шаг 6/7: Docker Nginx — конфиги в ./nginx/conf.d и контейнер lendry-id-nginx..." ensure_nginx_gateway_watch_script patch_legacy_nginx_proxy_pass local ssl_type @@ -4137,7 +4225,7 @@ action_fix_all_errors() { fi ok "Docker Nginx запущен — проверьте: docker ps | grep lendry-id-nginx" - log "Шаг 6/6: финальная проверка (HTTPS + CORS preflight)..." + log "Шаг 7/7: финальная проверка (HTTPS + CORS preflight)..." diagnose_common_issues || true check_https_api_with_origin || warn "Проверка cross-origin API не прошла — см. вывод выше" @@ -4183,6 +4271,7 @@ show_menu() { echo " 2) Настроить / изменить домены и Nginx + SSL" echo " 3) SSL-сертификаты (обновить / включить custom / Let's Encrypt)" echo " 4) Перезапуск / пересборка контейнеров (+ очистка Docker)" + echo " 11) Миграция БД и пересборка (после git pull)" echo " 5) Статус сервисов" echo " 6) Удалить конфиги Nginx IdP" echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)" @@ -4192,7 +4281,7 @@ show_menu() { echo "" local choice - read -r -p "Выберите пункт [0-10]: " choice + read -r -p "Выберите пункт [0-11]: " choice case "$choice" in 1) NON_INTERACTIVE=0; action_full_install ;; @@ -4200,6 +4289,7 @@ show_menu() { 2) NON_INTERACTIVE=0; action_configure_domains ;; 3) action_renew_ssl ;; 4) action_restart ;; + 11) action_migrate_rebuild ;; 5) show_status ;; 6) remove_nginx_configs; ok "Готово" ;; 7) action_reset_db; action_restart ;; @@ -4225,6 +4315,7 @@ main() { configure-domains) action_configure_domains ;; renew-ssl) action_renew_ssl ;; restart) action_restart ;; + migrate-rebuild) action_migrate_rebuild ;; docker-prune) action_docker_prune ;; fix-proxy) action_fix_host_proxy ;; fix-all) action_fix_all_errors ;;