Pular para o conteúdo principal

Guia 2 — Estrutura Mínima de Projeto Perl com Carton

Referências arquiteturais: ADR-012 — Estrutura Mínima de Projeto · ADR-005 — Carton + cpanm


O que você vai construir

Ao final deste guia você terá a estrutura de arquivos obrigatória para qualquer projeto Crystallized Perl, criada a partir do zero como esqueleto da Stega:

crystallized-perl-stega/
├── .gitignore
├── .gitattributes
├── cpanfile ← dependências declaradas com versões fixas
├── cpanfile.snapshot ← versões transitivas congeladas pelo Carton
├── DEVELOPMENT.md ← guia de configuração para contribuidores
├── local/ ← módulos instalados (ignorado pelo Git)
├── lib/ ← código da aplicação (ainda vazio)
├── migrations/ ← arquivos SQL (ainda vazio)
├── script/ ← ponto de entrada Mojolicious (ainda vazio)
└── t/ ← testes (ainda vazio)

Pré-requisitos

  • Guia 1 concluído
  • Perl 5.42.2 ativo (perl -v confirma)
  • Carton instalado (carton --version confirma)
  • Git configurado com core.autocrlf false (Windows)

Passo 1 — Criar o repositório

mkdir crystallized-perl-stega
cd crystallized-perl-stega
git init

Passo 2 — .gitattributes (primeiro arquivo sempre)

O .gitattributes deve ser o primeiro arquivo criado. Ele garante que todos os arquivos de texto usem LF independentemente do sistema operacional do desenvolvedor — crítico para scripts executados dentro de containers Linux:

# .gitattributes

# Força LF em todos os arquivos de texto
* text=auto eol=lf

# Perl
*.pl text eol=lf
*.pm text eol=lf
*.t text eol=lf

# Shell
*.sh text eol=lf

# SQL
*.sql text eol=lf

# YAML / JSON / TOML
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.toml text eol=lf

# Markdown
*.md text eol=lf

# PowerShell — manter CRLF (terminais Windows se comportam melhor)
*.ps1 text eol=crlf

Por que .gitattributes antes de qualquer código? Sem ele, um desenvolvedor Windows que clone o repositório obterá CRLF silenciosamente em todos os arquivos. Scripts com CRLF falham dentro de containers Linux com erros confusos como /usr/bin/env: 'perl\r': No such file or directory.


Passo 3 — .gitignore

# .gitignore

# Carton — módulos instalados localmente (nunca commitar)
local/

# Variáveis de ambiente locais (nunca commitar credenciais)
.env
.env.local
.env.*.local

# Perl — artefatos de build
blib/
*.bak
*.old
*.orig
*.rej
pm_to_blib
Makefile
Makefile.old
MYMETA.json
MYMETA.yml
META.yml
META.json

# Cobertura de testes
cover_db/

# macOS
.DS_Store

# Windows
Thumbs.db

# Editores
.vscode/
.idea/
*.swp
*.swo

Atenção: cpanfile.snapshot é incluído no Git (não listado acima). Ele garante que todos os ambientes instalem as mesmas versões de módulos.


Passo 4 — cpanfile

O cpanfile declara as dependências da Stega com versões mínimas fixadas. A primeira linha declara a versão mínima de Perl — validada automaticamente pelo Carton:

# cpanfile

# Versão mínima do Perl — ver ADR-012 e ADR-005
requires 'perl', '5.042';

# Framework web (ADR-004)
requires 'Mojolicious', '9.0';

# Contrato de API OpenAPI v3 (ADR-015)
requires 'Mojolicious::Plugin::OpenAPI', '5.0';

# Acesso a banco de dados (ADR-016)
requires 'Mojo::Pg', '4.0';

# Sistema de OO para modelos de domínio (ADR-006)
requires 'Moo', '2.0';
requires 'namespace::clean';

# Autenticação JWT (ADR-009)
requires 'Crypt::JWT';

# RabbitMQ — publicação não-bloqueante da aplicação (ADR-008)
requires 'Mojo::RabbitMQ::Client';

# RabbitMQ — consumo bloqueante no worker (ADR-008)
requires 'Net::AMQP::RabbitMQ';

# Fila local de jobs (ADR-018)
requires 'Minion';
requires 'Minion::Backend::Pg';

# Dependências de teste — não incluídas na imagem de produção
on 'test' => sub {
requires 'Test::More';
requires 'Test::MockObject';
requires 'Devel::Cover';
};

Passo 5 — Instalar as dependências com Carton

carton install

O Carton:

  1. Lê o cpanfile
  2. Resolve todas as dependências transitivas
  3. Instala os módulos em local/
  4. Gera (ou atualiza) o cpanfile.snapshot com as versões exatas de tudo

Verifique o snapshot gerado:

head -5 cpanfile.snapshot
# CHECKSUMS 1
# ...
# Carton v1.0.34 snapshot
# ...

Adicionar uma nova dependência segue o mesmo fluxo:

# 1. Declarar no cpanfile
echo "requires 'Some::Module';" >> cpanfile

# 2. Instalar e atualizar o snapshot
carton install

Passo 6 — DEVELOPMENT.md

O DEVELOPMENT.md é destinado a desenvolvedores que contribuem com o projeto. Deve ser suficiente para rodar o projeto localmente sem consultar documentação externa:

# Guia de Desenvolvimento — Stega

## Visão geral

A Stega usa Perl 5.42+ (gerenciado por perlbrew/berrybrew — não modifique o
Perl do sistema). Dependências são gerenciadas pelo Carton. Serviços de apoio
(PostgreSQL, RabbitMQ, Keycloak) rodam via Docker Compose.

## Pré-requisitos

- Docker Desktop 4.28+
- Perl 5.42.2 via perlbrew (Linux/macOS) ou berrybrew (Windows)
- Carton: `cpanm Carton`

## Setup inicial

```bash
# 1. Clonar
git clone https://github.com/hibex-solutions/crystallized-perl-stega.git
cd crystallized-perl-stega

# 2. Copiar variáveis de ambiente
cp .env.example .env

# 3. Instalar dependências
carton install

# 4. Subir serviços de apoio
docker compose up -d postgres rabbitmq keycloak

# 5. Aplicar migrations
carton exec perl eng/migrate.pl

# 6. Popular dados de exemplo
carton exec perl eng/seed.pl

# 7. Iniciar a aplicação
carton exec perl script/stega daemon --listen http://*:3000

Variáveis de ambiente obrigatórias

Consulte .env.example — todas as variáveis estão documentadas com valores de exemplo para desenvolvimento local.

Rodando os testes

carton exec prove -lr t/

Scripts de engenharia (eng/)

ScriptO que faz
perl eng/migrate.plAplica migrations pendentes
perl eng/seed.plPopula banco com dados de exemplo
perl eng/setup.plVerifica dependências do ambiente
perl eng/worker.plInicia o NotificationWorker RabbitMQ

---

## Passo 7 — Criar diretórios de código

```bash
mkdir -p lib/Stega/Controller
mkdir -p lib/Stega/Model
mkdir -p lib/Stega/Job
mkdir -p lib/Stega/Worker
mkdir -p migrations
mkdir -p script
mkdir -p t/unit/model
mkdir -p t/api
mkdir -p t/integration
mkdir -p eng
mkdir -p api

Passo 8 — Verificar a estrutura

find . -not -path './.git/*' -not -path './local/*' | sort

Resultado esperado:

.
./.gitattributes
./.gitignore
./DEVELOPMENT.md
./api/
./cpanfile
./cpanfile.snapshot
./eng/
./lib/
./lib/Stega/
./lib/Stega/Controller/
./lib/Stega/Job/
./lib/Stega/Model/
./lib/Stega/Worker/
./migrations/
./script/
./t/
./t/api/
./t/integration/
./t/unit/
./t/unit/model/

Por que cada arquivo existe

Arquivo/DiretórioPropósitoReferência
.gitattributesGarante LF em todos os sistemas operacionaisADR-012
.gitignoreEvita que local/ e credenciais sejam commitadosADR-012
cpanfileDeclara dependências com versões mínimasADR-005
cpanfile.snapshotCongela versões exatas (commitado no Git)ADR-005
local/Módulos instalados pelo Carton (não commitado)ADR-005
DEVELOPMENT.mdGuia de configuração inicial para novos contribuidoresADR-012
lib/Código Perl da aplicação (namespaces Stega::)ADR-004
migrations/Arquivos SQL de migration (NNN_descricao.sql)ADR-016
script/Ponto de entrada MojoliciousADR-004
t/Testes organizados em unit/, api/, integration/ADR-011
eng/Scripts de engenharia em PerlADR-013
api/Contrato OpenAPI v3 (stega.yaml)ADR-015

Próximos passos

Com a estrutura criada, prossiga para: