Compare commits

..

No commits in common. "main" and "release/first" have entirely different histories.

14 changed files with 528 additions and 1959 deletions

View File

@ -53,8 +53,7 @@ steps:
path: /root/.nuget/packages path: /root/.nuget/packages
commands: commands:
- cd flea - cd flea
- mkdir -p /root/.nuget/NuGet - dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
- cp nuget.config /root/.nuget/NuGet/NuGet.Config
- echo "🔄 Restoring all projects..." - echo "🔄 Restoring all projects..."
- dotnet restore telegram-listener/Nocr.TelegramListener.sln - dotnet restore telegram-listener/Nocr.TelegramListener.sln
- dotnet restore telegram-client/Nocr.TelegramClient.sln - dotnet restore telegram-client/Nocr.TelegramClient.sln
@ -95,7 +94,6 @@ steps:
depends_on: depends_on:
- dotnet-build - dotnet-build
- docker - docker
--- ---
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 📝 Pipeline 2: Main Branch Validation # 📝 Pipeline 2: Main Branch Validation
@ -148,8 +146,7 @@ steps:
path: /root/.nuget/packages path: /root/.nuget/packages
commands: commands:
- cd flea - cd flea
- mkdir -p /root/.nuget/NuGet - dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
- cp nuget.config /root/.nuget/NuGet/NuGet.Config
- dotnet restore telegram-listener/Nocr.TelegramListener.sln - dotnet restore telegram-listener/Nocr.TelegramListener.sln
- dotnet restore telegram-client/Nocr.TelegramClient.sln - dotnet restore telegram-client/Nocr.TelegramClient.sln
- dotnet restore text-matcher/Nocr.TextMatcher.sln - dotnet restore text-matcher/Nocr.TextMatcher.sln
@ -204,6 +201,8 @@ trigger:
- refs/tags/* - refs/tags/*
event: event:
- tag - tag
branch:
- issues/*
clone: clone:
disable: true disable: true
@ -224,10 +223,10 @@ steps:
- name: check-trigger - name: check-trigger
image: alpine/git image: alpine/git
commands: commands:
- cd flea
- COMMIT_MSG=$(git log -1 --pretty=%B)
- echo "Commit message - $COMMIT_MSG"
- | - |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
echo "Commit message - $COMMIT_MSG"
if echo "$COMMIT_MSG" | grep -q "contracts_only:"; then if echo "$COMMIT_MSG" | grep -q "contracts_only:"; then
echo "✅ contracts_only detected, proceeding..." echo "✅ contracts_only detected, proceeding..."
exit 0 exit 0
@ -247,13 +246,12 @@ steps:
NUGETAPIKEY: NUGETAPIKEY:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea
- COMMIT_MSG=$(git log -1 --pretty=%B)
- | - |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
if echo "$COMMIT_MSG" | grep -q "contracts_only:telegram_listener"; then if echo "$COMMIT_MSG" | grep -q "contracts_only:telegram_listener"; then
echo "📦 Publishing telegram-listener contracts..." echo "📦 Publishing telegram-listener contracts..."
mkdir -p /root/.nuget/NuGet dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
cp nuget.config /root/.nuget/NuGet/NuGet.Config
dotnet pack telegram-listener/Nocr.TelegramListener.sln -o ./bin -p:PackageVersion=${DRONE_TAG} dotnet pack telegram-listener/Nocr.TelegramListener.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
else else
@ -271,13 +269,12 @@ steps:
NUGETAPIKEY: NUGETAPIKEY:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea
- COMMIT_MSG=$(git log -1 --pretty=%B)
- | - |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
if echo "$COMMIT_MSG" | grep -q "contracts_only:text_matcher"; then if echo "$COMMIT_MSG" | grep -q "contracts_only:text_matcher"; then
echo "📦 Publishing text-matcher contracts..." echo "📦 Publishing text-matcher contracts..."
mkdir -p /root/.nuget/NuGet dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
cp nuget.config /root/.nuget/NuGet/NuGet.Config
dotnet pack text-matcher/Nocr.TextMatcher.sln -o ./bin -p:PackageVersion=${DRONE_TAG} dotnet pack text-matcher/Nocr.TextMatcher.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
else else
@ -285,6 +282,7 @@ steps:
fi fi
depends_on: depends_on:
- check-trigger - check-trigger
- telegram-listener-contracts
- name: users-contracts - name: users-contracts
image: mcr.microsoft.com/dotnet/sdk:8.0 image: mcr.microsoft.com/dotnet/sdk:8.0
@ -295,13 +293,12 @@ steps:
NUGETAPIKEY: NUGETAPIKEY:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea
- COMMIT_MSG=$(git log -1 --pretty=%B)
- | - |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
if echo "$COMMIT_MSG" | grep -q "contracts_only:users"; then if echo "$COMMIT_MSG" | grep -q "contracts_only:users"; then
echo "📦 Publishing users contracts..." echo "📦 Publishing users contracts..."
mkdir -p /root/.nuget/NuGet dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
cp nuget.config /root/.nuget/NuGet/NuGet.Config
dotnet pack users/Nocr.Users.sln -o ./bin -p:PackageVersion=${DRONE_TAG} dotnet pack users/Nocr.Users.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
else else
@ -309,7 +306,7 @@ steps:
fi fi
depends_on: depends_on:
- check-trigger - check-trigger
- text-matcher-contracts
--- ---
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 🚀 Pipeline 4: Full Release # 🚀 Pipeline 4: Full Release
@ -325,9 +322,11 @@ metadata:
trigger: trigger:
ref: ref:
- refs/tags/* - refs/tags/v*
event: event:
- tag - tag
branch:
- release/*
clone: clone:
disable: true disable: true
@ -348,10 +347,10 @@ steps:
- name: check-trigger - name: check-trigger
image: alpine/git image: alpine/git
commands: commands:
- cd flea
- COMMIT_MSG=$(git log -1 --pretty=%B)
- echo "Commit message - $COMMIT_MSG"
- | - |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
echo "Commit message - $COMMIT_MSG"
if echo "$COMMIT_MSG" | grep -qE "contracts_only:|deploy_only:"; then if echo "$COMMIT_MSG" | grep -qE "contracts_only:|deploy_only:"; then
echo "⏭️ contracts_only or deploy_only detected, skipping full release..." echo "⏭️ contracts_only or deploy_only detected, skipping full release..."
exit 78 exit 78
@ -376,8 +375,7 @@ steps:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea - cd flea
- mkdir -p /root/.nuget/NuGet - dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
- cp nuget.config /root/.nuget/NuGet/NuGet.Config
- dotnet pack telegram-listener/Nocr.TelegramListener.sln -o ./bin -p:PackageVersion=${DRONE_TAG} - dotnet pack telegram-listener/Nocr.TelegramListener.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
- dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate - dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
depends_on: depends_on:
@ -393,8 +391,7 @@ steps:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea - cd flea
- mkdir -p /root/.nuget/NuGet - dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
- cp nuget.config /root/.nuget/NuGet/NuGet.Config
- dotnet pack text-matcher/Nocr.TextMatcher.sln -o ./bin -p:PackageVersion=${DRONE_TAG} - dotnet pack text-matcher/Nocr.TextMatcher.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
- dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate - dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
depends_on: depends_on:
@ -411,8 +408,7 @@ steps:
from_secret: nuget_musk_api_key from_secret: nuget_musk_api_key
commands: commands:
- cd flea - cd flea
- mkdir -p /root/.nuget/NuGet - dotnet nuget add source --name musk https://gitea.musk.fun/api/packages/nocr/nuget/index.json
- cp nuget.config /root/.nuget/NuGet/NuGet.Config
- dotnet pack users/Nocr.Users.sln -o ./bin -p:PackageVersion=${DRONE_TAG} - dotnet pack users/Nocr.Users.sln -o ./bin -p:PackageVersion=${DRONE_TAG}
- dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate - dotnet nuget push ./bin/*Contract*.nupkg --api-key $NUGETAPIKEY --source musk --skip-duplicate
depends_on: depends_on:
@ -420,7 +416,7 @@ steps:
- text-matcher-nuget - text-matcher-nuget
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# STAGE 2: Build Docker Images with Kaniko (sequential) # STAGE 2: Build Docker Images with Kaniko (3 parallel streams)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- name: telegram-listener-build-push - name: telegram-listener-build-push
@ -433,20 +429,19 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/telegram-listener
- cp nuget.config telegram-listener/ - /kaniko/executor
- cd telegram-listener --context=.
- | --dockerfile=src/Nocr.TelegramListener.Host/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/telegram_listener:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/telegram_listener:${DRONE_TAG}
--dockerfile=src/Nocr.TelegramListener.Host/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/telegram_listener:latest
--destination=hub.musk.fun/k8s/nocr/telegram_listener:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/telegram_listener:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-telegram-listener
--destination=hub.musk.fun/k8s/nocr/telegram_listener:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-telegram-listener \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- telegram-listener-nuget
- text-matcher-nuget
- users-nuget - users-nuget
- name: telegram-client-build-push - name: telegram-client-build-push
@ -459,18 +454,15 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/telegram-client
- cp nuget.config telegram-client/ - /kaniko/executor
- cd telegram-client --context=.
- | --dockerfile=src/Nocr.TelegramClient.Host/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/telegram_client:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/telegram_client:${DRONE_TAG}
--dockerfile=src/Nocr.TelegramClient.Host/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/telegram_client:latest
--destination=hub.musk.fun/k8s/nocr/telegram_client:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/telegram_client:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-telegram-client
--destination=hub.musk.fun/k8s/nocr/telegram_client:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-telegram-client \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- telegram-listener-build-push - telegram-listener-build-push
@ -485,21 +477,20 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/text-matcher
- cp nuget.config text-matcher/ - /kaniko/executor
- cd text-matcher --context=.
- | --dockerfile=src/Nocr.TextMatcher.Host/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/text_matcher:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/text_matcher:${DRONE_TAG}
--dockerfile=src/Nocr.TextMatcher.Host/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/text_matcher:latest
--destination=hub.musk.fun/k8s/nocr/text_matcher:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/text_matcher:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-text-matcher
--destination=hub.musk.fun/k8s/nocr/text_matcher:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-text-matcher \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- telegram-client-build-push - telegram-listener-nuget
- text-matcher-nuget
- users-nuget
- name: text-matcher-migrator-build-push - name: text-matcher-migrator-build-push
image: gcr.io/kaniko-project/executor:debug image: gcr.io/kaniko-project/executor:debug
@ -511,18 +502,15 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/text-matcher
- cp nuget.config text-matcher/ - /kaniko/executor
- cd text-matcher --context=.
- | --dockerfile=src/Nocr.TextMatcher.Migrator/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:${DRONE_TAG}
--dockerfile=src/Nocr.TextMatcher.Migrator/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:latest
--destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-text-matcher-migrator
--destination=hub.musk.fun/k8s/nocr/text_matcher_migrator:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-text-matcher-migrator \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- text-matcher-build-push - text-matcher-build-push
@ -537,21 +525,20 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/users
- cp nuget.config users/ - /kaniko/executor
- cd users --context=.
- | --dockerfile=src/Nocr.Users.Host/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/users:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/users:${DRONE_TAG}
--dockerfile=src/Nocr.Users.Host/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/users:latest
--destination=hub.musk.fun/k8s/nocr/users:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/users:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-users
--destination=hub.musk.fun/k8s/nocr/users:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-users \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- text-matcher-migrator-build-push - telegram-listener-nuget
- text-matcher-nuget
- users-nuget
- name: users-migrator-build-push - name: users-migrator-build-push
image: gcr.io/kaniko-project/executor:debug image: gcr.io/kaniko-project/executor:debug
@ -563,18 +550,15 @@ steps:
commands: commands:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"hub.musk.fun\":{\"username\":\"$HUB_USERNAME\",\"password\":\"$HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cd flea - cd flea/users
- cp nuget.config users/ - /kaniko/executor
- cd users --context=.
- | --dockerfile=src/Nocr.Users.Migrator/Dockerfile
/kaniko/executor \ --destination=hub.musk.fun/k8s/nocr/users_migrator:${DRONE_COMMIT_SHA:0:7}
--context=. \ --destination=hub.musk.fun/k8s/nocr/users_migrator:${DRONE_TAG}
--dockerfile=src/Nocr.Users.Migrator/Dockerfile \ --destination=hub.musk.fun/k8s/nocr/users_migrator:latest
--destination=hub.musk.fun/k8s/nocr/users_migrator:${DRONE_COMMIT_SHA:0:7} \ --cache=true
--destination=hub.musk.fun/k8s/nocr/users_migrator:${DRONE_TAG} \ --cache-repo=hub.musk.fun/k8s/cache/nocr-users-migrator
--destination=hub.musk.fun/k8s/nocr/users_migrator:latest \
--cache=true \
--cache-repo=hub.musk.fun/k8s/cache/nocr-users-migrator \
--compressed-caching=true --compressed-caching=true
depends_on: depends_on:
- users-build-push - users-build-push
@ -585,79 +569,14 @@ steps:
- name: deploy-to-k8s - name: deploy-to-k8s
image: bitnami/kubectl:latest image: bitnami/kubectl:latest
environment:
KUBECONFIG_CONTENT:
from_secret: kubeconfig
commands: commands:
- mkdir -p $HOME/.kube
- echo "$KUBECONFIG_CONTENT" > $HOME/.kube/config
- chmod 600 $HOME/.kube/config
- cd flea/_deploy/scripts - cd flea/_deploy/scripts
- sh deploy.sh "${DRONE_TAG}" "${DRONE_COMMIT_SHA:0:7}" - chmod +x deploy.sh
- ./deploy.sh ${DRONE_TAG} ${DRONE_COMMIT_SHA:0:7}
depends_on: depends_on:
- telegram-client-build-push
- text-matcher-migrator-build-push
- users-migrator-build-push - users-migrator-build-push
when: when:
ref: ref:
- refs/tags/* - refs/tags/*
---
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 🚀 Pipeline 5: Deploy-Only
# Trigger: Tag with commit message containing "deploy_only:"
# Purpose: Fast deploy of already-built images
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
kind: pipeline
type: kubernetes
name: deploy-only
metadata:
namespace: musk-drone
trigger:
ref:
- refs/tags/*
event:
- tag
clone:
disable: true
steps:
- name: clone
image: alpine/git
commands:
- git clone https://gitea.musk.fun/nocr/flea
- cd flea
- git checkout $DRONE_TAG
- git submodule update --init --recursive
- name: check-trigger
image: alpine/git
commands:
- |
cd flea
COMMIT_MSG=$(git log -1 --pretty=%B)
echo "Commit message - $COMMIT_MSG"
if echo "$COMMIT_MSG" | grep -q "deploy_only:"; then
echo "✅ deploy_only detected, proceeding..."
exit 0
else
echo "⏭️ No deploy_only marker, skipping..."
exit 78
fi
depends_on:
- clone
- name: deploy
image: bitnami/kubectl:latest
environment:
KUBECONFIG_CONTENT:
from_secret: kubeconfig
commands:
- mkdir -p $HOME/.kube
- echo "$KUBECONFIG_CONTENT" > $HOME/.kube/config
- chmod 600 $HOME/.kube/config
- cd flea/_deploy/scripts
- sh deploy.sh "${DRONE_TAG}" "" "latest"
depends_on:
- check-trigger

429
CLAUDE.md
View File

@ -27,39 +27,28 @@ The services follow a message bus pattern using RabbitMQ for async communication
**Note:** WTelegram sends both `UpdateNewChannelMessage` and `UpdateEditChannelMessage` for the same message. TelegramListener publishes separate events to avoid duplicate notifications downstream. **Note:** WTelegram sends both `UpdateNewChannelMessage` and `UpdateEditChannelMessage` for the same message. TelegramListener publishes separate events to avoid duplicate notifications downstream.
Each service follows Clean Architecture with separate projects for: Each service follows Clean Architecture with separate projects for:
- **Host** (API/entry point) - ASP.NET Core application, controllers, startup configuration - Host (API/entry point)
- **AppServices** (business logic) - Use cases, business logic, command/query handlers - AppServices (business logic)
- **Core** (shared utilities) - Domain entities, interfaces, shared logic - Core (shared utilities)
- **Api.Contracts** (REST API contracts) - DTOs, request/response models for REST endpoints (published as NuGet) - Api.Contracts (REST API contracts)
- **Async.Api.Contracts** (event contracts) - Event DTOs for RabbitMQ messaging (published as NuGet) - Async.Api.Contracts (event contracts)
- **Persistence** (database layer) - EF Core DbContext, repositories, data access (text-matcher, users only) - Persistence (database layer, where applicable)
- **Migrator** (database migrations) - EF Core migrations, migration scripts (text-matcher, users only) - Migrator (database migrations, where applicable)
**Project Structure Examples:**
- telegram-listener: Host, AppServices, Core, Async.Api.Contracts (no database)
- telegram-client: Host, AppServices, Core (no database, no published contracts)
- text-matcher: Host, AppServices, Core, Api.Contracts, Async.Api.Contracts, Persistence, Migrator
- users: Host, AppServices, Core, Api.Contracts, Persistence, Migrator
## Development Commands ## Development Commands
### Running the System ### Running the System
```bash ```bash
# IMPORTANT: Before building with Docker Compose, prepare the build environment
./prepare-build.sh
# Start all services with Docker Compose # Start all services with Docker Compose
docker-compose up docker-compose up
# Start individual services for development (no preparation needed) # Start individual services for development
cd telegram-client && dotnet run --project src/Nocr.TelegramClient.Host cd telegram-client && dotnet run --project src/Nocr.TelegramClient.Host
cd telegram-listener && dotnet run --project src/Nocr.TelegramListener.Host cd telegram-listener && dotnet run --project src/Nocr.TelegramListener.Host
cd text-matcher && dotnet run --project src/Nocr.TextMatcher.Host cd text-matcher && dotnet run --project src/Nocr.TextMatcher.Host
cd users && dotnet run --project src/Nocr.Users.Host cd users && dotnet run --project src/Nocr.Users.Host
``` ```
**Note:** The `prepare-build.sh` script copies `nuget.config` to all submodule roots, which is required for Docker builds. This step is automatic in CI/CD but must be run manually for local Docker Compose builds.
### Building ### Building
```bash ```bash
# Build individual services # Build individual services
@ -71,17 +60,8 @@ dotnet build src/Nocr.<ServiceName>.Host
### Testing ### Testing
```bash ```bash
# Run all tests in text-matcher # Run unit tests (only text-matcher has tests currently)
cd text-matcher && dotnet test cd text-matcher && dotnet test
# Run tests for a specific project
cd text-matcher && dotnet test tests/Nocr.TextMatcher.AppServices.UnitTests/Nocr.TextMatcher.AppServices.UnitTests.csproj
# Run tests with verbose output
cd text-matcher && dotnet test --verbosity detailed
# Run tests with code coverage (if configured)
cd text-matcher && dotnet test --collect:"XPlat Code Coverage"
``` ```
### Database Migrations ### Database Migrations
@ -95,29 +75,6 @@ cd users && ./src/Nocr.Users.Migrator/AddMigration.sh MyMigrationName
# Apply migrations (handled automatically by migrator containers in docker-compose) # Apply migrations (handled automatically by migrator containers in docker-compose)
``` ```
### Working with Git Submodules
```bash
# Initialize submodules after cloning the repository
git submodule update --init --recursive
# Update all submodules to their latest commits on main
./update-submodules.sh
# Commit and push changes to all submodules at once
./commit-all.sh "Your commit message"
# Update a single submodule
cd telegram-listener
git pull origin main
cd ..
git add telegram-listener
git commit -m "Update telegram-listener submodule"
# Check status of all submodules
git submodule status
```
## Configuration ## Configuration
**📖 See [CONFIGURATION.md](CONFIGURATION.md) for detailed configuration guide.** **📖 See [CONFIGURATION.md](CONFIGURATION.md) for detailed configuration guide.**
@ -176,47 +133,13 @@ When running with docker-compose:
## Key Technologies ## Key Technologies
- **.NET 8** - All services built on .NET 8 - .NET 8
- **ASP.NET Core Web APIs** - REST endpoints and hosting - ASP.NET Core Web APIs
- **Entity Framework Core with MariaDB** - ORM for text-matcher and users databases - Entity Framework Core with MariaDB
- **WTelegramClient** - MTProto API client for telegram-listener - WTelegramClient for Telegram API
- **Telegram.Bot** - Bot API client for telegram-client - Rebus for message bus (RabbitMQ)
- **Rebus** - Message bus abstraction over RabbitMQ - Docker & Docker Compose for containerization
- **RabbitMQ** - Message broker for async event-driven communication - Drone CI/CD on Kubernetes
- **Docker & Docker Compose** - Local development and containerization
- **Kaniko** - Container image building in CI/CD
- **Drone CI** - CI/CD pipeline on Kubernetes
## NuGet Package Management
The project uses **Central Package Management (CPM)** with **Package Source Mapping** to manage NuGet dependencies:
### Package Sources
- **nuget.org**: All public packages (Microsoft.*, Serilog.*, etc.)
- **musk** (private): Internal `Nocr.*` contract packages
### Configuration
The `nuget.config` file in the project root defines package source mapping:
```xml
<packageSourceMapping>
<packageSource key="musk">
<package pattern="Nocr.*" />
</packageSource>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
```
### How It Works
1. **Local Development**: Copy `nuget.config` to each submodule root when needed
2. **CI/CD**: Drone automatically copies `nuget.config` to `/root/.nuget/NuGet/NuGet.Config`
3. **Docker Builds**: Kaniko copies `nuget.config` to submodule root before building
This eliminates NuGet warning NU1507 and ensures consistent package resolution across all environments.
## CI/CD Pipeline ## CI/CD Pipeline
@ -225,240 +148,39 @@ This eliminates NuGet warning NU1507 and ensures consistent package resolution a
The project uses Drone CI with 5 specialized pipelines: The project uses Drone CI with 5 specialized pipelines:
### 1. Feature Validation (`feature/*`, `fix/*` branches) ### 1. Feature Validation (`feature/*`, `fix/*` branches)
**Purpose**: Test feature branches before merging to main - Triggered on push to feature/fix branches
**How to trigger**:
```bash
# Create feature branch and push
git checkout -b feature/my-new-feature
# ... make changes ...
git add .
git commit -m "Add new feature"
git push origin feature/my-new-feature
```
**What happens**:
- Runs build + tests with Testcontainers support - Runs build + tests with Testcontainers support
- Provides fast feedback before merge - Provides fast feedback before merge
- Duration: ~3-5 minutes - Duration: ~3-5 minutes
### 2. Main Validation (`main` branch) ### 2. Main Validation (`main` branch)
**Purpose**: Ensure main branch stays healthy after merge - Triggered on push to main
**How to trigger**:
```bash
# Merge feature to main
git checkout main
git merge feature/my-new-feature
git push origin main
```
**What happens**:
- Same checks as feature validation - Same checks as feature validation
- Ensures main branch builds and tests pass - Ensures main branch stays healthy
- Duration: ~3-5 minutes - Duration: ~3-5 minutes
### 3. Contracts-Only Publish ### 3. Contracts-Only Publish (tags with `contracts_only:`)
**Purpose**: Publish NuGet contracts without building Docker images (fast iteration) - Triggered by tag + commit message containing `contracts_only:<service>`
- Publishes NuGet contracts without building Docker images
**How to trigger**: - Fast iteration on contract changes
```bash
# Update contracts in a submodule
cd telegram-listener
# ... update Async.Api.Contracts ...
git add . && git commit -m "Add MessageEdited event"
git push
# From parent repo, tag with contracts_only marker
cd ..
git add telegram-listener
git commit -m "contracts_only:telegram_listener - Add MessageEdited event"
git tag 0.7.41
git push && git push --tags
```
**What happens**:
- Publishes only the specified service's NuGet contracts
- Skips Docker image builds
- Duration: ~2 minutes - Duration: ~2 minutes
- Example: `git commit -m "contracts_only:telegram_listener - Add MessageEdited event"`
**Services**: `telegram_listener`, `text_matcher`, `users` ### 4. Full Release (clean tags)
- Triggered by tag without special markers
### 4. Full Release - Complete release cycle:
**Purpose**: Complete release - contracts + images + deployment 1. Publish all NuGet contracts (parallel)
2. Build all Docker images with Kaniko (parallel, after contracts)
**How to trigger**: 3. Deploy to Kubernetes (automatic for `v*` tags)
```bash
# Make your changes, commit to main
git add .
git commit -m "Implement new feature"
git push
# Tag for full release (no special markers in commit message)
git tag v1.3.0
git push --tags
```
**What happens**:
1. Publishes all NuGet contracts (parallel)
2. Builds all Docker images with Kaniko (parallel, after contracts)
3. Deploys to Kubernetes (automatic for `v*` tags)
- Duration: ~8-10 minutes - Duration: ~8-10 minutes
- Example: `git tag v1.3.0`
### 5. Deploy-Only ### 5. Deploy-Only (tags with `deploy_only:`)
**Purpose**: Deploy existing images without rebuilding (rollbacks, hotfixes) - Triggered by tag + commit message containing `deploy_only:`
- Skips building, only deploys existing images
**How to trigger**: - Useful for rollbacks and hotfixes
```bash
# Deploy already-built images (e.g., rollback to previous version)
git commit --allow-empty -m "deploy_only: Rollback to v1.2.9"
git tag deploy-v1.2.9
git push && git push --tags
# Or deploy latest images
git commit --allow-empty -m "deploy_only: Deploy latest"
git tag deploy-latest
git push && git push --tags
```
**What happens**:
- Skips building entirely
- Deploys specified tag's images (or `latest`)
- Duration: ~1 minute - Duration: ~1 minute
- Example: `git commit --allow-empty -m "deploy_only: Deploy v1.2.9"`
## Development Workflows
### Making Changes to a Single Service
When working on a specific service (e.g., telegram-listener):
```bash
# 1. Navigate to the submodule
cd telegram-listener
# 2. Create a feature branch in the submodule
git checkout -b feature/new-feature
# 3. Make your changes to the code
# ... edit files ...
# 4. Test locally (if tests exist)
dotnet test
# 5. Commit and push in the submodule
git add .
git commit -m "Add new feature"
git push origin feature/new-feature
# 6. Return to parent repo and update submodule reference
cd ..
git add telegram-listener
git commit -m "Update telegram-listener: Add new feature"
git push origin main
```
### Updating Contract Packages
When you change event contracts (Async.Api.Contracts) or REST contracts (Api.Contracts):
```bash
# 1. Make changes to contracts in the submodule
cd text-matcher
# ... edit Nocr.TextMatcher.Async.Api.Contracts ...
git add . && git commit -m "Add new event contract"
git push origin main
# 2. Return to parent repo and publish contracts only
cd ..
git add text-matcher
git commit -m "contracts_only:text_matcher - Add new event contract"
git tag 0.8.6
git push && git push --tags
# 3. Other services can now reference the new contract version
# Update their .csproj or Directory.Packages.props to use version 0.8.6
```
### Working Across Multiple Services
When implementing a feature that spans multiple services:
```bash
# 1. Update each submodule in sequence
cd telegram-listener
git checkout -b feature/cross-service-feature
# ... make changes ...
git commit -m "Part 1: Update listener"
git push origin feature/cross-service-feature
cd ../text-matcher
git checkout -b feature/cross-service-feature
# ... make changes ...
git commit -m "Part 2: Update matcher"
git push origin feature/cross-service-feature
# 2. Update parent repo to reference all changes
cd ..
git add telegram-listener text-matcher
git commit -m "Implement cross-service feature"
git push origin main
# 3. Tag for full release
git tag v1.5.0
git push --tags
```
## Common CI/CD Workflows
### Test a Feature Branch
```bash
git checkout -b feature/add-logging
# ... make changes ...
git add . && git commit -m "Add structured logging"
git push origin feature/add-logging
# ✅ Drone runs feature-validation pipeline
```
### Publish Contracts After API Changes
```bash
cd text-matcher
# Update Nocr.TextMatcher.Async.Api.Contracts
git add . && git commit -m "Add UserDeleted event"
git push
cd ..
git add text-matcher
git commit -m "contracts_only:text_matcher - Add UserDeleted event"
git tag 0.8.5
git push && git push --tags
# ✅ Drone publishes text-matcher contracts to NuGet
```
### Full Release Workflow
```bash
# Work on main branch
git add .
git commit -m "Implement payment processing"
git push
# ✅ Drone runs main-validation
# Tag for release
git tag v2.0.0
git push --tags
# ✅ Drone runs full-release pipeline:
# 1. Publishes all contracts
# 2. Builds all Docker images
# 3. Deploys to Kubernetes
```
### Emergency Rollback
```bash
# Rollback to last known good version
git commit --allow-empty -m "deploy_only: Emergency rollback to v1.9.5"
git tag rollback-v1.9.5
git push && git push --tags
# ✅ Drone deploys v1.9.5 images immediately (~1 minute)
```
### Deployment Scripts ### Deployment Scripts
@ -474,82 +196,3 @@ Located in `_deploy/scripts/`:
- **Proper dependency order**: Contracts → Images → Deploy - **Proper dependency order**: Contracts → Images → Deploy
- **Kaniko layer caching** for faster Docker builds - **Kaniko layer caching** for faster Docker builds
- **Docker-in-Docker** support for Testcontainers in tests - **Docker-in-Docker** support for Testcontainers in tests
## Troubleshooting
### Submodule Issues
**Problem:** Submodule directories are empty after cloning
```bash
# Solution: Initialize submodules
git submodule update --init --recursive
```
**Problem:** Submodule is in detached HEAD state
```bash
# Solution: Check out the main branch in the submodule
cd <submodule-name>
git checkout main
git pull origin main
cd ..
```
**Problem:** Changes in submodule not reflected in parent repo
```bash
# Solution: Update submodule reference in parent
cd .. # Return to parent repo
git add <submodule-name>
git commit -m "Update <submodule-name> reference"
```
### Build Issues
**Problem:** NuGet package restore fails with NU1507 warning
```bash
# Solution: Copy nuget.config to submodule root
cp nuget.config telegram-listener/
cd telegram-listener && dotnet restore
```
**Problem:** Cannot find Nocr.* contract packages
```bash
# Solution: Ensure you have access to the private NuGet feed
# Check nuget.config has the correct source configuration
# Verify credentials for the "musk" package source
```
### Docker Compose Issues
**Problem:** Service cannot connect to RabbitMQ
```bash
# Solution: Use the Docker network hostname, not localhost
# In docker-compose environment: nocr-rabbitmq:5672
# In local development: localhost:5672
```
**Problem:** Database connection fails
```bash
# Solution: Wait for database health checks to pass
# Check docker-compose logs for database container
docker-compose logs nocr-text-matcher-db
# Database takes 10-30 seconds to be ready on first start
```
### CI/CD Issues
**Problem:** Pipeline doesn't trigger on tag
```bash
# Solution: Ensure tag matches expected patterns
# Feature validation: feature/*, fix/*, issues/*
# Main validation: main branch
# Contracts: Tag with commit message containing "contracts_only:<service>"
# Full release: Any tag without special markers
# Deploy-only: Tag with commit message containing "deploy_only:"
```
**Problem:** Docker image build fails in Kaniko
```bash
# Solution: Check if nuget.config is correctly copied
# Verify _deploy/deploy.sh contains nuget.config copy step
# Check Drone logs for nuget.config presence in build context
```

View File

@ -1,48 +1,48 @@
# Руководство по конфигурации # Configuration Guide
Этот документ описывает, как настроить микросервисную систему NOCR для различных сценариев развертывания. This document describes how to configure the NOCR microservices system for different deployment scenarios.
## Содержание ## Table of Contents
1. [Обзор системы конфигурации](#обзор-системы-конфигурации) 1. [Configuration System Overview](#configuration-system-overview)
2. [Сценарии развертывания](#сценарии-развертывания) 2. [Deployment Scenarios](#deployment-scenarios)
- [Локальная разработка (VS Code)](#локальная-разработка-vs-code) - [Local Development (VS Code)](#local-development-vs-code)
- [Docker Compose](#docker-compose) - [Docker Compose](#docker-compose)
- [Kubernetes](#kubernetes) - [Kubernetes](#kubernetes)
3. [Приоритет конфигурации](#приоритет-конфигурации) 3. [Configuration Priority](#configuration-priority)
4. [Настройки для конкретных сервисов](#настройки-для-конкретных-сервисов) 4. [Service-Specific Settings](#service-specific-settings)
5. [Режим отладки](#режим-отладки) 5. [Debug Mode](#debug-mode)
6. [Устранение неполадок](#устранение-неполадок) 6. [Troubleshooting](#troubleshooting)
--- ---
## Обзор системы конфигурации ## Configuration System Overview
Система использует многоуровневый подход конфигурации ASP.NET Core со следующими источниками (от низшего к высшему приоритету): The system uses ASP.NET Core's layered configuration approach with the following sources (listed from lowest to highest priority):
1. `appsettings.json` - Базовая конфигурация (коммитится в git) 1. `appsettings.json` - Base configuration (committed to git)
2. `appsettings.{Environment}.json` - Настройки для конкретного окружения (некоторые коммитятся, некоторые нет) 2. `appsettings.{Environment}.json` - Environment-specific settings (some committed, some not)
3. User Secrets - Секреты только для разработки (хранятся локально, не в git) 3. User Secrets - Development-only secrets (stored locally, not in git)
4. **Переменные окружения** - **Наивысший приоритет** (переопределяют всё) 4. **Environment Variables** - **Highest priority** (overrides everything)
### Важные примечания ### Important Notes
- **Никогда не коммитьте секреты в git** - **Never commit secrets to git**
- Используйте файлы `.example` как шаблоны - Use `.example` files as templates
- Переменные окружения всегда имеют наивысший приоритет - Environment Variables always win in priority
- Каждый сервис имеет свои требования к конфигурации - Each service has its own configuration requirements
--- ---
## Сценарии развертывания ## Deployment Scenarios
### Локальная разработка (VS Code) ### Local Development (VS Code)
Для отладки отдельных сервисов в VS Code: For debugging services individually in VS Code:
#### Шаг 1: Создание конфигурации для окружения #### Step 1: Create Environment-Specific Configuration
Для каждого сервиса, который вы хотите запустить, создайте `appsettings.Development.json` из примера: For each service you want to run, create `appsettings.Development.json` from the example:
```bash ```bash
# Telegram Listener # Telegram Listener
@ -62,11 +62,11 @@ cd telegram-client/src/Nocr.TelegramClient.Host
cp appsettings.Development.json.example appsettings.Development.json cp appsettings.Development.json.example appsettings.Development.json
``` ```
#### Шаг 2: Заполните ваши значения #### Step 2: Fill in Your Values
Отредактируйте каждый файл `appsettings.Development.json` и замените placeholder-значения на ваши реальные учетные данные. Edit each `appsettings.Development.json` file and replace placeholder values with your actual credentials.
**Пример для Telegram Listener:** **Example for Telegram Listener:**
```json ```json
{ {
"RebusRabbitMqOptions": { "RebusRabbitMqOptions": {
@ -80,13 +80,13 @@ cp appsettings.Development.json.example appsettings.Development.json
} }
``` ```
#### Шаг 3: Альтернатива - использование переменных окружения #### Step 3: Alternative - Use Environment Variables
Вместо создания `appsettings.Development.json`, вы можете использовать переменные окружения в `.vscode/launch.json`: Instead of creating `appsettings.Development.json`, you can use environment variables in `.vscode/launch.json`:
```json ```json
{ {
"name": "Запуск сервиса", "name": "Launch Service",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"env": { "env": {
@ -99,57 +99,57 @@ cp appsettings.Development.json.example appsettings.Development.json
} }
``` ```
**Примечание:** Используйте двойное подчеркивание `__` для представления вложенных секций конфигурации в переменных окружения. **Note:** Use double underscores `__` to represent nested configuration sections in environment variables.
#### Шаг 4: Запуск инфраструктуры #### Step 4: Start Infrastructure
Вам нужны работающие RabbitMQ и базы данных: You need RabbitMQ and databases running:
```bash ```bash
# Запустить только инфраструктурные сервисы # Start only infrastructure services
docker-compose up nocr-rabbitmq nocr-text-matcher-db nocr-users-db -d docker-compose up nocr-rabbitmq nocr-text-matcher-db nocr-users-db -d
``` ```
#### Шаг 5: Отладка в VS Code #### Step 5: Debug in VS Code
Нажмите F5 или используйте панель Run and Debug для запуска вашего сервиса. Press F5 or use the Run and Debug panel to start your service.
--- ---
### Docker Compose ### Docker Compose
Для запуска всей системы локально с Docker: For running the entire system locally with Docker:
#### Шаг 1: Создание файла .nocr.env #### Step 1: Create .nocr.env File
```bash ```bash
cd /путь/к/корню/проекта cd /path/to/project/root
cp .nocr.env.example .nocr.env cp .nocr.env.example .nocr.env
``` ```
#### Шаг 2: Редактирование .nocr.env #### Step 2: Edit .nocr.env
Откройте `.nocr.env` и заполните ваши реальные учетные данные: Open `.nocr.env` and fill in your actual credentials:
```bash ```bash
# Telegram Listener - получить на https://my.telegram.org/apps # Telegram Listener - get from https://my.telegram.org/apps
WTelegramClientOptions__ApiId=22101230 WTelegramClientOptions__ApiId=22101230
WTelegramClientOptions__ApiHash=c72f884d8eb84cb7134a14362bff060b WTelegramClientOptions__ApiHash=c72f884d8eb84cb7134a14362bff060b
WTelegramClientOptions__PhoneNumber=79167310711 WTelegramClientOptions__PhoneNumber=79167310711
# Telegram Client Bot - получить у @BotFather # Telegram Client Bot - get from @BotFather
TelegramBotOptions__Token=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz TelegramBotOptions__Token=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
# Опционально: включить отладочное логирование # Optional: Enable debug logging
# NOCR_DEBUG_MODE=true # NOCR_DEBUG_MODE=true
``` ```
#### Шаг 3: Создание конфигурационных файлов для DockerCompose #### Step 3: Create DockerCompose Configuration Files
Каждому сервису нужен `appsettings.DockerCompose.json`: Each service needs `appsettings.DockerCompose.json`:
```bash ```bash
# Для каждого сервиса # For each service
cd telegram-listener/src/Nocr.TelegramListener.Host cd telegram-listener/src/Nocr.TelegramListener.Host
cp appsettings.DockerCompose.json.example appsettings.DockerCompose.json cp appsettings.DockerCompose.json.example appsettings.DockerCompose.json
@ -163,21 +163,21 @@ cd telegram-client/src/Nocr.TelegramClient.Host
cp appsettings.DockerCompose.json.example appsettings.DockerCompose.json cp appsettings.DockerCompose.json.example appsettings.DockerCompose.json
``` ```
**Примечание:** Эти файлы содержат имена хостов Docker-сети (например, `nocr-rabbitmq:5672` вместо `localhost:5672`). **Note:** These files contain Docker network hostnames (e.g., `nocr-rabbitmq:5672` instead of `localhost:5672`).
#### Шаг 4: Запуск всех сервисов #### Step 4: Start All Services
```bash ```bash
docker-compose up docker-compose up
``` ```
Или со сборкой: Or build and start:
```bash ```bash
docker-compose up --build docker-compose up --build
``` ```
#### Шаг 5: Проверка работоспособности сервисов #### Step 5: Verify Services are Running
- Telegram Listener: http://localhost:5040/health - Telegram Listener: http://localhost:5040/health
- Text Matcher: http://localhost:5041/health - Text Matcher: http://localhost:5041/health
@ -189,32 +189,32 @@ docker-compose up --build
### Kubernetes ### Kubernetes
Для production-развертывания на Kubernetes: For production deployment on Kubernetes:
#### Шаг 1: Создание Kubernetes Secrets #### Step 1: Create Kubernetes Secrets
**НЕ используйте файл `.nocr.env` в K8s.** Вместо этого создайте Secrets: **Do NOT use `.nocr.env` file in K8s.** Instead, create Secrets:
```bash ```bash
# Создать namespace # Create namespace
kubectl create namespace nocr kubectl create namespace nocr
# Создать secrets для Telegram Listener # Create secrets for Telegram Listener
kubectl create secret generic telegram-listener-secrets \ kubectl create secret generic telegram-listener-secrets \
--from-literal=WTelegramClientOptions__ApiId=22101230 \ --from-literal=WTelegramClientOptions__ApiId=22101230 \
--from-literal=WTelegramClientOptions__ApiHash=c72f884d8eb84cb7134a14362bff060b \ --from-literal=WTelegramClientOptions__ApiHash=c72f884d8eb84cb7134a14362bff060b \
--from-literal=WTelegramClientOptions__PhoneNumber=79167310711 \ --from-literal=WTelegramClientOptions__PhoneNumber=79167310711 \
-n nocr -n nocr
# Создать secrets для Telegram Client # Create secrets for Telegram Client
kubectl create secret generic telegram-client-secrets \ kubectl create secret generic telegram-client-secrets \
--from-literal=TelegramBotOptions__Token=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz \ --from-literal=TelegramBotOptions__Token=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz \
-n nocr -n nocr
``` ```
#### Шаг 2: Ссылка на Secrets в Deployment #### Step 2: Reference Secrets in Deployment
Пример манифеста Kubernetes deployment: Example Kubernetes deployment manifest:
```yaml ```yaml
apiVersion: apps/v1 apiVersion: apps/v1
@ -236,9 +236,9 @@ spec:
name: telegram-listener-secrets name: telegram-listener-secrets
``` ```
#### Шаг 3: Создание appsettings.Production.json #### Step 3: Create appsettings.Production.json
Создайте production-конфигурационные файлы с именами сервисов K8s: Create production config files with K8s service names:
```json ```json
{ {
@ -248,9 +248,9 @@ spec:
} }
``` ```
**Примечание:** Секреты из переменных окружения переопределят эти значения. **Note:** Secrets from environment variables will override these values.
#### Шаг 4: Деплой #### Step 4: Deploy
```bash ```bash
kubectl apply -f deployment/ kubectl apply -f deployment/
@ -258,36 +258,36 @@ kubectl apply -f deployment/
--- ---
## Приоритет конфигурации ## Configuration Priority
Понимание приоритета критически важно при устранении проблем с конфигурацией. Understanding priority is crucial when troubleshooting configuration issues.
### Порядок приоритета (от низшего к высшему) ### Priority Order (Lowest → Highest)
1. ⬇️ `appsettings.json` (базовый) 1. ⬇️ `appsettings.json` (base)
2. ⬆️ `appsettings.{Environment}.json` (например, Development, DockerCompose, Production) 2. ⬆️ `appsettings.{Environment}.json` (e.g., Development, DockerCompose, Production)
3. ⬆️ User Secrets (только Development) 3. ⬆️ User Secrets (Development only)
4. ⬆️⬆️ **Переменные окружения (ВСЕГДА ВЫИГРЫВАЮТ)** 4. ⬆️⬆️ **Environment Variables (ALWAYS WINS)**
### Пример сценария ### Example Scenario
Если у вас есть: If you have:
- `appsettings.json`: `"ConnectionString": ""` - `appsettings.json`: `"ConnectionString": ""`
- `appsettings.DockerCompose.json`: `"ConnectionString": "amqp://admin:admin@nocr-rabbitmq:5672/"` - `appsettings.DockerCompose.json`: `"ConnectionString": "amqp://admin:admin@nocr-rabbitmq:5672/"`
- Переменная окружения: `RebusRabbitMqOptions__ConnectionString=amqp://admin:admin@localhost:5672/` - Environment Variable: `RebusRabbitMqOptions__ConnectionString=amqp://admin:admin@localhost:5672/`
**Результат:** Переменная окружения побеждает! Подключение будет использовать `localhost:5672`. **Result:** Environment variable wins! Connection will use `localhost:5672`.
Именно поэтому мы удалили `appsettings.protected.json` - он неправильно переопределял настройки Docker Compose. This is why we removed `appsettings.protected.json` - it was overriding Docker Compose settings incorrectly.
--- ---
## Настройки для конкретных сервисов ## Service-Specific Settings
### Telegram Listener ### Telegram Listener
**Обязательная конфигурация:** **Required Configuration:**
```json ```json
{ {
@ -302,17 +302,17 @@ kubectl apply -f deployment/
} }
``` ```
**Как получить учетные данные Telegram:** **How to obtain Telegram credentials:**
1. Посетите https://my.telegram.org/apps 1. Visit https://my.telegram.org/apps
2. Войдите с вашим номером телефона 2. Log in with your phone number
3. Создайте новое приложение 3. Create a new application
4. Скопируйте `api_id` и `api_hash` 4. Copy `api_id` and `api_hash`
--- ---
### Text Matcher ### Text Matcher
**Обязательная конфигурация:** **Required Configuration:**
```json ```json
{ {
@ -325,7 +325,7 @@ kubectl apply -f deployment/
} }
``` ```
**Порты по окружениям:** **Ports by environment:**
- Development: `localhost:3316` - Development: `localhost:3316`
- Docker Compose: `nocr-text-matcher-db:3306` - Docker Compose: `nocr-text-matcher-db:3306`
- Kubernetes: `text-matcher-db-service:3306` - Kubernetes: `text-matcher-db-service:3306`
@ -334,7 +334,7 @@ kubectl apply -f deployment/
### Users ### Users
**Обязательная конфигурация:** **Required Configuration:**
```json ```json
{ {
@ -344,7 +344,7 @@ kubectl apply -f deployment/
} }
``` ```
**Порты по окружениям:** **Ports by environment:**
- Development: `localhost:3326` - Development: `localhost:3326`
- Docker Compose: `nocr-users-db:3306` - Docker Compose: `nocr-users-db:3306`
- Kubernetes: `users-db-service:3306` - Kubernetes: `users-db-service:3306`
@ -353,7 +353,7 @@ kubectl apply -f deployment/
### Telegram Client ### Telegram Client
**Обязательная конфигурация:** **Required Configuration:**
```json ```json
{ {
@ -372,45 +372,45 @@ kubectl apply -f deployment/
} }
``` ```
**Как получить Bot Token:** **How to obtain Bot Token:**
1. Откройте Telegram и найдите @BotFather 1. Open Telegram and find @BotFather
2. Отправьте команду `/newbot` 2. Send `/newbot` command
3. Следуйте инструкциям для создания вашего бота 3. Follow instructions to create your bot
4. Скопируйте предоставленный токен 4. Copy the token provided
--- ---
## Режим отладки ## Debug Mode
Включите режим отладки для вывода маскированных значений конфигурации при запуске. Enable debug mode to print masked configuration values on startup.
### Как включить ### How to Enable
Установите переменную окружения: Set environment variable:
```bash ```bash
export NOCR_DEBUG_MODE=true export NOCR_DEBUG_MODE=true
``` ```
Или в `.nocr.env`: Or in `.nocr.env`:
```bash ```bash
NOCR_DEBUG_MODE=true NOCR_DEBUG_MODE=true
``` ```
Или в `docker-compose.yml`: Or in `docker-compose.yml`:
```yaml ```yaml
environment: environment:
NOCR_DEBUG_MODE: "true" NOCR_DEBUG_MODE: "true"
``` ```
### Пример вывода ### Example Output
Когда режим отладки включен, вы увидите маскированную конфигурацию при запуске: When debug mode is enabled, you'll see masked configuration on startup:
``` ```
=== [NOCR_DEBUG] Значения конфигурации === === [NOCR_DEBUG] Configuration Values ===
[NOCR_DEBUG] RebusRabbitMqOptions: [NOCR_DEBUG] RebusRabbitMqOptions:
[NOCR_DEBUG] ConnectionString: amqp://admin:***@nocr-rabbitmq:5672/ [NOCR_DEBUG] ConnectionString: amqp://admin:***@nocr-rabbitmq:5672/
[NOCR_DEBUG] InputQueueName: nocr.telegram.listener.queue [NOCR_DEBUG] InputQueueName: nocr.telegram.listener.queue
@ -420,144 +420,144 @@ environment:
[NOCR_DEBUG] ApiId: 22101230 [NOCR_DEBUG] ApiId: 22101230
[NOCR_DEBUG] ApiHash: c7...0b [NOCR_DEBUG] ApiHash: c7...0b
[NOCR_DEBUG] PhoneNumber: 79...11 [NOCR_DEBUG] PhoneNumber: 79...11
=== [NOCR_DEBUG] Конец конфигурации === === [NOCR_DEBUG] End Configuration ===
``` ```
**Безопасность:** Пароли и секреты автоматически маскируются для защиты конфиденциальных данных. **Security:** Passwords and secrets are automatically masked to protect sensitive data.
--- ---
## Устранение неполадок ## Troubleshooting
### Проблема: Сервис не может подключиться к RabbitMQ ### Problem: Service can't connect to RabbitMQ
**Симптомы:** **Symptoms:**
``` ```
Connection refused to nocr-rabbitmq:5672 Connection refused to nocr-rabbitmq:5672
``` ```
**Решение:** **Solution:**
1. Проверьте, работает ли RabbitMQ: `docker-compose ps nocr-rabbitmq` 1. Check if RabbitMQ is running: `docker-compose ps nocr-rabbitmq`
2. Включите режим отладки: `NOCR_DEBUG_MODE=true` 2. Enable debug mode: `NOCR_DEBUG_MODE=true`
3. Проверьте ConnectionString в выводе отладки 3. Verify ConnectionString in debug output
4. Для Docker Compose убедитесь, что hostname - `nocr-rabbitmq:5672`, НЕ `localhost:5672` 4. For Docker Compose, ensure hostname is `nocr-rabbitmq:5672`, NOT `localhost:5672`
5. Проверьте, не переопределяет ли переменная окружения appsettings 5. Check if environment variable is overriding appsettings
--- ---
### Проблема: Сервис не может подключиться к базе данных ### Problem: Service can't connect to database
**Симптомы:** **Symptoms:**
``` ```
Unable to connect to any of the specified MySQL hosts Unable to connect to any of the specified MySQL hosts
``` ```
**Решение:** **Solution:**
1. Проверьте, что база данных запущена: `docker-compose ps nocr-text-matcher-db` 1. Check database is running: `docker-compose ps nocr-text-matcher-db`
2. Включите режим отладки для просмотра маскированной строки подключения 2. Enable debug mode to see masked connection string
3. Проверьте hostname в строке подключения: 3. Verify hostname in connection string:
- Docker Compose: `nocr-text-matcher-db:3306` - Docker Compose: `nocr-text-matcher-db:3306`
- Локальная разработка: `localhost:3316` - Local dev: `localhost:3316`
4. Подождите прохождения healthcheck (может занять 10-30 секунд при первом запуске) 4. Wait for database healthcheck to pass (may take 10-30 seconds on first start)
--- ---
### Проблема: Значения конфигурации не применяются ### Problem: Configuration values not applied
**Симптомы:** **Symptoms:**
- Настройки в `appsettings.Development.json` игнорируются - Settings in `appsettings.Development.json` are ignored
- Сервис использует неправильную конфигурацию - Service uses wrong configuration
**Решение:** **Solution:**
1. Проверьте, что `ASPNETCORE_ENVIRONMENT` установлен правильно: 1. Check `ASPNETCORE_ENVIRONMENT` is set correctly:
- VS Code: `Development` - VS Code: `Development`
- Docker Compose: `DockerCompose` - Docker Compose: `DockerCompose`
- K8s: `Production` - K8s: `Production`
2. Включите режим отладки для просмотра загруженных значений 2. Enable debug mode to see which values are loaded
3. Проверьте переменные окружения, переопределяющие ваши настройки 3. Check for environment variables overriding your settings
4. Помните: **Переменные окружения всегда выигрывают!** 4. Remember: **Environment Variables always win!**
--- ---
### Проблема: Секреты раскрыты в логах ### Problem: Secrets exposed in logs
**Решение:** **Solution:**
- Режим отладки автоматически маскирует конфиденциальные значения - Debug mode automatically masks sensitive values
- Никогда не логируйте конфигурацию в production без маскировки - Never log configuration in production without masking
- Проверьте формат вывода отладки в `Startup.cs`: - Review debug output format in `Startup.cs`:
- Пароли: `amqp://user:***@host` - Passwords: `amqp://user:***@host`
- Секреты: `ab...yz` (только первые 2 + последние 2 символа) - Secrets: `ab...yz` (first 2 + last 2 chars only)
--- ---
### Проблема: Отсутствует файл .nocr.env ### Problem: Missing .nocr.env file
**Симптомы:** **Symptoms:**
``` ```
docker-compose up падает с ошибкой отсутствующих переменных окружения docker-compose up fails with missing environment variables
``` ```
**Решение:** **Solution:**
1. Скопируйте файл-пример: `cp .nocr.env.example .nocr.env` 1. Copy example file: `cp .nocr.env.example .nocr.env`
2. Заполните ваши реальные значения 2. Fill in your actual values
3. Убедитесь, что `.nocr.env` находится в корне проекта (на том же уровне, что и `docker-compose.yml`) 3. Make sure `.nocr.env` is in the project root (same level as `docker-compose.yml`)
--- ---
## Краткая справка ## Quick Reference
### Соглашение об именовании переменных окружения ### Environment Variable Naming Convention
ASP.NET Core использует двойное подчеркивание `__` для представления вложенной JSON-структуры: ASP.NET Core uses double underscores `__` to represent nested JSON structure:
```bash ```bash
# JSON: { "Section": { "Key": "Value" } } # JSON: { "Section": { "Key": "Value" } }
# Переменная окружения: # Environment Variable:
Section__Key=Value Section__Key=Value
# Примеры: # Example:
WTelegramClientOptions__ApiId=12345 WTelegramClientOptions__ApiId=12345
RebusRabbitMqOptions__ConnectionString=amqp://localhost RebusRabbitMqOptions__ConnectionString=amqp://localhost
``` ```
### Расположение файлов ### File Locations
``` ```
flea/ # Корень проекта flea/ # Project root
├── .nocr.env # Ваши секреты (gitignored) ├── .nocr.env # Your secrets (gitignored)
├── .nocr.env.example # Шаблон (коммитится) ├── .nocr.env.example # Template (committed)
├── docker-compose.yml # Ссылается на .nocr.env ├── docker-compose.yml # References .nocr.env
├── telegram-listener/ ├── telegram-listener/
│ └── src/Nocr.TelegramListener.Host/ │ └── src/Nocr.TelegramListener.Host/
│ ├── appsettings.json # Базовый (коммитится) │ ├── appsettings.json # Base (committed)
│ ├── appsettings.Development.json # Локальная разработка (gitignored) │ ├── appsettings.Development.json # Local dev (gitignored)
│ ├── appsettings.Development.json.example # Шаблон (коммитится) │ ├── appsettings.Development.json.example # Template (committed)
│ ├── appsettings.DockerCompose.json # Docker (gitignored) │ ├── appsettings.DockerCompose.json # Docker (gitignored)
│ └── appsettings.DockerCompose.json.example # Шаблон (коммитится) │ └── appsettings.DockerCompose.json.example # Template (committed)
└── [та же структура для text-matcher, users, telegram-client] └── [same structure for text-matcher, users, telegram-client]
``` ```
--- ---
## Рекомендации по безопасности ## Security Best Practices
1. ✅ **Никогда не коммитьте секреты** - используйте файлы `.example` как шаблоны 1. ✅ **Never commit secrets** - Use `.example` files as templates
2. ✅ **Используйте переменные окружения** для конфиденциальных данных в production 2. ✅ **Use environment variables** for sensitive data in production
3. ✅ **Используйте K8s Secrets** для развертывания в Kubernetes 3. ✅ **Use K8s Secrets** for Kubernetes deployments
4. ✅ **Включайте режим отладки** только при устранении неполадок 4. ✅ **Enable debug mode** only when troubleshooting
5. ✅ **Ротируйте учетные данные** регулярно 5. ✅ **Rotate credentials** regularly
6. ✅ **Используйте User Secrets** для локальной разработки (опционально) 6. ✅ **Use User Secrets** for local development (optional)
7. ❌ **Не коммитьте** `.nocr.env` или `appsettings.*.json` (кроме файлов `.example`) 7. ❌ **Don't commit** `.nocr.env` or `appsettings.*.json` (except `.example` files)
8. ❌ **Не используйте** `appsettings.protected.json` (удален из кода) 8. ❌ **Don't use** `appsettings.protected.json` (removed from code)
--- ---
## Дополнительные ресурсы ## Additional Resources
- [Документация конфигурации ASP.NET Core](https://learn.microsoft.com/ru-ru/aspnet/core/fundamentals/configuration/) - [ASP.NET Core Configuration Docs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/)
- [Переменные окружения Docker Compose](https://docs.docker.com/compose/environment-variables/) - [Docker Compose Environment Variables](https://docs.docker.com/compose/environment-variables/)
- [Kubernetes Secrets](https://kubernetes.io/ru/docs/concepts/configuration/secret/) - [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)
- [Документация Telegram API](https://core.telegram.org/api) - [Telegram API Documentation](https://core.telegram.org/api)
- [Telegram Bot API](https://core.telegram.org/bots/api) - [Telegram Bot API](https://core.telegram.org/bots/api)

464
README.md
View File

@ -1,446 +1,22 @@
# NOCR - Система мониторинга Telegram-каналов # Спец проект для работы с зависимостями, внешними и внутренними сервисами и приложениями.
Аккумуляция всех вложенных проектов.
[telegram-listener](https://gitea.musk.fun/nocr/telegram-listener)
Модуль, отвечающий за скан открытых каналов и чатов.
[telegram-client](https://gitea.musk.fun/nocr/telegram-client)
Модуль, отвечающий за клиентский интерфейс самого бота взаимодействия с пользователем.
[users](https://gitea.musk.fun/nocr/users)
Модуль, отвечающий за управление пользователями сервиса и их предпочтениями.
[text-matcher](https://gitea.musk.fun/nocr/text-matcher)
Модуль, отвечающий за сравнивание всего объема подписанных сообщений через listener по пересечению с пользовательскими интересами.
---
docker-compose.yml файл используется для старта проектов и зависисмостей внутри докера. Конфигурация хостовых сервисов опирается на конфигурационный файл общего назначения `appsettings.json` и специфичный для докера `appsettings.DockerCompose.json` (частный файл). Однако общие чувствительные для всех видов запуска секреты хранятся в `appsettings.protected.json`. Для личного пользования и отдельного запуска проектов необходимо двигаться по пути `appsettings.Development.json`.
# Статус сборки drone:
[![Build Status](https://drone.musk.fun/api/badges/nocr/flea/status.svg?ref=refs/heads/main)](https://drone.musk.fun/nocr/flea) [![Build Status](https://drone.musk.fun/api/badges/nocr/flea/status.svg?ref=refs/heads/main)](https://drone.musk.fun/nocr/flea)
Микросервисная система на базе Telegram Bot для мониторинга и уведомлений о текстовых совпадениях в открытых каналах и чатах.
## 📋 Обзор проекта
Это родительский проект, содержащий все сервисы как **git submodules**. Каждый сервис является отдельным репозиторием, что обеспечивает независимую разработку и версионирование.
### Архитектура сервисов
Система состоит из 4 основных микросервисов, взаимодействующих через RabbitMQ:
#### 1. [telegram-listener](https://gitea.musk.fun/nocr/telegram-listener)
**Назначение:** Сканирование открытых Telegram-каналов и чатов
- Подписка на каналы через Telegram MTProto API
- Публикация событий о новых и отредактированных сообщениях в message bus
- Хранение сессий пользователей
#### 2. [text-matcher](https://gitea.musk.fun/nocr/text-matcher)
**Назначение:** Сопоставление сообщений с пользовательскими подписками
- Обработка событий от telegram-listener
- Проверка совпадений по регулярным выражениям и ключевым словам
- Хранение истории совпадений в БД (MariaDB)
- Публикация событий о найденных совпадениях
#### 3. [telegram-client](https://gitea.musk.fun/nocr/telegram-client)
**Назначение:** Клиентский интерфейс бота для взаимодействия с пользователями
- Прием команд от пользователей через Telegram Bot API
- Управление подписками на каналы
- Отправка уведомлений о найденных совпадениях
- Интеграция с users и text-matcher через REST API
#### 4. [users](https://gitea.musk.fun/nocr/users)
**Назначение:** Управление пользователями и их настройками
- CRUD операции для пользователей
- Хранение предпочтений и подписок
- REST API для других сервисов
---
## 🚀 Быстрый старт
### Вариант 1: Docker Compose (рекомендуется)
```bash
# 1. Создайте файл с секретами
cp .nocr.env.example .nocr.env
# 2. Заполните ваши Telegram API ключи в .nocr.env
# - API ID и Hash: https://my.telegram.org/apps
# - Bot Token: @BotFather в Telegram
# 3. Запустите все сервисы
docker-compose up
```
**Проверка работоспособности:**
- Telegram Listener: http://localhost:5040/health
- Text Matcher: http://localhost:5041/health
- Users: http://localhost:5042/health
- Telegram Client: http://localhost:5050/health
- RabbitMQ UI: http://localhost:15672 (admin/admin)
### Вариант 2: Локальная разработка (VS Code)
```bash
# 1. Запустите инфраструктуру (RabbitMQ + базы данных)
docker-compose up nocr-rabbitmq nocr-text-matcher-db nocr-users-db -d
# 2. Создайте конфигурационные файлы для каждого сервиса
cd telegram-listener/src/Nocr.TelegramListener.Host
cp appsettings.Development.json.example appsettings.Development.json
# Повторите для всех сервисов
# 3. Заполните ваши секреты в appsettings.Development.json
# 4. Запустите сервисы через VS Code (F5)
```
**📖 Подробная документация:** См. [CONFIGURATION.md](CONFIGURATION.md)
---
## 🏗️ Архитектура взаимодействия
```
┌──────────────────┐ ┌───────────────┐ ┌──────────────────┐
│ Telegram Channel │────────▶│ Listener │────────▶│ Text Matcher │
│ (MTProto API) │ │ (Scan msgs) │ │ (Match rules) │
└──────────────────┘ └───────┬───────┘ └────────┬─────────┘
│ │
│ │
│ RabbitMQ │
│ Message Bus │
│ │
▼ ▼
┌───────────────┐ ┌──────────────────┐
│ Event Topics │ │ Telegram Bot │
& Queues │◀────────│ Client │
└───────────────┘ │ (Notifications) │
└──────────────────┘
┌──────────────────┐
│ Users Service │
│ (User Management)│
└──────────────────┘
```
**Паттерн взаимодействия:**
- **Event-driven**: Асинхронная обработка через RabbitMQ
- **REST API**: Синхронные запросы между telegram-client и другими сервисами
- **Clean Architecture**: Разделение на слои Host/AppServices/Core/Persistence
**📖 Подробная диаграмма:** См. [architecture.md](architecture.md)
---
## 🔧 Технологический стек
- **.NET 8** - Фреймворк для всех сервисов
- **ASP.NET Core** - Web API
- **Entity Framework Core** - ORM для MariaDB
- **WTelegramClient** - MTProto API для telegram-listener
- **Telegram.Bot** - Bot API для telegram-client
- **Rebus** - Message bus поверх RabbitMQ
- **MariaDB** - Базы данных для text-matcher и users
- **RabbitMQ** - Брокер сообщений
- **Docker & Docker Compose** - Контейнеризация
- **Drone CI** - CI/CD на Kubernetes
---
## 📦 CI/CD Pipeline
Проект использует **Drone CI** с 5 специализированными пайплайнами:
### 1. 🧪 Feature Validation
**Триггер:** Push в ветки `feature/*`, `fix/*`, `issues/*`
**Длительность:** ~3-5 минут
- Сборка всех сервисов
- Запуск тестов с Testcontainers
- Быстрая обратная связь перед PR
### 2. ✅ Main Validation
**Триггер:** Push в ветку `main`
**Длительность:** ~3-5 минут
- Валидация после мерджа в main
- Гарантия стабильности основной ветки
### 3. 📝 Contracts-Only Publish
**Триггер:** Tag с сообщением `contracts_only:<service>`
**Длительность:** ~2 минуты
- Публикация NuGet-пакетов контрактов
- Без сборки Docker-образов
```bash
git commit -m "contracts_only:telegram_listener - Add MessageEdited event"
git tag v1.2.4-contracts && git push origin v1.2.4-contracts
```
### 4. 🚀 Full Release
**Триггер:** Tag без специальных маркеров
**Длительность:** ~8-10 минут
1. Публикация всех контрактов (параллельно)
2. Сборка Docker-образов с Kaniko (параллельно)
3. Деплой в Kubernetes (для тегов `v*`)
```bash
git tag v1.3.0 && git push origin v1.3.0
```
### 5. ⚡ Deploy-Only
**Триггер:** Tag с сообщением `deploy_only:`
**Длительность:** ~1 минута
- Деплой существующих образов без пересборки
- Откат к предыдущей версии
```bash
git commit --allow-empty -m "deploy_only: Rollback to v1.2.9"
git tag v1.2.9-deploy && git push origin v1.2.9-deploy
```
**📖 Полная документация CI/CD:** См. [_deploy/README.md](_deploy/README.md)
---
## 🛠️ Команды разработки
### Сборка
```bash
# Сборка конкретного сервиса
cd telegram-listener && dotnet build
# Сборка всех сервисов
dotnet build telegram-listener/Nocr.TelegramListener.sln
dotnet build telegram-client/Nocr.TelegramClient.sln
dotnet build text-matcher/Nocr.TextMatcher.sln
dotnet build users/Nocr.Users.sln
```
### Тестирование
```bash
# Запуск тестов (text-matcher)
cd text-matcher && dotnet test
```
### Миграции БД
```bash
# Добавить новую миграцию
cd text-matcher
./src/Nocr.TextMatcher.Migrator/AddMigration.sh MyMigrationName
cd users
./src/Nocr.Users.Migrator/AddMigration.sh MyMigrationName
# Применение миграций автоматически при запуске через docker-compose
```
### Работа с субмодулями
```bash
# Инициализация субмодулей после клонирования
git submodule update --init --recursive
# Обновление всех субмодулей до последних коммитов
git submodule update --remote --merge
# Автокоммит изменений в субмодулях (скрипт)
./commit-submodules.sh "Update submodules"
```
---
## 📊 Порты сервисов
При запуске через Docker Compose:
| Сервис | Порт | Health Check |
|--------|------|--------------|
| telegram-listener | 5040 | http://localhost:5040/health |
| text-matcher | 5041 | http://localhost:5041/health |
| users | 5042 | http://localhost:5042/health |
| telegram-client | 5050 | http://localhost:5050/health |
| RabbitMQ AMQP | 5672 | - |
| RabbitMQ Management | 15672 | http://localhost:15672 |
| MariaDB (text-matcher) | 3316 | - |
| MariaDB (users) | 3326 | - |
---
## 🔐 Конфигурация
### Приоритет источников конфигурации
1. **appsettings.json** (базовые настройки)
2. **appsettings.{Environment}.json** (Development/DockerCompose/Production)
3. **User Secrets** (только для Development)
4. **Environment Variables** ⬆️ **НАИВЫСШИЙ ПРИОРИТЕТ**
### Важные правила
- ❌ **Никогда не коммитьте секреты** в git
- ✅ Используйте файлы `.example` как шаблоны
- ✅ Environment Variables переопределяют все остальное
- ✅ Docker Compose использует `.nocr.env` (gitignored)
- ✅ Kubernetes использует Secrets
### Режим отладки
Для вывода маскированных значений конфигурации:
```bash
export NOCR_DEBUG_MODE=true
```
**📖 Полное руководство:** См. [CONFIGURATION.md](CONFIGURATION.md)
---
## 📚 Документация
- [CONFIGURATION.md](CONFIGURATION.md) - Подробное руководство по конфигурации
- [_deploy/README.md](_deploy/README.md) - CI/CD пайплайны и деплой
- [architecture.md](architecture.md) - Архитектурная диаграмма
- [CLAUDE.md](CLAUDE.md) - Инструкции для Claude Code AI
### Документация сервисов
- [telegram-listener/README.md](telegram-listener/README.md)
- [telegram-client/README.md](telegram-client/README.md)
- [text-matcher/README.md](text-matcher/README.md)
- [users/README.md](users/README.md)
---
## 🤝 Рабочий процесс разработки
### Создание новой функции
```bash
# 1. Создайте feature-ветку
git checkout -b feature/add-filter
# 2. Работайте в субмодуле
cd telegram-listener
git checkout -b feature/add-filter
# Внесите изменения...
git commit -m "Add new filter"
git push origin feature/add-filter
# 3. Обновите родительский проект
cd ..
git add telegram-listener
git commit -m "Update telegram-listener: Add new filter"
git push origin feature/add-filter
# 4. Создайте PR и дождитесь прохождения CI
```
### Релиз новой версии
```bash
# 1. Убедитесь, что все изменения в main
git checkout main && git pull
# 2. Создайте тег
git tag v1.4.0 -m "Release v1.4.0: New features"
git push origin v1.4.0
# 3. Drone автоматически:
# - Опубликует NuGet-пакеты
# - Соберет Docker-образы
# - Задеплоит в Kubernetes (для v* тегов)
```
---
## 🐛 Troubleshooting
### Сервис не подключается к RabbitMQ
```bash
# 1. Проверьте, что RabbitMQ запущен
docker-compose ps nocr-rabbitmq
# 2. Включите режим отладки
export NOCR_DEBUG_MODE=true
# 3. Проверьте ConnectionString в логах
# Для Docker: должно быть nocr-rabbitmq:5672, НЕ localhost:5672
```
### Ошибка подключения к базе данных
```bash
# 1. Проверьте статус БД
docker-compose ps nocr-text-matcher-db
# 2. Подождите прохождения healthcheck (10-30 сек при первом запуске)
# 3. Проверьте порт в connection string:
# - Docker: nocr-text-matcher-db:3306
# - Local: localhost:3316
```
### Pipeline падает на тестах
```bash
# 1. Проверьте, что Testcontainers может подключиться к Docker
# В pipeline должна быть переменная DOCKER_HOST
# 2. Запустите тесты локально
cd text-matcher
dotnet test
# 3. Проверьте логи в Drone UI
```
---
## 📈 Мониторинг
### Проверка здоровья сервисов
```bash
# Локально
curl http://localhost:5040/health # telegram-listener
curl http://localhost:5041/health # text-matcher
curl http://localhost:5042/health # users
curl http://localhost:5050/health # telegram-client
# В Kubernetes (из deploy pod)
cd _deploy/scripts
./health-check.sh
```
### Просмотр логов
```bash
# Docker Compose
docker-compose logs -f telegram-listener
docker-compose logs -f text-matcher
# Kubernetes
kubectl logs -f deployment/telegram-listener -n nocr
kubectl logs -f deployment/text-matcher -n nocr
```
---
## 📝 История изменений (15-16 октября 2025)
### Основные улучшения
- ✨ **Новый CI/CD**: 5 специализированных пайплайнов Drone
- 🔧 **Исправления .drone.yml**: Корректная обработка YAML с многострочными командами
- 📦 **Contracts-only пайплайн**: Быстрая публикация контрактов без пересборки образов
- 🚀 **Deploy-only пайплайн**: Быстрый откат и деплой существующих образов
- 🔄 **MessageEdited события**: Отдельная обработка отредактированных сообщений
- 📝 **Автокоммит субмодулей**: Скрипт для упрощения работы с субмодулями
- ⚡ **Оптимизации**: Shared NuGet cache, параллельная сборка, Kaniko caching
### Исправленные проблемы
- 🐛 Исправлен парсинг YAML в `.drone.yml` (строка 126)
- 🐛 Корректная обработка `${DRONE_COMMIT_SHA:0:7}` в командах
- 🐛 Правильные отступы в многострочных bash-скриптах
- 🐛 Зависимости между этапами pipeline
---
## 📄 Лицензия
[Укажите лицензию вашего проекта]
## 👥 Авторы
[Укажите авторов проекта]
---
**Дополнительные ссылки:**
- [Drone CI](https://drone.musk.fun/nocr/flea)
- [Gitea Repository](https://gitea.musk.fun/nocr/flea)

View File

@ -1,228 +1,208 @@
# 🚀 Документация CI/CD Pipeline NOCR # 🚀 Nocr CI/CD Pipeline Documentation
## 📋 Обзор ## 📋 Overview
Проект NOCR использует современную многопайплайновую CI/CD систему на базе Drone CI, работающую на Kubernetes. Этот документ описывает 5 специализированных пайплайнов и способы их использования. The Nocr project uses a modern, multi-pipeline CI/CD setup powered by Drone CI on Kubernetes. This document describes the 5 specialized pipelines and how to use them.
--- ---
## 🎯 Архитектура пайплайнов ## 🎯 Pipeline Architecture
### Пайплайн 1: **Feature Validation (Валидация функциональных веток)** ### Pipeline 1: **Feature Validation**
**Триггер:** Push в ветки `feature/*`, `fix/*` или `issues/*` **Trigger:** Push to `feature/*` or `fix/*` branches
**Назначение:** Быстрая обратная связь для разработчиков **Purpose:** Fast feedback for developers
**Длительность:** ~3-5 минут **Duration:** ~3-5 minutes
**Что делает:** **What it does:**
- Клонирует репозиторий с субмодулями - Clones repo with submodules
- Восстанавливает все NuGet-пакеты (общий кэш) - Restores all NuGet packages (shared cache)
- Собирает все 4 сервиса в Debug-режиме - Builds all 4 services in Release mode
- Запускает unit и integration тесты с Testcontainers - Runs unit and integration tests with Testcontainers
**Пример рабочего процесса:** **Example workflow:**
```bash ```bash
git checkout -b feature/add-new-filter git checkout -b feature/add-new-filter
# Внесите изменения... # Make changes...
git add . git add .
git commit -m "Add new filter functionality" git commit -m "Add new filter functionality"
git push origin feature/add-new-filter git push origin feature/add-new-filter
``` ```
Drone автоматически запустит тесты. Проверьте результаты перед созданием PR. Drone automatically runs tests. Check results before creating PR.
--- ---
### Пайплайн 2: **Main Validation (Валидация основной ветки)** ### Pipeline 2: **Main Validation**
**Триггер:** Push в ветку `main` **Trigger:** Push to `main` branch
**Назначение:** Валидация основной ветки после мерджа **Purpose:** Validate main branch after merge
**Длительность:** ~3-5 минут **Duration:** ~3-5 minutes
**Что делает:** **What it does:**
- То же, что и Feature Validation - Same as Feature Validation
- Гарантирует, что ветка main всегда в рабочем состоянии - Ensures main branch is always in working state
**Пример рабочего процесса:** **Example workflow:**
```bash ```bash
# После мерджа PR в main # After PR is merged to main
# Пайплайн запускается автоматически # Pipeline runs automatically
``` ```
--- ---
### Пайплайн 3: **Contracts-Only Publish (Публикация только контрактов)** ### Pipeline 3: **Contracts-Only Publish**
**Триггер:** Тег с сообщением коммита, содержащим `contracts_only:<service>` **Trigger:** Tag with commit message containing `contracts_only:<service>`
**Назначение:** Быстрая публикация NuGet-пакетов контрактов без сборки Docker-образов **Purpose:** Fast publish of contract packages without building images
**Длительность:** ~2 минуты **Duration:** ~2 minutes
**Что делает:** **What it does:**
- Упаковывает контракты указанного сервиса в NuGet-пакеты - Packs specified service contracts into NuGet packages
- Публикует во внутреннем NuGet-фиде - Publishes to internal NuGet feed
- Пропускает сборку Docker-образов - Skips Docker image builds
**Пример рабочего процесса:** **Example workflow:**
```bash ```bash
# Обновите контракты telegram-listener # Update telegram-listener contracts
cd telegram-listener cd telegram-listener
# Внесите изменения в Async.Api.Contracts... # Make changes to Async.Api.Contracts...
git add . git add .
git commit -m "contracts_only:telegram_listener - Add MessageEdited event" git commit -m "contracts_only:telegram_listener - Add MessageEdited event"
git push origin main git push origin main
# Создайте тег # Create tag
git tag v1.2.4-contracts git tag v1.2.4-contracts
git push origin v1.2.4-contracts git push origin v1.2.4-contracts
``` ```
**Поддерживаемые маркеры:** **Supported markers:**
- `contracts_only:telegram_listener` - `contracts_only:telegram_listener`
- `contracts_only:text_matcher` - `contracts_only:text_matcher`
- `contracts_only:users` - `contracts_only:users`
--- ---
### Пайплайн 4: **Full Release (Полный релиз)** ### Pipeline 4: **Full Release**
**Триггер:** Тег на main БЕЗ `contracts_only` или `deploy_only` в сообщении коммита **Trigger:** Tag on main WITHOUT `contracts_only` or `deploy_only` in commit message
**Назначение:** Полный цикл релиза **Purpose:** Complete release cycle
**Длительность:** ~8-10 минут **Duration:** ~8-10 minutes
**Что делает:** **What it does:**
1. **Этап 1:** Публикация всех контрактов в NuGet (параллельно) 1. **Stage 1:** Publish all contracts to NuGet (parallel)
2. **Этап 2:** Сборка всех Docker-образов с Kaniko (3 параллельных потока) 2. **Stage 2:** Build all Docker images with Kaniko (3 parallel streams)
3. **Этап 3:** Деплой в Kubernetes (только для тегов, начинающихся с `v`) 3. **Stage 3:** Deploy to Kubernetes (only for tags matching `v*`)
**Пример рабочего процесса:** **Example workflow:**
```bash ```bash
# Готовы к релизу # Ready to release
git tag v1.3.0 git tag v1.3.0
git push origin v1.3.0 git push origin v1.3.0
# Drone выполнит: # Drone will:
# 1. Публикацию контрактов # 1. Publish contracts
# 2. Сборку образов (с тегами v1.3.0, commit SHA, и latest) # 2. Build images (tagged with v1.3.0, commit SHA, and latest)
# 3. Деплой в k8s (если тег начинается с 'v') # 3. Deploy to k8s (if tag starts with 'v')
``` ```
**Создаваемые теги образов:** **Image tags created:**
- `hub.musk.fun/k8s/nocr/telegram_listener:v1.3.0` - `hub.musk.fun/k8s/nocr/telegram_listener:v1.3.0`
- `hub.musk.fun/k8s/nocr/telegram_listener:abc1234` (commit SHA) - `hub.musk.fun/k8s/nocr/telegram_listener:abc1234` (commit SHA)
- `hub.musk.fun/k8s/nocr/telegram_listener:latest` - `hub.musk.fun/k8s/nocr/telegram_listener:latest`
--- ---
### Пайплайн 5: **Deploy-Only (Только деплой)** ### Pipeline 5: **Deploy-Only**
**Триггер:** Тег с сообщением коммита, содержащим `deploy_only: <version>` **Trigger:** Tag with commit message containing `deploy_only:`
**Назначение:** Быстрый деплой уже собранных образов **Purpose:** Fast deploy of already-built images
**Длительность:** ~1 минута **Duration:** ~1 minute
**Что делает:** **What it does:**
- Пропускает сборку - Skips building
- Деплоит указанные образы в Kubernetes - Deploys specified images to Kubernetes
- Полезно для отката или продвижения существующих образов - Useful for rolling back or promoting existing images
**ВАЖНО:** В сообщении коммита нужно указать версию образов для деплоя: **Example workflow:**
**Пример рабочего процесса:**
```bash ```bash
# Деплой существующих образов v1.2.9 # Deploy existing images
git commit --allow-empty -m "deploy_only: v1.2.9" git commit --allow-empty -m "deploy_only: Deploy v1.2.9"
git tag deploy-v1.2.9 git tag v1.2.9-deploy
git push origin deploy-v1.2.9 git push origin v1.2.9-deploy
# Откат на предыдущую версию v1.2.8
git commit --allow-empty -m "deploy_only: v1.2.8"
git tag rollback-v1.2.8
git push origin rollback-v1.2.8
``` ```
**Формат commit message:**
- `deploy_only: v1.2.9` - деплоит образы с тегом `v1.2.9`
- Скрипт извлекает версию из сообщения и использует соответствующие образы
- Образы должны существовать в registry (собраны ранее через full-release)
--- ---
## 🛠️ Скрипты деплоя ## 🛠️ Deployment Scripts
Все скрипты деплоя находятся в `_deploy/scripts/`: All deployment scripts are located in `_deploy/scripts/`:
### `deploy.sh` ### `deploy.sh`
**Назначение:** Деплой сервисов в Kubernetes **Purpose:** Deploy services to Kubernetes
**Использование:** **Usage:**
```bash ```bash
# Full release (использует TAG для образов) ./deploy.sh <tag> <commit-sha>
./deploy.sh v1.3.0 abc1234 ./deploy.sh v1.3.0 abc1234
# Deploy only (переопределяет тег образа)
./deploy.sh deploy-v1.2.9 def5678 v1.2.9
``` ```
**Параметры:** **Features:**
1. `tag` - Git тег (обязательный) - Updates deployment manifests with new image tags
2. `commit-sha` - SHA коммита (опциональный) - Applies manifests to cluster
3. `image-tag-override` - Переопределение тега образа (опциональный, для deploy_only) - Waits for rollouts to complete with timeout
- Runs health checks after deployment
**Возможности:** - Shows pod status
- Обновляет deployment-манифесты новыми тегами образов
- Применяет манифесты в кластер
- Ожидает завершения rollout с таймаутом
- Запускает проверки здоровья после деплоя
- Показывает статус подов
### `rollback.sh` ### `rollback.sh`
**Назначение:** Откат деплоев к предыдущей версии **Purpose:** Rollback deployments to previous version
**Использование:** **Usage:**
```bash ```bash
# Откат одного сервиса # Rollback single service
./rollback.sh telegram-listener ./rollback.sh telegram-listener
# Откат всех сервисов # Rollback all services
./rollback.sh all ./rollback.sh all
``` ```
**Возможности:** **Features:**
- Показывает историю ревизий - Shows revision history
- Выполняет kubectl rollout undo - Performs kubectl rollout undo
- Ожидает завершения отката - Waits for rollback to complete
- Запускает проверки здоровья после отката - Runs health checks after rollback
### `health-check.sh` ### `health-check.sh`
**Назначение:** Проверка здоровья всех сервисов NOCR **Purpose:** Check health of all Nocr services
**Использование:** **Usage:**
```bash ```bash
./health-check.sh ./health-check.sh
``` ```
**Проверяет:** **Checks:**
- Статус подов (Running/Ready) - Pod status (Running/Ready)
- Health-эндпоинты (/health) - Health endpoints (/health)
- Последние события для упавших подов - Recent events for failed pods
--- ---
## 📦 Оптимизации ## 📦 Optimizations
### Общий NuGet-кэш ### Shared NuGet Cache
Все пайплайны используют общий временный volume для NuGet-пакетов: All pipelines use a shared temp volume for NuGet packages:
- Первый `dotnet restore` скачивает пакеты - First `dotnet restore` downloads packages
- Последующие сборки переиспользуют кэшированные пакеты - Subsequent builds reuse cached packages
- **~60% быстрее**, чем индивидуальное восстановление для каждого сервиса - **~60% faster** than individual restores per service
### Параллельное выполнение ### Parallel Execution
- Публикация контрактов: 3 сервиса параллельно - Contract publishing: 3 services in parallel
- Сборка Docker: 3 параллельных потока - Docker builds: 3 parallel streams
- Независимые операции никогда не блокируют друг друга - Independent operations never block each other
### Кэширование Kaniko ### Kaniko Caching
Все сборки Kaniko используют: All Kaniko builds use:
- `--cache=true` - Включено кэширование слоев - `--cache=true` - Layer caching enabled
- `--cache-repo=hub.musk.fun/k8s/cache/*` - Общий репозиторий кэша - `--cache-repo=hub.musk.fun/k8s/cache/*` - Shared cache repo
- `--compressed-caching=true` - Быстрая передача кэша - `--compressed-caching=true` - Faster cache transfer
--- ---
## 🧪 Поддержка Testcontainers ## 🧪 Testcontainers Support
Пайплайны валидации Feature и Main включают Docker-in-Docker сервис для Testcontainers: Feature and Main validation pipelines include Docker-in-Docker service for Testcontainers:
```yaml ```yaml
services: services:
@ -231,149 +211,91 @@ services:
privileged: true privileged: true
``` ```
Тесты могут использовать Testcontainers для запуска реальных баз данных, очередей сообщений и т.д. Tests can use Testcontainers to spin up real databases, message queues, etc.
--- ---
## 🔒 Необходимые секреты ## 🔒 Required Secrets
Настройте эти секреты в Drone: Configure these in Drone:
- `hub_username` - Имя пользователя Docker registry - `hub_username` - Docker registry username
- `hub_password` - Пароль Docker registry - `hub_password` - Docker registry password
- `nuget_musk_api_key` - API-ключ NuGet-фида - `nuget_musk_api_key` - NuGet feed API key
--- ---
## 📊 Дерево решений пайплайна ## 📊 Pipeline Decision Tree
``` ```
Push в feature/* → Feature Validation (сборка + тесты) Push to feature/* → Feature Validation (build + test)
Push в main → Main Validation (сборка + тесты) Push to main → Main Validation (build + test)
Тег + "contracts_only:" → Contracts Publish Tag + "contracts_only:" → Contracts Publish
Тег + "deploy_only:" → Deploy Only Tag + "deploy_only:" → Deploy Only
Тег (без маркеров) → Full Release (контракты → образы → деплой) Tag (no markers) → Full Release (contracts → images → deploy)
``` ```
--- ---
## 🎓 Лучшие практики ## 🎓 Best Practices
1. **Функциональные ветки** 1. **Feature Branches**
- Всегда создавайте функциональные ветки для новой работы - Always create feature branches for new work
- Дайте CI валидировать перед мерджем в main - Let CI validate before merging to main
2. **Изменения контрактов** 2. **Contracts Changes**
- Используйте `contracts_only:` для быстрого обновления контрактов - Use `contracts_only:` for quick contract updates
- Другие сервисы могут сразу обновить ссылки - Other services can update references immediately
3. **Процесс релиза** 3. **Release Process**
- Создавайте теги только из ветки main - Tag only from main branch
- Используйте семантическое версионирование (v1.2.3) - Use semantic versioning (v1.2.3)
- Теги, начинающиеся с `v`, автоматически деплоятся в k8s - Tags starting with `v` auto-deploy to k8s
4. **Экстренный откат** 4. **Emergency Rollback**
```bash ```bash
# Быстрый откат через deploy-only # Quick rollback via deploy-only
git commit --allow-empty -m "deploy_only: v1.2.8" git commit --allow-empty -m "deploy_only: Rollback to v1.2.8"
git tag rollback-v1.2.8 git tag v1.2.8-rollback
git push origin rollback-v1.2.8 git push origin v1.2.8-rollback
# Или используйте скрипт отката напрямую в кластере # Or use rollback script directly on the cluster
kubectl exec -it deploy-pod -- bash kubectl exec -it deploy-pod -- bash
cd /flea/_deploy/scripts cd /flea/_deploy/scripts
./rollback.sh all ./rollback.sh all
``` ```
5. **Мониторинг деплоев** 5. **Monitoring Deployments**
- Следите за UI Drone для прогресса пайплайна - Watch Drone UI for pipeline progress
- Проверяйте логи подов: `kubectl logs -f deployment/telegram-listener -n nocr` - Check pod logs: `kubectl logs -f deployment/telegram-listener -n nocr`
- Запускайте проверки здоровья: `./_deploy/scripts/health-check.sh` - Run health checks: `./_deploy/scripts/health-check.sh`
--- ---
## 🐛 Устранение неполадок ## 🐛 Troubleshooting
### Пайплайн завис на "Waiting for contracts" ### Pipeline stuck on "Waiting for contracts"
**Причина:** Публикация контракта упала **Cause:** Contract publish failed
**Решение:** Проверьте NuGet-фид, проверьте API-ключ **Solution:** Check NuGet feed, verify API key
### Сборка Docker падает с ошибкой "unauthorized" ### Docker build fails with "unauthorized"
**Причина:** Неверные учетные данные registry **Cause:** Invalid registry credentials
**Решение:** Обновите секреты `hub_username` и `hub_password` **Solution:** Update `hub_username` and `hub_password` secrets
### Тесты падают с ошибкой "Cannot connect to Docker daemon" ### Tests fail with "Cannot connect to Docker daemon"
**Причина:** Testcontainers не может достичь Docker-in-Docker сервиса **Cause:** Testcontainers can't reach Docker-in-Docker service
**Решение:** Проверьте, что переменная окружения `DOCKER_HOST` установлена правильно **Solution:** Check `DOCKER_HOST` environment variable is set correctly
### Деплой падает с ошибкой "ImagePullBackOff" ### Deployment fails with "ImagePullBackOff"
**Причина:** Образ не найден в registry **Cause:** Image not found in registry
**Решение:** Проверьте, что образ был собран и запушен успешно на предыдущем этапе **Solution:** Verify image was built and pushed successfully in previous step
### YAML-ошибки в .drone.yml
**Причина:** Неправильное форматирование многострочных команд или двоеточие в переменных
**Решение:**
- Используйте блоки `|` для многострочных команд
- Экранируйте переменные с двоеточиями (например, `"${VAR:0:7}"`)
- Проверьте YAML: `python3 -c "import yaml; list(yaml.safe_load_all(open('.drone.yml')))"`
--- ---
## 📚 Дополнительные ресурсы ## 📚 Additional Resources
- [Документация Drone CI](https://docs.drone.io/) - [Drone CI Documentation](https://docs.drone.io/)
- [Документация Kaniko](https://github.com/GoogleContainerTools/kaniko) - [Kaniko Documentation](https://github.com/GoogleContainerTools/kaniko)
- [Testcontainers для .NET](https://dotnet.testcontainers.org/) - [Testcontainers for .NET](https://dotnet.testcontainers.org/)
- [Kubernetes Deployments](https://kubernetes.io/ru/docs/concepts/workloads/controllers/deployment/) - [Kubernetes Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
---
## 🔄 История изменений (15-16 октября 2025)
### Исправлена критическая проблема с YAML
**Проблема:**
- Ошибка `yaml: line 126: mapping values are not allowed in this context`
- Многострочные команды `/kaniko/executor` содержали переменные с двоеточием (`${DRONE_COMMIT_SHA:0:7}`)
- YAML парсер интерпретировал двоеточие как разделитель ключ:значение
**Решение:**
1. Обернули все команды `/kaniko/executor` в многострочные блоки с `|`
2. Добавили обратные слэши `\` для продолжения команды
3. Экранировали аргументы с двоеточиями в кавычках
**Пример:**
```yaml
# До (неправильно):
commands:
- /kaniko/executor
--destination=hub.musk.fun/image:${DRONE_COMMIT_SHA:0:7}
# После (правильно):
commands:
- |
/kaniko/executor \
--destination=hub.musk.fun/image:${DRONE_COMMIT_SHA:0:7}
```
### Добавлены новые функции
- ✨ Контракты-только пайплайн для быстрой итерации
- 🚀 Деплой-только пайплайн для откатов
- 🔄 Обработка MessageEdited событий
- 📝 Скрипт автокоммита субмодулей
- ⚡ Оптимизированный общий NuGet-кэш
- 🔧 Параллельная сборка и деплой
---
## 📞 Поддержка
Если у вас возникли проблемы с CI/CD:
1. Проверьте логи в Drone UI: https://drone.musk.fun/nocr/flea
2. Проверьте статус подов: `kubectl get pods -n nocr`
3. Запустите health-check: `./health-check.sh`
4. Проверьте логи контейнеров: `kubectl logs -f <pod-name> -n nocr`
Для вопросов по инфраструктуре обращайтесь к DevOps-команде.

View File

@ -4,34 +4,20 @@ set -e
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 🚀 Nocr Services Deployment Script # 🚀 Nocr Services Deployment Script
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Usage: ./deploy.sh <tag> [commit-sha] [image-tag-override] # Usage: ./deploy.sh <tag> <commit-sha>
# Examples: # Example: ./deploy.sh v1.2.3 abc1234
# Full release: ./deploy.sh v1.2.3 abc1234
# Deploy only: ./deploy.sh deploy-v1.2.3 def5678 v1.2.3
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TAG=${1:-latest} TAG=${1:-latest}
COMMIT_SHA=${2:-} COMMIT_SHA=${2:-latest}
NAMESPACE="nocr" NAMESPACE="nocr"
DEPLOYMENT_FILE="../k8s/deployment.yaml" DEPLOYMENT_FILE="../k8s/deployment.yaml"
IMAGE_TAG_OVERRIDE=${3:-}
# Determine image tag to use
# Priority: 1) IMAGE_TAG_OVERRIDE (from command line), 2) TAG
if [ -n "$IMAGE_TAG_OVERRIDE" ]; then
IMAGE_TAG=$IMAGE_TAG_OVERRIDE
else
IMAGE_TAG=${TAG}
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🚀 Starting deployment of Nocr services" echo "🚀 Starting deployment of Nocr services"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 Tag: $TAG" echo "📦 Tag: $TAG"
echo "🏷️ Image Tag: $IMAGE_TAG"
if [ -n "$COMMIT_SHA" ]; then
echo "📝 Commit SHA: $COMMIT_SHA" echo "📝 Commit SHA: $COMMIT_SHA"
fi
echo "🎯 Namespace: $NAMESPACE" echo "🎯 Namespace: $NAMESPACE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@ -56,12 +42,12 @@ cp "$DEPLOYMENT_FILE" "$TEMP_DEPLOYMENT"
echo "🔧 Updating image tags in deployment manifests..." echo "🔧 Updating image tags in deployment manifests..."
# Update image tags for all services # Update image tags for all services
sed -i "s|hub.musk.fun/k8s/nocr/telegram_listener:.*|hub.musk.fun/k8s/nocr/telegram_listener:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/telegram_listener:.*|hub.musk.fun/k8s/nocr/telegram_listener:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
sed -i "s|hub.musk.fun/k8s/nocr/telegram_client:.*|hub.musk.fun/k8s/nocr/telegram_client:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/telegram_client:.*|hub.musk.fun/k8s/nocr/telegram_client:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
sed -i "s|hub.musk.fun/k8s/nocr/text_matcher:.*|hub.musk.fun/k8s/nocr/text_matcher:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/text_matcher:.*|hub.musk.fun/k8s/nocr/text_matcher:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
sed -i "s|hub.musk.fun/k8s/nocr/text_matcher_migrator:.*|hub.musk.fun/k8s/nocr/text_matcher_migrator:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/text_matcher_migrator:.*|hub.musk.fun/k8s/nocr/text_matcher_migrator:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
sed -i "s|hub.musk.fun/k8s/nocr/users:.*|hub.musk.fun/k8s/nocr/users:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/users:.*|hub.musk.fun/k8s/nocr/users:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
sed -i "s|hub.musk.fun/k8s/nocr/users_migrator:.*|hub.musk.fun/k8s/nocr/users_migrator:${IMAGE_TAG}|g" "$TEMP_DEPLOYMENT" sed -i "s|hub.musk.fun/k8s/nocr/users_migrator:.*|hub.musk.fun/k8s/nocr/users_migrator:${COMMIT_SHA}|g" "$TEMP_DEPLOYMENT"
echo "✅ Image tags updated" echo "✅ Image tags updated"
@ -74,18 +60,11 @@ rm "$TEMP_DEPLOYMENT"
echo "✅ Manifests applied" echo "✅ Manifests applied"
echo "" echo ""
# Force restart deployments to pull latest images
echo "🔄 Restarting deployments to pull new images..."
DEPLOYMENTS=("telegram-listener" "text-matcher" "users" "telegram-client")
for deployment in "${DEPLOYMENTS[@]}"; do
kubectl rollout restart deployment/"$deployment" -n "$NAMESPACE"
echo " ↻ Restarted $deployment"
done
echo ""
echo "⏳ Waiting for rollouts to complete..." echo "⏳ Waiting for rollouts to complete..."
echo "" echo ""
# Wait for each deployment to roll out
DEPLOYMENTS=("telegram-listener" "text-matcher" "users" "telegram-client")
TIMEOUT="300s" TIMEOUT="300s"
for deployment in "${DEPLOYMENTS[@]}"; do for deployment in "${DEPLOYMENTS[@]}"; do

View File

@ -1,389 +1,47 @@
# Архитектура системы NOCR
Диаграмма взаимодействия между сервисами системы мониторинга Telegram-каналов.
```mermaid ```mermaid
classDiagram classDiagram
TelegramListener --|> Bus : publishes TelegramListener <|-- Bus
Bus --|> TextMatcher : subscribes TextMatcher <|-- TelegramClient
TextMatcher --|> Bus : publishes TextMatcher <|-- Bus
Bus --|> TelegramClient : subscribes Bus <|-- TextMatcher
TelegramClient --|> Users : REST API TelegramClient <|-- Bus
TelegramClient --|> TextMatcher : REST API Users <|-- TelegramClient
Bus <|-- TelegramListener
class Bus{ class Bus{
<<RabbitMQ Message Broker>> +2024-03-28 18:27:50.551 [info] Installing honnef.co/go/tools/cmd/staticcheck@latest (/Users/nazarovsa/go/bin/staticcheck) SUCCEEDED
+MessageReceived events
+MessageEdited events
+TextSubscriptionMatched events
+TextSubscriptionUpdated events
} }
class TelegramListener { class TelegramListener {
<<Сканер каналов>> +MessageReceived
+publishes: MessageReceived -TextMatcher.TextMatchCreated
+publishes: MessageEdited
---
WTelegramClient (MTProto API)
Хранение сессий пользователей
} }
class TextMatcher { class TextMatcher {
<<Обработчик совпадений>> +TextMatchCreated
+publishes: TextSubscriptionMatched +TextMatchMatched
+publishes: TextSubscriptionUpdated -TelegramListener.MessageReceived
-subscribes: MessageReceived +long Create(CreateTextMatchRequest request)
-subscribes: MessageEdited
---
REST API:
+long Create(CreateTextMatchRequest)
+TextMatchData? GetById(long id) +TextMatchData? GetById(long id)
+TextMatchData[] GetByUserId(long userId) +TextMatchData[] GetByUserId(long userId)
+void Delete(long id) +void Delete(long id)
+void Activate(long id) +void Activate(long id)
+void Disable(long id) +void Disable(long id)
---
БД: История совпадений (MariaDB)
Проверка регулярных выражений
} }
class Users { class Users {
<<Управление пользователями>> +long Create(CreateUserRequest request)
---
REST API:
+long Create(CreateUserRequest)
+UserData? GetById(long id) +UserData? GetById(long id)
+UserData? GetByIdentity(type, identity) +UserData? GetByIdentity(UserIdentityType identityType, string identity)
---
БД: Пользователи и настройки (MariaDB)
} }
class TelegramClient { class TelegramClient {
<<Telegram Bot интерфейс>> -TextMatcher.TextMatchMatched
-subscribes: TextSubscriptionMatched
-subscribes: TextSubscriptionUpdated
---
Telegram.Bot (Bot API)
Обработка команд пользователей
Отправка уведомлений
---
REST клиенты:
-Users.Create() -Users.Create()
-Users.GetById() -Users.GetById()
-Users.GetByIdentity() -Users.GetByIdentity()
-TextMatcher.GetByUserId() -TextMatcher.GetByUserId()
-TextMatcher.Create() -TextMatcher.Create()
} }
```
## Описание компонентов
### 1. TelegramListener (Сканер каналов)
**Технологии:** .NET 8, WTelegramClient, Rebus
**Ответственность:**
- Подключение к Telegram через MTProto API
- Подписка на открытые каналы и чаты
- Получение новых и отредактированных сообщений
- Публикация событий в RabbitMQ
**Публикуемые события:**
- `MessageReceived` - новое сообщение получено
- `MessageEdited` - сообщение отредактировано
**Примечание:** WTelegram отправляет оба события (`UpdateNewChannelMessage` и `UpdateEditChannelMessage`) для одного и того же сообщения. TelegramListener публикует отдельные события, чтобы избежать дублирования уведомлений.
---
### 2. TextMatcher (Обработчик совпадений)
**Технологии:** .NET 8, Entity Framework Core, MariaDB, Rebus
**Ответственность:**
- Подписка на события сообщений от TelegramListener
- Проверка совпадений с пользовательскими подписками (regex, ключевые слова)
- Хранение истории совпадений в БД
- Публикация событий о найденных совпадениях
- REST API для управления подписками
**Подписывается на события:**
- `MessageReceived` - проверка нового сообщения
- `MessageEdited` - обновление ранее найденного совпадения
**Публикуемые события:**
- `TextSubscriptionMatched` - новое совпадение найдено
- `TextSubscriptionUpdated` - обновление ранее найденного совпадения
**REST API эндпоинты:**
- `POST /api/textmatch` - Создать новую подписку
- `GET /api/textmatch/{id}` - Получить подписку по ID
- `GET /api/textmatch/user/{userId}` - Получить все подписки пользователя
- `DELETE /api/textmatch/{id}` - Удалить подписку
- `POST /api/textmatch/{id}/activate` - Активировать подписку
- `POST /api/textmatch/{id}/disable` - Отключить подписку
---
### 3. TelegramClient (Telegram Bot)
**Технологии:** .NET 8, Telegram.Bot, Rebus, RestEase
**Ответственность:**
- Интерфейс бота для взаимодействия с пользователями
- Обработка команд бота (/start, /subscribe, /list и т.д.)
- Подписка на события совпадений
- Отправка уведомлений пользователям
- Интеграция с Users и TextMatcher через REST API
**Подписывается на события:**
- `TextSubscriptionMatched` - отправка уведомления о новом совпадении
- `TextSubscriptionUpdated` - уведомление об обновлении
**REST клиенты:**
- **Users API:** управление пользователями
- **TextMatcher API:** управление подписками
---
### 4. Users (Управление пользователями)
**Технологии:** .NET 8, Entity Framework Core, MariaDB
**Ответственность:**
- CRUD операции для пользователей
- Хранение предпочтений и настроек
- REST API для других сервисов
**REST API эндпоинты:**
- `POST /api/users` - Создать нового пользователя
- `GET /api/users/{id}` - Получить пользователя по ID
- `GET /api/users/identity/{type}/{identity}` - Найти пользователя по Telegram ID
---
### 5. RabbitMQ (Message Bus)
**Технологии:** RabbitMQ 3.x, Rebus
**Ответственность:**
- Асинхронная доставка событий между сервисами
- Гарантия доставки сообщений
- Очереди и обмены (exchanges)
**Настройка:**
- **Direct Exchange:** `nocr.direct` - для точечной маршрутизации
- **Topic Exchange:** `nocr.topics` - для публикации/подписки по топикам
- **Очереди:** Каждый сервис имеет свою input queue
---
## Паттерны взаимодействия
### Event-Driven Architecture (Асинхронная)
```
TelegramListener → RabbitMQ → TextMatcher → RabbitMQ → TelegramClient
```
**Преимущества:**
- Слабая связанность сервисов
- Масштабируемость (можно добавить несколько обработчиков)
- Отказоустойчивость (сообщения не теряются при падении сервиса)
### Request-Response (Синхронная)
```
TelegramClient → REST API → Users
TelegramClient → REST API → TextMatcher
```
**Использование:**
- Создание/получение данных пользователей
- Управление подписками
- Запросы, требующие немедленного ответа
---
## Потоки данных
### Основной поток (Мониторинг и уведомления)
1. **Сканирование:**
- TelegramListener подключается к Telegram MTProto
- Получает новые сообщения из каналов
- Публикует `MessageReceived` в RabbitMQ
2. **Обработка:**
- TextMatcher получает `MessageReceived`
- Проверяет сообщение на совпадение с подписками
- Сохраняет историю в БД
- Публикует `TextSubscriptionMatched` в RabbitMQ
3. **Уведомление:**
- TelegramClient получает `TextSubscriptionMatched`
- Получает данные пользователя из Users API
- Отправляет уведомление через Telegram Bot API
### Поток редактирования сообщений
1. **Обновление:**
- TelegramListener получает `UpdateEditChannelMessage`
- Публикует `MessageEdited` в RabbitMQ
2. **Повторная проверка:**
- TextMatcher получает `MessageEdited`
- Проверяет, было ли это сообщение ранее найдено
- Если было, публикует `TextSubscriptionUpdated`
3. **Уведомление об обновлении:**
- TelegramClient получает `TextSubscriptionUpdated`
- Отправляет обновленное уведомление пользователю
---
## Clean Architecture
Каждый сервис следует принципам Clean Architecture:
``` ```
┌─────────────────────────────────────────┐
│ Host (API / Entry Point) │ ← ASP.NET Core, Controllers
├─────────────────────────────────────────┤
│ AppServices (Business Logic) │ ← Use Cases, Handlers
├─────────────────────────────────────────┤
│ Core (Domain / Shared) │ ← Entities, Interfaces
├─────────────────────────────────────────┤
│ Persistence (Data Access) │ ← EF Core, Repositories
├─────────────────────────────────────────┤
│ Async.Api.Contracts (Event Contracts) │ ← RabbitMQ Events (NuGet)
├─────────────────────────────────────────┤
│ Api.Contracts (REST Contracts) │ ← DTOs, Requests (NuGet)
├─────────────────────────────────────────┤
│ Migrator (Database Migrations) │ ← EF Core Migrations
└─────────────────────────────────────────┘
```
**Преимущества:**
- Независимость от фреймворков
- Тестируемость
- Независимость от UI/Database
- Переиспользование контрактов через NuGet
---
## Базы данных
### TextMatcher Database (MariaDB)
**Порт:** 3316 (локально), 3306 (Docker/K8s)
**Таблицы:**
- `TextMatches` - Пользовательские подписки
- `MatchHistory` - История найденных совпадений
- `__EFMigrationsHistory` - История миграций EF Core
### Users Database (MariaDB)
**Порт:** 3326 (локально), 3306 (Docker/K8s)
**Таблицы:**
- `Users` - Пользователи системы
- `UserPreferences` - Настройки пользователей
- `__EFMigrationsHistory` - История миграций EF Core
---
## Развертывание
### Docker Compose (Локальная разработка)
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ telegram- │ │ telegram- │ │ text- │ │ users │
│ listener │ │ client │ │ matcher │ │ │
│ :5040 │ │ :5050 │ │ :5041 │ │ :5042 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │ │
└────────────────┴────────────────┴────────────────┘
┌─────────┴─────────┐
│ RabbitMQ │
│ :5672, :15672 │
└───────────────────┘
┌───────────────┴───────────────┐
│ │
┌───────┴────────┐ ┌────────┴────────┐
│ text-matcher- │ │ users-db │
│ db :3316 │ │ :3326 │
└────────────────┘ └─────────────────┘
```
### Kubernetes (Production)
- **Namespace:** nocr
- **Services:** ClusterIP для внутренней коммуникации
- **Deployments:** С health checks и resource limits
- **Secrets:** Для Telegram API credentials и Bot tokens
- **ConfigMaps:** Для конфигурации окружения
---
## Мониторинг и наблюдаемость
### Health Checks
Каждый сервис предоставляет `/health` эндпоинт:
- **telegram-listener:** http://localhost:5040/health
- **text-matcher:** http://localhost:5041/health
- **users:** http://localhost:5042/health
- **telegram-client:** http://localhost:5050/health
### Логирование
- Структурированное логирование через Serilog
- Логи выводятся в stdout для Docker/K8s
- Централизованное логирование через kubectl logs
### Метрики
- RabbitMQ Management UI: http://localhost:15672
- Мониторинг очередей и exchanges
- Просмотр активных подключений
---
## Масштабирование
### Горизонтальное масштабирование
**Можно масштабировать:**
- ✅ **TextMatcher** - несколько инстансов обрабатывают сообщения параллельно
- ✅ **TelegramClient** - несколько инстансов отправляют уведомления параллельно
- ✅ **Users** - stateless API, можно масштабировать без ограничений
**Ограничения:**
- ⚠️ **TelegramListener** - один инстанс на одну Telegram сессию (ограничение WTelegram)
### Вертикальное масштабирование
- Увеличение CPU/RAM для сервисов
- Оптимизация запросов к БД
- Настройка connection pools
---
## Безопасность
### Секреты
- Telegram API credentials хранятся в K8s Secrets
- Bot tokens хранятся в K8s Secrets
- Database credentials в environment variables
### Сетевая безопасность
- Все сервисы работают в приватной сети
- Только TelegramClient имеет доступ к внешним API
- RabbitMQ защищен credentials
### Валидация
- Входящие данные валидируются в AppServices
- REST API использует Data Annotations
- Event contracts строго типизированы
---
## Дополнительная информация
- **[README.md](README.md)** - Общая документация проекта
- **[CONFIGURATION.md](CONFIGURATION.md)** - Руководство по конфигурации
- **[_deploy/README.md](_deploy/README.md)** - CI/CD и деплой
- **[CLAUDE.md](CLAUDE.md)** - Инструкции для AI-ассистента
---
оследнее обновление: 16 октября 2025_

View File

@ -1,91 +0,0 @@
#!/bin/bash
# Check if commit message is provided
if [ -z "$1" ]; then
echo "Error: Commit message is required"
echo "Usage: ./commit-all.sh \"Your commit message\""
exit 1
fi
COMMIT_MSG="$1"
# Get list of submodules
SUBMODULES=$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }')
if [ -z "$SUBMODULES" ]; then
echo "No submodules found in this repository"
exit 0
fi
echo "🚀 Starting commit and push for all submodules..."
echo "📝 Commit message: $COMMIT_MSG"
echo ""
# Counter for tracking results
SUCCESS_COUNT=0
FAILED_COUNT=0
SKIPPED_COUNT=0
# Iterate through each submodule
for submodule in $SUBMODULES; do
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 Processing submodule: $submodule"
if [ ! -d "$submodule" ]; then
echo "⚠️ Warning: Submodule directory not found, skipping..."
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
continue
fi
cd "$submodule" || {
echo "❌ Failed to enter directory $submodule"
FAILED_COUNT=$((FAILED_COUNT + 1))
cd - > /dev/null
continue
}
# Check if there are any changes
if [ -z "$(git status --porcelain)" ]; then
echo " No changes to commit, skipping..."
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
cd - > /dev/null
continue
fi
# Add all changes
echo " → git add -A"
git add -A
# Commit changes
echo " → git commit"
if git commit -m "$COMMIT_MSG"; then
# Push to main branch
echo " → git push origin main"
if git push origin main; then
echo "✅ Successfully committed and pushed"
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
else
echo "❌ Failed to push"
FAILED_COUNT=$((FAILED_COUNT + 1))
fi
else
echo "❌ Failed to commit"
FAILED_COUNT=$((FAILED_COUNT + 1))
fi
cd - > /dev/null
echo ""
done
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📊 Summary:"
echo " ✅ Success: $SUCCESS_COUNT"
echo " ❌ Failed: $FAILED_COUNT"
echo " ⏭️ Skipped: $SKIPPED_COUNT"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $FAILED_COUNT -gt 0 ]; then
exit 1
fi
exit 0

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="musk" value="https://gitea.musk.fun/api/packages/nocr/nuget/index.json" />
</packageSources>
<!-- Package Source Mapping for Central Package Management -->
<packageSourceMapping>
<!-- All Nocr.* packages come from the private 'musk' feed -->
<packageSource key="musk">
<package pattern="Nocr.*" />
</packageSource>
<!-- All other packages come from nuget.org -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>

View File

@ -1,16 +0,0 @@
#!/bin/bash
# Prepares the build environment by copying nuget.config to all submodules
# This is required for both local docker-compose builds and CI/CD
set -e
echo "📦 Copying nuget.config to all submodules..."
for submodule in telegram-client telegram-listener text-matcher users; do
if [ -d "$submodule" ]; then
cp nuget.config "$submodule/"
echo "✓ Copied to $submodule/"
fi
done
echo "✅ Build preparation complete!"

@ -1 +1 @@
Subproject commit e8ee01cbe809867305ff02611155cddffccbb401 Subproject commit b754ae1c5b50feb757237c2036e0e25432cdd1e3

@ -1 +1 @@
Subproject commit 9ad504753550414edd96ef4194a3e0ee7e604e28 Subproject commit 7030e7bce2004ea342ceedf9eb5126077e267b72

@ -1 +1 @@
Subproject commit 1a55061e4b1b125d1b911f479fc830fb94cd93cc Subproject commit e0b6beab7e6ccdf3d89b56d07abef3b619cbfa32

2
users

@ -1 +1 @@
Subproject commit 30ae0c043ca2f8958223d6fb343b8b3e3561d727 Subproject commit 3a28060108887845256c5b0a6dd3f189665cd1cd