intermediate
licenca
condicoes
compliance

Relatorios de Condicoes de Licenca

Como linhas permit_conditions dirigem o scoreboard diario de compliance -- cap de frota, implantacao em zona de equidade, SLA de reclamacoes, relatorio de viagens EOD e utilizacao de corredores.

Equipe Levy FleetsMay 18, 202613 min read

Relatorios de Condicoes de Licenca

A maioria das licencas municipais incluem condicoes aplicaveis -- cap de frota, percentual de implantacao em zona de equidade, SLA de reclamacoes, relatorio de viagens de fim de dia, utilizacao de corredor de estacionamento. O Levy armazena cada uma como uma linha em permit_conditions, as avalia em um cronograma e renderiza a tendencia pass/fail tanto no dashboard do operador quanto no portal da cidade.

Os cinco tipos de condicao

condition_typeO que verificaCadencia
fleet_capCOUNT(veiculos ativos na jurisdicao) <= capDiaria
equity_zone_pct% da frota implantada dentro de geografias de equidade >= limiarHoraria
complaint_slaresponded_at de cada reclamacao dentro de N horas de created_atDiaria
trip_report_eodUm CSV de viagem e gerado diariamente as 23:59 hora local da jurisdicaoDiaria
corral_utilizationSnapshot horario da ocupacao do corredor de estacionamentoHoraria

Cada linha em permit_conditions carrega o jurisdiction_id, o condition_type e um JSONB config que varia por tipo.

Configurando uma condicao

Do dashboard do operador em /dashboard/compliance/{jurisdiction-id} -> aba Condicoes de licenca, clique em Adicionar condicao.

fleet_cap

{
  "cap": 250,
  "vehicle_types": ["scooter"],
  "exclude_statuses": ["maintenance", "removed"]
}

O avaliador conta veiculos onde:

  • subaccount_id corresponde a subconta da jurisdicao
  • last_lat/last_lng esta dentro de mds_jurisdictions.geometry (ou NULL com last_seen nas ultimas 24h -- generoso para veiculos que acabaram de perder GPS)
  • status NOT IN config.exclude_statuses
  • model.vehicle_type IN config.vehicle_types (se definido)

Pass = contagem <= cap. Fail = contagem > cap. O scoreboard do dashboard mostra a contagem atual e o cap lado a lado.

equity_zone_pct

{
  "threshold_pct": 20,
  "equity_geography_ids": ["geo-1", "geo-2"],
  "min_vehicles_required": 5
}

Pass = implantados-em-equidade / total-implantados >= threshold_pct / 100. O min_vehicles_required e um piso -- se houver menos do que isso implantados ao todo, a condicao e marcada n/a para a hora em vez de falhada (implantacoes esparsas no inicio da manha).

Geografias de equidade vem do feed de politica da cidade (regras com rule_type = 'equity_zone') ou de uma lista configurada manualmente (quando a cidade nao as publica -- comum em cidades menores). A lista manual vive no mesmo permit_conditions.config.

complaint_sla

{
  "max_response_hours": 24,
  "complaint_sources": ["311", "in-app", "email"]
}

O avaliador faz join em complaints para encontrar linhas onde responded_at IS NULL AND created_at < now() - interval '<hours>' (abertas e atrasadas) ou responded_at - created_at > interval '<hours>' (fechadas mas tarde). Pass = zero reclamacoes atrasadas na janela.

trip_report_eod

{
  "format": "csv",
  "delivery": "email",
  "recipient_email": "permits@city.gov"
}

Um relatorio agendado roda as 23:59 hora local da jurisdicao e emite um CSV de viagens para o dia. Pass = o relatorio foi entregue com sucesso. Fail = e-mail rejeitou ou a linha de relatorio nao materializou.

corral_utilization

{
  "min_utilization_pct": 10,
  "max_utilization_pct": 90,
  "exclude_corral_ids": []
}

