Visão Geral
Partiuuu Sistema de Gestão — SaaS multi-tenant para agências de turismo e empresas de experiências.
Problema
Agências de turismo operam com CRM em planilha, projetos no Trello, viagens no WhatsApp e financeiro no Excel. Sem integração, sem histórico, sem automação.
Solução
Plataforma integrada: CRM, viagens, projetos, financeiro, automações WhatsApp, eventos, cursos e site institucional num único lugar.
Estágio
Alpha funcional — multi-tenant operacional, ~25 módulos implementados, uso interno pela equipe Partiuuu. Lançamento de mercado planejado para 2026.
Monetização
Planos por tenant (módulos como feature flags), marketplace de add-ons, implementação white-label. Revenue share futuro em vendas geradas.
Mercado
Agências de turismo (nicho primário), empresas de experiências, organizadores de eventos. Ticket médio SaaS: R$300–R$1.500/mês.
Dívidas Técnicas
TypeScript errors não-bloqueantes no backend. Sem testes automatizados. Módulos com implementação parcial. PM2 sem zero-downtime deploy.
Ambientes
| Ambiente | URL | Porta | Status |
|---|---|---|---|
| SITEDEV | sitedev.partiuuu.com | 3010 | LIVE |
| DEV | devadmin.partiuuu.com | 3020 | ATIVO |
| STAGING | testadmin.partiuuu.com | 3011 | ESTÁTICO |
| PROD | admin.partiuuu.com | 443 | ATIVO |
| BACKEND | interno | 3001 | PM2 |
Stack Resumida
| Camada | Tecnologia | Versão |
|---|---|---|
| Frontend | Next.js App Router + TypeScript + Tailwind CSS | 14.2.x |
| Backend | Fastify + TypeScript (tsx, sem build) | 4.29.x |
| ORM | Prisma + PostgreSQL 16 | 6.x |
| Auth | JWT 7 dias + cookie + kill-switch via sessionVersion | — |
| Cache/Queue | Redis + BullMQ | — |
| Realtime | LiveKit (WebRTC self-hosted) | — |
| Baileys multi-device (⚠️ não-oficial) | 7.0-rc | |
| Storage | S3-compatible via AWS SDK v3 (por tenant) | — |
| IA | Claude (Anthropic) + OpenAI + Google Gemini | — |
| Pagamentos | Stripe + MercadoPago + PayPal | — |
| Infra | OpenLiteSpeed + Docker + PM2 — VPS Contabo | — |
Arquitetura
Monorepo npm workspaces. Frontend Next.js, Backend Fastify, Schema Prisma compartilhado.
Diagrama de Alto Nível
graph TD CF["☁️ Cloudflare DNS"] OLS["⚡ OpenLiteSpeed :80/:443"] NX["Next.js :3020"] BE["Fastify :3001 via PM2"] PG["PostgreSQL :5432"] RD["Redis :6379"] S3["S3 Storage"] LK["LiveKit :7880"] EXT["WhatsApp · IA · Pagamentos"] CF --> OLS OLS -->|proxy| NX OLS -->|proxy /api| BE NX -->|REST| BE BE --> PG & RD & S3 & LK & EXT
Estrutura do Monorepo
app/
├── frontend/src/app/
│ ├── (auth)/ login
│ ├── (dashboard)/ painel tenant (sidebar)
│ ├── (admin)/ super admin
│ ├── (agency)/ portal agência
│ ├── (portal)/ área do cliente
│ ├── (tenant-site)/ sites públicos dos tenants
│ └── (public)/ landing pages, formulários
├── backend/src/
│ ├── routes/ ~55 arquivos de rotas
│ ├── lib/ serviços (ai-agent, baileys, crypto, etc.)
│ └── plugins/ prisma, redis, auth
└── packages/db/ Prisma schema (2.697 linhas, ~110 models)
Multi-tenant
Isolamento por tenantId em todas as queries — não há schemas separados. O JWT carrega tenantId, userId, role e sessionVersion.
SUPER_ADMIN / PARTIUUU_OPERATOR ← sem tenant
└── ADMIN ← admin do tenant
└── MEMBER ← colaborador do tenant
Roteamento de Domínios Customizados
O middleware Next.js consulta /api/tenant/by-domain?domain=X a cada request de domínio externo. O retorno determina: rewrite para /site/[slug] (tipo "site"), headers de contexto (tipo "admin"), ou rewrite para /site-nao-encontrado (não mapeado).
Feature Gates (Planos)
Cada plano tem flags booleanas (hasCRM, hasTravel, etc.). O middleware bloqueia rotas para módulos não habilitados redirecionando para /upgrade?module=X.
Decisões de Design
| Decisão | Escolha | Trade-off |
|---|---|---|
| Isolamento tenant | Coluna tenantId | Simples de operar; risco de vazamento por bug |
| Auth | JWT + sessionVersion (kill-switch) | Stateless + invalidação imediata sem blocklist |
| Backend runtime | tsx sem build | Deploy rápido; TS errors silenciosos em produção |
| Baileys (não-oficial) | Sem custo; risco de ban | |
| IA | Multi-provider | Redundância; complexidade de configuração |
Módulos
~25 módulos implementados. Status: ATIVO = funcional, PARCIAL = backend pronto, frontend incompleto.
Core (sem feature flag)
Login multi-tenant, JWT com kill-switch, convites por email, reset de senha, portal de clientes separado, OAuth social.
Perfil do tenant, white-label (cores, logo), SMTP próprio por tenant, domínios customizados com verificação DNS, storage S3 por tenant.
RolePermission (defaults por role) + UserPermission (overrides individuais). Grupos reutilizáveis. SUPER_ADMIN bypassa tudo.
Ativação self-service de módulos. Sandbox com countdown, fluxo de implementação para módulos com installType IMPLEMENTATION.
CRUD de tenants, planos, super admins, colaborações agência↔tenant. Monitoramento de infra: containers Docker, PM2, CPU/memória.
Módulos Funcionais
Contatos com campos customizados, empresas (B2B), segmentos dinâmicos, deals em pipeline Kanban, atividades por contato/deal.
Projetos com membros, tarefas Kanban/Lista, subtarefas, comentários, time entries, milestones, campos customizados.
Roteiros por dias e items, galeria, passageiros vinculados ao CRM, lotes de vendas, landing pública em /roteiro/[slug].
Transações, pedidos com items, pagamentos via Stripe/MP/PayPal, webhooks, configuração de gateway por tenant, config NF-e.
Eventos com tipos de ingresso, QR code check-in, inscrições, pagamentos. Rota pública /e/[slug].
Conexão via Baileys (multi-device). QR code, inbox, atribuição de atendentes, integração com Flow Builder.
⚠️ Baileys usa engenharia reversa. Risco real de ban. Migrar para Cloud API antes de volumes altos.
Engine de execução de fluxos WhatsApp. Nodes/edges em JSON. Frontend visual não implementado.
Formulários com campos customizáveis, respostas, integração ao CRM. Rota pública /f/[slug]. Landing pages em /lp/[slug].
Cursos com módulos e aulas (vídeo/texto/quiz), progresso, matrículas, pagamentos. Área pública /cursos/[slug].
3 templates (Clássico, Moderno, Boutique) + "do zero". Wizard, editor de blocos, domínio customizado, "em construção" automático.
Lives ao vivo via LiveKit (WebRTC self-hosted), gravação S3. Reuniões com links de agendamento, sala pública sem login.
Espaços (fórum, canal, chat), posts, comentários, reações, memberships, moderação. Rota pública /comunidade/[slug].
Templates com variáveis, geração de PDF (Puppeteer), assinatura digital (link público), vinculação a pedidos.
Tickets com categorias, prioridade, mensagens, atribuição de agentes. Portal público para chamados de clientes.
Agentes configuráveis com system prompt, histórico por usuário, multi-provider (Claude / OpenAI / Gemini).
Snapshots de métricas, social posts agendados multi-conta, gestão de Google Ads e Meta Ads.
Modelo de Dados
PostgreSQL 16 com Prisma. Schema em packages/db/prisma/schema.prisma — 2.697 linhas, ~110 models.
Diagrama ER — Core
erDiagram
Plan ||--o{ Tenant : "possui"
Tenant ||--o{ User : "tem"
Tenant ||--o{ TenantModule : "módulos"
Tenant ||--o{ TenantDomain : "domínios"
Tenant ||--o| TenantSite : "site"
User }o--o| PermissionGroup : "grupo"
Tenant ||--o{ Contact : "contatos"
Contact ||--o{ Deal : "deals"
Tenant ||--o{ Pipeline : "pipelines"
Pipeline ||--o{ Stage : "stages"
Deal }o--|| Stage : "em"
Tenant ||--o{ Project : "projetos"
Project ||--o{ Task : "tarefas"
Tenant ||--o{ Itinerary : "roteiros"
Itinerary ||--o{ ItineraryDay : "dias"
ItineraryDay ||--o{ ItineraryItem : "items"
Tenant ||--o{ Order : "pedidos"
Order ||--o{ Payment : "pagamentos"
Entidades Principais
| Entidade | Campos Chave | Notas |
|---|---|---|
Tenant | id, slug, planId, isAgency, blocked, config (JSON) | Raiz do isolamento |
User | id, tenantId?, email (único global), role, sessionVersion | tenantId null = SUPER_ADMIN |
Plan | id, slug, has* (20+ flags), maxUsers, maxContacts | Feature gates |
Contact | tenantId, name, email, companyId | → Deal[], Activity[] |
Deal | tenantId, contactId, stageId, value | → Pipeline/Stage |
Project | tenantId, name, type, status, dueDate | → Task[], Milestone[] |
Itinerary | tenantId, title, slug, type, status | → ItineraryDay[], Passenger[] |
TenantSite | tenantId, isPublished, templateId, onboardingDone | → SitePage[] |
Order | tenantId, contactId, status, total, origin | → OrderItem[], Payment[] |
WhatsAppInstance | tenantId, provider, status | → Conversation[] |
Padrão de Auditoria
Todos os models relevantes têm createdAt, updatedAt, createdBy (userId), updatedBy (userId). Operações sensíveis geram registro em AuditLog.
# Nova migration
npm run db:migrate -- nome_da_migration
# Executado na raiz /home/docker-projects/partiuuu-dev/app/
⚠️ Após migrations em produção, execute seed se houver novos ModuleMeta ou planos.
APIs e Integrações
Backend Fastify em :3001. Rotas protegidas exigem Authorization: Bearer <jwt>. Rotas públicas têm prefixo /public.
Principais Endpoints
Auth
CRM
Site Builder
Super Admin
Integrações Externas
| Serviço | Biblioteca | Uso | Escopo |
|---|---|---|---|
| Stripe | stripe | Pagamentos internacionais | Por tenant |
| MercadoPago | mercadopago | Pagamentos BR (PIX, boleto) | Por tenant |
| PayPal | @paypal/checkout-server-sdk | Pagamentos internacionais | Por tenant |
| AWS S3 | @aws-sdk/client-s3 | Upload de mídias, PDFs, gravações | Por tenant |
| Anthropic Claude | @anthropic-ai/sdk | AI Agents | Global |
| OpenAI | openai | AI Agents (alternativa) | Global |
| Google Gemini | @google/generative-ai | AI Agents (alternativa) | Global |
| LiveKit | livekit-server-sdk | WebRTC (lives + reuniões) | Self-hosted |
| WhatsApp Baileys | @whiskeysockets/baileys | Inbox WhatsApp multi-device | Por tenant |
| Nodemailer | nodemailer | Emails transacionais | SMTP por tenant ou global |
| Google Ads | API direta | Gestão de campanhas | OAuth por tenant |
| Meta Ads | API direta | Gestão de campanhas | OAuth por tenant |
| Puppeteer | puppeteer | Geração de PDF (contratos) | Global |
| BullMQ + Redis | bullmq · ioredis | Fila de emails assíncrona | Global |
Reaproveitabilidade ⚠️
Análise honesta do que é infra genérica vs. core acoplado ao domínio de turismo/experiências.
⚠️ Esta seção é estratégica. Leia antes de tomar decisões de produto, spin-off ou arquitetura multi-produto.
Classificação por Módulo
| Módulo | Acoplamento | Reaproveitamento | Observação |
|---|---|---|---|
| Auth & Permissões | Baixo | Alto | Padrão de mercado, facilmente extraível |
| Marketplace de Módulos | Baixo | Alto | Feature flags por tenant é genérico |
| Site Builder | Médio | Alto | Engine genérica; templates verticalizados |
| Form Builder | Baixo | Alto | Completamente genérico |
| Cursos & EAD | Baixo | Alto | Vertical independente — pode ser produto separado |
| Comunidade | Baixo | Alto | Fórum/canal genérico |
| Lives & Reuniões | Baixo | Alto | WebRTC genérico; não acoplado a turismo |
| AI Agents | Baixo | Alto | Alta demanda de mercado, multi-provider |
| CRM | Médio | Médio | Pipeline/Kanban genérico; sem diferencial claro |
| Financeiro / Pedidos | Médio | Médio | Genérico; NF-e e parcelas são específicos BR |
| Eventos | Médio | Médio | Genérico; checkin/ingresso verticalizável |
| Contratos | Baixo | Médio | Genérico; PDF via Puppeteer é frágil |
| Flow Builder | Médio | Médio | Engine genérica; nodes WhatsApp são acoplados |
| Marketing / Tráfego | Médio | Baixo | Implementação rasa; concorrência forte |
| WhatsApp (Baileys) | Alto | Baixo | Não-oficial; risco de ban inviabiliza reaproveitamento |
| Viagens (Itinerários) | Alto | Nenhum | Verticalmente acoplado a turismo |
Recomendação Estratégica
Para estratégia multi-produto
1. Extrair o platform layer: Auth, permissões, marketplace de módulos e tenant management são genéricos o suficiente para virar biblioteca compartilhada entre produtos.
2. Spin-offs com maior potencial: Cursos+Comunidade+Lives (EdTech), AI Agents (assistente de atendimento), Site Builder (website builder white-label).
3. Não extrair agora: Viagens é o core do negócio atual. WhatsApp precisa migrar para Cloud API antes de qualquer extração.
4. O que limita reaproveitamento hoje: Ausência de testes, TypeScript errors silenciosos, e tenantId hardcoded em todas as queries dificultam extração sem refatoração significativa.
ADRs
Architecture Decision Records inferidas do código. Contexto, decisão e consequências.
Isolamento multi-tenant por coluna (não por schema)
Decisão: Coluna tenantId em todas as tabelas. Todas as queries filtram por tenantId do JWT.
+ Operações e migrations simples. Queries cross-tenant para Super Admin são diretas.
− Segurança em nível de aplicação apenas — um bug pode vazar dados entre tenants.
Backend executado via tsx sem compilação TypeScript
Decisão: PM2 executa npx tsx src/index.ts. TypeScript é usado como DX/linting, não como compilador de produção.
+ Deploys nunca bloqueados por type errors. Ciclo de dev mais rápido.
− Erros de tipo em produção passam silenciosamente. Dívida técnica acumulada.
Kill-switch de sessão via sessionVersion no JWT
Decisão: JWT inclui sessionVersion. Ao bloquear usuário, incrementa-se o campo no banco. Middleware rejeita tokens com sessionVersion divergente.
+ Bloqueio imediato sem blocklist nem Redis.
− Query extra ao banco por request protegido.
WhatsApp via Baileys em vez da Cloud API oficial
Decisão: Baileys para reduzir custo inicial e permitir qualquer número como sender.
+ Sem custo por mensagem. Qualquer número, sem aprovação Meta.
− Risco de ban. Pode parar sem aviso. Ação recomendada: Migrar para Cloud API antes de clientes com volume > 100 mensagens/dia.
Roteamento de domínios customizados no middleware Next.js
Decisão: Middleware faz HTTP request ao backend para resolver tenant por domínio a cada request de edge.
+ Suporte a ilimitados domínios sem redeploy.
− Latência extra por request. Dependência do backend no edge.
Changelog
Baseado em Keep a Changelog. Cada versão = um "chat" de desenvolvimento.
- Site Builder: 3 templates, wizard, editor de blocos, domínios customizados
- Lives via LiveKit (WebRTC self-hosted), gravação S3
- Reuniões com links de agendamento e sala pública
- AI Agents multi-provider (Claude / OpenAI / Gemini)
- Suporte/Help Desk com portal público
- Contratos: templates, PDF Puppeteer, assinatura digital
- Marketing: social posts agendados multi-conta
- Tráfego: Google Ads + Meta Ads
- Comunidade: espaços, posts, reações
- Cursos: módulos, aulas, progresso, matrículas
- Infra: painel super admin com monitoramento de containers e PM2
- Layouts mobile responsivos (pills em configurações, bottom nav em admin)
- CORS dinâmico no backend (aceita qualquer origin)
- sitedev.partiuuu.com como documentação técnica em produção
- Models: ModuleMeta, TenantModule, EmailTemplate, SmtpConfig, EmailLog
- GET /api/tenant/features — flags por plano + módulos sandbox
- Frontend: cards de módulos, status badges, sandbox countdown
- Seed com 6 ModuleMeta iniciais
- CRUD de usuários de tenants e agências via admin
- Kill-switch ao bloquear usuário (sessionVersion++)
- Tenant partiuuu-sistema protegido contra delete/block
- Roteamento pós-login por role (SUPER_ADMIN → /admin, agency → /agency, tenant → /dashboard)
- Painel Super Admin: tenants, planos, super admins
- Portal Agência: clientes, requests, workspace switcher
- Models: AgencyTenantLink, CollaborationRequest, PermissionGrant
- Nível 1: vínculo agência↔tenant; Nível 2: permissões por módulo
- Models: RolePermission, UserPermission
- Matrix: defaults por role + overrides individuais por usuário
- Roles: SUPER_ADMIN, PARTIUUU_OPERATOR, ADMIN, MEMBER
- Email único global, User.tenantId nullable, sessionVersion
- Model Plan com feature flags e quotas
- Monorepo npm workspaces (frontend, backend, packages/db, shared)
- Docker Compose: postgres, nginx dev/staging
- Fastify backend com JWT, bcrypt, Prisma
- Next.js 14 App Router + Tailwind + shadcn/ui
- Schema inicial: Tenant, User, Contact, Deal, Project, Task
Roadmap
Prioridades para 3, 6 e 12 meses.
3 meses — Estabilização
- Resolver TypeScript errors no backend (migrar para build limpo)
- Testes automatizados (mínimo: auth, permissões, criação de tenant)
- CI/CD pipeline (GitHub Actions → staging automático)
- Migração WhatsApp: Baileys → Cloud API antes do primeiro cliente com volume
- Completar Flow Builder frontend (editor visual de nodes)
- Onboarding self-service de tenants (registro + escolha de plano)
- Billing integrado (Stripe — cobrança automática de planos)
- Portal do cliente funcional (ingressos, cursos, contratos)
6 meses — Lançamento de Mercado
- Entrada com 5-10 agências piloto
- App mobile (React Native ou PWA) — painel básico
- API pública para integrações de terceiros
- Site Builder: drag-and-drop + troca de template sem recriar
- AI Agent para atendimento WhatsApp (resposta automática + escalada)
- Relatórios e dashboards por módulo
12 meses — Escala
- Multi-provider WhatsApp: Cloud API como padrão
- Internacionalização (i18n) — inglês e espanhol
- Extração do platform layer (auth/permissões como biblioteca)
- Avaliação de spin-off: Cursos+Comunidade+Lives como produto EdTech
- Marketplace de templates de site da comunidade
- Zero-downtime deploy (PM2 cluster + migrations com rollback)
- LGPD compliance formal
Guias Operacionais
Setup local, deploy, comandos úteis e template de novo módulo.
Setup Local
git clone <repo> && cd app
npm install
cp .env.example .env # Editar DATABASE_URL, JWT_SECRET, etc.
docker-compose up -d postgres
npm run db:migrate -- init
npm run db:seed
# Backend:
cd backend && npx tsx src/index.ts
# Frontend (outro terminal):
cd frontend && npm run dev
Comandos do Servidor
# Backend
pm2 restart partiuuu-backend
pm2 logs partiuuu-backend --lines 50
# Frontend — rebuild Docker
docker rm -f partiuuu-nextjs
docker build -t partiuuu-nextjs -f app/frontend/Dockerfile.dev app/frontend/
docker run -d --name partiuuu-nextjs -p 3020:3010 partiuuu-nextjs
# OLS reload graceful
sudo /usr/local/lsws/bin/lswsctrl reload
# Migrations
npm run db:migrate -- nome
npm run db:seed
ℹ️ O .env do PM2 é lido de backend/.env (cwd do processo), não da raiz do monorepo.
⚠️ Após migrations, execute seed se houver novos ModuleMeta ou planos.
Template de Novo Módulo
# 1. Schema (packages/db/prisma/schema.prisma)
model NomeModelo {
id String @id @default(uuid())
tenantId String
tenant Tenant @relation(fields: [tenantId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy String?
updatedBy String?
}
# Adicionar: nomeModelos NomeModelo[] em Tenant
# 2. Migration
npm run db:migrate -- add_nome_modulo
# 3. Route (backend/src/routes/nome-modulo.ts)
server.get("/", { preHandler: [authenticate] }, async (req, reply) => {
const { tenantId } = req.user as { tenantId: string };
return server.prisma.nomeModelo.findMany({ where: { tenantId } });
});
# 4. Registrar no index.ts
app.register(nomeModuloRoutes, { prefix: "/api/nome-modulo" });
# 5. Frontend: app/(dashboard)/nome-modulo/page.tsx
# 6. Adicionar ao PROTECTED_PREFIXES em middleware.ts
# 7. Feature flag no model Plan (se módulo opcional)
# 8. pm2 restart partiuuu-backend
Pós-migration Checklist
- Verificar migration:
SELECT * FROM "_prisma_migrations" ORDER BY finished_at DESC LIMIT 5; - Seed se necessário:
npm run db:seed - Reiniciar backend:
pm2 restart partiuuu-backend - Health check:
curl http://localhost:3001/health - Testar endpoint afetado em devadmin.partiuuu.com