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) — faixa travada abaixo da versão que
# introduziu uma dependência XS (Net::IDN::Encode) incompatível com Perl 5.42
requires 'Mojolicious::Plugin::OpenAPI', '>= 5.11, < 5.12';
requires 'JSON::Validator', '>= 5.13, < 5.16';

# 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::autoclean', '0.29';

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

# Assinatura HMAC para webhooks
requires 'Digest::HMAC', '1.04';

# JSON puro-Perl (disponível no core do Perl mas fixado em versão mínima)
requires 'JSON::PP', '4.0';

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

# Filas de eventos multi-consumidor: PgQue (ADR-022) não precisa de dependência
# própria — é SQL puro, consumido via Mojo::Pg (já declarado acima)

# Dependências de teste — não incluídas na imagem de produção
on 'test' => sub {
requires 'Test::More', '1.302';
requires 'Devel::Cover', '1.38';
};
Números de versão no cpanfile são mínimos, não exatos

requires 'Mojolicious', '9.0'; significa "9.0 ou mais recente" — o carton install instala a versão mais nova disponível que satisfaça essa condição. A fixação exata de versão acontece no cpanfile.snapshot (próximo passo), não no cpanfile. Quando um teto de versão é necessário — como no caso do Mojolicious::Plugin::OpenAPI acima — use a sintaxe de intervalo: '>= 5.11, < 5.12'. Ver ADR-005 para a explicação completa.


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
(quatro instâncias PostgreSQL, Keycloak) rodam via Docker Compose.

## Pré-requisitos

- Docker Desktop 4.28+
- Perl 5.42.2 via perlbrew (Linux/macOS) ou berrybrew (Windows)
- Carton: `cpanm --notest 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-app postgres-jobs postgres-events postgres-keycloak keycloak

# 5. Aplicar migrations e instalar o PgQue
carton exec perl eng/migrate.pl
carton exec perl eng/bootstrap_pgque.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/) e processos da aplicação (script/)

eng/ é apoio ao desenvolvimento/implantação; script/ são processos que rodam em produção (ADR-013, revisão 2026-07-07):

ScriptO que faz
perl eng/migrate.plAplica migrations pendentes em db-app
perl eng/seed.plPopula banco com dados de exemplo
perl eng/setup.plVerifica dependências do ambiente
perl eng/bootstrap_pgque.plInstala o PgQue em db-events (idempotente)
perl script/workerInicia o NotificationWorker (consumidor PgQue)
perl script/pgque_tickerTick de rotação do PgQue

---

## 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/lib/Stega/Test
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/lib/
./t/lib/Stega/
./t/lib/Stega/Test/

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/Uma pasta por versão (N/up.sql, N/down.sql), via from_dirADR-016
script/Processos de execução da aplicação: entry point Mojolicious e demais processos de longa duração (worker, ticker)ADR-004, ADR-013
t/Testes com prefixo numérico (NNN_nome.t); helpers de teste em t/lib/ADR-011
eng/Ferramentas de apoio ao desenvolvimento/implantação, em PerlADR-013
api/Contrato OpenAPI v3 (stega.yaml)ADR-015

Próximos passos

Com a estrutura criada, prossiga para: