소스 정보
- 저장소
- tomevault-io/skills-registry
- 최근 소스 활동
- 2026년 5월 11일 15:30
- 감지된 SKILL.md 언어
- 영어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill fastapi-senior-dev명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | fastapi-senior-dev |
| description | name: fastapi-senior-dev Use when this capability is needed. |
Transform into a Senior Python Backend Engineer for production-ready FastAPI applications.
/fastapi-init - Scaffold new project with clean architecture/fastapi-structure - Analyze & restructure existing project/fastapi-audit - Code review for patterns, performance, securityLoad appropriate references based on task context:
| Category | Reference | When to Load |
|---|---|---|
| Database | references/database-sqlalchemy.md | PostgreSQL, async ORM, migrations |
| Database | references/database-mongodb.md | MongoDB with Beanie/Motor |
| Caching | references/caching-redis.md | Redis caching, sessions, pub/sub |
| Security | references/security-auth.md | OAuth2, JWT, OIDC, RBAC |
| Security | references/security-owasp.md | OWASP compliance, hardening |
| Observability | references/observability.md | Logging, metrics, tracing |
| Microservices | references/microservices.md | Celery, Kafka, event-driven |
| API Design | references/api-lifecycle.md | Versioning, deprecation, docs |
| Operations | references/production-ops.md | Health checks, K8s, deployment |
Routes handle HTTP concerns only. Business logic lives in services.
# WRONG: Logic in route
@router.post("/orders")
async def create_order(order: OrderCreate, db: AsyncSession = Depends(get_db)):
if not await db.get(Product, order.product_id):
raise HTTPException(404, "Product not found")
# ... 50 more lines of business logic
return order
# RIGHT: Thin route, fat service
@router.post("/orders", response_model=OrderResponse)
async def create_order(
order: OrderCreate,
service: OrderService = Depends(get_order_service)
) -> OrderResponse:
return await service.create(order)
Use pydantic-settings as foundational concern. Split by domain.
# core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class DatabaseSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="DB_")
host: str = "localhost"
port: int = 5432
name: str
user: str
password: str
pool_size: int = 10
max_overflow: int = 20
@property
def async_url(self) -> str:
return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.name}"
class AuthSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="AUTH_")
secret_key: str
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
refresh_token_expire_days: int = 7
class Settings(BaseSettings):
debug: bool = False
db: DatabaseSettings = DatabaseSettings()
auth: AuthSettings = AuthSettings()
settings = Settings()
Choose architecture based on project size. Be consistent.
Vertical Slice (Recommended for most projects)
src/
├── users/
│ ├── router.py
│ ├── service.py
│ ├── schemas.py
│ ├── models.py
│ └── dependencies.py
├── orders/
│ ├── router.py
│ ├── service.py
│ └── ...
└── core/
├── config.py
├── database.py
└── security.py
Layered Architecture (Large teams, strict boundaries)
src/
├── api/
│ ├── routes/
│ ├── deps/
│ └── schemas/
├── services/
├── repositories/
├── models/
│ ├── domain/
│ └── db/
└── core/
Use services with direct ORM access. Avoid unnecessary repository abstraction.
# services/user_service.py
class UserService:
def __init__(self, db: AsyncSession, cache: Redis):
self.db = db
self.cache = cache
async def get_by_id(self, user_id: int) -> User | None:
# Check cache first
cached = await self.cache.get(f"user:{user_id}")
if cached:
return User.model_validate_json(cached)
# Direct ORM query - no repository needed
result = await self.db.execute(
select(UserModel)
.options(selectinload(UserModel.profile))
.where(UserModel.id == user_id)
)
user_model = result.scalar_one_or_none()
if user_model:
user = User.model_validate(user_model)
await self.cache.setex(f"user:{user_id}", 300, user.model_dump_json())
return user
return None
Chain dependencies for validation and composition.
# deps/common.py
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
# deps/users.py
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> User:
payload = verify_token(token)
user = await db.get(UserModel, payload["sub"])
if not user:
raise HTTPException(401, "User not found")
return user
async def get_current_active_user(
user: User = Depends(get_current_user)
) -> User:
if not user.is_active:
raise HTTPException(403, "Inactive user")
return user
# deps/resources.py
async def valid_post_id(
post_id: int,
db: AsyncSession = Depends(get_db)
) -> Post:
post = db.get(PostModel, post_id)
post:
HTTPException(, )
post
() -> Post:
post.owner_id != user.:
HTTPException(, )
post
() -> PostResponse:
...
# Async DB with proper session handling
async def get_user(db: AsyncSession, user_id: int) -> User | None:
result = await db.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
# Concurrent independent calls
async def get_dashboard_data(user_id: int) -> DashboardData:
user, orders, notifications = await asyncio.gather(
user_service.get(user_id),
order_service.list_recent(user_id),
notification_service.get_unread(user_id),
return_exceptions=True
)
return DashboardData(user=user, orders=orders, notifications=notifications)
# Background tasks for non-blocking operations
@router.post("/users")
async def create_user(user: UserCreate, background: BackgroundTasks):
db_user = await user_service.create(user)
background.add_task(send_welcome_email, db_user.email)
background.add_task(analytics.track, "user_created", db_user.id)
return db_user
# WRONG: Blocking calls in async context
time.sleep(5) # Use: await asyncio.sleep(5)
requests.get(url) # Use: async with httpx.AsyncClient() as client
open("file").read() # Use: aiofiles.open()
# WRONG: Sequential when parallel is possible
user = await get_user(id)
orders = await get_orders(id) # Use asyncio.gather()
# WRONG: Sync dependencies in async routes
def get_db(): # Should be: async def get_db()
return SessionLocal()
from pydantic import BaseModel, ConfigDict, Field, field_validator
from datetime import datetime
class BaseSchema(BaseModel):
"""Base for all schemas with common config."""
model_config = ConfigDict(
from_attributes=True,
str_strip_whitespace=True,
validate_assignment=True,
)
class UserCreate(BaseSchema):
email: str = Field(..., min_length=5, max_length=255)
password: str = Field(..., min_length=8)
@field_validator("email")
@classmethod
def normalize_email(cls, v: str) -> str:
return v.lower().strip()
class UserUpdate(BaseSchema):
model_config = ConfigDict(extra="forbid")
name: str | None = None
avatar_url: str | None = None
class UserResponse(BaseSchema):
id: int
email: str
name: str | None
created_at: datetime
():
hashed_password:
# core/exceptions.py
from fastapi import Request
from fastapi.responses import JSONResponse
class AppException(Exception):
def __init__(self, message: str, code: str, status_code: int = 400):
self.message = message
self.code = code
self.status_code = status_code
class NotFoundError(AppException):
def __init__(self, resource: str, identifier: Any):
super().__init__(
message=f"{resource} with id '{identifier}' not found",
code="NOT_FOUND",
status_code=404
)
class AuthorizationError(AppException):
def __init__(self, message: str = "Not authorized"):
super().__init__(message=message, code="FORBIDDEN", status_code=403)
# Register handler
@app.exception_handler(AppException)
async def ():
JSONResponse(
status_code=exc.status_code,
content={
: {
: exc.code,
: exc.message,
}
}
)
():
logger.exception(, exc_info=exc)
JSONResponse(
status_code=,
content={: {: , : }}
)
See references/security-auth.md and references/security-owasp.md for complete patterns.
| Don't | Do |
|---|---|
| Business logic in routes | Move to services |
| DB queries in routes | Use service layer |
requests in async code | Use httpx.AsyncClient |
time.sleep() | Use asyncio.sleep() |
| Hardcoded config | Use pydantic-settings |
| Return dict from routes | Return Pydantic models |
| Skip type hints | Type everything |
| Global scoped_session | Request-scoped via Depends |
| Repository pattern overkill | Service + direct ORM |
| python-jose for JWT | Use PyJWT |
scripts/scaffold_structure.py - Generate clean architecture foldersscripts/generate_migration.py - Alembic wrapper for async migrationsassets/docker-compose.yml - Postgres + Redis + API stackassets/Dockerfile - Multi-stage production buildWhen running /fastapi-audit, check:
Architecture
Async
Security (load references/security-owasp.md)
Database (load references/database-sqlalchemy.md)
Observability (load references/observability.md)
Converted and distributed by TomeVault — claim your Tome and manage your conversions.