MENTE SERENAECO COMPLIANCE · ARQUITETURA TÉCNICA v1.0

Arquitetura de Engenharia de Software

Documento de referência técnica para os 3 motores de automação do módulo Eco Compliance: Pipeline Jurídico de Outorgas, Engine de Laudos e Gov Gateway.

Esquema relacional principal com suporte a JSONB para campos dinâmicos de laudos, parâmetros analíticos e logs de transmissão governamental.

TABELA: clients

ColunaTipoDescrição
idUUID PKIdentificador único
cnpjVARCHAR(18) UNIQUECNPJ da empresa
razao_socialTEXTRazão social
ufCHAR(2)Estado de operação
cert_a1_encBYTEACertificado A1 criptografado (AES-256)
cert_a1_senha_hashTEXTHash bcrypt da senha do certificado
cert_validadeTIMESTAMPTZValidade do certificado A1
created_atTIMESTAMPTZDEFAULT NOW()

TABELA: pocos (Poços/Pontos de Captação)

ColunaTipoDescrição
idUUID PK
client_idUUID FK → clients
codigoVARCHAR(20)Ex: P-01, P-02
tipoENUM('artesiano','semi_artesiano','superficial','acumulacao')
latDECIMAL(10,7)Latitude WGS-84
lngDECIMAL(10,7)Longitude WGS-84
profundidade_mDECIMAL(8,2)Metros de profundidade
vazao_instalada_lpsDECIMAL(8,3)L/s instalados
telemetriaJSONB{"ultima_leitura": ..., "nivel_estatico_m": ..., "volume_diario_m3": ...}

TABELA: outorgas

ColunaTipoDescrição
idUUID PK
client_idUUID FK
poco_idUUID FK → pocos (nullable)
numero_processoVARCHAR(50) UNIQUEEx: DAEE-SP-2022/1453
orgaoENUM('DAEE','ANA','IGAM','CERH','INEMA',...)
tipoENUM('captacao_superficial','captacao_sub','lancamento','acumulacao')
volume_autorizado_m3dDECIMAL(12,3)Volume diário em m³
vazao_maxima_m3hDECIMAL(10,3)Vazão pico
data_emissaoDATE
data_vencimentoDATEINDEXED — base dos cron jobs
statusENUM('vigente','a_renovar','em_analise','vencida','cancelada')
condicionantesJSONBArray de strings com obrigações
alerta_12m_enviadoBOOLEAN DEFAULT FALSE
alerta_6m_enviadoBOOLEAN DEFAULT FALSE
alerta_3m_enviadoBOOLEAN DEFAULT FALSE
arquivo_original_urlTEXTS3/Storage URL
ocr_extraidoJSONBDados brutos extraídos pelo OCR

TABELA: laudos

ColunaTipoDescrição
idUUID PK
client_idUUID FK
poco_idUUID FK (nullable)
outorga_idUUID FK (nullable)
tipo_amostraENUM('potavel','efluente_industrial','efluente_dom','corpo_receptor','subterranea')
laboratorioTEXT
data_coletaDATE
numero_laudo_labVARCHAR(50)
arquivo_urlTEXT
parametrosJSONBArray: [{nome, valor, unidade, limite_legal, norma, status}]
conformidade_geralENUM('conforme','nao_conforme','atencao','pendente')
resumo_iaTEXTNarrativa gerada pelo LLM
status_validacaoENUM('aguardando_ia','fila_biologo','em_revisao','aprovado','reprovado','notificado')
biologo_idUUID FK → especialistas (nullable)
engenheiro_idUUID FK → especialistas (nullable)
assinatura_hashTEXTSHA-256 do conteúdo validado
art_numeroVARCHAR(30)
proxima_coletaDATE

TABELA: especialistas

ColunaTipoDescrição
idUUID PK
nomeTEXT
emailTEXT UNIQUE
perfilENUM('biologo','eng_ambiental','eng_civil','quimico','gestor')
registroVARCHAR(20)CRBio / CREA / CRQ
uf_atuacaoTEXT[]Array de UFs
art_ativaVARCHAR(30)
ativoBOOLEAN DEFAULT TRUE

TABELA: incidentes

ColunaTipoDescrição
idUUID PK
client_idUUID FK
laudo_idUUID FK (nullable)Se originado de inconformidade
tipoENUM('vazamento','contaminacao','falha_ete','amostra_fora','descarte_irr','ruptura')
gravidadeENUM('baixo','moderado','critico','emergencial')
statusENUM('em_apuracao','fila_tecnico','em_remediacao','resolvido','notificado_orgao')
hash_auditoriaTEXTSHA-256 para rastreabilidade jurídica
parecer_tecnicoJSONB{especialista_id, texto, timestamp, hash}
medidas_corretivasJSONBArray de ações

TABELA: gov_transmissoes (Log Gov Gateway)

ColunaTipoDescrição
idUUID PK
client_idUUID FK
orgaoENUM('DAEE','IBAMA','SISAGUA','CETESB','ANA')
tipo_transmissaoENUM('telemetria_mensal','rapp_anual','laudo_potabilidade','renovacao_licenca')
payload_enviadoJSONBCópia do payload assinado
protocolo_retornoTEXTNúmero de protocolo governamental
statusENUM('pendente','enviado','erro','confirmado')
erro_detalheTEXT
assinado_com_certBOOLEAN
timestamp_envioTIMESTAMPTZ
-- Relacionamentos principais
outorgas.client_id       → clients.id (ON DELETE CASCADE)
outorgas.poco_id         → pocos.id   (ON DELETE SET NULL)
laudos.client_id         → clients.id
laudos.poco_id           → pocos.id
laudos.biologo_id        → especialistas.id
laudos.engenheiro_id     → especialistas.id
incidentes.laudo_id      → laudos.id
gov_transmissoes.client_id → clients.id

-- Índices críticos de performance
CREATE INDEX idx_outorgas_vencimento   ON outorgas(data_vencimento) WHERE status != 'cancelada';
CREATE INDEX idx_laudos_conformidade   ON laudos(conformidade_geral, status_validacao);
CREATE INDEX idx_incidentes_gravidade  ON incidentes(gravidade, status);
CREATE INDEX idx_gov_status            ON gov_transmissoes(orgao, status, timestamp_envio);

1.1 — Algoritmo de Ingestão e OCR

FUNÇÃO processar_upload_outorga(arquivo_pdf, client_id, tipo_solicitacao):

  // ETAPA 1 — Armazenamento seguro
  url_s3 ← storage.upload(arquivo_pdf, path=f"clients/{client_id}/outorgas/")
  
  // ETAPA 2 — OCR + Extração estruturada via LLM
  texto_raw ← ocr_engine.extract(arquivo_pdf)  // Tesseract / AWS Textract
  
  dados_extraidos ← llm.extract_json(
    prompt = texto_raw,
    schema = {
      numero_processo: string,
      orgao_emissor: string,
      tipo: enum[captacao_sub|superficial|lancamento|acumulacao],
      volume_m3_dia: float,
      vazao_maxima_m3h: float,
      data_emissao: date,
      data_vencimento: date,
      condicionantes: array[string],
      coordenadas: {lat: float, lng: float} | null
    }
  )
  
  // ETAPA 3 — Persistência
  outorga_id ← db.insert('outorgas', {
    client_id,
    ...dados_extraidos,
    arquivo_original_url: url_s3,
    ocr_extraido: dados_extraidos,
    status: 'em_analise'
  })
  
  // ETAPA 4 — Agendar Cron Jobs de Alerta
  agendar_alertas_vencimento(outorga_id, dados_extraidos.data_vencimento)
  
  // ETAPA 5 — Enfileirar para revisão do Engenheiro
  fila_tecnica.push({
    tipo: 'revisao_outorga',
    outorga_id,
    client_id,
    prioridade: calcular_prioridade(dados_extraidos.data_vencimento),
    deadline: NOW() + 72h
  })
  
  RETORNAR { outorga_id, status: 'processando', eta_revisao: '72h' }

1.2 — Cron Job de Alertas de Vencimento

// Executa diariamente às 06:00 UTC
CRON 'alertas_outorga' SCHEDULE '0 6 * * *':

  outorgas_ativas ← db.query(
    "SELECT * FROM outorgas 
     WHERE status IN ('vigente','a_renovar')
     AND data_vencimento > NOW()"
  )
  
  PARA CADA outorga EM outorgas_ativas:
    dias_restantes ← DATEDIFF(outorga.data_vencimento, NOW())
    
    SE dias_restantes <= 90 AND NOT outorga.alerta_3m_enviado:
      emitir_alerta(outorga, nivel='CRITICO', meses=3)
      db.update('outorgas', outorga.id, {alerta_3m_enviado: true, status: 'a_renovar'})
      notificar_dashboard(outorga.client_id, tipo='VENCIMENTO_3M', outorga_id=outorga.id)
    
    SENÃO SE dias_restantes <= 180 AND NOT outorga.alerta_6m_enviado:
      emitir_alerta(outorga, nivel='WARNING', meses=6)
      db.update('outorgas', outorga.id, {alerta_6m_enviado: true})
    
    SENÃO SE dias_restantes <= 365 AND NOT outorga.alerta_12m_enviado:
      emitir_alerta(outorga, nivel='INFO', meses=12)
      db.update('outorgas', outorga.id, {alerta_12m_enviado: true})

FUNÇÃO emitir_alerta(outorga, nivel, meses):
  db.insert('alertas', {
    client_id: outorga.client_id,
    tipo: 'VENCIMENTO_OUTORGA',
    nivel,
    mensagem: f"Outorga {outorga.numero_processo} vence em {meses} meses ({outorga.data_vencimento})",
    referencia_id: outorga.id,
    lido: false
  })
  enviar_email(outorga.client_id, template='ALERTA_VENCIMENTO', dados=outorga)
  enviar_whatsapp(outorga.client_id, template='ALERTA_VENCIMENTO_WPP', dados=outorga)

1.3 — Geração da DVI (Declaração de Viabilidade)

FUNÇÃO gerar_dvi(outorga_id, dados_tecnicos_adicionais):
  
  outorga ← db.get('outorgas', outorga_id)
  poco    ← db.get('pocos', outorga.poco_id)
  client  ← db.get('clients', outorga.client_id)
  
  // Buscar normas vigentes do órgão
  normas ← normas_db.get(orgao=outorga.orgao, uf=client.uf)
  
  // LLM gera o documento técnico formal
  dvi_conteudo ← llm.generate(
    prompt = f"""
      Elabore uma Declaração de Viabilidade Hídrica técnica e juridicamente fundamentada:
      Empresa: {client.razao_social} | CNPJ: {client.cnpj} | UF: {client.uf}
      Processo: {outorga.numero_processo} | Órgão: {outorga.orgao}
      Tipo captação: {outorga.tipo} | Volume: {outorga.volume_m3_dia} m³/dia
      Coordenadas: {poco.lat}, {poco.lng}
      Dados adicionais: {dados_tecnicos_adicionais}
      Base legal: {normas.base_legal}
    """,
    formato = 'documento_tecnico_formal'
  )
  
  db.update('outorgas', outorga_id, {dvi_gerada: true, dvi_conteudo: dvi_conteudo})
  fila_tecnica.push({tipo: 'assinar_dvi', outorga_id, requer: 'engenheiro_ambiental'})
  
  RETORNAR dvi_conteudo

2.1 — Tabela de Limites Legais (Hardcoded)