Snapshot horario da ocupacao de cada corredor de estacionamento. Pass = todos os corredores entre o piso e teto configurados. Fail = pelo menos um corredor fora da faixa. A condicao e usada por cidades que querem garantir que estacionamento esta realmente sendo usado (extremo baixo) e que operadores nao estao superconcentrando (extremo alto).

O scoreboard

Operadores veem o scoreboard em /dashboard/compliance/{jurisdiction-id}. Cidades veem dentro do portal da cidade em /city/{slug}. A forma e a mesma:

CondicaoValor atualLimiarStatus (hoje)Taxa de pass de 30 dias
Cap de frota247 veiculos250Pass100%
Equidade %18%>= 20%Fail88%
SLA de reclamacao2 abertas mais de 24h0Fail92%
Relatorio viagem EODEntreguen/aPass100%
Utilizacao de corredor6 de 6 na faixaTodos na faixaPass95%

Condicoes falhando sao destacadas em vermelho. A taxa de pass de 30 dias e computada do historico city_compliance_reports.

A biblioteca reporter

src/lib/compliance/permit-reporter.ts expoe avaliadores por condicao. Cada um recebe a jurisdicao + o permit_conditions.config relevante e retorna:

type ConditionResult = {
  condition_id: string;
  passed: boolean;
  current_value: number | string;
  threshold: number | string;
  measured_at: string; // RFC3339
  details: Record<string, unknown>;
};

O relatorio agregado no momento do digest:

const report = await buildComplianceReport({
  jurisdictionId,
  period: 'daily', // ou 'weekly' / 'monthly'
  date: '2026-05-18',
});

// report.conditions: ConditionResult[]
// report.summary.passed: number
// report.summary.failed: number
// report.trips: { count, total_distance_km, ... }
// report.complaints: { open, closed, late, ... }
// report.enforcement_events: { speed_limits_applied, locks_issued, ... }

Esta forma e o que o e-mail de digest renderiza, o que a API de compliance-report serve e o que e persistido para city_compliance_reports.payload.

A API de compliance-report

Contatos municipais puxam relatorios formais de:

GET /api/city/{slug}/compliance-report?period=monthly&date=2026-05

Retorna a mesma forma JSON que o digest, mais um pdf_url quando period=monthly (renderizamos um PDF de uma pagina para relatorios mensais -- util para renovacoes de licenca).

Cada relatorio buscado e persistido em city_compliance_reports -- a trilha de auditoria de cada relatorio que a cidade realmente recuperou. Se um auditor municipal pergunta "voces enviaram um relatorio para janeiro?", a linha em city_compliance_reports e a resposta.

Quando condicoes falham

Uma condicao falhando nao pausa automaticamente sua frota. Ela e exposta como:

  • Uma linha vermelha no scoreboard
  • Uma linha no digest de hoje
  • Um breadcrumb Sentry marcado compliance.condition.failed

O que voce faz a respeito depende da condicao. Para excesso de fleet_cap, implante menos veiculos. Para equity_zone_pct, redistribua. Para complaint_sla, responda as reclamacoes abertas. O sistema nao toma decisoes operacionais por voce.

A excecao e fleet_cap, onde o dashboard oferece um toggle "Pausar novas viagens iniciando na jurisdicao". Esse e um soft constraint -- viagens existentes continuam, nenhuma nova viagem comeca na jurisdicao ate o cap voltar a ficar abaixo do limiar. O toggle e controlado pelo operador; nao o ativamos automaticamente porque pausas auto falsas-positivas seriam muito piores que um fail de fleet_cap transiente.

Condicoes customizadas

Se sua licenca inclui uma condicao que nao se encaixa nos cinco tipos embutidos (por exemplo, "deve atingir 90% de sinalizacao multilingue"), adicione uma linha com condition_type = 'custom' e um campo passed manual. O avaliador retorna o que voce define; cidades ainda veem no scoreboard. Esta e a saida de emergencia para licencas com uma clausula estranha.

Proximos passos