โ† Back to list
eco2-team

clean-architecture

by eco2-team

๐ŸŒฑ ์ด์ฝ”์—์ฝ”(Ecoยฒ) BE

โญ 0๐Ÿด 0๐Ÿ“… Jan 25, 2026

SKILL.md


name: clean-architecture description: Guide for implementing Clean Architecture in Python/FastAPI projects. Use when creating new modules, refactoring existing code to Clean Architecture, designing layer structures, or implementing Port/Adapter patterns. Triggers on "clean architecture", "hexagonal", "ports and adapters", "layer structure", "DIP", "dependency inversion".

Clean Architecture Implementation Guide

Quick Reference

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         Dependency Rule                          โ”‚
โ”‚          Dependencies ALWAYS point inward (to Domain)            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                  โ”‚
โ”‚   Presentation โ”€โ”€โ–ถ Application โ”€โ”€โ–ถ Domain โ—€โ”€โ”€ Infrastructure    โ”‚
โ”‚   (Controllers)    (Use Cases)    (Entities)   (Adapters)       โ”‚
โ”‚                                                                  โ”‚
โ”‚   Infrastructure IMPLEMENTS Domain/Application Ports             โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Layer Responsibilities

LayerResponsibilityAllowed Dependencies
DomainBusiness rules, Entities, Value ObjectsNone (pure Python)
ApplicationUse Cases, OrchestrationDomain only
InfrastructureDB, External APIs, Framework adaptersDomain, Application
PresentationHTTP/CLI, Request/Response handlingApplication

Standard Directory Structure

app_name/
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ entities/           # Aggregate roots, Entities
โ”‚   โ”œโ”€โ”€ value_objects/      # Immutable value types
โ”‚   โ”œโ”€โ”€ services/           # Domain services (stateless)
โ”‚   โ”œโ”€โ”€ ports/              # Domain-level abstractions
โ”‚   โ”œโ”€โ”€ enums/              # Domain enumerations
โ”‚   โ””โ”€โ”€ exceptions/         # Domain exceptions
โ”‚
โ”œโ”€โ”€ application/
โ”‚   โ”œโ”€โ”€ commands/           # Write Use Cases (Interactors)
โ”‚   โ”œโ”€โ”€ queries/            # Read Use Cases (QueryServices)
โ”‚   โ”œโ”€โ”€ ports/              # Application-level abstractions
โ”‚   โ”œโ”€โ”€ dto/                # Data Transfer Objects
โ”‚   โ”œโ”€โ”€ services/           # Application services
โ”‚   โ””โ”€โ”€ exceptions/         # Application exceptions
โ”‚
โ”œโ”€โ”€ infrastructure/
โ”‚   โ”œโ”€โ”€ adapters/           # Port implementations
โ”‚   โ”œโ”€โ”€ persistence/        # ORM, migrations
โ”‚   โ”œโ”€โ”€ integrations/       # External API clients
โ”‚   โ””โ”€โ”€ exceptions/         # Infrastructure exceptions
โ”‚
โ”œโ”€โ”€ presentation/
โ”‚   โ””โ”€โ”€ http/
โ”‚       โ”œโ”€โ”€ controllers/    # FastAPI routers
โ”‚       โ”œโ”€โ”€ dependencies/   # FastAPI Depends
โ”‚       โ””โ”€โ”€ schemas/        # Pydantic request/response
โ”‚
โ””โ”€โ”€ setup/
    โ”œโ”€โ”€ config.py           # Settings
    โ””โ”€โ”€ dependencies.py     # DI wiring

Port & Adapter Pattern

Defining Ports (Interfaces)

# application/ports/user_repository.py
from typing import Protocol

class UserRepository(Protocol):
    """Port: Abstract interface for user persistence"""

    async def get_by_id(self, user_id: UserId) -> User | None: ...
    async def save(self, user: User) -> None: ...
    async def exists_by_email(self, email: Email) -> bool: ...

Implementing Adapters

# infrastructure/adapters/postgres_user_repository.py
class PostgresUserRepository:
    """Adapter: Concrete implementation using PostgreSQL"""

    def __init__(self, session: AsyncSession):
        self._session = session

    async def get_by_id(self, user_id: UserId) -> User | None:
        stmt = select(UserModel).where(UserModel.id == user_id.value)
        result = await self._session.execute(stmt)
        row = result.scalar_one_or_none()
        return self._to_entity(row) if row else None

CQRS Pattern

Command (Write Operation)

# application/commands/create_user.py
@dataclass(frozen=True)
class CreateUserCommand:
    email: str
    password: str

class CreateUserInteractor:
    def __init__(
        self,
        user_repo: UserRepository,
        hasher: PasswordHasher,
        tx: TransactionManager,
    ):
        self._repo = user_repo
        self._hasher = hasher
        self._tx = tx

    async def execute(self, cmd: CreateUserCommand) -> UserId:
        # Domain logic
        user = User.create(
            email=Email(cmd.email),
            password_hash=await self._hasher.hash(cmd.password),
        )
        await self._repo.save(user)
        await self._tx.commit()
        return user.id

Query (Read Operation)

# application/queries/get_user.py
class GetUserQueryService:
    def __init__(self, reader: UserQueryGateway):
        self._reader = reader

    async def execute(self, user_id: UUID) -> UserDTO | None:
        return await self._reader.get_by_id(user_id)

Naming Conventions

TypePatternExample
Port (data access){Entity}Repository or {Entity}GatewayUserRepository
Port (action){Action}erPasswordHasher, TokenGenerator
Adapter{Tech}{Port}PostgresUserRepository, BcryptHasher
Command Use Case{Verb}{Noun}InteractorCreateUserInteractor
Query Use Case{Verb}{Noun}QueryServiceListUsersQueryService
Value Object{Noun} (noun form)Email, UserId, Money

Reference Files

Ecoยฒ Project Conventions

This project follows conventions from docs/foundations/16-fastapi-clean-example-analysis.md:

  • Use Protocol over ABC for interfaces (structural typing)
  • Gateway naming for CQRS split (CommandGateway, QueryGateway)
  • Separate Flusher and TransactionManager ports
  • Value Objects with self-validation in __post_init__

Score

Total Score

60/100

Based on repository quality metrics

โœ“SKILL.md

SKILL.mdใƒ•ใ‚กใ‚คใƒซใŒๅซใพใ‚Œใฆใ„ใ‚‹

+20
โœ“LICENSE

ใƒฉใ‚คใ‚ปใƒณใ‚นใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+10
โ—‹่ชฌๆ˜Žๆ–‡

100ๆ–‡ๅญ—ไปฅไธŠใฎ่ชฌๆ˜ŽใŒใ‚ใ‚‹

0/10
โ—‹ไบบๆฐ—

GitHub Stars 100ไปฅไธŠ

0/15
โ—‹ๆœ€่ฟ‘ใฎๆดปๅ‹•

3ใƒถๆœˆไปฅๅ†…ใซๆ›ดๆ–ฐใŒใ‚ใ‚‹

0/10
โ—‹ใƒ•ใ‚ฉใƒผใ‚ฏ

10ๅ›žไปฅไธŠใƒ•ใ‚ฉใƒผใ‚ฏใ•ใ‚Œใฆใ„ใ‚‹

0/5
โœ“Issue็ฎก็†

ใ‚ชใƒผใƒ—ใƒณIssueใŒ50ๆœชๆบ€

+5
โœ“่จ€่ชž

ใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐ่จ€่ชžใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

+5
โ—‹ใ‚ฟใ‚ฐ

1ใคไปฅไธŠใฎใ‚ฟใ‚ฐใŒ่จญๅฎšใ•ใ‚Œใฆใ„ใ‚‹

0/5

Reviews

๐Ÿ’ฌ

Reviews coming soon