iGRPIGRP 3.0Documentation

Projetos

projects/ — como os teus projetos correm ao lado da plataforma em Docker — um compose por projeto, arranque, rotas, contrato de env e armadilhas.

Cada projeto em projects/ (criado no Studio — ver Primeiro projeto) tem o seu próprio compose, igrp-compose-<projeto>.yaml, e liga-se à rede e à infraestrutura da stack principal. Os frontends autenticam no Access Management e os backends publicam nele os seus recursos. Não há token estático — todo o M2M é client_credentials.

TipoRotaCliente OAuth
Spring Boot/gateway-api/<projeto>próprio
Next.js/apps/<projeto>login pelo seeded · M2M próprio

Backends Spring Boot

O que muda na v2

Áreav1v2
Biblioteca authcore-spring-boot beta-120.2.0-beta.8
Spring Boot / Java3.5.10 / 213.5.16 / Java 26
Beans do frameworknenhum registado@Import explícito
M2MIGRP_ACCESS_M2M_SYNC_TOKENIGRP_ACCESS_M2M_CLIENT_ID / _SECRET
AUTH_JWT_ISSUER/auth/realms/igrp/gateway-api/<ws>-access-management
SPRING_APPLICATION_NAMEnome livreigual ao client ID
Converter JWTpróprioIgrpJwtAuthenticationConverter da livraria
Adaptador—igrp.authorization.service.adapter=igrp

Java 26 é obrigatório

A cv.igrp.framework.auth:core-spring-boot:0.2.0-beta.8 é publicada com bytecode Java 26 (class file 70).

O sintoma não aponta para a causa

Com release 21 o javac rejeita-a (bad class file ... has wrong version 70.0) e o erro aborta a ronda de annotation processing — o que se manifesta como centenas de cannot find symbol em getters do Lombok. Quem vir isso vai procurar o problema no Lombok, e não está lá.

Requisitos: Spring Boot ≥ 3.5.16, <java.version>26</java.version>, e imagens de build e runtime com JDK/JRE ≥ 26.

Beans que têm de ser importados

A auto-configuração da livraria só declara o bean apiClient. O resto vive em cv.igrp.framework.auth.core, fora do component scan, e sem @Import nada é criado:

@Import({
  AuthorizationSyncRunner.class,          // publica recursos/permissões no arranque
  IgrpAuthorizationService.class,         // resolve roles/permissões no AM
  IgrpAuthorizationServiceAdapter.class,  // @ConditionalOnProperty(...="igrp")
  IgrpJwtAuthenticationConverter.class,   // fornece o JwtAuthenticationConverter
  MethodSecurityEnableConfig.class,       // @PreAuthorize sobre permissões IGRP
})

Sem AuthorizationSyncRunner o sync falha em silêncio

Não aparece nenhuma linha [Authorization Sync] nos logs, e nada acontece.

SecurityConfig

A v2 exige o converter da livraria, que resolve roles pelo IAuthorizationServiceAdapter. Um JwtAuthenticationConverter próprio só lê authorities do JWT e tem de ser removido. O da livraria é injectado com ObjectProvider, porque é condicional:

public SecurityFilterChain securityFilterChain(
        HttpSecurity http,
        ObjectProvider<JwtAuthenticationConverter> jwtAuthenticationConverter) { ... }

Um SecurityConfig desactivado autentica tudo com HTTP Basic

Se as anotações estiverem comentadas e a segurança excluída em spring.autoconfigure.exclude, sem uma SecurityFilterChain o Spring Boot cai no default. Reactiva-o.

Annotation processor

A cv.igrp.framework.auth:core gera o PermissionsRegistry. Tem de estar em annotationProcessorPaths depois do Lombok e com o Lombok excluído — dois Lombok no processor path quebram a geração de getters. O maven-compiler-plugin tem de ser ≥ 3.14.1: a 3.11.0 não resolve uma versão gerida num annotationProcessorPath.

Propriedades

spring.application.name=${SPRING_APPLICATION_NAME:<projeto>}
igrp.access.api.base-url=${IGRP_ACCESS_API_BASE_URL}
igrp.access.m2m.client-id=${IGRP_ACCESS_M2M_CLIENT_ID:}
igrp.access.m2m.client-secret=${IGRP_ACCESS_M2M_CLIENT_SECRET:}
igrp.access.m2m.scope=${IGRP_ACCESS_M2M_SCOPE:}
igrp.authorization.service.adapter=${IGRP_AUTHORIZATION_SERVICE_ADAPTER:igrp}

O igrp.access.m2m.sync-token foi removido de propósito: sem fallback, uma credencial em falta falha de forma visível em vez de degradar para o modo depreciado.

Eureka: a chave do mapa não faz binding por env var

EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE não funciona

O eureka.client.service-url é um Map. A env var produz a chave defaultzone em minúsculas, e o Eureka lê defaultZone — ficando com o default http://localhost:8761/eureka/. O sintoma é Cannot execute request on any known server mesmo com o servidor acessível.

Declara a zona no application-development.properties:

eureka.client.service-url.defaultZone=${EUREKA_SERVICE_URL:http://<slug>-eureka:8761/eureka/}

Frontends Next.js

O migrador oficial faz o grosso

Não é preciso escrever código de auth à mão: o @igrp/framework-next-auth já traz withIGRPAuth(), createAuthProviderFromEnv(), refreshOidcAccessToken() e revokeOidcSession().

cd projects/theque
pnpm dlx @igrp/template-migrator@latest status
pnpm dlx @igrp/template-migrator@latest plan
pnpm dlx @igrp/template-migrator@latest apply

O design system exige peers exactos

Sem eles o npm install recusa-se a resolver. E os lockfiles têm de ser regerados de raiz — um lockfile antigo bloqueia a resolução com um ERESOLVE que aponta para a versão velha. Se o projeto tiver package-lock.json e yarn.lock, deixa só o que o Dockerfile usa.

Contrato de env

AUTH_PROVIDER=igrp-auth
IGRP_AUTH_CLIENT_ID / _SECRET / _ISSUER / _SCOPES
NEXTAUTH_URL (com basePath E /api/auth) / NEXTAUTH_URL_INTERNAL / NEXTAUTH_SECRET
IGRP_ACCESS_MANAGEMENT_API
IGRP_SERVICE_ID / IGRP_M2M_CLIENT_ID / IGRP_M2M_CLIENT_SECRET
IGRP_APP_CODE / NEXT_PUBLIC_IGRP_APP_CODE
IGRP_PREVIEW_MODE / IGRP_SYNC_ACCESS / IGRP_SYNC_ON_CODE_MENUS / ..._MENU_ROLES
NEXT_IGRP_APP_CENTER_URL / NEXT_PUBLIC_BASE_PATH / NEXT_PUBLIC_IGRP_APP_HOME_SLUG
  • Login pelo cliente seeded, M2M pelo cliente próprio. O OIDC usa ACCESS_MANAGEMENT_OAUTH_CLIENT_ID/SECRET, com os callbacks registados automaticamente; o sync usa o cliente próprio, com Basic em ${IGRP_ACCESS_MANAGEMENT_API}/oauth2/token e o IGRP_SERVICE_ID no header X-Machine-Service-ID.
  • IGRP_AUTH_SCOPES=openid email. O discovery anuncia scopes_supported: ["openid"]; pedir profile não é seguro sem o registar no Authorization Server.
  • IGRP_SYNC_ON_CODE_MENUS=true empurra src/temp/menus e sobrescreve os menus no Access Management. Passa a false quando o AM for a fonte de verdade.
  • O código lê NEXT_IGRP_APP_CENTER_URL, não IGRP_APP_CENTER_URL.
  • O NEXTAUTH_SECRET tem de ser o mesmo em todos os frontends do host, senão trocar de app força novo login.

Correções de código que o upgrade exige

O migrador não toca no código próprio da app:

O que mudouEfeito
IGRPUserDTO.id passou de number a stringerro de tipos
IGRPCombobox e IGRPDatePicker perderam gridSizesó sobrevive em IGRPRadioGroup; o className adjacente já define o span
IGRPDatePicker passou a união discriminadaexige mode; startDate/endDate deram lugar a disableBefore/disableAfter
Guardas de sessão antigasa função é hoje do IGRPSessionWatcher

Dynamic Code Evaluation not allowed in Edge Runtime

Sob webpack, o bundle Edge de middleware.ts → lib/auth.ts pode falhar com este erro. A correcção é passar o build a next build --turbopack.

Correções no Dockerfile

O standalone fica aninhado

Com output: "standalone" e o turbopack.root do template, o server.js sai em .next/standalone/app/server.js. Sem ajuste o contentor morre com Cannot find module '/app/server.js'. Os estáticos e o public vão para ./app/... e o arranque passa a node app/server.js — também no command de warmup do compose.

NEXTAUTH_SECRET é preciso no estágio de build

O framework pré-renderiza /_not-found, esse render lê a sessão e falha com NEXTAUTH_SECRET must be set in production. O valor existe só no builder, que é descartado.


Arrancar

Com a stack principal a correr e o registo dos clientes OAuth concluído — um projeto novo só recebe o seu cliente no próximo arranque da stack principal.

No cartão do projeto, Deploy Docker constrói a imagem e arranca o projeto; depois, Open in Browser. O projeto aparece no grupo Project de Serviços → Visão Geral.

Usa sempre --build nos projetos

Os composes de projeto usam build:, por isso têm imagem própria. Um docker build -t <nome> avulso produz uma tag que o compose nunca usa, e o contentor continua a correr o código antigo. Passa --build na primeira vez e depois de mexer no código ou no Dockerfile.


Verificação

Backends:

[Authorization Sync] Authenticating to Access Management via client_credentials grant (clientId=...)
[Authorization Sync] Resource synchronization completed.
[Permission Sync] Successfully synchronized N permissions.

N=0 é esperado enquanto as apps não tiverem anotações de permissão. A linha No client_credentials configured ... deprecated static-token mode significa que os segredos M2M não chegaram ao contentor.

Frontends: ✓ Ready + Application <APP_CODE> metadata synced successfully. + Access Management sync completed.

Rotas — sempre por ${DOCKER_IP}:${NGINX_HTTP_PORT}:

curl http://<slug>:<porta>/apps/<frontend>
curl http://<slug>:<porta>/gateway-api/<backend>/actuator/health
curl -o /dev/null -w "%{http_code}" http://<slug>:<porta>/apps/<frontend>/igrp/logo.png

Um CSS ou imagem a 404 significa imagem antiga — falta o --build.


Armadilhas da plataforma descobertas ao arrancar

Bugs pré-existentes que impediam a stack de subir, e que vale a pena reconhecer:

ProblemaCausa e correcção
set: illegal option - numa tarefa de initCRLF nos scripts montados — o shebang fica #!/bin/sh\r. Normalizar para LF e fixar por .gitattributes
Healthcheck do Access Management sempre unhealthyA imagem é distroless: sem shell nem curl. O command: era entregue à JVM como argumentos e nunca corria. Substituído pela tarefa -ready
granted=0 e Permission 'igrp.client.list' not foundDefeito do primeiro arranque — um único restart resolve
Nginx sempre unhealthyHealthcheck na porta errada (:80 em vez de ${NGINX_HTTP_PORT})
Redirect de login para um endereço internoNo nginx, um proxy_set_header dentro de um location descarta todos os headers do nível server. O bloco do Access Management só declarava X-Forwarded-Prefix; sem Host/X-Forwarded-Host o Host passava a $proxy_host, e como o AM se regista no Eureka com prefer-ip-address, os redirects absolutos saíam pelo IP do contentor. Os seis headers têm de ser repetidos no bloco
authorization_request_not_found no callbackCookie de sessão Secure sobre HTTP — a imagem traz server.servlet.session.cookie.secure=true e o browser descarta-o, criando sessão nova a cada pedido
Redirects pós-login do App Center para o contentorNEXTAUTH_URL_INTERNAL apontava para o contentor. Tem de ser http://${DOCKER_IP}:${NGINX_HTTP_PORT} — confirmável em GET /api/auth/providers

E no lado dos projetos

ProblemaCorrecção
Perfil dev pede uma variável que o compose não dá${SERVER_PORT:${SERVICE_PORT:8080}} em vez de assumir uma delas
H2 fixo e exclusão da segurança em todos os perfismover para um perfil local explícito
data.sql com INSERTs sem guarda e mode=alwaysduplica dados a cada reinício. O default passa a never
Eureka apontado ao host erradousar o nome do serviço do workspace
Bucket MinIO que o script de init nunca criaderivar a configuração de IGRP_OBJECT_STORAGE_* no compose
IGRP_PREVIEW_MODE=true num frontenddesliga a autenticação. Nunca em nada que não seja uma demo
How is this guide?

Última atualização: