feat: updated CLAUDE.md

This commit is contained in:
Artem Tsyrulnikov
2025-12-23 10:43:01 +03:00
parent 829cd82bcf
commit c6d3c78e0c

View File

@@ -7,9 +7,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
This is a FastAPI + Telegram Bot backend application for managing Telegram channel integrations. The project uses: This is a FastAPI + Telegram Bot backend application for managing Telegram channel integrations. The project uses:
- **FastAPI** for HTTP API endpoints - **FastAPI** for HTTP API endpoints
- **aiogram** for Telegram bot functionality - **aiogram** for Telegram bot functionality
- **SQLAlchemy 2.0** (async) for database operations - **Tortoise ORM** (async) for database operations
- **PostgreSQL** with asyncpg driver - **PostgreSQL** with asyncpg driver
- **Alembic** for database migrations - **aerich** for database migrations
- **uv** for Python package management - **uv** for Python package management
## Development Commands ## Development Commands
@@ -23,7 +23,7 @@ uv sync
docker-compose up -d docker-compose up -d
# Run database migrations # Run database migrations
uv run alembic upgrade head make migrate-up # or: export $(cat .env | xargs) && aerich upgrade
``` ```
### Running the Application ### Running the Application
@@ -58,14 +58,19 @@ uv run pytest tests/test_file.py::test_function_name
### Database Migrations ### Database Migrations
```bash ```bash
# Create a new migration # Create a new migration (auto-generated based on model changes)
uv run alembic revision --autogenerate -m "description" make migrate-create # or: export $(cat .env | xargs) && aerich migrate
# Apply migrations # Apply migrations
uv run alembic upgrade head make migrate-up # or: export $(cat .env | xargs) && aerich upgrade
# Rollback one migration # Rollback one migration
uv run alembic downgrade -1 make migrate-down # or: export $(cat .env | xargs) && aerich downgrade
# NOTE: For custom constraints (CHECK, custom indexes, etc.) that cannot be defined
# in Tortoise ORM models, create empty migrations and edit them manually:
export $(cat .env | xargs) && aerich migrate --name "add_check_constraint" --empty
# Then edit the created file and add `# ruff: noqa` and `# mypy: ignore-errors` at the top.
``` ```
## Architecture ## Architecture
@@ -75,12 +80,12 @@ uv run alembic downgrade -1
The codebase follows a clean architecture pattern with clear separation of concerns: The codebase follows a clean architecture pattern with clear separation of concerns:
1. **Domain Layer** (`src/domain/`) 1. **Domain Layer** (`src/domain/`)
- SQLAlchemy ORM models that represent database entities - Tortoise ORM models that represent database entities
- All models inherit from `domain.Base` which provides: - All models inherit from `domain.base.TimestampedModel` which provides:
- Auto-generated `id` (UUID primary key) - Auto-generated `id` (UUID primary key)
- Timestamps: `created_at`, `updated_at`, `deleted_at` - Timestamps: `created_at`, `updated_at`, `deleted_at`
- Automatic table naming (pluralized lowercase class name)
- Timezone-aware datetime fields - Timezone-aware datetime fields
- Use `class Meta: table = 'table_name'` for explicit table naming
2. **Use Case Layer** (`src/usecase/`) 2. **Use Case Layer** (`src/usecase/`)
- Business logic functions organized by feature - Business logic functions organized by feature
@@ -322,17 +327,55 @@ await self.telegram_bot.send_message_with_inline_keyboard('Message', chat_id, bu
**Типизация Enum в Domain:** **Типизация Enum в Domain:**
- Используйте `enum.StrEnum` для строковых enum (Python 3.11+) - Используйте `enum.StrEnum` для строковых enum (Python 3.11+)
- Enum значения в lowercase с underscores - Enum значения в lowercase с underscores
- Передавайте enum в SQLAlchemy через `Enum(EnumClass)` - Используйте `fields.CharEnumField()` в Tortoise ORM
```python ```python
import enum import enum
from sqlalchemy import Enum from tortoise import fields
from sqlalchemy.orm import Mapped, mapped_column from .base import TimestampedModel
class TelegramStateEnum(enum.StrEnum): class TelegramStateEnum(enum.StrEnum):
CREATIVE_WAITING_CHANNEL = 'creative_waiting_channel' CREATIVE_WAITING_CHANNEL = 'creative_waiting_channel'
CREATIVE_WAITING_NAME = 'creative_waiting_name' CREATIVE_WAITING_NAME = 'creative_waiting_name'
class TelegramState(Base): class TelegramState(TimestampedModel):
state: Mapped[TelegramStateEnum] = mapped_column(Enum(TelegramStateEnum), nullable=False) state = fields.CharEnumField(TelegramStateEnum, max_length=26)
class Meta:
table = 'telegram_state'
```
**Database Constraints:**
- Foreign keys: Use `fields.ForeignKeyField()` with `on_delete=fields.CASCADE`
- Unique constraints: Use `unique=True` or `unique_together` in Meta
- CHECK constraints: Cannot be defined in Tortoise models - create manual migrations
- Indexes: Use `index=True` on fields or define in Meta
Example with CHECK constraint:
```bash
# Create empty migration
export $(cat .env | xargs) && aerich migrate --name "add_check_constraint" --empty
```
Then edit the created file:
```python
# migrations/models/1_xxx_add_check_constraint.py
# ruff: noqa
# mypy: ignore-errors
from tortoise import BaseDBAsyncClient
RUN_IN_TRANSACTION = True
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "table_name"
ADD CONSTRAINT "constraint_name"
CHECK (your_condition);
"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "table_name"
DROP CONSTRAINT IF EXISTS "constraint_name";
"""
``` ```