From 5c6309e2289414495be66b5e13cdd2527bd0b3f5 Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 14 Jan 2026 18:47:34 +0700 Subject: [PATCH 1/6] NCBACK-33 fix check company name --- .../handler/validator/RegRequestValidator.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java index f3dbda7..19d4c77 100644 --- a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java +++ b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java @@ -13,7 +13,7 @@ import java.util.*; @Component public class RegRequestValidator implements Validator { - private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()]{0,200}$"; + private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()\"\"]{1,200}$"; private static final String NAME_REGEX = "^[a-zA-Zа-яА-ЯёЁ\\s\\-'.]{2,100}$"; @@ -74,21 +74,6 @@ public class RegRequestValidator implements Validator { errors.rejectValue("companyName", "companyName.invalid.chars", "Company name contains invalid characters"); } - - validateForbiddenWords(trimmedCompany, "companyName", errors, - Arrays.asList("admin", "root", "system", "test")); - } - - private void validateForbiddenWords(String text, String fieldName, - Errors errors, List forbiddenWords) { - String lowerText = text.toLowerCase(); - for (String word : forbiddenWords) { - if (lowerText.contains(word)) { - errors.rejectValue(fieldName, fieldName + ".forbidden.word", - "Contains forbidden word: " + word); - break; - } - } } private void validateEmail(String email, Errors errors) { From d3e50aa8d151caace253ad0d8256e9b2fc017777 Mon Sep 17 00:00:00 2001 From: vladp Date: Wed, 14 Jan 2026 19:10:22 +0700 Subject: [PATCH 2/6] NCBACK-19 add all case for json --- src/main/java/ru/soune/nocopy/dto/BaseRequest.java | 2 ++ src/main/java/ru/soune/nocopy/dto/BaseResponse.java | 2 ++ src/main/java/ru/soune/nocopy/dto/LoginRequest.java | 2 ++ src/main/java/ru/soune/nocopy/dto/RegRequest.java | 2 ++ src/main/java/ru/soune/nocopy/dto/UserRequest.java | 1 + 5 files changed, 9 insertions(+) diff --git a/src/main/java/ru/soune/nocopy/dto/BaseRequest.java b/src/main/java/ru/soune/nocopy/dto/BaseRequest.java index b02ad8c..684e79a 100644 --- a/src/main/java/ru/soune/nocopy/dto/BaseRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/BaseRequest.java @@ -1,9 +1,11 @@ package ru.soune.nocopy.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) public class BaseRequest { @JsonProperty("version") Integer version; diff --git a/src/main/java/ru/soune/nocopy/dto/BaseResponse.java b/src/main/java/ru/soune/nocopy/dto/BaseResponse.java index b60419a..75f1543 100644 --- a/src/main/java/ru/soune/nocopy/dto/BaseResponse.java +++ b/src/main/java/ru/soune/nocopy/dto/BaseResponse.java @@ -1,11 +1,13 @@ package ru.soune.nocopy.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) public class BaseResponse { @JsonProperty("msg_id") private Integer msgId; diff --git a/src/main/java/ru/soune/nocopy/dto/LoginRequest.java b/src/main/java/ru/soune/nocopy/dto/LoginRequest.java index d64fa8b..b0548bc 100644 --- a/src/main/java/ru/soune/nocopy/dto/LoginRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/LoginRequest.java @@ -1,5 +1,6 @@ package ru.soune.nocopy.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; @@ -10,6 +11,7 @@ import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) public class LoginRequest { @NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128) diff --git a/src/main/java/ru/soune/nocopy/dto/RegRequest.java b/src/main/java/ru/soune/nocopy/dto/RegRequest.java index e08f404..d7adfea 100644 --- a/src/main/java/ru/soune/nocopy/dto/RegRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/RegRequest.java @@ -1,10 +1,12 @@ package ru.soune.nocopy.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.*; import lombok.Data; @Data +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) public class RegRequest { @NotEmpty(message = "Full name is required") private String fullName; diff --git a/src/main/java/ru/soune/nocopy/dto/UserRequest.java b/src/main/java/ru/soune/nocopy/dto/UserRequest.java index c5f1662..91f7379 100644 --- a/src/main/java/ru/soune/nocopy/dto/UserRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/UserRequest.java @@ -10,6 +10,7 @@ import ru.soune.nocopy.entity.GenderType; import java.time.LocalDate; @Data +@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) public class UserRequest { @Size(min = 2) private String fullName; From 82a57a2983c5b8d0b7c1f26bab5c4a7528c53cf0 Mon Sep 17 00:00:00 2001 From: vladp Date: Thu, 15 Jan 2026 11:09:05 +0700 Subject: [PATCH 3/6] NCBACK-32 add all case for json --- .../ru/soune/nocopy/handler/validator/RegRequestValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java index 19d4c77..e01df8e 100644 --- a/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java +++ b/src/main/java/ru/soune/nocopy/handler/validator/RegRequestValidator.java @@ -13,7 +13,7 @@ import java.util.*; @Component public class RegRequestValidator implements Validator { - private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()\"\"]{1,200}$"; + private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()\"\"«»„‟”“”‘'’‹›❛❜❝❞〝〞〟]{1,200}$"; private static final String NAME_REGEX = "^[a-zA-Zа-яА-ЯёЁ\\s\\-'.]{2,100}$"; From 1a6823f7a916ebbc9321942c3f688b3cb947e434 Mon Sep 17 00:00:00 2001 From: vladp Date: Thu, 15 Jan 2026 16:17:03 +0700 Subject: [PATCH 4/6] DEV_DB change db creds --- .env | 6 +- docker-compose.yaml | 19 ++-- infrastructure/jenkins/deploy.groovy | 129 ++++++++++++++------------- init-scripts/init-user.sql | 19 ++++ 4 files changed, 102 insertions(+), 71 deletions(-) create mode 100644 init-scripts/init-user.sql diff --git a/.env b/.env index d3e4347..e54b26f 100644 --- a/.env +++ b/.env @@ -1,10 +1,10 @@ POSTGRES_DB=no_copy_ -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres +POSTGRES_USER=ncp_db +POSTGRES_PASSWORD=ncpDbApp POSTGRES_PORT=5432 POSTGRES_HOST=postgres REDIS_HOST=redis REDIS_PORT=6379 -SERVER_PORT=8080 +SERVER_PORT=8080 \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 192b2d6..6a69921 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -18,7 +18,7 @@ services: restart: unless-stopped db: - image: postgres:17 + image: postgres:17.7 restart: always deploy: resources: @@ -30,14 +30,17 @@ services: memory: 1G environment: POSTGRES_DB: no_copy_ - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres +# POSTGRES_USER: postgres +# POSTGRES_PASSWORD: postgres + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_SHARED_BUFFERS: 512MB POSTGRES_EFFECTIVE_CACHE_SIZE: 1536MB ports: - "54320:5432" volumes: - pgdata:/var/lib/postgresql/data + - ./init-scripts:/docker-entrypoint-initdb.d:ro container_name: postgres networks: app-network: @@ -61,8 +64,10 @@ services: # FILE_CHUNK_SIZE: 1048576 FILE_CHUNK_SIZE: 1000000 POSTGRES_DB: no_copy_ - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres +# POSTGRES_USER: postgres +# POSTGRES_PASSWORD: postgres + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PORT: 5432 POSTGRES_HOST: db STORAGE_SERVICE_URL: http://storage:8081 @@ -82,6 +87,10 @@ services: - api volumes: - uploads_data:/data/uploads:rw + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d no_copy_" ] + interval: 10s + retries: 5 grafana: image: grafana/grafana:10.3.1 diff --git a/infrastructure/jenkins/deploy.groovy b/infrastructure/jenkins/deploy.groovy index 7611efe..b57f515 100644 --- a/infrastructure/jenkins/deploy.groovy +++ b/infrastructure/jenkins/deploy.groovy @@ -30,6 +30,7 @@ pipeline { } } + stage('Deploy with docker-compose') { steps { script { @@ -38,71 +39,73 @@ pipeline { credentialsId: 'server-root-password', usernameVariable: 'SSH_USER', passwordVariable: 'SSH_PASS' - ) + ), + string(credentialsId: 'db-user', variable: 'DB_USER'), + string(credentialsId: 'db-password', variable: 'DB_PASSWORD') ]) { sh """ - echo "Deploying branch: ${params.BRANCH}" - - echo "Copying files to server..." - sshpass -p '$SSH_PASS' ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER "mkdir -p /opt/deployments/${params.BRANCH}" - sshpass -p '$SSH_PASS' scp -r -o StrictHostKeyChecking=no ./* $SSH_USER@$SERVER:/opt/deployments/${params.BRANCH}/ - - sshpass -p '$SSH_PASS' ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER " - cd /opt/deployments/${params.BRANCH} - - echo '1. Остановка старого приложения...' - docker stop app-backend 2>/dev/null || echo 'Контейнер не найден' - docker rm app-backend 2>/dev/null || echo 'Контейнер не найден' - - echo '2. Удаление старых образов...' - docker images --filter 'reference=*app*' -q | xargs -r docker rmi -f 2>/dev/null || echo 'Нет образов для удаления' - - echo '3. Создание сети если нужно...' - docker network create app-network 2>/dev/null || echo 'Сеть уже существует' - - echo '4. Запуск инфраструктуры...' - docker-compose up -d db storage - - echo '5. Ожидание PostgreSQL...' - sleep 10 - - echo '6. Сборка нового образа приложения...' - docker build --no-cache -t app-backend:latest . - - echo '7. Запуск приложения...' - docker run -d \\ - --name app-backend \\ - --network app-network \\ - --network-alias app \\ - -p 80:8080 \\ - -v uploads_data:/data/uploads:rw \\ - -e POSTGRES_DB=no_copy_ \\ - -e POSTGRES_USER=postgres \\ - -e POSTGRES_PASSWORD=postgres \\ - -e POSTGRES_PORT=5432 \\ - -e POSTGRES_HOST=db \\ - --restart unless-stopped \\ - app-backend:latest - - echo '8. Запуск мониторинга...' - docker-compose up -d grafana prometheus loki tempo alloy - - echo '9. Проверка...' - sleep 5 - - echo 'Статус контейнеров:' - docker ps --format 'table {{.Names}}\\t{{.Image}}\\t{{.Status}}' - - echo '10. Проверка health...' - if curl -s -f http://localhost:80/health > /dev/null 2>&1; then - echo 'Приложение работает' - echo 'URL: http://${params.SERVER}:80' - else - echo 'Проверка health не удалась' - docker logs app-backend --tail=20 - fi - " - """ + echo "Deploying branch: ${params.BRANCH}" + + echo "Copying files to server..." + sshpass -p '$SSH_PASS' ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER "mkdir -p /opt/deployments/${params.BRANCH}" + sshpass -p '$SSH_PASS' scp -r -o StrictHostKeyChecking=no ./* $SSH_USER@$SERVER:/opt/deployments/${params.BRANCH}/ + + sshpass -p '$SSH_PASS' ssh -o StrictHostKeyChecking=no $SSH_USER@$SERVER " + cd /opt/deployments/${params.BRANCH} + + echo '1. Остановка старого приложения...' + docker stop app-backend 2>/dev/null || echo 'Контейнер не найден' + docker rm app-backend 2>/dev/null || echo 'Контейнер не найден' + + echo '2. Удаление старых образов...' + docker images --filter 'reference=*app*' -q | xargs -r docker rmi -f 2>/dev/null || echo 'Нет образов для удаления' + + echo '3. Создание сети если нужно...' + docker network create app-network 2>/dev/null || echo 'Сеть уже существует' + + echo '4. Запуск инфраструктуры...' + docker-compose up -d db storage + + echo '5. Ожидание PostgreSQL...' + sleep 10 + + echo '6. Сборка нового образа приложения...' + docker build --no-cache -t app-backend:latest . + + echo '7. Запуск приложения...' + docker run -d \\ + --name app-backend \\ + --network app-network \\ + --network-alias app \\ + -p 80:8080 \\ + -v uploads_data:/data/uploads:rw \\ + -e POSTGRES_DB=no_copy_ \\ + -e POSTGRES_USER=$DB_USER \\ + -e POSTGRES_PASSWORD=$DB_PASSWORD \\ + -e POSTGRES_PORT=5432 \\ + -e POSTGRES_HOST=db \\ + --restart unless-stopped \\ + app-backend:latest + + echo '8. Запуск мониторинга...' + docker-compose up -d grafana prometheus loki tempo alloy + + echo '9. Проверка...' + sleep 5 + + echo 'Статус контейнеров:' + docker ps --format 'table {{.Names}}\\t{{.Image}}\\t{{.Status}}' + + echo '10. Проверка health...' + if curl -s -f http://localhost:80/health > /dev/null 2>&1; then + echo 'Приложение работает' + echo 'URL: http://${params.SERVER}:80' + else + echo 'Проверка health не удалась' + docker logs app-backend --tail=20 + fi + " + """ } } } diff --git a/init-scripts/init-user.sql b/init-scripts/init-user.sql new file mode 100644 index 0000000..f1d560e --- /dev/null +++ b/init-scripts/init-user.sql @@ -0,0 +1,19 @@ +DO +$do$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'ncp_db') THEN + CREATE USER ncp_db WITH PASSWORD 'ncpDbApp'; +END IF; +END +$do$; + +DO +$do$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_database WHERE datname = 'no_copy_') THEN + CREATE DATABASE no_copy_ OWNER ncp_db; +END IF; +END +$do$; + +GRANT ALL PRIVILEGES ON DATABASE no_copy_ TO ncp_db; \ No newline at end of file From de810e32b473dd55acddf63a71d223b512b90f81 Mon Sep 17 00:00:00 2001 From: vladp Date: Thu, 15 Jan 2026 16:42:37 +0700 Subject: [PATCH 5/6] DEV_DB change db creds --- README.md | 48 ++++++++++++++++++++++++++++ infrastructure/jenkins/deploy.groovy | 4 +-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e69de29..72cd929 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,48 @@ +суперпользователь БД: +postgres/postgres +пользователь бд для бэка +ncp_db / ncpDbApp + +Подключение к БД для приложения,если volume не существует : + +Создаться автоматически. + +Если уже существует volume : + +docker exec -it postgres psql -U postgres -d postgres + +CREATE USER ncp_db WITH PASSWORD 'ncpDbApp'; + +GRANT ALL PRIVILEGES ON DATABASE no_copy_ TO ncp_db; + +\du + +\q + +------- + +psql -U postgres -d no_copy_ + +-- база + +GRANT CONNECT ON DATABASE no_copy_ TO ncp_db; + +-- схема + +GRANT USAGE ON SCHEMA public TO ncp_db; + +-- существующие таблицы + +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ncp_db; + +-- существующие sequence (очень важно для id) + +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ncp_db; + +-- будущие таблицы + +ALTER DEFAULT PRIVILEGES IN SCHEMA public +GRANT ALL ON TABLES TO ncp_db; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public +GRANT ALL ON SEQUENCES TO ncp_db; diff --git a/infrastructure/jenkins/deploy.groovy b/infrastructure/jenkins/deploy.groovy index b57f515..dc09c2e 100644 --- a/infrastructure/jenkins/deploy.groovy +++ b/infrastructure/jenkins/deploy.groovy @@ -40,8 +40,8 @@ pipeline { usernameVariable: 'SSH_USER', passwordVariable: 'SSH_PASS' ), - string(credentialsId: 'db-user', variable: 'DB_USER'), - string(credentialsId: 'db-password', variable: 'DB_PASSWORD') + string(credentialsId: 'DB_USER', variable: 'DB_USER'), + string(credentialsId: 'DB_PASSWORD', variable: 'DB_PASSWORD') ]) { sh """ echo "Deploying branch: ${params.BRANCH}" From 0ed3f958ffeb3a4469c13b9466ddd857390b063a Mon Sep 17 00:00:00 2001 From: vladp Date: Thu, 15 Jan 2026 16:52:33 +0700 Subject: [PATCH 6/6] DEV_DB change db creds --- init-scripts/01-init.sql | 19 +++++++++++++++++++ init-scripts/init-user.sql | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 init-scripts/01-init.sql delete mode 100644 init-scripts/init-user.sql diff --git a/init-scripts/01-init.sql b/init-scripts/01-init.sql new file mode 100644 index 0000000..60bedbc --- /dev/null +++ b/init-scripts/01-init.sql @@ -0,0 +1,19 @@ +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'ncp_db') THEN + CREATE USER ncp_db WITH PASSWORD 'ncpDbApp'; +END IF; +END +$$; + +GRANT CONNECT ON DATABASE no_copy_ TO ncp_db; +GRANT USAGE ON SCHEMA public TO ncp_db; + +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ncp_db; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ncp_db; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public +GRANT ALL ON TABLES TO ncp_db; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public +GRANT ALL ON SEQUENCES TO ncp_db; \ No newline at end of file diff --git a/init-scripts/init-user.sql b/init-scripts/init-user.sql deleted file mode 100644 index f1d560e..0000000 --- a/init-scripts/init-user.sql +++ /dev/null @@ -1,19 +0,0 @@ -DO -$do$ -BEGIN - IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'ncp_db') THEN - CREATE USER ncp_db WITH PASSWORD 'ncpDbApp'; -END IF; -END -$do$; - -DO -$do$ -BEGIN - IF NOT EXISTS (SELECT FROM pg_database WHERE datname = 'no_copy_') THEN - CREATE DATABASE no_copy_ OWNER ncp_db; -END IF; -END -$do$; - -GRANT ALL PRIVILEGES ON DATABASE no_copy_ TO ncp_db; \ No newline at end of file