Files
ai_agent/.claude/rules/schemas-models.md
T
furyhawk 8351e73d39 feat: add Zustand stores for conversation, file preview, sidebar, theme, and knowledge base selection
- Implemented `conversation-store` for managing conversations and messages.
- Created `file-preview-store` to handle file preview state.
- Added `sidebar-store` for sidebar visibility management.
- Developed `theme-store` for theme persistence and management.
- Introduced `kb-selection-store` for managing active knowledge base selections with persistence.

chore: define API and chat types

- Added types for API responses, authentication, chat messages, conversations, and projects.
- Defined interfaces for various entities including users, sessions, and message ratings.

build: configure TypeScript and testing setup

- Set up `tsconfig.json` for TypeScript configuration.
- Created `vitest.config.ts` for testing configuration with Vitest.
- Added `vitest.setup.ts` for global test setup including mocks for Next.js router and media queries.
- Configured Vercel deployment settings in `vercel.json`.
2026-06-11 16:54:43 +08:00

2.8 KiB

description, globs
description globs
Pydantic schema patterns and SQLAlchemy model conventions
backend/app/schemas/**/*.py
backend/app/db/models/**/*.py
backend/app/db/base.py

Schemas & Models

Pydantic Schemas (app/schemas/)

Base schema with shared config:

class BaseSchema(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,
        populate_by_name=True,
        str_strip_whitespace=True,
    )

Separate models per operation:

class UserCreate(BaseSchema):
    email: EmailStr = Field(max_length=255)
    password: str = Field(min_length=8, max_length=128)
    full_name: str | None = Field(default=None, max_length=255)

class UserUpdate(BaseSchema):
    email: EmailStr | None = Field(default=None, max_length=255)
    password: str | None = Field(default=None, min_length=8, max_length=128)
    full_name: str | None = Field(default=None, max_length=255)
    is_active: bool | None = None

class UserRead(BaseSchema, TimestampSchema):
    id: UUID
    email: EmailStr
    full_name: str | None = None
    role: UserRole = UserRole.USER
    avatar_url: str | None = None

class UserList(BaseSchema):
    items: list[UserRead]
    total: int

Rules:

  • *Create — required fields for creation, with Field() constraints
  • *Update — all fields optional (type | None = None)
  • *Read — includes id and timestamps, inherits TimestampSchema
  • *Listitems list + total count
  • Use @field_validator for complex deserialization (e.g., JSON string → dict)

SQLAlchemy Models (app/db/models/)

class User(Base, TimestampMixin):
    __tablename__ = "users"

    id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)
    hashed_password: Mapped[str | None] = mapped_column(String(255), nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

    conversations: Mapped[list["Conversation"]] = relationship(
        "Conversation", back_populates="user", cascade="all, delete-orphan"
    )

    def __repr__(self) -> str:
        return f"<User(id={self.id}, email={self.email})>"

Rules:

  • Always inherit Base and TimestampMixin (provides created_at, updated_at)
  • Use Mapped[type] with mapped_column() for all columns
  • ForeignKey with ondelete="CASCADE" for parent references
  • Always define __repr__
  • Naming convention in Base.metadata: {table}_{col}_key, {table}_{col}_fkey, etc.

TimestampMixin

class TimestampMixin:
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    updated_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), onupdate=func.now(), nullable=True
    )