// Constantes imutáveis — atualizadas apenas por revisão de engenharia
LIMITES_LEGAIS = {
  
  // Portaria GM/MS 888/2021 — Água para Consumo Humano (SISAGUA)
  POTAVEL: {
    pH:               { min: 6.0,  max: 9.5,  norma: "MS888/2021" },
    turbidez_NTU:     { max: 5.0,             norma: "MS888/2021" },
    cloro_residual:   { min: 0.2,  max: 5.0,  norma: "MS888/2021" },
    coliformes_totais:{ max: 0,               norma: "MS888/2021 §40" },  // ausência em 100mL
    e_coli:           { max: 0,               norma: "MS888/2021 §40" },
    nitrato_mg_L:     { max: 10.0,            norma: "MS888/2021" },
    fluoreto_mg_L:    { max: 1.5,             norma: "MS888/2021" },
    arsenio_ug_L:     { max: 10.0,            norma: "MS888/2021" },
    chumbo_ug_L:      { max: 10.0,            norma: "MS888/2021" },
  },
  
  // CONAMA 430/2011 — Lançamento de Efluentes
  EFLUENTE_LANCAMENTO: {
    pH:               { min: 5.0,  max: 9.0,  norma: "CONAMA430/2011" },
    temperatura_C:    { max: 40.0,            norma: "CONAMA430/2011 §5" },
    DBO_mg_L:         { max: 120.0,           norma: "CONAMA430/2011 (ou 60% remoção)" },
    DQO_mg_L:         { max: 200.0,           norma: "CONAMA430/2011" },
    SS_mg_L:          { max: 150.0,           norma: "CONAMA430/2011" },
    oleo_mineral_mg_L:{ max: 20.0,            norma: "CONAMA430/2011" },
    oleo_vegetal_mg_L:{ max: 50.0,            norma: "CONAMA430/2011" },
    cianeto_mg_L:     { max: 0.2,             norma: "CONAMA430/2011" },
    arsenio_mg_L:     { max: 0.5,             norma: "CONAMA430/2011" },
    cadmio_mg_L:      { max: 0.2,             norma: "CONAMA430/2011" },
    cromo_hexa_mg_L:  { max: 0.1,             norma: "CONAMA430/2011" },
    chumbo_mg_L:      { max: 0.5,             norma: "CONAMA430/2011" },
    mercurio_mg_L:    { max: 0.01,            norma: "CONAMA430/2011" },
    niquel_mg_L:      { max: 2.0,             norma: "CONAMA430/2011" },
    zinco_mg_L:       { max: 5.0,             norma: "CONAMA430/2011" },
  },
  
  // CONAMA 357/2005 — Corpo receptor (Classe II padrão)
  CORPO_RECEPTOR: {
    pH:               { min: 6.0,  max: 9.0,  norma: "CONAMA357/2005" },
    OD_mg_L:          { min: 5.0,             norma: "CONAMA357/2005 ClasseII" },
    DBO_mg_L:         { max: 5.0,             norma: "CONAMA357/2005" },
    turbidez_NTU:     { max: 100.0,           norma: "CONAMA357/2005" },
    coliformes_term:  { max: 1000,            norma: "CONAMA357/2005 (NMP/100mL)" },
    nitrogenio_total: { max: 2.18,            norma: "CONAMA357/2005 pH>7.5" },
    fosforo_total_mg: { max: 0.1,             norma: "CONAMA357/2005 ambiente lêntico" },
  }
}

2.2 — Algoritmo de Validação de Conformidade

FUNÇÃO validar_laudo(laudo_id):

  laudo ← db.get('laudos', laudo_id)
  
  // PASSO 1 — Selecionar tabela de limites pelo tipo de amostra
  SWITCH laudo.tipo_amostra:
    'potavel'            → limites ← LIMITES_LEGAIS.POTAVEL
    'efluente_industrial' → limites ← LIMITES_LEGAIS.EFLUENTE_LANCAMENTO
    'corpo_receptor'     → limites ← LIMITES_LEGAIS.CORPO_RECEPTOR
    DEFAULT              → limites ← LIMITES_LEGAIS.POTAVEL
  
  parametros_validados = []
  inconformidades      = []
  alertas_atencao      = []
  
  // PASSO 2 — Iterar cada parâmetro extraído do laudo
  PARA CADA param EM laudo.parametros:
    limite ← limites[param.nome]
    
    SE limite É NULO: CONTINUAR  // parâmetro não regulado
    
    valor_num ← to_float(param.valor)
    violacao  ← false
    
    SE limite.min EXISTE E valor_num < limite.min:
      violacao ← true
      tipo_violacao ← 'ABAIXO_MINIMO'
    
    SE limite.max EXISTE E valor_num > limite.max:
      violacao ← true
      tipo_violacao ← 'ACIMA_MAXIMO'
    
    // Zona de atenção: 80-100% do limite máximo
    SENÃO SE limite.max EXISTE E valor_num > (limite.max * 0.8):
      alertas_atencao.append(param.nome)
    
    status_param ← SE violacao ENTÃO 'NAO_CONFORME' SENÃO 'CONFORME'
    
    parametros_validados.append({
      ...param,
      limite_legal: limite,
      status: status_param,
      norma: limite.norma,
      desvio_percentual: calcular_desvio(valor_num, limite)
    })
    
    SE violacao:
      inconformidades.append({parametro: param.nome, valor: valor_num, limite, tipo_violacao})
  
  // PASSO 3 — Determinar conformidade geral
  SE inconformidades.length > 0:
    conformidade_geral ← 'NAO_CONFORME'
    grau_risco ← classificar_risco(inconformidades)  // CRITICO|ALTO|MODERADO
    
    // PASSO 4A — Rota de Inconformidade
    db.update('laudos', laudo_id, {
      parametros: parametros_validados,
      conformidade_geral: 'NAO_CONFORME',
      status_validacao: 'fila_biologo',
      resumo_ia: gerar_resumo_ia(inconformidades)
    })
    
    // Gerar incidente associado
    incidente_id ← db.insert('incidentes', {
      client_id: laudo.client_id,
      laudo_id,
      tipo: inferir_tipo_incidente(inconformidades),
      gravidade: grau_risco,
      status: 'fila_tecnico'
    })
    
    // Notificar Biólogo com prioridade
    biologo ← selecionar_biologo_disponivel(laudo.client_id)
    notificar_especialista(biologo.id, {
      tipo: 'INCONFORMIDADE_CRITICA',
      laudo_id,
      incidente_id,
      parametros_violados: inconformidades,
      sugestao_intervencao: gerar_sugestao_tratamento(inconformidades),
      prazo: NOW() + 24h
    })
  
  SENÃO SE alertas_atencao.length > 0:
    db.update('laudos', laudo_id, {conformidade_geral: 'ATENCAO', status_validacao: 'fila_biologo'})
  
  SENÃO:
    // PASSO 4B — Conformidade OK
    db.update('laudos', laudo_id, {
      conformidade_geral: 'CONFORME',
      status_validacao: 'aprovado',
      resumo_ia: 'Todos os parâmetros analisados estão dentro dos limites legais vigentes.'
    })
  
  RETORNAR { conformidade_geral, inconformidades, parametros_validados }

FUNÇÃO gerar_sugestao_tratamento(inconformidades):
  // LLM gera recomendação técnica baseada nos parâmetros violados
  RETORNAR llm.generate(
    prompt = f"Para os parâmetros violados {inconformidades}, sugira tratamento técnico.",
    modelo = 'claude_sonnet'
  )

3.1 — Autenticação com Certificado Digital A1

MÓDULO cert_manager:

  FUNÇÃO carregar_certificado(client_id):
    client ← db.get('clients', client_id)
    
    // Descriptografar certificado armazenado (AES-256-GCM)
    cert_pem ← crypto.decrypt(
      ciphertext = client.cert_a1_enc,
      key        = ENV.APP_ENCRYPTION_KEY,
      iv         = client.cert_iv
    )
    
    // Parse do certificado PKCS#12
    { cert, privateKey, chain } ← pkcs12.parse(cert_pem, client.cert_a1_senha_hash)
    
    // Validar validade
    SE cert.validTo < NOW():
      LANÇAR ERRO 'CERTIFICADO_VENCIDO'
    
    RETORNAR { cert, privateKey, chain }

  FUNÇÃO assinar_payload_soap(payload_xml, client_id):
    { cert, privateKey } ← carregar_certificado(client_id)
    
    // Assinatura XmlDSig (padrão ICP-Brasil)
    assinatura ← xmldsig.sign(
      xml         = payload_xml,
      privateKey  = privateKey,
      certificate = cert,
      algoritmo   = 'RSA-SHA256',
      canonicalizacao = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
    )
    
    RETORNAR payload_xml_assinado

  FUNÇÃO assinar_payload_rest(payload_json, client_id):
    { cert, privateKey } ← carregar_certificado(client_id)
    
    // JWT assinado com chave privada do certificado (mTLS alternativo)
    jwt_token ← jwt.sign(
      payload    = { ...payload_json, iat: NOW(), iss: cert.subject.cnpj },
      privateKey = privateKey,
      algorithm  = 'RS256'
    )
    
    RETORNAR { jwt_token, client_cert: cert.pem }

3.2 — API DAEE/SP Águas — Telemetria Mensal

// Cron: Dia 1 de cada mês às 04:00 UTC
CRON 'transmissao_daee' SCHEDULE '0 4 1 * *':

  clientes_daee ← db.query(
    "SELECT c.* FROM clients c
     JOIN outorgas o ON o.client_id = c.id
     WHERE o.orgao = 'DAEE' AND o.status = 'vigente'"
  )
  
  PARA CADA client EM clientes_daee:
    TRY:
      // Agregar telemetria do mês anterior
      telemetria ← db.query(f"""
        SELECT poco_id,
               SUM((telemetria->>'volume_diario_m3')::float) AS volume_total_m3,
               AVG((telemetria->>'nivel_estatico_m')::float) AS nivel_medio_m,
               MAX(updated_at) AS ultima_medicao
        FROM pocos
        WHERE client_id = '{client.id}'
        AND updated_at >= DATE_TRUNC('month', NOW() - INTERVAL '1 month')
        GROUP BY poco_id
      """)
      
      payload_xml ← templates.daee_telemetria({
        cnpj:      client.cnpj,
        competencia: format(LAST_MONTH, 'YYYY-MM'),
        outorgas:  telemetria
      })
      
      payload_assinado ← cert_manager.assinar_payload_soap(payload_xml, client.id)
      
      resposta ← http.post(
        url     = 'https://sisplu.daee.sp.gov.br/ws/medicoes',
        headers = {'Content-Type': 'text/xml; charset=utf-8', 'SOAPAction': 'EnviarMedicao'},
        body    = payload_assinado,
        tls     = { cert: client.cert_pem, key: client.cert_key }
      )
      
      db.insert('gov_transmissoes', {
        client_id: client.id,
        orgao: 'DAEE',
        tipo_transmissao: 'telemetria_mensal',
        payload_enviado: { telemetria },
        protocolo_retorno: xml.parse(resposta).protocolo,
        status: 'confirmado',
        assinado_com_cert: true
      })
      
    CATCH erro:
      db.insert('gov_transmissoes', {..., status: 'erro', erro_detalhe: erro.message})
      alertar_admin(client.id, 'FALHA_TRANSMISSAO_DAEE', erro)

3.3 — API SISAGUA — Laudos de Potabilidade

FUNÇÃO transmitir_laudo_sisagua(laudo_id):

  laudo ← db.get('laudos', laudo_id)
  
  // Só transmite se: potável + aprovado pelo biólogo
  SE laudo.tipo_amostra != 'potavel' OR laudo.status_validacao != 'aprovado':
    RETORNAR { ignorado: true, motivo: 'Critérios não atendidos' }
  
  client ← db.get('clients', laudo.client_id)
  
  payload ← {
    cnpjPrestador:    client.cnpj,
    codigoFormulario: 'A05',  // Padrão SISAGUA para análise física
    dataColeta:       laudo.data_coleta,
    pontoCaptacao:    laudo.poco_id,
    parametros:       laudo.parametros.map(p => ({
      codigo:  SISAGUA_CODIGOS[p.nome],  // Mapa de codificação SISAGUA
      valor:   p.valor,
      unidade: p.unidade
    })),
    responsavelTecnico: {
      crbio:  laudo.biologo.registro,
      nome:   laudo.biologo.nome
    }
  }
  
  payload_assinado ← cert_manager.assinar_payload_rest(payload, client.id)
  
  resposta ← http.post(
    url     = 'https://sisagua.saude.gov.br/sisagua/api/v1/amostras',
    headers = { 'Authorization': f'Bearer {payload_assinado.jwt_token}',
                'X-Client-Cert': payload_assinado.client_cert },
    body    = payload
  )
  
  db.insert('gov_transmissoes', {
    client_id: client.id,
    orgao: 'SISAGUA',
    tipo_transmissao: 'laudo_potabilidade',
    protocolo_retorno: resposta.numeroProtocolo,
    status: 'confirmado'
  })

3.4 — API IBAMA — RAPP Anual

// Cron: 15 de março de cada ano (prazo RAPP)
CRON 'rapp_ibama' SCHEDULE '0 8 15 3 *':

  PARA CADA client EM db.query("SELECT * FROM clients WHERE ativo = true"):
    
    // Consolidar dados do ano anterior
    dados_anuais ← {
      volume_captado_m3:  somar_telemetria_anual(client.id, ano=ANO_ANTERIOR),
      efluentes_m3:       somar_efluentes_lancados(client.id, ano=ANO_ANTERIOR),
      laudos_conformes:   contar_laudos(client.id, status='conforme', ano=ANO_ANTERIOR),
      incidentes:         listar_incidentes(client.id, ano=ANO_ANTERIOR),
      outorgas_ativas:    listar_outorgas(client.id, status='vigente')
    }
    
    // LLM pré-preenche o RAPP no formato CTF/IBAMA
    rapp_preenchido ← llm.generate(
      prompt = f"Preencha o RAPP {ANO_ANTERIOR} para empresa {client.razao_social} com dados: {dados_anuais}",
      formato = 'xml_ibama_rapp_v4'
    )
    
    payload_assinado ← cert_manager.assinar_payload_soap(rapp_preenchido, client.id)
    
    // Submeter ao CTF/IBAMA
    resposta ← http.post(
      url = 'https://servicos.ibama.gov.br/ctf/ws/rapp/envio',
      body = payload_assinado
    )
    
    notificar_client(client.id, 'RAPP_ENVIADO', {protocolo: resposta.protocolo})

Diagrama textual passo a passo de como uma inconformidade detectada pela IA migra para o Biólogo/Engenheiro e retorna tratada ao cliente.

1

📤 INPUT — Cliente faz upload do laudo PDF

O cliente (indústria/produtor) anexa o laudo físico-químico emitido pelo laboratório acreditado. O sistema registra o arquivo e cria registro com status 'aguardando_ia'.

2

🤖 IA ENGINE — OCR + Extração de Parâmetros

O motor OCR (Tesseract/Textract) extrai os parâmetros analíticos do PDF. O LLM estrutura os dados em JSON com: nome do parâmetro, valor numérico, unidade e método analítico.

3

⚖️ IA ENGINE — Validação contra Limites Legais Hardcoded

