vccs
Vue 3용 차트 컴포넌트 모음, Recharts에서 포팅
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기App web para consulta de veiculos
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
SaaS de consulta veicular para despachantes — placa, ficha técnica, FIPE, débitos e restrições em um só lugar. Um produto DOCTYPE. Abra http://localhost:3000.README 전문 보기 ↗
SaaS de consulta veicular para despachantes — placa, ficha técnica, FIPE, débitos e restrições em um só lugar. Um produto DOCTYPE.
npm install
cp .env.example .env.local # preencha com suas chaves (veja "Backend" abaixo)
npm run dev
Abra http://localhost:3000.
app/login — login e cadastro de despachante (Supabase Auth)app/forgot-password — recuperação de senhaapp/assinar — página com os 3 planos (Essencial/Profissional/Escritório) + "Fale com a gente" pra alto volume; usuário sem assinatura ativa é redirecionado pra cáapp/dashboard — consulta de veículo por placa, com ficha técnica, FIPE, débitos e restrições (protegido: exige login + assinatura ativa); topbar mostra o saldo de consultas avançadas do períodoapp/dashboard/historico — histórico de placas consultadas, salvo no banco; tem botão "Limpar histórico" (apaga tudo, com confirmação)app/api/checkout — cria a sessão de Stripe Checkout para o usuário logadoapp/api/stripe/webhook — recebe eventos do Stripe e atualiza a assinatura no bancoapp/api/veiculo — consulta dados reais de veículo por placa (exige login + assinatura ativa)app/api/consulta-avancada — consulta avançada real de multas/roubo-furto/Renajud, sob demanda (exige login + assinatura ativa)app/admin — painel administrativo (exige is_admin); inclui "Criar acesso de teste", que convida um e-mail (novo ou já cadastrado) com cota fixa e prazo definido na hora, sem cobrançaapp/api/cron/expirar-testes — roda 1x/dia (agendado em vercel.json) e revoga sozinho os testes cujo prazo já passoulib/vehicle.ts — camada de dados mock (débitos — ainda simulado, exibido junto com o dado real)lib/dados-veiculo.ts — client do provedor de dados veiculares ativo (veja "Dados reais de veículo" abaixo)lib/dados-avancados.ts — client do provedor de consulta avançada (veja "Consulta avançada" abaixo)lib/plans.ts — os 3 planos (nome, cota mensal de consultas avançadas, preço) e o preço da consulta avulsa fora da cotalib/uso-avancada.ts — conta o uso do período atual e registra cada consulta avançada realizada (tabela avancada_usage)lib/infosimples.ts — client da Infosimples, hoje não usado (endpoint de veículo não autorizado na conta atual); mantido caso a consulta de multas ANTT/SIFAMA seja retomadalib/supabase/ — clients Supabase (browser, server, admin/service-role) e o proxy de sessãolib/stripe.ts — client Stripeproxy.ts — protege as rotas de /dashboard redirecionando para /login sem sessãosupabase/migrations/0001_init.sql — schema do banco (perfis, assinaturas, histórico)components/Guardiao.tsx — mascote oficial DOCTYPE, usado nos momentos de espera/aprovação/confirmação do apppublic/mascote/ — imagens do Guardião (veja "Identidade visual" abaixo)O app segue o manual de marca DOCTYPE: laranja #FF6400 como cor de ação, navy #06133F como base institucional, texto em #101419, fundo neutro #F7F8FA e cinza de apoio #8A93A2. Títulos usam Montserrat e o corpo de texto usa Inter (carregadas via next/font/google em app/layout.tsx), sem dependência externa de CSS.
O mascote Guardião — o "monitor" de todos os produtos DOCTYPE — aparece nos momentos-chave da jornada (tela de login, aguardando a primeira consulta, durante a verificação da placa, pedindo aprovação da assinatura, confirmando envio de e-mail). O componente components/Guardiao.tsx referencia os arquivos em public/mascote/:
guardiao-aguardando.png — login e estados vazios ("aguardamos seu retorno")guardiao-verificando.png — carregando o resultado de uma consultaguardiao-aprovacao.png — página de assinaturaguardiao-enviado.png — confirmações de e-mail (cadastro, recuperação de senha)guardiao-sucesso.png — reservado para estados de sucessoEsses arquivos ainda não estão no repositório — o componente se esconde automaticamente (sem quebrar o layout) quando a imagem correspondente não existe. Basta adicionar os PNGs com esses nomes em public/mascote/ para o mascote aparecer.
O app precisa de duas contas externas configuradas antes de funcionar de verdade:
Crie um projeto em supabase.com.
Abra SQL Editor e rode o conteúdo dos arquivos em supabase/migrations/, em ordem (0001_init.sql, 0002_..., etc.) — cada um é rodado manualmente, não há pipeline automático de migração.
Em Authentication > Providers, confirme que "Email" está habilitado. Em Authentication > Emails, decida se exige confirmação de e-mail (recomendado em produção).
Em Project Settings > API Keys, copie:
https://xxxx.supabase.co) → NEXT_PUBLIC_SUPABASE_URLsb_publishable_...) → NEXT_PUBLIC_SUPABASE_ANON_KEYsb_secret_...) → SUPABASE_SERVICE_ROLE_KEY (secreta — só no servidor)(Em projetos Supabase mais antigos essas chaves aparecem como anon public / service_role — funcionam da mesma forma, só o nome muda.)
Depois de adicionar/alterar variáveis na Vercel, é preciso fazer um novo deploy para elas passarem a valer — variáveis de ambiente não afetam deploys já publicados.
SMTP próprio (obrigatório para suportar múltiplos cadastros). Por padrão o Supabase manda os e-mails de confirmação/recuperação de senha pelo servidor deles, compartilhado entre todos os projetos gratuitos — o limite é de poucos e-mails por hora, e estoura rápido (erro email rate limit exceeded). Pra suportar dezenas de despachantes se cadastrando, configure um SMTP próprio:
smtp.resend.com465Crie um produto e três preços recorrentes mensais em Product catalog — um por plano (Essencial, Profissional, Escritório; valores e cotas em lib/plans.ts). Copie cada price_... → STRIPE_PRICE_ESSENCIAL / STRIPE_PRICE_PROFISSIONAL / STRIPE_PRICE_ESCRITORIO.
Em Developers > API keys, copie a Secret key → STRIPE_SECRET_KEY.
Em Developers > Webhooks, crie um novo destino de evento (não reaproveite um endpoint de outro projeto) apontando para https://SEU-DOMINIO/api/stripe/webhook, escutando: customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, checkout.session.completed, checkout.session.async_payment_succeeded. Copie o Signing secret → STRIPE_WEBHOOK_SECRET.
O último evento (async_payment_succeeded) cobre métodos de pagamento assíncronos (boleto, por exemplo): checkout.session.completed dispara assim que o cliente gera o boleto, não quando ele paga — payment_status continua "unpaid" até a compensação (1-3 dias úteis). O webhook (app/api/stripe/webhook/route.ts) checa payment_status === "paid" antes de liberar qualquer crédito/documento, então sem esse evento configurado, uma compra paga via boleto nunca seria processada depois que compensasse.
Se sua conta usa Sandboxes (contas Stripe novas), confirme que o produto, a chave e o webhook estão todos dentro do mesmo sandbox — cada sandbox tem chaves e webhooks isolados.
Cobrança avulsa do excedente: quando o despachante estoura a cota de consultas avançadas ou simples do plano no período (e, no caso de consulta simples, não tem crédito de recarga disponível), app/api/consulta-avancada e app/api/veiculo criam um item de fatura avulso (stripe.invoiceItems.create) nos valores de PRECO_AVULSO_CENTAVOS / PRECO_AVULSO_SIMPLES_CENTAVOS (lib/plans.ts) — o Stripe inclui isso automaticamente na próxima fatura do cliente, sem precisar de nenhum job agendado.
Pacotes de recarga de créditos: não exigem nenhum Price cadastrado no Stripe — app/api/checkout-creditos cria a sessão de checkout com inline (valores em , ), e o webhook () credita os créditos ao usuário via . Créditos expiram 6 meses após a compra, ou imediatamente se a assinatura for cancelada (, chamada tanto pelo webhook quanto pela revogação manual de acesso no admin).
gateway.apibrasil.io, produto endereco-telefone-por-placa) — mesmo token das outras consultas desse provedor → APIBRASIL_TOKEN. Não precisa de variável própria.lib/dados-veiculo.ts chama esse provedor e devolve ficha do veículo (placa, chassi, Renavam, marca/modelo, ano, cor, combustível) e o dossiê completo do proprietário atual.app/api/crm/proprietario), que expõe dado pessoal parecido atrás desses dois controles. Foi uma escolha deliberada do produto; revise as implicações de LGPD antes de mudar esse comportamento de novo.
cpfCnpjCliente em app/dashboard/page.tsx) — não vem da API, não é persistido, existe só naquela consulta/impressão.lib/infosimples.ts fica sem uso por enquanto (endpoint de veículo não autorizado na conta atual) — mantido só caso a consulta de multas ANTT/SIFAMA seja retomada."http", nunca no simples "essa placa não existe"), lib/dados-veiculo.ts tenta automaticamente um segundo fornecedor (wdapi2.com.br, revendido também como placas.com.br/apiplacas.com.br) → WDAPI2_TOKEN. Esse provedor só devolve dado do veículo (placa, chassi mascarado, marca/modelo, ano, cor, FIPE) — sem dossiê do proprietário. Sem o token configurado, o fallback é simplesmente pulado.PLACA_DEBITOS_API_TOKEN.lib/dados-avancados.ts chama esse provedor sob demanda — só quando o despachante clica no botão "Consultar multas, roubo/furto e Renajud reais" na ficha, nunca automaticamente numa consulta normal, já que cada chamada tem custo. Devolve: multas em aberto (item a item: descrição, valor, pontos, gravidade, órgão competente, artigo e o papel do responsável — "Proprietário" ou "Condutor", nunca um nome de pessoa), totais agregados, ocorrência de roubo/furto (tipo, data, município) e restrições judiciais ativas no Renajud (tribunal, número do processo, tipo de restrição). O provedor não devolve data nem local de cada multa individual — só o que está listado acima existe na resposta dele.sanitizeAvancada() em lib/dados-avancados.ts só libera o nome e, quando o documento tem 14 dígitos (pessoa jurídica), o CNPJ; documento de 11 dígitos (CPF de pessoa física) nunca é exposto por esse provedor específico — diferente da consulta simples (item 3 da seção acima), que hoje já traz o CPF por decisão de produto. O campo infrator de cada multa também foi conferido: é só a categoria de quem responde pela multa, não um nome — validado com uma amostra real antes de liberar a listagem item a item.Diferente dos dois provedores acima (consulta por placa de terceiros), "Meus Veículos" (app/dashboard/meus-veiculos) é um cofre pessoal por despachante: cada um cadastra manualmente ou importa o JSON obtido na própria sessão autenticada do Portal SENATRAN — dado que o despachante já possui legitimamente antes de entrar no sistema.
meus_veiculos, migração 0007_meus_veiculos.sql) e o PDF do CRLV num bucket privado do Supabase Storage (crlv-pdfs), ambos isolados por despachante via RLS (auth.uid() = user_id).meus_veiculos_auditoria) registra usuário, ação e veículo por id interno — nunca nome, CPF/CNPJ, Renavam ou chassi.Recurso pago à parte (R$65,00 por emissão, Stripe Checkout avulso), separado da consulta de dados do veículo — usa outro provedor (API Brasil), acionado só quando o despachante pede.
app.apibrasil.io > Bearer Token) → APIBRASIL_TOKEN.lib/crlv.ts chama POST https://gateway.apibrasil.io/api/v2/consulta/veiculos/credits com {"tipo":"crlve","placa","uf","homolog":false}, autenticado com Authorization: Bearer <token>./dashboard/documentos → app/api/checkout-crlv cria uma sessão de Stripe Checkout avulsa (preço inline, PRECO_CRLV_CENTAVOS em lib/crlv.ts, sem exigir Price cadastrado) → só depois do pagamento confirmado (checkout.session.completed) o webhook chama a API Brasil e salva o resultado em documentos_crlv (migração 0011_documentos_crlv.sql). O PDF retornado (base64) é decodificado e salvo no mesmo bucket privado crlv-pdfs já usado por "Meus Veículos" (pasta ${user_id}/emissoes/${id}.pdf), reaproveitando a policy de RLS existente — nenhum bucket novo é necessário.Consulta a situação de um transportador (RNTRC/ANTT) — útil pra despachante que atende frota/transporte de carga, não só veículo de passeio. Mesmo provedor/token do CRLV-e (APIBRASIL_TOKEN), endpoint diferente.
lib/rntrc.ts chama POST https://gateway.apibrasil.io/api/v2/consulta/api-rntrc/credits com {"tipo":"search","homolog":false,"filters":{"cpf_cnpj":"..."} ou {"rntrc":"..."},"pagination":{"page":1,"page_size":1}}./dashboard/logistica: CPF/CNPJ direto, número do RNTRC direto, ou placa do caminhão — nesse último caso, app/api/logistica/rntrc primeiro resolve a placa pro CNPJ do proprietário (via consultarVeiculoPorPlaca, mesma função da consulta simples) e só então busca o RNTRC desse CNPJ. A API do RNTRC indexa por transportador, não por veículo — não existe filtro por placa nela. Só funciona quando o dono é pessoa jurídica: o app nunca expõe CPF de proprietário pessoa física (LGPD), então não há CPF disponível aqui pra buscar quando o dono é pessoa física.app/api/consulta-avancada (cota do plano → crédito de recarga → avulso cobrado no Stripe), gravando o uso em avancada_usage (coluna placa guarda o CPF/CNPJ ou RNTRC consultado nesse caso, não necessariamente uma placa de veículo).Consulta o proprietário atual de um veículo sem sanitização — nome completo e CPF/CNPJ, ao contrário de todo o resto do app (que nunca expõe CPF de pessoa física). Decisão deliberada, pra atender despachante/profissional veicular que precisa desse dado completo — atrás de proteções extras, não do jeito aberto.
lib/proprietario.ts chama o mesmo endpoint do CRLV-e (POST .../consulta/veiculos/credits) com {"tipo":"proprietario-atual-v2","placa":"...","homolog":false}./dashboard/crm, migração 0013_crm_proprietario.sql):
profiles.cpf_cnpj, via /api/perfil/cpf-cnpj) — nunca pedido no cadastro inicial.app/api/crm/proprietario rejeita se não bater com o cadastrado.crm_proprietario_auditoria: usuário, placa, quando) — nunca o nome/CPF do proprietário retornado, só o fato de que a consulta aconteceu.avancada_usage/recargas_avancada), sem tabela de crédito própria.lib/proprietario.ts em nenhum outro fluxo sem manter as três proteções acima — é a única exceção deliberada à regra de nunca expor CPF de pessoa física.Em Project Settings > Environment Variables do projeto doc-car-app, adicione as variáveis acima. Depois de salvar, é preciso um novo deploy (as variáveis não afetam deploys já publicados) — basta mesclar qualquer PR em main para gerar um.
Sem essas variáveis configuradas, o app sobe normalmente mas login/cadastro, assinatura e consulta real mostram erro — é esperado até a configuração ser concluída.
O projeto está conectado à Vercel via este repositório GitHub: todo push no branch main gera um deploy automático. Não é necessário publicar manualmente — basta abrir um PR, revisar e fazer merge em main.
resend[email protected])DOC.CARprice_dataPACOTES_RECARGAlib/plans.tscheckout.session.completedregistrarRecarga()expirarCreditosPorCancelamento()PIX na compra de recarga: app/api/checkout-creditos já pede payment_method_types: ["card", "pix"] — mas o Stripe só oferece PIX de fato se ele estiver ativado pra sua conta. Confirme em Settings > Payment methods que PIX aparece como "On" (contas brasileiras novas costumam já vir habilitadas; se não vier, tem que ativar manualmente ali). Sem isso, o checkout cai só no cartão. A assinatura mensal (app/api/checkout) continua só cartão — PIX não é reutilizável pra cobrança automática recorrente.