Skip to content

Repository files navigation

Hackathon RPG Java

Objetivo

Este projeto foi desenvolvido como parte de um Hackathon para modernizar uma regra de validação de crédito oriunda de um ambiente legado RPG/AS/400 para uma API moderna em Java 21.

A ideia é demonstrar como uma regra antiga, tradicionalmente mantida em linguagem RPG Free, pode ser transformada em uma solução prática, evolutiva e reutilizável sob o padrão de Clean Architecture e Governança Agêntica (MCP), integrando:

  • Java 21 (LTS)
  • Spring Boot 3
  • JPA/Hibernate
  • SQLite (Banco local)
  • API RESTful (OpenAPI/Swagger)
  • Appwrite Cloud para serviços de integração externa e nuvem

Cenário de negócio e a "Regra Oculta"

A aplicação original simula a validação de crédito de clientes considerando os limites físicos e regras de negócio do mainframe. No entanto, migrações sintáticas comuns de código costumam falhar por não identificarem a lógica procedural de negócio implícita no fluxo do RPG:

  • A Regra Oculta do RPG (SITCLI = 'I'): No programa procedural legado (CONCLI.RPGLE), existe uma verificação de segurança: se a situação cadastral do cliente for inativa (SITCLI = 'I'), a liberação do crédito é rejeitada imediatamente (pAprovado = *off), abortando o processo antes de validar o limite matemático (wSomaPedidos < limCred). [81, 82]
  • A Solução Java: Essa validação de negócio foi portada de forma isolada e elegante na camada de serviços (ClienteService.java), lançando uma exceção personalizada (ClienteInativoException) que impede o avanço de requisições de clientes suspensos.

Tabela de Mapeamento Físico e Lógico (TAMAPO)

Para garantir que o buffer de dados e os comprimentos definidos no DDS original (CLIENTES.PF) sejam rigorosamente mantidos sem riscos de overflow ou perda de precisão decimal, o mapeamento para as anotações do Jakarta Validation no Java 21 segue a especificação técnica abaixo: [80]

Campo Legado Tipo DDS (Original) Campo Java Moderno Tipo Java 21 Validação Jakarta / JPA Descrição
CODCLI Packed (6, 0) codigo Long @Max(999999) Código de identificação do cliente (máximo 6 dígitos) [80]
NOMECLI Character (40) nome String @Size(max = 40) Nome completo do cliente [80]
CPFCLI Character (11) cpf String @Size(max = 11) CPF do cliente (formato e tamanho exato) [80]
LIMCRED Packed (9, 2) limiteCredito BigDecimal @Digits(integer = 7, fraction = 2) Limite de crédito aprovado (precisão exata) [80]
SITCLI Character (1) situacao String @Size(max = 1) Situação cadastral ('A' = Ativo, 'I' = Inativo) [80]

Equivalência Técnica: Do RPG ao Java 21

Legado Procedural em RPG Free (CONCLI.RPGLE)

// Busca cliente no DB2 por chave primária
chain pCodigo clientes clienteDS;

if %found(clientes);
   pNome = %trim(nomecLi);
   pLimite = limCred;

   // REGRA OCULTA: Cliente inativo não possui aprovação
   if sitCli = 'I';
      pAprovado = *off;
   else;
      // Validação do limite matemático com soma de pedidos pendentes
      if wSomaPedidos < limCred;
         pAprovado = *on;
      else;
         pAprovado = *off;
      endif;
   endif;
else;
   pNome = 'NAO ENCONTRADO';
   pAprovado = *off;
endif;
``` [81, 82]

### Modernização em Java 21 (`ClienteService.java`)
```java
@Service
public class ClienteService {

    @Autowired
    private ClienteRepository repository;

    @Autowired
    private AppwriteIntegrationService appwriteService;

    public ClienteDTO consultarEValidarLimite(Long codigo, BigDecimal somaPedidos) {
        // 1. Busca o cliente na base de dados
        Cliente cliente = repository.findById(codigo)
                .orElseThrow(() -> new ResourceNotFoundException("Cliente não cadastrado no sistema."));

        // 2. Regra oculta de inatividade portada do RPG
        if ("I".equalsIgnoreCase(cliente.getSituacao())) {
            throw new ClienteInativoException("Limite rejeitado: O cliente encontra-se INATIVO.");
        }

        // 3. Validação matemática do limite com alta precisão decimal
        boolean aprovado = somaPedidos.compareTo(cliente.getLimiteCredito()) < 0;

        // 4. Registro/Auditoria externa na nuvem (Appwrite)
        appwriteService.registrarConsultaCredito(cliente.getCodigo(), aprovado);

        return new ClienteDTO(
                cliente.getCodigo(),
                cliente.getNome(),
                cliente.getLimiteCredito(),
                aprovado,
                cliente.getSituacao()
        );
    }
}

Stack tecnológica

Backend

  • Java 21 (LTS): Uso de Records para imutabilidade e alta performance de DTOs.
  • Spring Boot 3.3.x: Endpoints sob arquitetura REST, injeção de dependência nativa e tratamento global de erros.
  • Spring Data JPA & Hibernate: Desacoplamento e abstração da persistência de dados.
  • SQLite: Persistência relacional local simples de inicializar.

Serviços Externos & Nuvem

  • Appwrite Cloud: SDK integrado para auditorias e sincronização externa de dados. [62]

Arquitetura e Governança

  • Clean Architecture / MVC: Estrutura organizada com divisão clara de atribuições (controller, service, repository, model/entity). [75]
  • Segurança por Design: Chaves e dados sensíveis de integração com o Appwrite Cloud injetados dinamicamente via variáveis de ambiente (${APPWRITE_API_KEY}), sem dados fixos (hardcoded) no código. [67, 75]

Estrutura do projeto

Hackathon-rpg-java/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/ibm/modernizacao/
│       │       ├── config/
│       │       │   └── AppwriteConfig.java
│       │       ├── controller/
│       │       │   └── ClienteController.java
│       │       ├── exception/
│       │       │   ├── ClienteInativoException.java
│       │       │   └── GlobalExceptionHandler.java
│       │       ├── model/
│       │       │   ├── dto/
│       │       │   │   └── ClienteDTO.java
│       │       │   └── entity/
│       │       │       └── Cliente.java
│       │       ├── repository/
│       │       │   └── ClienteRepository.java
│       │       ├── service/
│       │       │   ├── AppwriteIntegrationService.java
│       │       │   └── ClienteService.java
│       │       └── ValidacaoCreditoApplication.java
│       └── resources/
│           └── application.properties
├── AGENTS.md                  # Briefing de governança e comportamento do agente de IA [75]
├── mcp.json                   # Configuração de conexão dos servidores MCP locais [4]
├── schema.sql
├── pom.xml
└── README.md

Requisitos

Antes de rodar o projeto, certifique-se de ter instalado:

  • Java 21 (LTS) [94]
  • Maven
  • Git

Como rodar localmente

1) Clonar o projeto

git clone <url-do-repositorio>
cd Hackathon-rpg-java

2) Verificar a versão do Java

java -version

A versão esperada é Java 21. [95]

3) Configurar Variáveis de Ambiente (Segurança)

Antes de iniciar a aplicação, configure as variáveis de ambiente necessárias para a integração segura com a nuvem do Appwrite. Nunca versione chaves de API no repositório: [67]

export APPWRITE_ENABLED="true"                   # ativa a integração com a nuvem
export SUPABASE_URL="https://jqdbscialntgtmdhkmpz.supabase.co"
export SUPABASE_SERVICE_ROLE="COLE_SUA_CHAVE_SUPABASE_AQUI (gerada no painel em Settings -> API)"

Sem o collectionId e a apiKey, a aplicação funciona apenas com o fallback SQLite local e recusa operações na nuvem de forma deliberada.

4) Compilar o projeto

mvn clean install

5) Iniciar a aplicação

mvn spring-boot:run

6) Acessar a API

Após o boot da aplicação, a API estará disponível em: http://localhost:8082 (configurado em application.properties).

Endpoints:

Método Rota Descrição
GET /api/appwrite/status Verifica a conexão com o Appwrite Cloud (somente leitura)
GET /api/clientes/{codigo} Consulta cliente no SQLite local (fallback)
POST /api/clientes Cria cliente (nuvem se APPWRITE_ENABLED=true, senão SQLite)
PUT /api/clientes/{codigo} Atualiza cliente (nuvem se APPWRITE_ENABLED=true, senão SQLite)

Exemplo de consulta:

http://localhost:8082/api/clientes/100?somaPedidos=500

Exemplo de criação/atualização:

curl -X PUT http://localhost:8082/api/clientes/1 \
  -H "Content-Type: application/json" \
  -d '{"nome":"Cliente Nuvem","cpf":"12345678901","limite":5000.00,"situacao":"A"}'

Banco de dados

O projeto utiliza SQLite e o schema inicial está em:

schema.sql
``` [6]

A configuração do banco está em:
```text
src/main/resources/application.properties

Integração com Appwrite Cloud

A persistência principal usa SQLite local (fallback). Quando APPWRITE_ENABLED=true, as operações de criação (POST) e atualização (PUT) de clientes são persistidas no Appwrite Cloud via REST, usando os endpoints oficiais de documentos:

  • GET /databases/{db}/collections/{collection}/documents — listar
  • POST /databases/{db}/collections/{collection}/documents — criar (documentId + data)
  • PATCH /databases/{db}/collections/{collection}/documents/{documentId} — atualizar

O documentId usado é o codcli do cliente. Os atributos gravados são os campos equivalentes ao DDS legado: codcli, nomecli, cpfcli, limcred e sitcli.

Diagnóstico de conexão: GET /api/appwrite/status

Endpoint de leitura que valida project/database/collection/API key sem modificar dados. Faça um teste de conexão antes de operar na nuvem.

  • 200 com "conexao": "OK" → IDs e chave corretos (retorna totalDocumentos).
  • 502 com "conexao": "ERRO" → ID(s) incorreto(s) ou falta de permissão; o corpo traz o motivo.
  • 503 com "Appwrite desabilitado..."APPWRITE_ENABLED não está true.

Respostas úteis de erro do Appwrite: 404 resource not found indica project/database/collection incorretos; 401/403 indica API key inválida ou sem o scope necessário.


Observações importantes

  • O banco SQLite será inicializado localmente no diretório do projeto.
  • O arquivo schema.sql já foi configurado para evitar erros de criação repetida da tabela quando a aplicação é iniciada diversas vezes.
  • O projeto pode ser expandido para integrar autenticação e outros serviços do Appwrite conforme a evolução do Hackathon. [62]

Roadmap: Deploy e Integração no PUB400

Para complementar o ciclo de vida deste projeto legado, as próximas fases técnicas preveem a integração direta com o ambiente físico IBM i público do PUB400.com:

  1. Usuário Reservado: Perfil BRASIL01 criado e aguardando provisionamento.
  2. Biblioteca de Fontes (BRASIL011): Área dedicada no servidor para armazenamento dos fontes físicos legados em pastas dedicadas do sistema de arquivos integrado (IFS) ou membros clássicos (QDDSRC e QRPGLESRC).
  3. Biblioteca de Objetos (BRASIL012): Biblioteca alvo das compilações físicas do arquivo físico (CLIENTES.PF) e do programa executável RPG (CONCLI.RPGLE).
  4. Governança VS Code: Toda a manipulação de membros e execução de comandos CL será realizada via conexão SSH usando a extensão Code for IBM i, dispensando o uso do emulador 5250 ("tela verde").

Próximos passos possíveis

  • Ativar a integração em tempo real com o PUB400.com usando o SDK Java do IBM i.
  • Adicionar autenticação federada com Appwrite.
  • Criar testes unitários e de integração utilizando JUnit 5 e Mockito.
  • Expor mais endpoints REST para criação e atualização cadastral de clientes.
  • Incluir regras de negócio mais sofisticadas originárias do legado.

Contribuição

Este projeto foi desenvolvido como material de estudo e prova de conceito para modernização de aplicações legadas IBM i em Java + Spring Boot utilizando Governança Agêntica (MCP). [248]

About

Backend API developed in Java with Spring Boot integrated with Appwrite Cloud Database for a Hackathon project.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages