一键导入
py-feature
Use when implementing a new feature, endpoint, or use case in a Python/FastAPI backend with clean architecture, SQLAlchemy, and PostgreSQL
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when implementing a new feature, endpoint, or use case in a Python/FastAPI backend with clean architecture, SQLAlchemy, and PostgreSQL
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when the user wants to free disk space, investigate disk usage, clean caches, remove unused artifacts, or when disk capacity is high. Also use when asked to "clean up", "free space", "disk full", or "what's using disk space". Always uses AskUserQuestion for every deletion decision.
Use at the start of every conversation and for every user message — orchestrates the full engineering skills suite by understanding intent, clarifying requirements interactively, and invoking the right skills
Use when refactoring Go code, cleaning up legacy codebases, optimizing performance, or enforcing clean architecture boundaries in a Go/Fiber backend
Use when refactoring Python code, cleaning up legacy codebases, optimizing performance, enforcing type safety, or improving clean architecture in a FastAPI backend
Use when refactoring React components, cleaning up legacy frontends, optimizing performance, improving component architecture, or reducing bundle size
Use when reviewing changed code before committing or after completing a feature — checks performance, architecture, type safety, and code quality against project standards
| name | py-feature |
| description | Use when implementing a new feature, endpoint, or use case in a Python/FastAPI backend with clean architecture, SQLAlchemy, and PostgreSQL |
Layer-by-layer TDD workflow for FastAPI backends following clean architecture. Build inside-out: domain → application → infrastructure → interfaces. All code fully typed with mypy strict.
Core principle: Every layer gets its own test before implementation. Type safety is non-negotiable.
# src/domain/user.py
from dataclasses import dataclass, field
from datetime import datetime
from uuid import UUID, uuid4
@dataclass(frozen=True)
class User:
email: str
name: str
id: UUID = field(default_factory=uuid4)
created_at: datetime = field(default_factory=datetime.utcnow)
def __post_init__(self) -> None:
if not self.email:
raise ValueError("Email is required")
Test first: Parametrized tests for validation.
@pytest.mark.parametrize("email,expected_error", [
("valid@test.com", None),
("", "Email is required"),
])
def test_create_user(email: str, expected_error: str | None) -> None:
if expected_error:
with pytest.raises(ValueError, match=expected_error):
User(email=email, name="Test")
else:
user = User(email=email, name="Test")
assert user.email == email
# src/domain/repositories.py
from typing import Protocol
class UserRepository(Protocol):
async def create(self, user: User) -> User: ...
async def get_by_id(self, id: UUID) -> User | None: ...
async def get_by_email(self, email: str) -> User | None: ...
# src/application/create_user.py
class CreateUserUseCase:
def __init__(self, repo: UserRepository) -> None:
self._repo = repo
async def execute(self, input: CreateUserInput) -> User:
existing = await self._repo.get_by_email(input.email)
if existing:
raise DuplicateEmailError(input.email)
user = User(email=input.email, name=input.name)
return await self._repo.create(user)
Test with mocks: Use unittest.mock.AsyncMock for the protocol.
# src/infrastructure/postgres/user_repository.py
class SQLAlchemyUserRepository:
def __init__(self, session: AsyncSession) -> None:
self._session = session
async def create(self, user: User) -> User:
model = UserModel.from_domain(user)
self._session.add(model)
await self._session.flush()
return model.to_domain()
REQUIRED: Invoke py-integration-test for testcontainers patterns.
# src/interfaces/http/users.py
router = APIRouter(prefix="/users", tags=["users"])
@router.post("/", status_code=201, response_model=UserResponse)
async def create_user(
body: CreateUserRequest,
use_case: CreateUserUseCase = Depends(get_create_user),
) -> UserResponse:
result = await use_case.execute(body.to_input())
return UserResponse.from_domain(result)
Test with httpx:
async def test_create_user(client: AsyncClient) -> None:
resp = await client.post("/api/v1/users", json={"email": "t@t.com", "name": "T"})
assert resp.status_code == 201
assert resp.json()["data"]["email"] == "t@t.com"
| Layer | Package | Tests | Dependencies |
|---|---|---|---|
| Domain | src/domain/ | Unit (parametrize) | None |
| Application | src/application/ | Unit (AsyncMock) | Domain |
| Infrastructure | src/infrastructure/ | Integration (testcontainers) | Domain, SQLAlchemy |
| Interfaces | src/interfaces/http/ | HTTP (httpx AsyncClient) | Application |
Protocol for repository interfaces (not ABC)Mapped[type] for SQLAlchemy modelsBaseModel for request/responseAsyncGenerator for session fixturessuperpowers:test-driven-development at each layercode-quality standards — no N+1 queries (use selectinload/joinedload), batch operations, set-based lookups, asyncio.gather for independent I/Oclaude-md)py-migrate before implementing repositoryapi-design for request/response patterns