World Vibe Web
The distributed app store for vibe-coded projects. Browse, discover, and install open-source apps from across GitHub.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證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).