Cada parâmetro é comparado com a tabela de limites (MS 888/2021, CONAMA 430/2011, CONAMA 357/2005) conforme o tipo de amostra. Status individual: CONFORME | NÃO CONFORME | ATENÇÃO.

4A

✅ ROTA VERDE — Conformidade OK

Todos os parâmetros dentro dos limites legais. Sistema atualiza status para 'APROVADO', gera resumo narrativo automático, agenda próxima coleta conforme periodicidade contratada e notifica cliente no dashboard.

4B

🚨 ROTA VERMELHA — Inconformidade Crítica Detectada

Um ou mais parâmetros violam a norma. Sistema: (a) atualiza laudo para 'NÃO CONFORME', (b) cria registro de Incidente Hídrico vinculado, (c) gera hash de auditoria SHA-256 imutável para fins jurídicos.

5

🔔 NOTIFICAÇÃO PRIORITÁRIA — Fila do Biólogo

Sistema empurra notificação em tempo real (WebSocket) para o Biólogo responsável com: lista dos parâmetros violados, valores vs limites legais, sugestão automática de intervenção gerada pelo LLM e prazo de resposta de 24h.

6

🔬 BANCO TÉCNICO — Revisão do Biólogo (Painel Técnico)

Biólogo acessa o Painel Técnico do sistema, visualiza parâmetros violados, contexto histórico do poço/ETE, laudos anteriores e a sugestão de intervenção da IA. Pode: Validar sugestão, ajustar recomendação ou escalar para Engenheiro Ambiental.

7

✍️ BANCO TÉCNICO — Emissão de Parecer Técnico Formal

Biólogo/Engenheiro redige parecer técnico no sistema, define medidas corretivas específicas (tratamento, coleta de emergência, interdição parcial), aplica assinatura digital (SHA-256 + timestamp + CRBio/CREA) e assina digitalmente o documento.

8

📋 SISTEMA — Atualização e Rastreabilidade

Sistema atualiza o Incidente para 'EM_REMEDIAÇÃO', registra o hash de auditoria do parecer, atualiza o laudo para 'APROVADO_COM_RESSALVAS' e armazena trilha de auditoria completa (imutável) no banco.

9

📣 NOTIFICAÇÃO CLIENTE — Resultado da Mediação

Cliente recebe no dashboard: parecer técnico completo, medidas corretivas priorizadas (Plano de Ação 5W2H), prazo de reimplementação e nova data de coleta para reavaliação. Sistema agenda nova coleta automática.

10

🌐 GOV GATEWAY — Notificação Compulsória (se necessário)

Se gravidade = CRÍTICO ou EMERGENCIAL: sistema aciona automaticamente o órgão ambiental competente (CETESB/DAEE/IBAMA) via API com o payload assinado digitalmente pelo Certificado A1, anexando o laudo inconformidade e o parecer técnico.

11

✅ ENCERRAMENTO — Incidente Resolvido

Após nova coleta e novo laudo com conformidade confirmada, o Biólogo encerra o incidente no sistema. Status final: 'RESOLVIDO'. Hash de auditoria final gerado, cliente recebe certificado de regularidade ambiental digital.

📊 SLAs do Fluxo

EtapaResponsávelSLAEscalação
OCR + Validação IASistema Automático< 3 minRetry automático 3x
Notificação ao BiólogoSistema Automático< 30 segPush + E-mail + WhatsApp
Parecer Técnico BiólogoBiólogo24 horasEscala para Engenheiro
Parecer Técnico EngenheiroEng. Ambiental48 horasAlerta ao coordenador
Notificação ao ClienteSistema Automático< 1 min após parecer
Transmissão GOV (crítico)Sistema Automático< 2 horasRetry + alerta admin
Mente Serena Eco Compliance · Arquitetura Técnica v1.0 · Confidencial
Base legal: Lei 9.433/97 · CONAMA 357/2005 · CONAMA 430/2011 · Portaria MS 888/2021 · Lei 12.651/2012