Pular para o conteúdo principal

C4 Component

Introdução ao documento

Este documento registra uma visão de componentes no nível C4 adaptada ao que o repositório realmente expõe em runtime. O recorte prioriza módulos que mudam juntos e pontos cuja falha interrompe cadastro, autenticação, confirmação por OTP, redirecionamento para grupo ou operação básica da aplicação.

Fato observado

  • O repositório combina interface em app/, APIs internas em pages/api/ e app/api/, e adapters HTTP em src/features/api/external/.
  • O app é um frontend Next.js com comportamento de BFF fino para autenticação, participant upsert, OTP, telemetria e integrações externas.

Inferência controlada

  • No contexto deste repositório, o "serviço" é melhor entendido como um app web com componentes client/server e uma camada de integração server-side, e não como um backend monolítico com domínio persistente local.

Evidências:

Versionamento

Este documento deve ser atualizado quando houver mudança em:

  • rotas principais de experiência (/[slug], inscrição, OTP, grupo, manutenção);
  • mecanismo de autenticação e sessão (NextAuth, AMEI/Keycloak, guards client-side);
  • contratos da API interna (pages/api/*, app/api/*);
  • integrações externas que afetam elegibilidade, upsert de participante, OTP, tracking ou probes operacionais.

Fato observado

  • Essas responsabilidades estão espalhadas entre rotas App Router, handlers Pages Router e adapters de integração, então alterações em qualquer um desses pontos mudam a topologia de componentes.

Evidências:

Referencial teórico

Este documento usa um recorte C4 de componentes, mas adaptado às fronteiras reais do código:

  • rotas e layouts do Next.js como componentes de experiência;
  • providers, sessão e guards como componentes de acesso;
  • handlers HTTP internos como componentes de aplicação/BFF;
  • adapters external/* e utilitários de resiliência como componentes de integração.

Fato observado

  • O código já está organizado nessas fronteiras: app/, pages/api/, src/common/components/providers, src/features/api/external.

Inferência controlada

  • Esse corte é o mais útil aqui porque coincide com as áreas que quebram juntas em produção.

Evidências:

Responsabilidade do serviço/app

Fato observado

  • Renderizar a página pública de curso a partir de customização e status externos.
  • Autenticar participantes por CPF com NextAuth e, opcionalmente, por AMEI/Keycloak.
  • Validar elegibilidade de matrícula antes de liberar o fluxo.
  • Ler, criar ou atualizar participante e disparar OTP por WhatsApp.
  • Confirmar OTP, reenviar template de fluxo e redirecionar para link de grupo.
  • Expor configuração de runtime e endpoints operacionais (health, readiness, liveness).

Inferência controlada

  • O app funciona como frontend transacional de onboarding, com lógica de negócio leve concentrada em autenticação, elegibilidade e orquestração de integrações.

Evidências:

Dependências

Banco de dados

Fato observado

  • Não há cliente de banco, ORM ou migration local declarados nas dependências principais do app.
  • Os acessos a dados comprovados no código de aplicação deste repositório acontecem por HTTP para serviços externos.

Inferência controlada

  • Se existir banco persistente no ecossistema, ele está atrás dos serviços externos e não dentro deste repositório.

Evidências:

Cache

Fato observado

  • O app usa AppRouterCacheProvider no browser para integração do MUI com App Router.
  • As chamadas HTTP compartilhadas desabilitam cache do fetch com cache: 'no-store'.
  • Não há evidência local de Redis, Memcached ou outro cache externo dedicado.

Evidências:

Fila, cron, worker

Fato observado

  • Não há dependência explícita de fila/consumer nas dependências principais do app.
  • Não há módulos dedicados de worker de negócio em app/, pages/ ou src/.
  • O único "worker" comprovado no repositório é o msw para mocking em desenvolvimento.

Evidências:

Storage

Fato observado

  • Não há cliente explícito de object storage ou filesystem remoto nas dependências principais.
  • O estado persistido no cliente que impacta o fluxo é sessionStorage para a flag amei_auth.
  • O repositório usa assets estáticos locais, inclusive para imagens e para o diretório do worker MSW.

Evidências:

Serviços externos

Fato observado

  • WordPress backend: customização do curso, status do curso, manutenção, lookup/update/create de participante, status de matrícula e link de grupo.
  • WhatsApp API: envio de OTP, confirmação de OTP e envio de template de fluxo.
  • Registration backend: adapter presente no código para busca/criação/atualização de pessoa por CPF.
  • AMEI/Keycloak: configuração carregada em runtime e montada pelo UserAuthProvider.
  • Datadog: RUM inicializado no cliente a partir de /api/envs.
  • Meta Graph API: eventos enviados pela rota server-side /api/meta-conversion.

Evidências:

Componentes internos agrupados por camada

1. Camada de experiência e navegação

Fato observado

  • RootLayout: injeta SessionProvider, Providers, DatadogInit, MetaPixel, metadados e inicialização opcional do MSW.
  • CourseDetailsPage: carrega status e customização do curso e decide entre notFound, manutenção ou detalhe do curso.
  • SignupConfirmation e OTPConfirmation: etapas protegidas do fluxo de cadastro e confirmação.
  • GrupoPage: resolve o link do grupo e redireciona o participante.

Evidências:

2. Camada de acesso, sessão e guardas

Fato observado

  • Providers: carrega configuração de Keycloak via /api/config/keycloak, monta UserAuthProvider quando habilitado e encapsula ThemeProvider, SnackbarProvider e AppRouterCacheProvider.
  • CourseRegistration: inicia login por CPF com signIn("cpf") e também o caminho alternativo AMEI.
  • NextAuth credentials provider: consulta participante, valida elegibilidade por matrícula e popula a sessão JWT.
  • AuthProtected: bloqueia páginas internas quando não há sessão nem usuário AMEI.

Evidências:

3. Camada de aplicação e BFF interno

Fato observado

  • pages/api/v1/cursos/[slug]: expõe customização simplificada do curso.
  • pages/api/v1/participantes/[cpf]: autentica sessão e orquestra leitura/criação/atualização de participante.
  • pages/api/v1/otp/send e pages/api/v1/otp/confirm: encapsulam o fluxo OTP server-side.
  • pages/api/v1/flow/resend: reenvia template de fluxo usando dados da sessão.
  • pages/api/config/keycloak, app/api/envs e app/api/meta-conversion: fornecem runtime config e tracking server-side.
  • health, readiness, liveness: endpoints de operação e probes.

Evidências:

4. Camada de integração, resiliência e telemetria

Fato observado

  • config.ts centraliza URLs e tokens de integrações externas.
  • fetchWithTimeout impõe timeout, AbortController, cache: 'no-store' e keepalive: false.
  • Os adapters external/wp, external/whats e external/registrations encapsulam contratos externos.
  • middleware.ts consulta modo de manutenção com timeout de 3s e política fail-open.
  • DatadogInit e /api/envs formam o bootstrap de observabilidade client-side.

Evidências:

Fluxos críticos

1. Entrada no curso e desvio para manutenção

Fato observado

  • O middleware consulta getMaintenanceMode() com timeout de 3s e, se o modo estiver ativo, redireciona para /maintenance.
  • A página /[slug] também consulta status e customização do curso e pode renderizar manutenção no nível da feature.

Por que quebra o sistema:

  • Se a customização não vier, a página cai em notFound.
  • Se o contrato de manutenção quebrar, a experiência pode divergir entre middleware e página.

Evidências:

2. Autenticação por CPF/AMEI e validação de elegibilidade

Fato observado

  • CourseRegistration dispara signIn("cpf") com cpf e course_slug, ou usa o caminho AMEI quando habilitado.
  • O CredentialsProvider consulta participante no backend WordPress, busca status de matrícula e aplica bloqueios por inscrição existente, mesma categoria, concorrência ou excesso de cancelamentos.

Por que quebra o sistema:

  • Esse é o principal gate de entrada no fluxo protegido.
  • Falhas em getUserByCpf, getUserEnrollStatus ou na montagem da sessão impedem progresso em todas as etapas seguintes.

Evidências:

3. Confirmação de perfil, upsert de participante e envio do OTP

Fato observado

  • SignupConfirmation monta o participante a partir da sessão local ou do usuário AMEI e, no caso AMEI, ainda busca o ID canônico por CPF.
  • ProfileForm chama subscribeToCourse(), que faz PUT /v1/participantes/{cpf}.
  • O handler /v1/participantes/{cpf} decide entre updateUserById e createUser.
  • Após o upsert, o frontend chama sendOtpCode(), que usa /v1/otp/send.

Por que quebra o sistema:

  • Qualquer divergência entre sessão, CPF, ID retornado ou backend de participante impede a etapa OTP.
  • É um ponto de acoplamento alto entre frontend, sessão e WordPress.

Evidências:

4. Confirmação do OTP e disparo do template de fluxo

Fato observado

  • A tela de OTP envia phone e code para /v1/otp/confirm.
  • O handler confirma o código no backend WhatsApp, lê flow_template_id e flow_template_header_image no WordPress e dispara sendFlowTemplate.
  • O endpoint /v1/flow/resend repete essa orquestração a partir da sessão, sem input adicional do cliente.

Por que quebra o sistema:

  • Essa é a transição entre validação do usuário e entrada na etapa final de turma/grupo.
  • Exige consistência simultânea entre sessão, WhatsApp API e customização do curso.

Evidências:

Fato observado

  • A rota /grupo/[uid] decodifica o identificador, chama getGroupLink() e faz redirect() para group_link.
  • Se o link não vier, a página degrada para uma tela de erro de negócio.

Por que quebra o sistema:

  • É a última entrega funcional do onboarding; sem esse link o usuário conclui o fluxo, mas não entra no grupo associado.

Evidências:

Diagrama Mermaid

Evidências:

Pendências

  • Confirmar qual backend é a fonte canônica de pessoa/participante no ecossistema: WordPress ou API_REGISTRATION_BACKEND_URL.
  • Confirmar se o adapter de Registration API está ativo em produção ou apenas preservado no código para uso futuro/paralelo.
  • Confirmar se API_CLASSES_BACKEND_URL ainda faz parte da arquitetura alvo, já que o valor é declarado, mas não há consumo comprovado fora de config.ts.
  • Confirmar a decisão arquitetural de manter app/ e pages/api/ coexistindo como topologia estável.
  • Resolver a divergência entre NEXT_DATADOG_CLIENT_ID em .env.example e NEXT_DATADOG_CLIENT_TOKEN consumido pelo runtime.
  • Confirmar o papel obrigatório da integração AMEI em todos os ambientes, já que ela depende de toggle e runtime config.

Evidências: