image

Acesse bootcamps ilimitados e +650 cursos pra sempre

60
%OFF
Vanderlei Fontenelle
Vanderlei Fontenelle21/08/2025 11:45
Share

Site de voluntariado - sistema javascript

    Objetivo: conectar voluntários a pessoas/ONGs que precisam de ajuda em serviços (ex.: design, jurídico, aulas, tecnologia) e consultorias (mentorias, aconselhamento).

    Funcionalidades-chave:

    • Cadastro/login (usuário e voluntário).
    • Perfil de voluntário (bio, habilidades, áreas, disponibilidade, atendimento remoto/presencial).
    • Busca/filtragem por habilidade, causa, cidade e modalidade.
    • Página de oferta (serviço/consultoria) com botão “Agendar”.
    • Agenda/slots de disponibilidade e sistema de reservas.
    • Mensageria básica (DM) entre solicitante e voluntário.
    • Avaliações pós-atendimento.
    • Painel do admin (aprovar perfis/ofertas, moderar).
    • Base para LGPD (consentimento, exclusão de dados, termos).

    2) Arquitetura sugerida (simples e barata)

    • Frontend/SSR: Next.js (App Router)
    • UI: Tailwind CSS + shadcn/ui
    • Banco: PostgreSQL (Supabase, Neon, Railway ou RDS)
    • ORM: Prisma
    • Auth: NextAuth (Email + Google/GitHub opcionais)
    • Armazenamento de arquivos (opcional): Supabase Storage
    • Mensagens em tempo real (opcional): Pusher/Ably (ou polling simples para começar)
    • Emails transacionais: Resend / SendGrid
    • Deploy: Vercel (web) + provedor do Postgres
    Dá pra trocar por Node/Express puro + React/Vite, mas Next.js + Prisma acelera.

    3) Modelo de dados (mínimo viável)

    Entidades principais:

    • User (todos): id, nome, email, role (USER/VOLUNTEER/ADMIN), cidade, país, createdAt.
    • VolunteerProfile: userId, bio, causas (lista), modalidades (ONLINE/PRESENCIAL), rating.
    • Skill: id, nome (ex.: “Design”, “Aulas de Matemática”).
    • VolunteerSkill: (N:N) volunteerProfileId, skillId.
    • Offering (ofertas): id, volunteerId, título, descrição, categoria, status (ACTIVE/PAUSED).
    • AvailabilitySlot: id, volunteerId, start, end, timezone.
    • Booking: id, requesterId, offeringId, slotId, status (PENDING/CONFIRMED/DONE/CANCELLED), notas.
    • Message: id, bookingId, senderId, conteúdo, createdAt.
    • Review: id, bookingId, rating (1–5), comentário, authorId, createdAt.

    Exemplo de schema Prisma (trecho)

    prisma
    
    Copiar código
    model User { id String @id @default(cuid()) name String email String @unique role Role @default(USER) city String? country String? createdAt DateTime @default(now()) profile VolunteerProfile? bookings Booking[] @relation("UserBookings") messages Message[] @relation("UserMessages") } enum Role { USER VOLUNTEER ADMIN } model VolunteerProfile { id String @id @default(cuid()) user User @relation(fields: [userId], references: [id]) userId String @unique bio String? modalities String[] // ["ONLINE","PRESENCIAL"] causes String[] // ["Educação","Meio Ambiente"] rating Float? skills VolunteerSkill[] offerings Offering[] slots AvailabilitySlot[] } model Skill { id String @id @default(cuid()) name String @unique links VolunteerSkill[] } model VolunteerSkill { volunteerId String skillId String volunteer VolunteerProfile @relation(fields: [volunteerId], references: [id]) skill Skill @relation(fields: [skillId], references: [id]) @@id([volunteerId, skillId]) } model Offering { id String @id @default(cuid()) volunteer VolunteerProfile @relation(fields: [volunteerId], references: [id]) volunteerId String title String description String category String status String @default("ACTIVE") bookings Booking[] } model AvailabilitySlot { id String @id @default(cuid()) volunteer VolunteerProfile @relation(fields: [volunteerId], references: [id]) volunteerId String start DateTime end DateTime timezone String booking Booking? } model Booking { id String @id @default(cuid()) requester User @relation("UserBookings", fields: [requesterId], references: [id]) requesterId String offering Offering @relation(fields: [offeringId], references: [id]) offeringId String slot AvailabilitySlot @relation(fields: [slotId], references: [id]) slotId String @unique status String @default("PENDING") notes String? messages Message[] review Review? createdAt DateTime @default(now()) } model Message { id String @id @default(cuid()) booking Booking @relation(fields: [bookingId], references: [id]) bookingId String sender User @relation("UserMessages", fields: [senderId], references: [id]) senderId String content String createdAt DateTime @default(now()) } model Review { id String @id @default(cuid()) booking Booking @relation(fields: [bookingId], references: [id]) bookingId String @unique rating Int comment String? author User @relation(fields: [authorId], references: [id]) authorId String createdAt DateTime @default(now()) } 
    

    4) Fluxos principais

    1. Cadastro/Login: NextAuth (Email link mágico) → cria User.
    2. Tornar-se voluntário: usuário preenche bio, causas, modalidades e skills → cria VolunteerProfile e VolunteerSkill.
    3. Criar ofertas: voluntário publica uma ou mais Offering.
    4. Disponibilidade: voluntário cadastra AvailabilitySlot.
    5. Busca e descoberta: visitante filtra por skill/causa/cidade/modalidade → lista de Offering.
    6. Agendamento: solicitante escolhe oferta + slot → cria Booking(PENDING) → voluntário confirma (CONFIRMED).
    7. Mensagens: canal privado por Booking.
    8. Concluir & avaliar: status DONE e Review (impacta média no perfil).
    9. Admin: aprova perfis/ofertas suspeitas, bloqueia conteúdo, exporta métricas.

    5) Passo a passo técnico

    5.1 Projeto base

    bash
    
    Copiar código
    npx create-next-app voluntariado --ts --eslint --tailwind --app cd voluntariado npm i @prisma/client prisma next-auth @auth/prisma-adapter zod npm i -D prisma npx prisma init 
    
    • Ajuste DATABASE_URL no .env para seu Postgres.
    • Cole o schema.prisma (acima), depois:
    bash
    
    Copiar código
    npx prisma migrate dev -n init npx prisma db seed # opcional, crie um script de seed 
    

    5.2 Autenticação (NextAuth)

    • Rota app/api/auth/[...nextauth]/route.ts com EmailProvider (ou Google).
    • Use PrismaAdapter para persistência.
    • Proteja rotas server-side com getServerSession.

    5.3 API (App Router – route handlers)

    • app/api/offerings/route.ts (GET lista / POST cria)
    • app/api/slots/route.ts (GET/POST)
    • app/api/bookings/route.ts (POST cria; PATCH status)
    • app/api/messages/route.ts (GET/POST por bookingId)
    • Validação com Zod.

    Exemplo (criar Booking)

    ts
    
    Copiar código
    // app/api/bookings/route.ts import { NextResponse } from 'next/server'; import { z } from 'zod'; import { getServerSession } from 'next-auth'; import { prisma } from '@/lib/prisma'; const BookingSchema = z.object({ offeringId: z.string().cuid(), slotId: z.string().cuid(), notes: z.string().optional(), }); export async function POST(req: Request) { const session = await getServerSession(); if (!session?.user?.email) return NextResponse.json({error:'unauthorized'}, {status:401}); const body = await req.json(); const parsed = BookingSchema.safeParse(body); if (!parsed.success) return NextResponse.json(parsed.error.flatten(), {status:400}); const user = await prisma.user.findUnique({where:{email: session.user.email}}); if(!user) return NextResponse.json({error:'user not found'}, {status:404}); // Evita overbooking: slot só pode ter 1 booking const existing = await prisma.booking.findUnique({where:{slotId: parsed.data.slotId}}); if (existing) return NextResponse.json({error:'slot already booked'}, {status:409}); const booking = await prisma.booking.create({ data: { requesterId: user.id, offeringId: parsed.data.offeringId, slotId: parsed.data.slotId, notes: parsed.data.notes ?? null, } }); return NextResponse.json(booking, {status:201}); } 
    

    5.4 Páginas principais (Next.js)

    • Home: destaque causas, busca rápida por skill/cidade.
    • /voluntarios: filtros (skill, modalidade, cidade) + cards.
    • /oferta/[id]: detalhes da oferta, perfil do voluntário, calendário de slots, botão “Agendar”.
    • /dashboard (voluntário): gerenciar ofertas, slots, reservas.
    • /inbox: mensagens por reserva.
    • /admin: aprovações, relatórios.

    Exemplo de card de voluntário (React + Tailwind)

    tsx
    
    Copiar código
    // components/VolunteerCard.tsx import Link from "next/link"; export default function VolunteerCard({ v }: { v: { id: string, name: string, bio?: string, skills: string[], city?: string, rating?: number }}) { return ( <div className="rounded-2xl border p-4 shadow-sm hover:shadow-md transition"> <div className="flex justify-between items-start"> <h3 className="text-lg font-semibold">{v.name}</h3> {v.rating ? <span className="text-sm">⭐ {v.rating.toFixed(1)}</span> : null} </div> <p className="text-sm mt-1 line-clamp-3">{v.bio ?? "Voluntário(a) engajado(a) em causas sociais."}</p> <div className="flex flex-wrap gap-2 mt-3"> {v.skills.map(s => <span key={s} className="text-xs border rounded-full px-2 py-1">{s}</span>)} </div> <div className="flex justify-between items-center mt-4"> <span className="text-xs opacity-70">{v.city ?? "Remoto"}</span> <Link href={`/voluntarios/${v.id}`} className="text-sm underline">Ver perfil</Link> </div> </div> ) } 
    

    5.5 Mensagens

    • MVP: tabela Message + rota GET/POST por bookingId + polling (a cada 5–10s).
    • Depois, evoluir para Pusher/Ably/WebSockets.

    5.6 Avaliações

    • Permitir avaliação somente após Booking.status === "DONE".
    • Média do perfil = média das notas nas reservas concluídas.

    5.7 Admin

    • Flag Role.ADMIN no User.
    • Painel para: listar novos perfis/ofertas, aprovar/reprovar, ver denúncias, banir usuário, exportar CSV.

    6) Como usar o ChatGPT durante o desenvolvimento (prompts prontos)

    Arquitetura & decisões

    “Sou dev construindo uma plataforma de voluntariado com Next.js, Prisma e Postgres. Quero um diagrama simples da arquitetura (frontend, API, DB, Auth, mensagens), riscos e trade-offs de usar polling vs Pusher. Gere também uma checklist de segurança para LGPD.”

    Modelagem de dados

    “Considere as entidades User, VolunteerProfile, Skill, Offering, AvailabilitySlot, Booking, Message e Review. Proponha o schema Prisma, validações Zod e 3 queries otimizadas para busca por skill+cidade+modalidade.”

    Geração de código

    “Escreva um route handler Next.js (App Router) para criar uma reserva (‘Booking’). Valide com Zod, cheque slot único e trate erros 400/401/404/409/500. Inclua testes unitários com Vitest.”

    UI/UX

    “Crie um formulário acessível de criação de oferta (Offering) com React Hook Form + Zod, estados de loading, mensagens de erro/sucesso e i18n pt-BR.”

    Testes

    “Gere 10 testes de integração (Playwright) para o fluxo: login → virar voluntário → criar oferta → adicionar slot → fazer reserva → enviar mensagem → concluir → avaliar.”

    Conteúdo & políticas

    “Escreva Termos de Uso, Política de Privacidade e Código de Conduta para uma plataforma de voluntariado no Brasil, alinhados à LGPD.”

    Migrações/Seeds

    “Gere um script de seed Prisma com 8 skills populares, 5 perfis de voluntários com ofertas e slots ao longo das próximas 2 semanas.”

    7) Segurança, privacidade e moderação

    • LGPD: base legal (consentimento/interesse legítimo), política clara; rota para exportar e excluir dados do usuário.
    • Rate limiting & Proteções: limitar POST /bookings /messages; validação forte; sanitização; CSRF nas rotas de formulário.
    • Uploads: antivírus (se aceitar anexos), limitar tipos/tamanho.
    • Moderação: botão “Denunciar”; fila para admin revisar.
    • Logs e auditoria: sem dados sensíveis em logs; retenção mínima necessária.
    • Spam/abuso: verificação de email; CAPTCHA no cadastro/primeiro post.

    8) Deploy e custos

    • Vercel (free/low): frontend + serverless.
    • Postgres (free tiers): Supabase/Neon/Railway.
    • Resend/SendGrid: camada gratuita para emails.
    • Pusher/Ably: free tier para começar.
    • Monitore limites do plano gratuito (conexões DB, invocações, cold starts).

    9) Roadmap enxuto (2–3 sprints)

    Sprint 1 (MVP núcleo):

    • Auth, perfis, ofertas, slots, busca simples, agendamento PENDING → CONFIRMED.
    • UI responsiva (mobile-first).

    Sprint 2 (Engajamento & confiança):

    • Mensagens, avaliações, média no perfil, denúncias, admin básico.

    Sprint 3 (Qualidade & escala):

    • Filtros avançados, calendário melhorado, emails transacionais, relatórios admin, Pusher em tempo real, SEO.

    10) Próximos passos práticos

    1. Criar projeto Next.js + Tailwind + Prisma (com schema acima).
    2. Subir Postgres gerenciado e aplicar migrate.
    3. Implementar Auth e as rotas offeringsslotsbookings.
    4. Construir páginas /voluntarios/oferta/[id]/dashboard e /inbox.
    5. Habilitar avaliações e admin básico.
    6. Escrever Termos/Privacidade e telas de consentimento LGPD.
    7. Fazer deploy (Vercel) + monitorar logs.

    se quiser, eu já te entrego:

    • schema completo do Prisma adaptado ao que você imaginar (ex.: categorias fixas, cidades do Brasil, etc.),
    • um seed realista com voluntários e slots,
    • e os route handlers base (GET/POST) para ofertas, slots, reservas e mensagens.
    Share
    Recommended for you
    Ri Happy - Front-end do Zero #2
    Avanade - Back-end com .NET e IA
    Akad - Fullstack Developer
    Comments (0)