Phase 7: End-to-End API Testing - Database setup, migrations, and application fixes

- Switched from psycopg2 to asyncpg for async SQLAlchemy support
- Fixed router registration in main.py - removed duplicate prefixes
- Added user_data export to routers/__init__.py
- Refactored decks router to use DeckManager service layer
- Integrated FuzzyCardMatcher into card_router search endpoints
- Made WishlistCreate.card_id optional for proper schema validation
- Set PostgreSQL password and configured scram-sha-256 auth
- Updated alembic.ini to use local PostgreSQL instead of Docker hostname
- Created generic_schemas.py for reusable schema patterns
- Added test_routers.py and test_schema_validation.py test files
- All 6 Alembic migrations applied successfully (37 tables created)
- Application running on port 8000 with all services connected
This commit is contained in:
2026-08-18 03:35:19 +00:00
parent bea91db64d
commit 1df04aea52
20 changed files with 862 additions and 513 deletions
+9 -34
View File
@@ -1,5 +1,5 @@
"""Pydantic schemas for user deck building features."""
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, ConfigDict
from typing import Optional, List, Dict, Any
from datetime import datetime
from enum import Enum
@@ -48,6 +48,8 @@ class UserDeckUpdate(BaseModel):
class UserDeckResponse(BaseModel):
"""Deck response with card count."""
model_config = ConfigDict(from_attributes=True)
id: int
user_id: int
name: str
@@ -62,9 +64,6 @@ class UserDeckResponse(BaseModel):
card_count: int = 0
is_owner: bool = False
class Config:
from_attributes = True
class UserDeckListResponse(BaseModel):
"""List of user decks."""
@@ -94,16 +93,14 @@ class DeckCardUpdate(BaseModel):
class DeckCardResponse(BaseModel):
"""Deck card response."""
model_config = ConfigDict(from_attributes=True)
id: int
deck_id: int
card_id: int
quantity: int
zone: str
position: Optional[int]
created_at: datetime
class Config:
from_attributes = True
class DeckCardWithDetailsResponse(DeckCardResponse):
@@ -139,6 +136,8 @@ class PrecedentUpdate(BaseModel):
class PrecedentResponse(BaseModel):
"""Deck precedent response."""
model_config = ConfigDict(from_attributes=True)
id: int
name: str
description: Optional[str]
@@ -149,9 +148,6 @@ class PrecedentResponse(BaseModel):
updated_at: datetime
card_count: int = 0
class Config:
from_attributes = True
class PrecedentListResponse(BaseModel):
"""List of deck precedents."""
@@ -172,6 +168,8 @@ class SuggestionCreate(BaseModel):
class SuggestionResponse(BaseModel):
"""Card suggestion response."""
model_config = ConfigDict(from_attributes=True)
id: int
deck_id: int
card_id: int
@@ -182,9 +180,6 @@ class SuggestionResponse(BaseModel):
created_at: datetime
card_name: str = ""
class Config:
from_attributes = True
class SuggestionListResponse(BaseModel):
"""List of card suggestions."""
@@ -220,23 +215,3 @@ class CardSearchRequest(BaseModel):
limit: int = Field(50, ge=1, le=200)
offset: int = Field(0, ge=0)
class CardSearchResponse(BaseModel):
"""Card search response."""
cards: List[Dict[str, Any]]
total: int
page: int
page_size: int
total_pages: int
# ===== Generic Schemas =====
class MessageResponse(BaseModel):
"""Generic message response."""
message: str
class CountResponse(BaseModel):
"""Generic count response."""
count: int