Saleor Store
우리 컬렉션을 쇼핑하세요
검증된 기업·프리랜서를 AI가 연결하고, 실제 평가와 보호된 결제를 제공
Conecte-se a empresas e profissionais autônomos verificados com ajuda de Inteligência Artificial, avaliações reais e pagamento protegido.
커머스TypeScript · JavaScriptGitHub @jmedeiroswashing-crypto온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Plataforma de intermediacao inteligente de servicos (IA, avaliacoes verificadas, reputacao digital)
저장소 README에서 가져옴
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.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).