Connect with verified companies and freelance professionals with the help of artificial intelligence, real reviews, and protected payment.
AI translation
Conecte-se a empresas e profissionais autônomos verificados com ajuda de Inteligência Artificial, avaliações reais e pagamento protegido.
CommerceTypeScript · JavaScriptGitHub @jmedeiroswashing-cryptoOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Plataforma de intermediacao inteligente de servicos (IA, avaliacoes verificadas, reputacao digital)
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Plataforma de intermediação inteligente de serviços — conecta clientes a empresas e profissionais autônomos (eletricistas, encanadores, advogados, médicos, designers, etc.) usando IA, avaliações verificadas e reputação digital. Este repositório contém o MVP: backend (API) + frontend web. Veja "Roadmap" abaixo para o que ainda falta em relação à visão completa do produto.Read the full README ↗
Plataforma de intermediação inteligente de serviços — conecta clientes a empresas e profissionais autônomos (eletricistas, encanadores, advogados, médicos, designers, etc.) usando IA, avaliações verificadas e reputação digital.
Este repositório contém o MVP: backend (API) + frontend web. Veja "Roadmap" abaixo para o que ainda falta em relação à visão completa do produto.
servicai/
├── apps/
│ ├── api/ # Backend NestJS + Prisma + PostgreSQL
│ └── web/ # Frontend Next.js + Tailwind + Framer Motion
└── docker-compose.yml # Postgres + Redis locais (opcional, alternativa ao Supabase)
@prisma/adapter-pg), PostgreSQL,
JWT (passport-jwt), Socket.IO (chat e notificações em tempo real), OpenAI SDK,
web-push (push notification real), nodemailer (e-mail transacional), bcryptjs
(troca feita a partir de bcrypt nativo — era a causa de queda em produção na
Vercel, que não compila binários nativos), rate limiting próprio (sem
@nestjs/throttler, que também quebrava o build serverless).sonner (toasts de erro).apps/api/.env).servicai e servicai-api, ver seção de Deploy).cd apps/api
npm install
cp .env.example .env # preencha DATABASE_URL, JWT_SECRET, OPENAI_API_KEY
npx prisma generate
npx prisma migrate dev
npm run start:dev # http://localhost:3001/api
cd apps/web
npm install
cp .env.local.example .env.local # ou crie com NEXT_PUBLIC_API_URL
npm run dev # http://localhost:3000
POST /listings/ai/generate-description,
POST /listings/ai/suggest-price).GET /search?q=... interpreta a frase do usuário via IA
(categoria, urgência, localização) e retorna os prestadores mais relevantes. Com
fallback heurístico local quando OPENAI_API_KEY não está configurada.Booking com status
(SOLICITADO → ACEITO/RECUSADO → EM_ANDAMENTO → CONCLUIDO/CANCELADO)./chat) para mensagens em tempo real.apps/api/src/subscriptions/plans.config.ts): reformulados para vender visibilidade
e oportunidades, não itens de funcionalidade soltos. A alavanca comercial central é
quantas propostas de oportunidade por mês o prestador pode enviar (Grátis: 5,
Profissional: 60, Premium: ilimitado) — cada proposta é uma chance real de fechar
negócio, o que é diferente de travar uma função. Premium também ganha o selo de
"prestador verificado" (reaproveita o campo Selo já existente). O enum Plan no
banco ainda tem BUSINESS por causa de dados de teste antigos (evitar remover valor
de enum no Postgres é mais seguro que recriar a tabela) — ele não é mais vendido,
GET /subscriptions/plans já filtra para mostrar só os 3 planos atuais, e assinantes
legados nesse plano são tratados com os benefícios do Premium.
apps/api/src/providers/ranking.ts): a
posição nos resultados de busca (/providers, /search) combina relevância de
categoria, localização, nota média, volume de avaliações, taxa de resposta
(aceite de solicitações), atividade recente e completude do perfil — o plano
contratado soma pontos (até 25 de ~130 possíveis), mas não decide sozinho.
Testado explicitamente: um prestador pago com perfil vazio e zero avaliações fica
só 1 posição à frente de um grátis com perfil completo, não dezenas de posições —
e nota+volume de avaliações têm o mesmo peso máximo que o plano, então um grátis
muito bem avaliado consegue superar um pago irrelevante./marketplace): venda de produtos usados entre usuários (CLIENTE
ou PRESTADOR), separado do fluxo de serviços — anúncio com fotos, favoritos, chat
próprio (marketplace-chat, WebSocket dedicado) entre comprador e vendedor./painel/agenda): compromissos do prestador com lembrete — notificação
push + in-app quando o horário está chegando (AppointmentsService.sendDueReminders,
cron a cada 5 min), mesmo com o app fechado. Tem PATCH pra reagendar./painel/faturamento): lançamento manual de receitas e despesas,
despesas recorrentes (geradas automaticamente todo mês), leitura de recibo por foto
via IA pra preencher o lançamento. Receita aqui é o valor combinado, não pagamento
confirmado — o app ainda não processa pagamento de verdade (ver Roadmap).identity.controller.ts), admin aprova/rejeita (/admin/identidade) e o selo de
identidade verificada aparece no perfil. Selfie/biometria facial continuam fora do
escopo.BookingDisputeSection), com resposta da outra parte
e checagem automática do que já foi combinado./admin/denuncias): denunciar usuário, produto, avaliação,
serviço ou reserva (ReportTargetType), com fila de análise e resolução pelo admin.nodemailer, tokens com expiração. Trocar ou redefinir a senha agora também invalida
qualquer token JWT emitido antes (User.tokenVersion) — sessões antigas (inclusive de
uma conta excluída) param de funcionar na hora, não só quando expiram sozinhas.web-push + VAPID, service worker em
apps/web/public/sw.js): funciona com o app/navegador fechado, diferente do
WebSocket. Precisa de VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY/VAPID_SUBJECT
configuradas — sem isso, a API loga um aviso e segue só com WebSocket./ajuda) e Termos de Uso/Política de Privacidade
(estrutura LGPD) com aviso na primeira visita./admin/denuncias), não detecção automática.POST /subscriptions/admin/:userId/cancel pra admin forçar um cancelamento duro, sem
tela própria.lat/lng no banco)./solicitar com IA é só texto.multer salvando
em disco local, o que não persiste entre invocações da função serverless da Vercel —
arquivo enviado em produção pode sumir. Prioridade alta pra quem for usar upload de
mídia/documento de identidade em produção.POST /subscriptions/me/trial ativa
14 dias de PRO ou PREMIUM a partir do Grátis, uma vez por prestador
(Subscription.trialUsedAt). Expira sozinho como qualquer assinatura paga — vira
Grátis automaticamente quando o prazo vence, reaproveitando a mesma checagem de
expiração que já existia. Botão "Testar grátis" em /precos, status "Em período de
teste" em /painel/plano.ProviderProfile.businessHours agora é
validado e editável em /painel/perfil, aparece no perfil público, e
POST /bookings recusa horário fora do expediente ou já ocupado por outra reserva
— antes disso, "Contratar agora" nem perguntava data/hora.PATCH /requests/:id) e recusar uma proposta específica
(POST /requests/:id/proposals/:proposalId/reject) sem precisar aceitar outra.PATCH /deals/:id) — antes só
dava pra cancelar e recriar. Mesmo padrão aplicado a Despesas, Receitas e
Compromissos.PATCH /subscriptions/me aceitava o plano legado
BUSINESS (benefícios do Premium de graça) — agora só aceita os planos
realmente vendidos.User.tokenVersion) — antes um token já emitido continuava funcionando até expirar
sozinho (até 7 dias), mesmo com a conta excluída.schema.prisma, e sim em prisma.config.ts (lido pela CLI) e é passada via
driver adapter (@prisma/adapter-pg) para o PrismaClient em runtime. O client
gerado fica em apps/api/src/generated/prisma (não versionado).prisma migrate precisa, mas pode ser usada em
produção para as queries normais da aplicação.20261013200000_add_token_version_and_performance_indexes e
20261013210000_add_subscription_trial foram escritas manualmente (SQL direto),
não geradas por prisma migrate dev — este ambiente não tinha acesso a um Postgres
real pra rodar o diff automático. Rode npx prisma migrate deploy (ou migrate dev
localmente) contra o banco de verdade pra aplicá-las antes de testar as mudanças de
segurança/índices/trial que vieram junto.apps/web) e backend (apps/api) são dois projetos Vercel
separados (servicai e servicai-api), cada um com seu próprio deploy a partir
deste monorepo. A API roda como função serverless (apps/api/api/index.mjs) — por
isso dependências nativas (ex: bcrypt) e filesystem persistente (ex: upload em
disco) não funcionam direito nesse ambiente; ver notas na seção Stack/Roadmap.DATABASE_URL, JWT_SECRET, OPENAI_API_KEY,
VAPID_*, SMTP para nodemailer, etc.) são configuradas direto no painel da Vercel
de cada projeto, não neste repositório.ATIVA/TESTE/PAGAMENTO_PENDENTE/ CANCELAMENTO_SOLICITADO/CANCELADA/INADIMPLENTE/EXPIRADA): cancelar é "soft" — o
prestador mantém os benefícios até o fim do período já pago
(POST /subscriptions/me/cancel), e a expiração de verdade é aplicada no backend
(não só na tela) sempre que a assinatura é lida: se o prazo pago já passou, o
prestador volta a valer como Grátis para ranking e limites, mesmo que a UI antiga
ainda não tenha sido recarregada. TESTE (período de teste) existe no modelo de
dados mas não tem um fluxo de ativação ainda — ficou definido para o futuro./painel/plano): plano atual + status, benefícios,
desempenho (visualizações do perfil, aparições em buscas, contatos, propostas
usadas no mês) e dados da assinatura (valor, próxima cobrança, upgrade,
cancelamento) — separada da página de preços (/precos), que continua sendo a
vitrine de comparação/venda.GET /subscriptions/admin/overview, role ADMIN,
tela /admin/planos): assinantes por plano, MRR estimado, taxa de conversão
grátis→pago, cancelamentos solicitados. Não construí CRUD de planos nem gráfico de
evolução histórica — isso exigiria uma tabela de auditoria de mudanças de plano que
ainda não existe (não quis simular dado falso). Não há fluxo de criação de conta
ADMIN — esse papel só existe via provisionamento manual do banco.role: "ADMIN"
diretamente pela API (a interface só oferecia Cliente/Vendedor, mas nada impedia
uma chamada direta). RegisterDto agora valida contra uma lista fixa
(CLIENTE/PRESTADOR), fechando a escalação de privilégio.GET /subscriptions/boost,
POST /subscriptions/me/boost). Comprar de novo com um impulso ainda ativo soma mais
7 dias ao prazo restante em vez de reiniciar. Mesma ressalva dos planos: sem gateway de
pagamento, ativado direto para fins de teste. Testado que o prestador impulsionado
aparece antes de um concorrente Premium na listagem pública.src/notifications, WebSocket namespace /notifications,
sino no canto superior direito): avisa sobre nova mensagem no chat, nova proposta
recebida numa solicitação e plano prestes a expirar/expirado — sempre com link direto
pra tela relevante. Persistidas em banco (GET /notifications, marcar como lida/todas)
e empurradas ao vivo via socket assim que o evento acontece, além de aparecerem na
lista na próxima vez que o usuário abrir o menu. O aviso de "plano expirando" é
deduplicado (no máximo 1 a cada 24h) para não virar spam./solicitar, aba "Conversar com a IA"):
em vez de preencher o formulário, o cliente descreve em texto livre o que precisa e a
IA vai extraindo categoria, título, descrição, cidade/estado, orçamento e data a cada
mensagem, mostrando o rascunho ao vivo ao lado da conversa; o formulário manual
continua disponível como alternativa. Funciona também sem OPENAI_API_KEY
configurada, com um fallback heurístico (por palavra-chave de categoria, regex de
valores em R$, "hoje"/"amanhã") que já testei extraindo corretamente categoria,
cidade e orçamento ao longo de duas mensagens — sem chave, a extração é mais simples
que com IA generativa, mas o fluxo completo funciona./precos)./mensagens, WebSocket namespace /chat)
e "Traçar rota" no perfil do prestador via Geolocation API + link de directions do
Google Maps (sem chave de API paga)./solicitar) com categoria, descrição, região e orçamento; prestadores veem, em
/painel/oportunidades, só as solicitações compatíveis com as categorias e a
cidade/estado do próprio perfil (GET /requests/matches, com filtros de categoria,
distância, orçamento e ordenação por mais recentes/mais próximos/melhor
correspondência). O prestador demonstra interesse enviando uma proposta (valor, prazo,
mensagem) via POST /requests/:id/proposals; o cliente acompanha as propostas
recebidas em /minhas-solicitacoes e pode abrir uma conversa direto com quem propôs.
Privacidade: a resposta de /requests/matches nunca inclui nome, telefone, e-mail
ou endereço do cliente — só os dados necessários para avaliar a oportunidade (testado
explicitamente). O "match inteligente" hoje compara categoria e cidade/estado; não há
geocodificação real, então "mais próximos" é uma aproximação por cidade/estado, não por
distância em km, e não há verificação de disponibilidade de agenda (não existe um
calendário de disponibilidade do prestador ainda).