Synaplan
기업을 위한 오픈소스 AI 플랫폼
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기MarcaSync — automação do processo de registro de marcas junto ao INPI (protótipo funcional)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Protótipo funcional do fluxo de produto do MarcaSync — automação do processo de registro de marcas junto ao INPI. Este repositório contém duas coisas:
prototype.html — o protótipo standalone (HTML/CSS/JS puro, um arquivo só), o
mesmo publicado como artifact durante a fase de validação de interface. Útil para
abrir direto no navegador sem instalar nada.src/ — o início real da aplicação em Next.js 16 (App Router) + React 19 +
TypeScript + Tailwind v4, com a mesma lógica portada para componentes tipados. É o
ponto de partida para o desenvolvimento de verdade.npm install
cp .env.example .env # preencha DATABASE_URL/DATABASE_URL_UNPOOLED (ver "Banco de dados")
npx prisma generate # sempre rode isso depois de mudar prisma/schema.prisma
npm run dev
Abra http://localhost:3000. Para checar tipos e build de produção antes de commitar:
npm run typecheck
npm run build
prisma/)Postgres via Neon (integração nativa do Vercel) — o "caderno de anotações" real do produto. Guarda cliente, processo (marca, descrição, análise, status, protocolo) e pagamento (setup/monitoramento, confirmado à mão depois que o cliente avisa por WhatsApp).
Era SQLite local até 26/08/2026 (prisma/dev.db, um arquivo só) — migrado pra
Postgres porque o Vercel não tem disco persistente: sistema de arquivos lá é só
leitura fora de /tmp, um arquivo .db local não sobrevive a um redeploy, muito menos
a instâncias diferentes rodando em paralelo.
prisma/schema.prisma — os 3 modelos: Cliente, Processo, Pagamento.src/lib/db.ts — cliente Prisma (singleton) + @prisma/adapter-neon (driver
serverless do Neon, baseado em WebSocket — por isso o polyfill ws no arquivo,
necessário em runtime Node.js)./admin — lista todos os processos e pagamentos, com botão "Marcar como pago". Sem
login próprio — protegido por senha simples via src/proxy.ts, ver seção
"Autenticação" abaixo.Setup: crie o banco em Vercel → aba Storage → Create Database → Postgres
(Neon, camada gratuita, sem cartão). O Vercel injeta sozinho DATABASE_URL (pooled,
usada em runtime) e DATABASE_URL_UNPOOLED (conexão direta, usada só por
prisma migrate/prisma.config.ts — o pooler do Neon não suporta todas as operações
de migração) — não precisa configurar nada extra no dashboard. Localmente, copie esses
dois valores pro seu .env (ver .env.example).
Prisma 7 mudou o modelo de configuração: a URL de conexão não vive mais no
schema.prisma, vive em prisma.config.ts. Se npx prisma migrate dev reclamar de
schema, veja esse arquivo antes de mexer no schema.prisma.
Pegadinha real, já caí nela várias vezes: npx prisma migrate dev nem sempre
regenera o client automaticamente depois de mudar schema.prisma (deveria, às vezes
não regenera). Se o servidor começar a reclamar de "Unknown argument" num campo que
você acabou de adicionar, rode npx prisma generate manualmente — e se ainda assim
persistir, reinicie o npm run dev (o processo antigo mantém o client velho
carregado em memória, um prisma generate sozinho não é suficiente).
src/proxy.ts)Basic Auth simples protegendo só /admin, GET /api/processos (lista todo mundo) e
POST /api/pagamentos/:id/confirmar — o resto da API fica sem senha de propósito,
porque é o que o wizard público precisa chamar pra funcionar (criar processo, avançar
etapa, registrar cobrança pendente). Usuário do Basic Auth pode ser qualquer coisa; só
a senha importa, definida em ADMIN_PASSWORD (padrão no código: 2001 — troque antes
de deploy público, é fraca de propósito).
Chamado proxy.ts, não middleware.ts — o Next.js 16 renomeou a convenção (ver
nextjs.org/docs/messages/middleware-to-proxy).
Projeto ligado em andersoncrushlink-7788s-projects/marcasync, com deploy automático a
cada push na main (integração Git conectada quando o projeto foi criado via
vercel link).
Variáveis de ambiente já configuradas no Vercel (Production + Preview):
DATABASE_URL, DATABASE_URL_UNPOOLED e as demais do Neon (injetadas sozinhas pela
integração de Storage), mais ADMIN_PASSWORD (adicionada
manualmente via vercel env add) NEXT_PUBLIC_WHATSAPP_NUMBER (ver "Contato pelo
WhatsApp" — trocar exige novo deploy) e CRON_SECRET (monitoramento da RPI).
Além dos testes unitários (npx vitest run), há dois que usam o site de verdade e só rodam contra localhost, porque criam pedidos de teste:
node scripts/testar-seguranca.mjs ataca a API como um visitante mal-intencionado: preço adulterado, vazamento de dados, áreas protegidas, upload falso, cabeçalhos, WhatsApp inválido, rotas do robô (token, senha do painel não vale como token, pedido não pago) e limite de abuso. Leva uns 2 minutos (espera a janela do limitador). Passe ROBO_TOKEN=... no ambiente para incluir as provas com o token certo.node scripts/testar-fluxo.mjs percorre o fluxo do cliente no navegador (precisa de cd robo && npm install): consulta, resultado, plano, pedido e pagamento, os bloqueios (WhatsApp, CPF, e-mail, confirmações), a lista de classes, o visual dos campos e a tela de celular sem rolagem lateral. Rode-o um minuto depois do de segurança, para o limitador de cadastros liberar.O cliente paga uma cobrança só, que cobre o serviço (R$ 499) e a taxa do INPI (GRU), por Pix ou cartão (até 3x), na página de pagamento (checkout) do AbacatePay. O valor sai de um dos 4 produtos "pacote" do AbacatePay (GRU 389 ou 394, com ou sem desconto), escolhido pelo servidor. O AbacatePay é a fonte da verdade: nada é marcado como pago sem a API confirmar, e o checkout é descartado se o valor do produto não bater com o que o servidor calculou.
src/lib/pacotes.ts — qual produto cobrar, parcelas do cartão e o endereço de retorno (SITE_URL, padrão https://www.marcasync.com.br).src/lib/abacatepay.ts — cliente da API v2 (checkout, pagador, consultar, estornar).src/lib/cobranca.ts — cria o checkout do pedido (cadastra antes o pagador com os dados do pedido, para ele não digitar de novo), confere o pago e estorna.src/lib/estorno.ts — regra de devolução: antes de pagar a GRU ao INPI volta tudo (estorno do AbacatePay); depois, só o serviço, à mão
(o AbacatePay não estorna parte do valor): você devolve por Pix e registra no /admin; após o protocolo, nada.GET /api/processos/[id]/cobrancas — a tela de pagamento consulta a cada 5 s (cria o checkout que faltar, sincroniza o status)./pedido/[id] — para onde o AbacatePay devolve o cliente depois de pagar; ele também pode retomar o pagamento por ali.POST /api/webhooks/abacatepay?webhookSecret=... — gatilho (checkout.completed): acha o id (bill_...) no corpo e pergunta o status à API.POST /api/admin/pagamentos/[id]/estornar — estorno total pelo /admin (protegido por senha).POST /api/admin/pagamentos/[id]/devolucao-manual — registra a devolução parcial feita por fora.POST /api/admin/processos/[id]/gru-paga — marca que a taxa já foi paga ao INPI (muda a regra de devolução).Variáveis de ambiente: ABACATEPAY_API_KEY (chave abc_dev_... no modo de teste, outra em produção, só no Vercel como
sensível), ABACATEPAY_WEBHOOK_SECRET (o mesmo valor do webhookSecret da URL cadastrada no painel) e, se o site não for
www.marcasync.com.br, SITE_URL. Permissões da chave: CHECKOUT:CREATE, CHECKOUT:READ, REFUND:CREATE,
CUSTOMER:CREATE e PRODUCT:READ (e PRODUCT:CREATE só para rodar o script de produtos).
O checkout cobra os produtos do catálogo, então eles precisam existir no ambiente da chave:
node --env-file=.env.local scripts/criar-produtos-abacatepay.mjs cria os produtos (4 pacotes com o serviço e a GRU 389 ou 394
embutidos, com e sem desconto; serviço e GRUs avulsos; monitoramento mensal). abc_dev_... cria no modo de teste; em produção
é preciso rodar de novo com a chave de produção. node --env-file=.env.local scripts/conferir-produtos-abacatepay.mjs confere
se os preços de lá batem com o catálogo do repositório.
Depois de pago, o pedido é protocolado por você no e-Marcas e registrado no /admin:
POST /api/admin/processos/[id]/protocolo): número do pedido (9 dígitos) e data e hora do
envio. Só aceita se o pagamento estiver confirmado. Muda o status, cria o prazo da
procuração (60 dias) e avisa o cliente. A regra de devolução passa a tratar o serviço como concluído.POST/GET /api/admin/processos/[id]/recibo): guardado no banco (até 2 MB, só PDF de verdade).src/lib/prazos.ts): a rotina diária (/api/cron/rpi) chama avisarPrazos e avisa quando faltam 30, 7 e 2
dias e quando vence, uma vez por nível. POST /api/admin/prazos/[id]/concluir encerra o prazo.src/lib/avisos.ts, notificar.ts, canais.ts): pagamento recebido, pedido protocolado e prazos, para
você e para o cliente. Todo aviso fica registrado em Notificacao e aparece no /admin.Canais de envio (todos opcionais; sem nenhum, o aviso fica só no painel):
| Variável | Para quê |
|---|---|
RESEND_API_KEY e EMAIL_REMETENTE (ex.: MarcaSync <[email protected]>) | e-mail ao cliente pela Resend, com o domínio verificado |
EMAIL_OPERADOR | e-mail avisando você (precisa das duas de cima) |
TELEGRAM_BOT_TOKEN e TELEGRAM_CHAT_ID | aviso instantâneo para você pelo Telegram |
CALLMEBOT_TELEFONE (55 + DDD + número) e CALLMEBOT_APIKEY | aviso para você pelo WhatsApp, pelo CallMeBot: serviço gratuito e não oficial, que só manda para o número de quem ativou a chave (você manda uma frase de ativação pelo seu WhatsApp e ele devolve a chave). A chave vai na URL, então fica só no Vercel, como sensível. |
ROBO_TOKEN | senha do robô do e-INPI (pasta robo/), que roda no seu computador: com ela ele lê os pedidos já pagos (GET /api/robo/tarefas), conta a conferência da GRU e dá sinal de vida. Sem ela as rotas /api/robo/* respondem 503 (desligadas). Sequência longa e aleatória, a mesma em robo/.env; no Vercel, como sensível. |
Aviso de novo interesse: quando alguém deixa nome e WhatsApp no Plano, você recebe nos canais ligados (Telegram, WhatsApp) quem é, a marca, o risco e a classe. No máximo 10 por hora, para um cadastro em massa não encher o seu celular.
src/lib/imagem-marca.ts)Marca figurativa ou mista precisa de imagem no e-Marcas: JPG, RGB, 300 dpi, no mínimo
945 x 945 px, até 2 MB (Manual de Marcas do INPI, item 3.5.2). O cliente envia PNG ou JPG
(até 5 MB) no formulário do pedido; o servidor converte e guarda no banco (tabela
ImagemMarca): o JPG pronto e o arquivo original.
src/components/ImagemMarcaUpload.tsx — escolhe o arquivo, mostra a prévia e o que ficou
guardado. A checagem do navegador é só UX.src/app/api/processos/[id]/imagem/route.ts — POST recebe e converte (com sharp:
fundo transparente vira branco, sRGB, 300 dpi, amplia se menor que 945 px e avisa);
GET devolve o JPG (ou ?tipo=original) e é protegido por senha em src/proxy.ts.Antes de considerar isso pronto pra clientes reais:
ADMIN_PASSWORD por algo mais forte que 2001 — 4 dígitos só era aceitável
rodando local./admin não tem rate limiting no Basic Auth — um site público sem isso é atacável
por força bruta, mesmo com senha forte. Considerar um WAF/rate limit (Vercel Firewall,
gratuito no plano atual) antes de divulgar a URL amplamente.vercel --prod (dentro da pasta do
projeto, com o CLI autenticado).Fluxo: Consulta → Resultado → Plano → Contato. O cliente pode ir pro WhatsApp já no
Resultado ("Falar comigo no WhatsApp") ou depois de ver o preço no Plano. Os botões são
<a href="https://wa.me/…"> de verdade (abrem em nova aba, sem bloqueio de pop-up); o
clique também move o wizard pro passo "Contato" e grava status = contato no processo —
dá pra ver no /admin quem já pediu conversa. Pelo Plano, também viram as 2 cobranças
pendentes (setup e, se ligado, monitoramento), criadas uma única vez mesmo se o cliente
voltar pelo Stepper e confirmar de novo.
A mensagem (src/lib/whatsapp.ts) já vai com nome, marca, risco real do INPI, classe
sugerida, plano escolhido e uma Ref. curta pra achar o pedido no /admin.
Configuração: NEXT_PUBLIC_WHATSAPP_NUMBER (só dígitos, DDI + DDD + número, ex.:
5585912345678). Por ser NEXT_PUBLIC_, o Next embute o valor no build — trocar o
número exige novo deploy. Sem a variável, o botão vira "Quero que me chamem" e a
conversa parte do WhatsApp que o próprio cliente informou na consulta (nunca um link
quebrado).
O plano de R$ 29/mês agora tem processo real por trás:
/admin (isso também marca o pedido como Protocolado). O cliente precisa ter o monitoramento ligado no plano./api/cron/rpi todo dia às 12h UTC (vercel.json). A RPI sai às terças; rodar todo dia pega edição atrasada. Edição já lida é pulada sem baixar nada (tabela LeituraRpi).src/lib/monitor-rpi.ts) baixa o XML oficial da edição, procura só os processos monitorados e grava um Alerta por despacho (chave única: reprocessar não duplica). Despacho com "oposição" no texto ganha prazo estimado de 60 dias da publicação (Lei 9.279/96, art. 158) — é estimativa, confira na RPI./admin, seção Alertas da RPI: botão "Avisar no WhatsApp" (abre a conversa com o cliente com a mensagem pronta e marca como avisado) e "Verificar RPI agora" para forçar a leitura.Frequência (src/lib/cadencia.ts): todo processo monitorado é semanal (a situação no INPI a cada 6+ dias, e toda edição nova da RPI)
até você confirmar que está tudo certo com o protocolo. No /admin, o botão "Protocolo OK: passar para mensal" (só depois de protocolar e
preencher o nº do INPI) passa o processo para mensal (situação a cada 27+ dias, e a RPI só quando completa o mês). Se o INPI mudar a
situação ou publicar um despacho, o processo volta para semanal sozinho (pode haver prazo correndo). "Voltar para semanal" também existe
no /admin. Atenção: no modo mensal, um despacho publicado numa edição que não foi lida só aparece pela mudança de situação, até 27 dias depois.
A rota do cron exige Authorization: Bearer $CRON_SECRET (a Vercel envia sozinha); sem a variável ela se recusa a rodar. RPI_BASE_URL existe só para testar contra uma edição simulada — não defina em produção.
Limites honestos: o aviso ao cliente é por WhatsApp, enviado por você (não há e-mail/push nem envio automático de mensagem). Não calcula decênio nem outros prazos — só lista despachos e o prazo de oposição. Se o INPI estiver fora do ar, a rotina falha com 502 e tenta de novo no dia seguinte.
A busca textual do INPI devolve só o que ela acha mais relevante (top 10) — uma grafia diferente ("Nubanc" para "Nubank") pode ficar de fora. Por isso o app guarda uma cópia local da base oficial de dados abertos do INPI (https://dadosabertos.inpi.gov.br/index/marcas/) e compara por som (foneticaBR) com tudo.
MarcaInpi, ~3 milhões de linhas, ~450 MB): marcas vivas (registro em vigor ou pedido em andamento) que têm nome — número, nome, situação, data de depósito e classes de Nice. Ficam de fora: extintas/arquivadas/indeferidas, as aguardando recurso contra indeferimento, e marcas só figurativas (sem texto para comparar).src/lib/marcas-locais.ts + colidencia.ts): a busca ao vivo do INPI e a base local rodam juntas; o resultado junta as duas (mesmo processo → vale o registro ao vivo) e mostra as 10 mais parecidas. Se a busca ao vivo cair, a base local responde sozinha (resultado continua real, com aviso) — só cai para a demonstração se as duas falharem.npm run ingerir:marcas (baixa ~5,7 GB, leva ~20 min). Use -- --dry para só contar e estimar sem gravar. O script troca a base inteira e se recusa a rodar se passar de 85% do limite do banco (hoje 1 GB no Neon).Branco + tons pastéis (menta, lavanda, pêssego, céu, manteiga), sem tema escuro de
propósito — um único conjunto de tokens em :root (globals.css) vale pro app inteiro
e pra landing. --accent é só preenchimento (botão, passo atual): menta pastel com
tinta escura por cima; pra texto ou foco use --accent-strong. Cada par texto×fundo
foi medido (WCAG) — ver comentário no topo de LandingPage.css.
src/lib/fonetica.ts) — redução fonética simplificada
para PT-BR + distância de Levenshtein, comparando a marca digitada contra uma base de
exemplo (src/lib/data.ts). Isto é uma heurística deliberadamente pequena para provar
a mecânica, não um Soundex/Metaphone validado — ver a seção "Próximos passos".src/lib/ncl.ts) — mapeamento por palavra-chave de uma
descrição em linguagem natural para uma das classes de Nice. Cobre 11 das 45 classes
reais, como prova de conceito.src/lib/inpi/, src/app/api/rpi/lookup/) —
não é mock: baixa e faz parsing do XML publicado semanalmente em
revistas.inpi.gov.br, o canal que o próprio INPI declara ser "para uso através de
aplicativos". Ver seção própria abaixo.src/lib/inpi/busca-client.ts,
src/lib/colidencia.ts, /api/colidencia) — API não documentada publicamente que
sustenta o portal servicos.busca.inpi.gov.br/marcas, integrada e testada com dado
real (ver seção própria abaixo). Alimenta o passo "Resultado"; só cai pra base de
exemplo se a busca real falhar de verdade.src/lib/whatsapp.ts, ContatoStep.tsx) — depois da
consulta o cliente cai direto numa conversa com o WhatsApp do MarcaSync, com a
mensagem já escrita. Ver a seção "Contato pelo WhatsApp".src/lib/inpi/)Isto substitui, de verdade, a promessa de "ler a RPI" — não é um setTimeout fingindo
progresso. GET /api/rpi/lookup?numero=<processo> baixa a edição mais recente da Revista
da Propriedade Industrial (Seção V — Marcas), publicada oficialmente e em formato aberto
pelo próprio INPI, e devolve os despachos reais de qualquer processo informado.
Validado em 25/08/2026 contra a edição real 2903 (peguei os bytes crus no navegador,
não confiei na documentação): a raiz é <revista numero="2903" data="25/08/2026">, cada
marca é <processo numero="..."> com <despachos><despacho codigo="IPASxxx" name="..."/></despachos> e <titulares><titular nome-razao-social="..." pais=".." uf=".."/></titulares>. O encoding é UTF-8 mesmo — o XML não mente sobre isso. src/lib/inpi/parse-rpi.ts
foi testado contra esse fragmento real antes de entrar no repositório.
Decisão de arquitetura que vale registrar: a edição descompactada tem ~65 MB e dezenas
de milhares de processos. buscarProcessosNaEdicao não faz parsing do XML inteiro numa
árvore de objetos — localiza cada bloco <processo numero="..."> por busca de substring
e parseia só esses fragmentos pequenos. Parsear tudo pra extrair meia dúzia de registros
seria gastar centenas de MB de memória por request à toa.
Página de prova viva: /rpi-teste (fora do fluxo de demonstração, deliberadamente) — bate
direto na API pra qualquer número de processo real que você digitar.
O que este canal NÃO resolve: é o canal certo para monitoramento (o que mudou esta semana), não para busca de anterioridade em tempo real (existe uma marca parecida?). Isso hoje é coberto pela integração de busca em tempo real, na seção seguinte.
Testado de ponta a ponta em 25/08/2026, localmente, com rede sem bloqueio:
GET /api/rpi/lookup?numero=905922891 devolveu a edição real 2903 com o despacho
IPAS161 e o titular "POLIMPORT - COMÉRCIO E EXPORTAÇÃO LTDA" — confirmado rodando
npm run dev e abrindo /rpi-teste, não apenas por inspeção estrutural. Numa sandbox que
bloqueie revistas.inpi.gov.br, repita esse teste antes de confiar nisto em produção.
src/lib/inpi/busca-client.ts)API não documentada publicamente que sustenta o portal moderno
servicos.busca.inpi.gov.br/marcas. Contrato obtido por engenharia reversa (reprodução
da chamada que o próprio portal dispara) e confirmado ao vivo em 25/08/2026:
POST https://api-servicos.busca.inpi.gov.br/api/trademarks/search
Content-Type: application/json
{ "state": { "current": 1, "filters": [], "resultsPerPage": 10, "searchTerm": "Nubank",
"sortDirection": "", "sortField": "", "sortList": [] },
"queryConfig": { "search_fields": { "mark_name": { "weight": 3 }, "process_number": {},
"holders.name": {} }, "result_fields": { "mark_name": {"raw":{}}, "process_number":
{"raw":{}}, "status": {"raw":{}}, "classification_code": {"raw":{}}, "filing_date":
{"raw":{}}, "nature_text": {"raw":{}}, "presentation_text": {"raw":{}}, "holders":
{"raw":{}} } } }
Resposta no formato Elastic App Search ({ raw: valor } em cada campo). Busca real por
"Nubank" devolveu 113 resultados, incluindo o processo 907206794, titular "NU
PAGAMENTOS S.A. - INSTITUIÇÃO DE PAGAMENTO", status "Registro de marca em vigor" —
validado tanto via curl direto quanto pelo fluxo normal do produto
(GET /api/inpi/busca?termo=Nubank&pagina=1, chamado pelo componente BuscaRealPanel
dentro do passo "Resultado").
Riscos herdados, sem mitigação total:
Access-Control-Allow-Origin: * (o INPI permite chamada direta
do navegador), mas a chamada foi mantida no servidor (/api/inpi/busca) mesmo assim,
para poder cachear em memória o Cache-Control: max-age=86400 que o upstream já
declara — evita martelar uma API de terceiro sem SLA a cada clique. Mesma ressalva do
cache da RPI: é Map em memória, não sobrevive a cold start serverless.AbortController, sem retry automático (deliberado — retry
esconderia sinal de instabilidade de uma API sem SLA conhecido).Antes de confiar nisto em produção: confirmar com o INPI (ou jurídico) se
api-servicos.busca.inpi.gov.br é de fato produção e se há alguma restrição de uso por
terceiros — ninguém validou isso ainda, só a mecânica técnica.
/api/health)GET /api/health verifica as duas integrações reais com o INPI e devolve 200 (tudo
saudável) ou 503 (alguma falhou). Cada checagem valida não só o status HTTP, mas a
forma mínima da resposta — uma API sem contrato formal (a busca em tempo real) pode
mudar de schema sem avisar e continuar respondendo 200 com corpo diferente; isso pega
esse caso, não só "está fora do ar".
Pensado pra ser chamado por um monitor externo gratuito (UptimeRobot, Better Uptime,
cron-job.org) a cada poucos minutos, alertando por e-mail/SMS quando não for 200 — mais
barato que construir alerta próprio numa fase sem volume de clientes. Ver
src/lib/inpi/health.ts.
A base de marcas usada na demonstração de colidência fonética (BASE_MARCAS em
src/lib/data.ts, usada pela tabela de similaridade do passo "Resultado") continua
sendo uma lista fixa de 14 marcas de exemplo — ela existe só pra ilustrar o algoritmo
fonético com números estáveis e reproduzíveis — hoje só aparece como fallback quando a
busca real no INPI falha (ver src/lib/colidencia.ts), sempre avisando que é exemplo.
Não há peticionamento automático: o protocolo no INPI é feito à mão, depois da conversa
no WhatsApp (ver item 4 abaixo).
api-servicos.busca.inpi.gov.br —
produção ou homologação, termos de uso pra terceiros — antes de expor a busca em
tempo real (/api/inpi/busca) pra usuário final em produção. A integração técnica
já está pronta e testada (ver seção acima); o que falta é a confirmação
institucional, não código./api/colidencia
(src/lib/colidencia.ts) tenta a base real do INPI primeiro; só cai pra
demonstração de exemplo se a busca real falhar de verdade (rede/timeout/schema) —
zero resultados reais não é falha, é "risco baixo" genuíno, e é tratado como tal
(não confundir os dois foi a parte que importava aqui). Passo "Resultado" agora
mostra uma única tabela/score, com badge indicando a fonte ("dado real" ou
"exemplo"), mais uma caixa de "buscar outro termo" que atualiza o mesmo resultado
em vez de abrir um bloco novo.src/lib/fonetica.ts) pra não superestimar
colidência quando uma marca é a outra + uma palavra extra genuína (ex.:
"Ronaldo" vs. "Ronaldo Soluções" caía em 47%, deveria ser bem mais baixo) sem
quebrar o caso de mesma sonoridade com grafia diferente (ex.: "Kazamarela"
vs. "Casa Amarela" continua em 100%) — ainda heurística, ainda pede revisão
por linguista antes de decisão real de negócio.docs/tutorial-procuracao-eletronica.md,
montado a partir do Manual de Marcas oficial do INPI. Precisa de revisão por
advogado antes de ir pra produção — não foi escrito nem validado por um. Regra dura
e não negociável, já cumprida no desenho: nunca capturar ou armazenar credenciais
gov.br de terceiros.prisma/, ver seção própria
acima), wizard grava cliente/processo/pagamento de verdade, /admin lista tudo e
confirma pagamento manualmente./admin depois que o
cliente avisa por WhatsApp (isso já tem onde gravar — item 5 resolvido). Automação de
verdade (cliente paga, sistema confirma sozinho) ainda depende de decidir entre gerar
o payload PIX "copia e cola" (padrão EMV/BR Code) estático com a chave PIX pessoal — o
mais simples, sem abrir conta em processador — ou Mercado Pago (Checkout Pro pro setup
único, Assinaturas/ pro monitoramento recorrente — são produtos
diferentes, não a mesma integração).src/
app/
layout.tsx — fontes via next/font/google (ver nota abaixo), metadata, shell HTML
page.tsx — monta <LandingPage /> — porta de entrada real (marketing)
consulta/page.tsx — monta <MarcaSyncApp /> — o assistente interativo em si
globals.css — tokens (paleta branco + pastel, SEM tema escuro) + estilos do app
icon.svg — favicon
api/
rpi/lookup/
route.ts — GET ?numero=... — consulta real à RPI oficial
inpi/busca/
route.ts — GET ?termo=...&pagina=... — busca real em tempo real
health/
route.ts — GET — healthcheck das duas integrações (status + schema)
colidencia/
route.ts — GET ?marca=...&descricao=... — busca unificada (real com fallback pra demo)
processos/
route.ts — GET lista, POST cria cliente+processo
[id]/route.ts — PATCH atualiza status/protocolo/monitoramento
[id]/pagamentos/route.ts — POST registra cobrança pendente
[id]/logo/route.ts — POST upload de logotipo (PNG, valida no servidor)
pagamentos/[id]/confirmar/
route.ts — POST marca pagamento como confirmado
admin/
page.tsx — "caderno de anotações": lista processos, confirma pagamento
rpi-teste/
page.tsx — página de prova viva da integração com a RPI
components/
LandingPage.tsx — página de marketing (Server Component; FAQ em <details>)
LandingPage.css — estilos da landing (classes .lp-*; a paleta vem de :root)
MarcaSyncApp.tsx — orquestrador: estado do wizard (etapa, marca, análise, plano...)
Stepper.tsx — navegação entre etapas, com trava de progresso
ConsultaStep.tsx — formulário de entrada
LoadingStep.tsx — checklist animado da análise
ResultadoStep.tsx — resumo de risco unificado (real com fallback pra demo) + busca de outro termo
PlanoStep.tsx — setup + monitoramento + upload de logotipo + botão WhatsApp
LogoUpload.tsx — drag-and-drop do logotipo (PNG, até 1000x1000)
ContatoStep.tsx — passo final: conversa no WhatsApp + o que acontece depois
lib/
fonetica.ts — algoritmo de colidência fonética + Levenshtein
ncl.ts — inferência de classe NCL + rótulos
data.ts — base de marcas de exemplo (fallback de colidencia.ts se a busca real falhar)
analysis.ts — colidência fonética contra a base de exemplo (usado só como fallback)
colidencia.ts — busca unificada: real primeiro, cai pra analysis.ts se falhar
marcas-locais.ts — busca por som na cópia local da base de marcas do INPI
situacoes-inpi.ts — código IPAS → descrição da situação
monitor-rpi.ts — leitura diária da RPI → alertas dos processos monitorados
whatsapp.ts — link wa.me com a mensagem montada a partir da consulta
planos.ts — preços (centavos) e formatação em reais
types.ts — tipos compartilhados (fonte única — fonetica.ts importa daqui)
inpi/
types.ts — tipos do XML oficial da RPI
parse-rpi.ts — parser de um bloco <processo> (testado contra dado real)
fetch-rpi.ts — descoberta de edição + download/parsing sob demanda
busca-types.ts — tipos da busca em tempo real
busca-client.ts — cliente da busca em tempo real (cache + timeout)
health.ts — verificações de status+schema das duas integrações
lib/db.ts — cliente Prisma (singleton)
proxy.ts — Basic Auth do /admin (ver seção "Autenticação")
prisma/
schema.prisma — modelos Cliente/Processo/Pagamento (ver seção "Banco de dados")
docs/
tutorial-procuracao-eletronica.md — rascunho pro cliente autorizar o MarcaSync no INPI
Nota sobre layout.tsx: as fontes usam next/font/google (self-hosted em build time).
Até 25/08/2026 eram carregadas via <link> porque o ambiente de build original
bloqueava fonts.googleapis.com; reavaliado e revertido nesta sessão depois de
confirmar rede livre localmente — ver comentário no próprio arquivo antes de reverter de
volta para <link> num ambiente restrito.
preapproval/adminsrc/proxy.ts, protege
/admin inteiro + GET /api/processos + POST /api/pagamentos/:id/confirmar (não
o resto da API — o wizard público precisa continuar chamando essas rotas sem
senha). Senha padrão no código é 2001 (combinado com o usuário) — 4 dígitos é
fraco de propósito só enquanto isto roda local; antes de qualquer deploy
público, defina ADMIN_PASSWORD no ambiente com algo mais forte, sem mudar
nenhum código.fetch-rpi.ts,
busca-client.ts) são só pra desenvolvimento (não sobrevivem a cold start
serverless, não são compartilhados entre instâncias). Produção precisa de Redis/S3,
TTL de 1 semana pra RPI e 24h pra busca (espelhando o Cache-Control do upstream).numeroProcesso ao
cliente e consultar fetch-rpi.ts periodicamente), ele volta como feature de
verdade — não como ilustração.NEXT_PUBLIC_WHATSAPP_NUMBER), mas o rodapé ainda não exibe o número em texto.