Como criar uma devstack moderna
Sempre que eu começava um novo projeto full stack, acabava repetindo o mesmo ritual: configurar Docker, ajustar proxy reverso, definir hosts locais, subir frontend e backend separadamente e documentar tudo para que outros desenvolvedores conseguissem rodar o ambiente.
O problema é que esse processo quase nunca era tão simples quanto deveria. Bastava faltar uma network no Docker, uma porta entrar em conflito ou um serviço subir fora da ordem para o setup local virar uma fonte de atrito.
Para resolver isso, montei no projeto Toothly uma estrutura de desenvolvimento local focada em projetos modernos com arquitetura app + api.
A ideia foi criar uma base que fosse:
- simples de entender
- rápida de subir
- reutilizável em outros projetos
- amigável para onboarding
Neste artigo, vou mostrar passo a passo como organizar essa stack usando Docker, Traefik, subdomínios locais, um script de bootstrap e um Makefile para centralizar os comandos.
Objetivo da stack
A proposta dessa devstack é resolver os principais problemas do ambiente local.
Ela entrega:
- Frontend (
app) - Backend (
api) - Proxy reverso com Traefik
- Subdomínios locais amigáveis
- Setup automatizado
- Comandos padronizados
- Zero dor de cabeça para novos devs
Estrutura do projeto
1
2
3
4
5
6
7
8
9
toothly/
├── app/
├── api/
├── docker-compose.yml
├── Makefile
├── scripts/
│ └── bootstrap.sh
└── traefik/
└── traefik.yml
Docker Compose
Aqui está uma versão simplificada da stack:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
services:
traefik:
image: traefik:v3.3
container_name: toothly-traefik
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
networks:
- dev-network
app:
image: node:22-alpine
working_dir: /app
volumes:
- ./app:/app
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.toothly.localhost`)
- traefik.http.routers.app.entrypoints=web
- traefik.http.services.app.loadbalancer.server.port=3000
networks:
- dev-network
api:
image: php:8.2-fpm
working_dir: /var/www
volumes:
- ./api:/var/www
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`api.toothly.localhost`)
- traefik.http.routers.api.entrypoints=web
- traefik.http.services.api.loadbalancer.server.port=9000
networks:
- dev-network
networks:
dev-network:
external: true
Por que usar Traefik?
O Traefik funciona como um proxy reverso inteligente. Com ele, você pode acessar:
- http://app.toothly.localhost
- http://api.toothly.localhost
Em vez de:
- localhost:3000
- localhost:8000
Isso melhora muito:
- organização
- legibilidade
- proximidade com ambiente de produção
O problema da netword Docker
Um problema comum: Se a network dev-network não existir, o projeto quebra. E isso é péssimo para onboarding.
Resolvendo com bootstrap.sh
Para evitar esse problema, criamos um script de bootstrap.
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env bash
set -e
NETWORK_NAME="dev-network"
if ! docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then
echo "Docker network '$NETWORK_NAME' não encontrada. Criando..."
docker network create "$NETWORK_NAME"
else
echo "Docker network '$NETWORK_NAME' já existe."
fi
echo "Ambiente pronto"
Centralizando comandos com Makefile
Em vez de decorar comandos Docker, usamos um Makefile:
bootstrap:
./scripts/bootstrap.sh
up:
docker compose up -d
down:
docker compose down
logs:
docker compose logs -f
restart:
docker compose down && docker compose up -d
Fluxo para novos desenvolvedores
Essa estrutura traz vários ganhos:
- Setup previsível
- Menos erro manual
- Onboarding rápido
- Padronização entre projetos
- Fácil reutilização
- Melhor experiência para o time
Próximos passos
Essa devstack pode evoluir facilmente:
- HTTPS local com certificados
- Integração com banco de dados
- Hot reload para frontend/backend
- Template base para novos projetos
- CLI própria para automação
Conclusão
No fim, mais do que subir containers, a proposta dessa devstack é criar um padrão de trabalho. Quando a estrutura é intuitiva:
- o time ganha velocidade
- o onboarding fica mais leve
- novos projetos começam mais rápido
E o melhor: você nunca mais precisa configurar tudo do zero.
