feat: updated CLAUDE.md
This commit is contained in:
73
CLAUDE.md
73
CLAUDE.md
@@ -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:
|
||||
- **FastAPI** for HTTP API endpoints
|
||||
- **aiogram** for Telegram bot functionality
|
||||
- **SQLAlchemy 2.0** (async) for database operations
|
||||
- **Tortoise ORM** (async) for database operations
|
||||
- **PostgreSQL** with asyncpg driver
|
||||
- **Alembic** for database migrations
|
||||
- **aerich** for database migrations
|
||||
- **uv** for Python package management
|
||||
|
||||
## Development Commands
|
||||
@@ -23,7 +23,7 @@ uv sync
|
||||
docker-compose up -d
|
||||
|
||||
# Run database migrations
|
||||
uv run alembic upgrade head
|
||||
make migrate-up # or: export $(cat .env | xargs) && aerich upgrade
|
||||
```
|
||||
|
||||
### Running the Application
|
||||
@@ -58,14 +58,19 @@ uv run pytest tests/test_file.py::test_function_name
|
||||
|
||||
### Database Migrations
|
||||
```bash
|
||||
# Create a new migration
|
||||
uv run alembic revision --autogenerate -m "description"
|
||||
# Create a new migration (auto-generated based on model changes)
|
||||
make migrate-create # or: export $(cat .env | xargs) && aerich migrate
|
||||
|
||||
# Apply migrations
|
||||
uv run alembic upgrade head
|
||||
make migrate-up # or: export $(cat .env | xargs) && aerich upgrade
|
||||
|
||||
# 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
|
||||
@@ -75,12 +80,12 @@ uv run alembic downgrade -1
|
||||
The codebase follows a clean architecture pattern with clear separation of concerns:
|
||||
|
||||
1. **Domain Layer** (`src/domain/`)
|
||||
- SQLAlchemy ORM models that represent database entities
|
||||
- All models inherit from `domain.Base` which provides:
|
||||
- Tortoise ORM models that represent database entities
|
||||
- All models inherit from `domain.base.TimestampedModel` which provides:
|
||||
- Auto-generated `id` (UUID primary key)
|
||||
- Timestamps: `created_at`, `updated_at`, `deleted_at`
|
||||
- Automatic table naming (pluralized lowercase class name)
|
||||
- Timezone-aware datetime fields
|
||||
- Use `class Meta: table = 'table_name'` for explicit table naming
|
||||
|
||||
2. **Use Case Layer** (`src/usecase/`)
|
||||
- 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.StrEnum` для строковых enum (Python 3.11+)
|
||||
- Enum значения в lowercase с underscores
|
||||
- Передавайте enum в SQLAlchemy через `Enum(EnumClass)`
|
||||
- Используйте `fields.CharEnumField()` в Tortoise ORM
|
||||
|
||||
```python
|
||||
import enum
|
||||
from sqlalchemy import Enum
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from tortoise import fields
|
||||
from .base import TimestampedModel
|
||||
|
||||
class TelegramStateEnum(enum.StrEnum):
|
||||
CREATIVE_WAITING_CHANNEL = 'creative_waiting_channel'
|
||||
CREATIVE_WAITING_NAME = 'creative_waiting_name'
|
||||
|
||||
class TelegramState(Base):
|
||||
state: Mapped[TelegramStateEnum] = mapped_column(Enum(TelegramStateEnum), nullable=False)
|
||||
class TelegramState(TimestampedModel):
|
||||
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";
|
||||
"""
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user