Nome do Projeto: python-hexagonal-study
Repositório: marcellmartini/python-hexagonal-study
Autor: Marcell Martini
Licença: MIT
Descrição: Projeto de estudo e demonstração de arquitetura hexagonal (Ports & Adapters) em Python com FastAPI. Inclui User Management com JWT, RBAC, File Storage com MinIO e Frontend React com shadcn/ui.
| Componente | Tecnologia | Versão |
|---|---|---|
| Framework | FastAPI | 0.127.x |
| Linguagem | Python | 3.10+ |
| ORM | SQLAlchemy | 2.x |
| Migrations | Alembic | 1.17.x |
| Auth | python-jose (JWT) | 3.x |
| Password | passlib + bcrypt | 1.7.x |
| Validation | Pydantic | 2.x |
| Settings | pydantic-settings | 2.x |
| Componente | Tecnologia | Versão |
|---|---|---|
| Framework | React | 19 |
| Build | Vite | 6.x |
| Linguagem | TypeScript | 5.x |
| Estilo | Tailwind CSS | 4.x |
| Componentes | shadcn/ui | latest |
| Estado | Zustand | 5.x |
| Routing | React Router | 7.x |
| HTTP | Axios | 1.7.x |
| Componente | Tecnologia | Versão |
|---|---|---|
| Database | PostgreSQL | 16 |
| Object Storage | MinIO | Latest |
| Container | Docker + Compose | Latest |
python-hexagonal-study/
├── apps/
│ ├── backend/ # API FastAPI
│ │ ├── src/
│ │ │ ├── domain/ # Entidades, Ports, Exceções
│ │ │ │ ├── user/ # User entity, UserPersistencePort
│ │ │ │ ├── storage/ # StoragePort
│ │ │ │ ├── builder/ # BuilderPort
│ │ │ │ ├── exceptions.py
│ │ │ │ └── value_objects.py
│ │ │ ├── application/ # Serviços de aplicação
│ │ │ │ ├── user/ # AuthService, UserService
│ │ │ │ └── services/ # FileService
│ │ │ ├── infrastructure/ # Adapters
│ │ │ │ ├── database/ # PostgreSQL adapter
│ │ │ │ └── storage/ # MinIO adapter
│ │ │ ├── api/ # FastAPI routes
│ │ │ │ ├── auth/ # /auth/*
│ │ │ │ ├── users/ # /users/*
│ │ │ │ ├── files/ # /files/*
│ │ │ │ └── security/ # Permissões
│ │ │ └── main.py
│ │ ├── tests/ # 122 testes, 100% coverage
│ │ ├── alembic/ # Migrations
│ │ ├── pyproject.toml
│ │ ├── Dockerfile
│ │ └── compose.yaml # PostgreSQL standalone
│ │
│ └── frontend/ # React + shadcn/ui
│ ├── src/
│ │ ├── components/
│ │ │ └── ui/ # Componentes shadcn/ui
│ │ ├── features/
│ │ │ ├── auth/ # Login, Register
│ │ │ ├── users/ # User management
│ │ │ ├── files/ # File manager
│ │ │ └── profile/ # User profile
│ │ ├── hooks/ # Custom hooks
│ │ ├── lib/
│ │ │ └── utils.ts # cn() utility
│ │ ├── services/
│ │ │ └── api.ts # Axios client
│ │ ├── stores/
│ │ │ └── auth.ts # Zustand store
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── index.css # Tailwind + CSS vars
│ ├── package.json
│ ├── vite.config.ts
│ ├── components.json # shadcn/ui config
│ ├── Dockerfile
│ └── nginx.conf
│
├── docker-compose.yaml # Full stack (postgres, minio, backend, frontend)
├── CLAUDE.md # Instruções para Claude CLI
├── PROJECT.md # Este arquivo
└── .gitignore
from typing import Protocol, runtime_checkable
@runtime_checkable
class UserPersistencePort(Protocol):
def save(self, user: User) -> User: ...
def find_by_id(self, user_id: UUID) -> Optional[User]: ...class DatabaseRegistry:
_builders: Dict[str, UserPersistenceBuilder] = {}
def register(self, provider: str, builder: UserPersistenceBuilder):
self._builders[provider] = builder
def create_user_persistence(session: Session) -> UserPersistencePort:
builder = DatabaseRegistry.get(config.provider)
return builder.build(session)| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| POST | /auth/register | - | Registrar usuário |
| POST | /auth/login | - | Login (retorna JWT) |
| POST | /auth/refresh | - | Refresh token |
| GET | /auth/me | ✓ | Dados do usuário atual |
| POST | /auth/logout | ✓ | Logout |
| Método | Endpoint | Auth | Role | Descrição |
|---|---|---|---|---|
| GET | /users | ✓ | any | Listar usuários |
| GET | /users/{id} | ✓ | any | Buscar usuário |
| POST | /users | ✓ | admin | Criar usuário |
| PUT | /users/{id} | ✓ | admin | Atualizar usuário |
| DELETE | /users/{id} | ✓ | admin | Deletar usuário |
| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| POST | /files/upload | ✓ | Upload de arquivo (owner: current user) |
| GET | /files/{id} | ✓ | Download de arquivo (owner ou admin) |
| GET | /files/ | ✓ | Listar arquivos (próprios ou todos se admin) |
| DELETE | /files/{id} | ✓ | Deletar arquivo (owner ou admin) |
| PUT | /files/{id} | ✓ | Atualizar arquivo (owner ou admin) |
- Python 3.10+
- Node.js 22+
- Docker e Docker Compose
- Poetry (Python)
- npm/pnpm/bun (Node)
# Clonar repositório
git clone https://github.com/marcellmartini/python-hexagonal-study.git
cd python-hexagonal-study
# Subir todos os serviços
docker compose up -d
# Acessar:
# - Frontend: http://localhost:3000
# - Backend API: http://localhost:8000/docs
# - MinIO Console: http://localhost:9001cd apps/backend
# Criar ambiente virtual
python -m venv .venv
source .venv/bin/activate
# Instalar dependências
pip install poetry
poetry install
# Subir PostgreSQL
docker compose up -d
# Rodar migrations
alembic upgrade head
# Rodar aplicação
PYTHONPATH=src uvicorn api.main:app --reloadcd apps/frontend
# Instalar dependências
npm install
# Adicionar componentes shadcn/ui
npx shadcn@latest add button card input form table dialog toast
# Rodar em desenvolvimento
npm run devshadcn/ui fornece componentes acessíveis e customizáveis baseados em Radix UI:
# Instalar componentes conforme necessário
npx shadcn@latest add button # Botões
npx shadcn@latest add card # Cards
npx shadcn@latest add input # Inputs
npx shadcn@latest add form # Formulários (react-hook-form + zod)
npx shadcn@latest add table # Tabelas
npx shadcn@latest add dialog # Modais
npx shadcn@latest add toast # Notificações
npx shadcn@latest add dropdown-menu # Menus
npx shadcn@latest add avatar # Avatares
npx shadcn@latest add badge # Badgessrc/features/auth/
├── components/
│ ├── LoginForm.tsx
│ └── RegisterForm.tsx
├── hooks/
│ └── useAuth.ts
└── pages/
├── LoginPage.tsx
└── RegisterPage.tsx
// stores/auth.ts
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
accessToken: null,
isAuthenticated: false,
setAuth: (user, token) => set({ user, accessToken: token, isAuthenticated: true }),
logout: () => set({ user: null, accessToken: null, isAuthenticated: false }),
}),
{ name: "auth-storage" }
)
)- Total de testes: 122
- Cobertura: 100%
- Tempo de execução: ~11s
cd apps/backend
# Rodar testes
PYTHONPATH=src pytest tests/ -v
# Com cobertura
PYTHONPATH=src pytest tests/ --cov=src --cov-report=term-missing
# Verificar cobertura mínima
PYTHONPATH=src pytest tests/ --cov=src --cov-fail-under=100# Subir tudo
docker compose up -d
# Parar tudo
docker compose down
# Ver logs
docker compose logs -f
# Rebuild
docker compose up -d --buildcd apps/backend
# Testes
PYTHONPATH=src pytest tests/ -v
# Linting
pylint src/
pyright src/
black src/ tests/
# Migrations
alembic upgrade head
alembic revision --autogenerate -m "description"cd apps/frontend
# Desenvolvimento
npm run dev
# Build
npm run build
# Lint
npm run lint
# Adicionar componente shadcn
npx shadcn@latest add [component]- Setup monorepo
- Estrutura React + Vite + TypeScript
- Configuração Tailwind CSS 4
- Configuração shadcn/ui
- Zustand store
- API client (Axios)
- Implementar páginas de auth (Login/Register)
- Implementar Dashboard
- Implementar User Management
- File Manager (com ownership por usuário e paginação)
- Profile page
- Dark mode toggle
- Sistema dual de temas (Spotlight + Catppuccin)
- Responsividade (mobile/tablet)
- Toggle animado para dark/light mode (ThemeModeToggle com sol/lua)
- Settings popover no sidebar (SettingsPopover)
- Settings drawer no user menu (SettingsDrawer - abre do lado direito)
- Página completa de settings (/settings)
- Notificações toast (sonner)
- Testes unitários (Vitest)
- Testes E2E (Playwright)
- CI/CD (GitHub Actions)
- Entidade User:
apps/backend/src/domain/user/entities.py- Campos: id, name, email, password_hash, role, birth_date, created_at, updated_at
- Roles: USER, ADMIN
- Port:
apps/backend/src/domain/user/ports.py(Protocol) - Services:
AuthService: JWT tokens, bcrypt hashing, autenticaçãoUserService: CRUD operations
- Adapter:
apps/backend/src/infrastructure/database/postgresql/user_adapter.py - API Routes:
/auth/*: register, login, refresh, me, logout/users/*: list, get, create, update, delete
- Port:
apps/backend/src/domain/storage/ports.py(StoragePort Protocol) - Service:
apps/backend/src/application/services/file_service.py - Adapter:
apps/backend/src/infrastructure/storage/minio/storage_adapter.py - API Routes:
/files/*: upload, download, list, delete, update
- Total: 122 testes
- Cobertura: 100%
- Estrutura:
tests/user/test_api.py: Integração (auth + users endpoints)tests/user/test_unit.py: Unitários (services + adapters)tests/files/test_api.py: Integração (file endpoints)tests/files/test_unit.py: Unitários (FileService)tests/storage/test_unit.py: Adapters de storagetests/domain/test_value_objects.py: Value objects
- Configuração Vite + React 19 + TypeScript
- Tailwind CSS 4 com CSS variables para temas
- shadcn/ui configurado (
components.json) - Zustand store para autenticação (
src/stores/auth.ts) - Axios client com interceptors JWT (
src/services/api.ts) - Dockerfile multi-stage + nginx.conf para produção
- Páginas de Auth: LoginPage, RegisterPage com validação (react-hook-form + zod)
- Dashboard: Welcome page com cards de estatísticas (dados reais da API)
- User Management: Tabela CRUD completa (list, create, edit inline, delete admin-only) com avatars e search
- File Manager: Página completa de gestão de arquivos (upload, list, download, delete) com ownership por usuário, paginação 5/10/20/50/100, ícones por tipo de arquivo
- Profile: Página de perfil do usuário com ícones coloridos
- Layout: Navbar responsiva, Sidebar com navegação, MainLayout (estilo Spotlight)
- Sistema de Temas: Dual theme system (Spotlight zinc/teal + Catppuccin Mocha/Latte)
- Estado: Zustand stores para auth, theme, users, files com persist
O frontend suporta dois color schemes, cada um com light/dark mode:
| Color Scheme | Light | Dark | Cores Principais |
|---|---|---|---|
| Spotlight | zinc white | zinc black | teal (#14b8a6 / #2dd4bf) |
| Catppuccin | Latte | Mocha | blue (#1e66f5 / #89b4fa) |
Arquivos de tema:
src/styles/themes/spotlight.css- Tema Spotlightsrc/styles/themes/catppuccin.css- Tema Catppuccinsrc/index.css- Importa ambos, fallback para Spotlight
Build-time config:
VITE_DEFAULT_COLOR_SCHEME=spotlight npm run build # ou catppuccin// src/services/api.ts - Já configurado com:
// - Request interceptor: adiciona Bearer token
// - Response interceptor: refresh automático em 401
// - Exports: authApi, usersApi, filesApi// src/stores/auth.ts - Já configurado com:
// - user, accessToken, refreshToken, isAuthenticated
// - setAuth(), setAccessToken(), logout()
// - persist() para localStorage- Toggle Animado: Switch animado sol/lua (
ThemeModeToggle.tsx) com tamanhos sm/md - Settings Popover: Engrenagem no footer do sidebar com quick settings
- Settings Drawer: Drawer completo no UserMenu (abre do lado direito)
- Settings Page: Página dedicada em
/settingscom todas as configurações - Notificações: Toast configurado (sonner)
- Responsividade: Otimização para mobile/tablet
- Testes E2E: Playwright para fluxos críticos (auth, user CRUD, file management)
Referência de animação: https://dribbble.com/shots/25421926-Toggle-Switch-Animation-with-Dark-and-Light-mode
- Structural typing (duck typing) vs nominal typing
- Não requer herança explícita
- Melhor integração com type checkers (mypy, pyright)
- Pattern mais Pythonic
- Desacoplamento total entre camadas
- Facilita testes (mock fácil)
- Suporta múltiplos providers (PostgreSQL, MySQL, etc.)
- Configuração via ambiente (sem código)
- API mais simples e direta
- Menos boilerplate
- Melhor performance (selective subscriptions)
- Integração nativa com persist middleware
- Componentes copiados para o projeto (não dependência)
- Customização total via CSS variables
- Baseado em Radix UI (acessibilidade)
- Tailwind CSS nativo
8625e32 docs: update for monorepo structure and frontend
3ae269c feat(docker): add full stack docker-compose
f556acf feat(frontend): add React 19 + Vite + shadcn/ui setup
e71a350 refactor(monorepo): move backend code to apps/backend
2991eb2 feat(docs): add PROJECT.md with complete project documentation
c9aff8f fix(user-tests): add missing test cases for full coverage
014e323 feat(file-tests): add comprehensive tests for file storage
665f83e feat(docs): add CLAUDE.md project documentation
6459aee feat(user-tests): add comprehensive tests for user management
45515e6 feat(alembic): add database migrations for users table
a1a2b3c feat(user-api): add auth and user endpoints with security
b2c3d4e feat(user-infra): add PostgreSQL adapter with registry pattern
c3d4e5f feat(user-services): add AuthService and UserService
d4e5f6g feat(user-domain): add User entity, ports and exceptions
Status: 13 commits ahead de origin/feat/user-management, aguardando PR para main