flea/CLAUDE.md
ruberoid 97798df417
All checks were successful
continuous-integration/drone/push Build is passing
docs: Add detailed CI/CD workflow examples to CLAUDE.md
- Add 'How to trigger' sections with exact git commands for each pipeline
- Include practical examples: feature testing, contract publishing, releases
- Add 'Common CI/CD Workflows' section with real-world scenarios
- Document emergency rollback procedure
- Clarify contract-only service names (telegram_listener vs telegram-listener)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 12:44:23 +04:00

348 lines
11 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is a microservices-based Telegram bot system for text monitoring and notifications. The system consists of 4 main services that communicate via RabbitMQ:
- **telegram-listener**: Scans open Telegram channels and chats for messages
- **telegram-client**: Bot interface for user interactions
- **text-matcher**: Matches incoming messages against user subscriptions
- **users**: Manages users and their preferences
**Important:** This repository is the parent project containing all services as **git submodules**. Each service (telegram-listener, telegram-client, text-matcher, users) is a separate repository added as a submodule. Git tags are created at the parent repository level, which triggers the Drone CI/CD pipeline to automatically build and publish NuGet packages with versions based on the git tag.
## Architecture
The services follow a message bus pattern using RabbitMQ for async communication:
- TelegramListener publishes:
- **MessageReceived** events (for new messages)
- **MessageEdited** events (for edited messages)
- TextMatcher subscribes to MessageReceived and MessageEdited, stores match history in database, and publishes:
- TextSubscriptionMatched events (for first-time matches)
- TextSubscriptionUpdated events (for updates to previously matched messages)
- TelegramClient subscribes to both TextSubscriptionMatched and TextSubscriptionUpdated events and notifies users
**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:
- Host (API/entry point)
- AppServices (business logic)
- Core (shared utilities)
- Api.Contracts (REST API contracts)
- Async.Api.Contracts (event contracts)
- Persistence (database layer, where applicable)
- Migrator (database migrations, where applicable)
## Development Commands
### Running the System
```bash
# Start all services with Docker Compose
docker-compose up
# Start individual services for development
cd telegram-client && dotnet run --project src/Nocr.TelegramClient.Host
cd telegram-listener && dotnet run --project src/Nocr.TelegramListener.Host
cd text-matcher && dotnet run --project src/Nocr.TextMatcher.Host
cd users && dotnet run --project src/Nocr.Users.Host
```
### Building
```bash
# Build individual services
cd <service-name> && dotnet build
# Build specific projects
dotnet build src/Nocr.<ServiceName>.Host
```
### Testing
```bash
# Run unit tests (only text-matcher has tests currently)
cd text-matcher && dotnet test
```
### Database Migrations
For text-matcher and users services:
```bash
# Add new migration (from service root directory)
cd text-matcher && ./src/Nocr.TextMatcher.Migrator/AddMigration.sh MyMigrationName
cd users && ./src/Nocr.Users.Migrator/AddMigration.sh MyMigrationName
# Apply migrations (handled automatically by migrator containers in docker-compose)
```
## Configuration
**📖 See [CONFIGURATION.md](CONFIGURATION.md) for detailed configuration guide.**
### Quick Start
The system uses ASP.NET Core's layered configuration with **Environment Variables having highest priority**.
**Configuration priority (lowest → highest):**
1. `appsettings.json` (base settings, committed)
2. `appsettings.{Environment}.json` (environment-specific, some committed via `.example` files)
3. User Secrets (Development only)
4. **Environment Variables (ALWAYS WINS)**
### Three Deployment Modes
1. **VS Code (Local Development)**
- Copy `appsettings.Development.json.example``appsettings.Development.json` in each service
- Or use environment variables in `.vscode/launch.json`
- Start infrastructure: `docker-compose up nocr-rabbitmq nocr-text-matcher-db nocr-users-db -d`
2. **Docker Compose (Local Full Stack)**
- Copy `.nocr.env.example``.nocr.env` in project root
- Fill in your Telegram API credentials and Bot token
- Run: `docker-compose up`
3. **Kubernetes (Production)**
- Create K8s Secrets (do NOT use `.nocr.env`)
- Reference secrets in deployment manifests via `envFrom`
### Debug Mode
Enable configuration debug logging on startup:
```bash
export NOCR_DEBUG_MODE=true
```
This prints masked configuration values to help troubleshoot issues.
### Important Notes
-**Never commit secrets** - use `.example` files as templates
- ✅ Environment variables override all appsettings files
- ✅ All services use `.example` files for documentation
- ✅ Docker Compose uses `.nocr.env` file (gitignored)
## Service Ports
When running with docker-compose:
- telegram-client: 5050 (http://localhost:5050/health)
- telegram-listener: 5040 (http://localhost:5040/health)
- text-matcher: 5041 (http://localhost:5041/health)
- users: 5042 (http://localhost:5042/health)
- RabbitMQ: 5672 (AMQP), 15672 (Management UI - http://localhost:15672, admin/admin)
- MariaDB: 3316 (text-matcher), 3326 (users)
## Key Technologies
- .NET 8
- ASP.NET Core Web APIs
- Entity Framework Core with MariaDB
- WTelegramClient for Telegram API
- Rebus for message bus (RabbitMQ)
- Docker & Docker Compose for containerization
- Drone CI/CD 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
**📖 See [_deploy/README.md](_deploy/README.md) for full CI/CD documentation.**
The project uses Drone CI with 5 specialized pipelines:
### 1. Feature Validation (`feature/*`, `fix/*` branches)
**Purpose**: Test feature branches before merging to main
**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
- Provides fast feedback before merge
- Duration: ~3-5 minutes
### 2. Main Validation (`main` branch)
**Purpose**: Ensure main branch stays healthy after merge
**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
- Ensures main branch builds and tests pass
- Duration: ~3-5 minutes
### 3. Contracts-Only Publish
**Purpose**: Publish NuGet contracts without building Docker images (fast iteration)
**How to trigger**:
```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
**Services**: `telegram_listener`, `text_matcher`, `users`
### 4. Full Release
**Purpose**: Complete release - contracts + images + deployment
**How to trigger**:
```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
### 5. Deploy-Only
**Purpose**: Deploy existing images without rebuilding (rollbacks, hotfixes)
**How to trigger**:
```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
## 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
Located in `_deploy/scripts/`:
- **deploy.sh** - Deploy services to Kubernetes with health checks
- **rollback.sh** - Rollback deployments to previous version
- **health-check.sh** - Check health of all services
### Key Optimizations
- **Shared NuGet cache** across pipeline steps (~60% faster builds)
- **Parallel execution** for independent operations
- **Proper dependency order**: Contracts → Images → Deploy
- **Kaniko layer caching** for faster Docker builds
- **Docker-in-Docker** support for Testcontainers in tests