Event OS — ERP vertical de eventos ao vivo
Solução enterprise-grade para casas de show, estádios e arenas: ERP verticalizado Full Stack cobrindo todo o ciclo operacional — locais esportivos/entretenimento, eventos com conflito de agenda inteligente, e emissão individualizada de ingressos com matriz de permissão por portão + bloqueio transacional de capacidade.
Contexto
ERP verticalizado enterprise-grade FULL STACK para a indústria de eventos ao vivo — ciclo operacional completo: locais esportivos/entretenimento, planejamento de eventos com conflito de agenda inteligente, até emissão individualizada de ingressos com matriz de permissão de acesso por portão. Github público: Basilato/Desafio-Node-Fullstack.
- ~7.200 linhas TS/TSX produtivas · 5 módulos · 28 entidades UI
- 7 entidades de domínio · 3 enums · 3 PKs compostas · 4 índices estratégicos
- Seed demo PRONTO: 1.482 ingressos · 3 locais · 20 portões · 3 eventos referência
- Três perfis ADMIN/MANAGER/ATTENDANT via enum · Fallback inteligente ADMIN demo
- Deploy 3 ambientes: Vercel FE · Railway.app BE (Nixpacks) · Supabase PostgreSQL 15
- WCAG 2.1 AA confirmado · TypeScript strict mode 0 erros · Conformidade OKLCH
Problema
6 desafios técnicos que eu resolvi no projeto:
- Conversão booleana quebrada em query params NestJS · `?used=false` retornava oposto (truthy string)
- Misdetection de build monorepo Railway — builder Railpack assumia frontend estático na raiz
- Prisma P1001 persistente free tier (Render+Supabase) bloqueio região + schema public + SSL
- Ultrapassagem de capacidade sob concorrência emissão (2 operadores paralelo race condition)
- Design System WCAG inconsistente HSL claro vs escuro (perceptualmente desbalanceado)
- Middleware auth bloqueando SEM round-trip desnecessário antes render SSR Next
Usuários
3 perfis nativos UserRole enum + convidado demo, compartilhando o mesmo monorepo deployado.
- Admin (ADMIN) — acesso TUDO: usuários, eventos, locais, portões, tipos ingresso, matriz permissão, emissão, trilha
- Manager (MANAGER) — criar/editar eventos, locais, tipos; emitir ingressos; ajustar liberações gate
- Attendant (ATTENDANT) — apenas consulta: listagem ingressos, busca por titular/status/portão, vistas recentes
- Demo Fallback — `/auth/profile` retorna primeiro ADMIN se JWT ausente/inválido (desenvolvimento
- Portaria operacional — 3 filtros server-side + 2 client-side (search / dropdown gate sync)
Papel
Implementação end-to-end Full Stack Engineer individual: arquitetura, modelagem ER, backend NestJS/Prisma, frontend Next.js 14 App Router, design system OKLCH, deploy 3 ambientes + QA.
Backend NestJS 10 + Prisma 5.10 ACID
- Modelei schema ER Prisma com 7 entidades · 3 enums · 3 PKs compostas · 4 índices (venue+data, venue nome, evento/gate ticket)
- Implementei 6 REGRAS DE NEGÓCIO CORE: 1 evento obrigatoriamente 1 venue · RN-04 `assertNoScheduleConflict` álgebra intervalos + /availability/conflict · Bloqueio transacional capacidade · Matriz gate×ticketType PK composta delete/recreate atômico · gate pertence ao mesmo venue no emit · Fallback ADMIN /auth/profile
- Criei helper `rawBoolean` custom DTO (8 representações true/false/1/0/yes/no/on/off + valores numéricos) para corrigir bug Nest `enableImplicitConversion`
- Configurei CORS dinâmico (aceita *.vercel.app/*.onrender.com/*.railway.app) · Swagger OpenAPI 3.0 persistAuthorization · nestjs-pino logs estruturados · bcrypt 10 rounds
- Estabeleci Vitest 1.3 + Supertest 6.3 configs separadas unit/E2E · Monorepo orquestração scripts cross-plataforma PowerShell
Frontend Next.js 14 App Router + shadcn/ui OKLCH
- Arquitetei 3 módulos tela: Dashboard KPIs · Eventos (lista/novo/editar/detalhe 3 abas Tipos/Portões/Ingressos) · Locais (lista/novo/editar/detalhe)
- Implementei `middleware.ts` Next bloqueio cookie localis_session_present ANTES render SSR (zero round-trip) · AuthProvider + TanStack Query 5 persist
- Construí Design System HEX → OKLCH: Electric Violet primary + Event Teal accent · CVA 18+ components shadcn/ui adaptados · category-badge · dashboard-stat-card
- Desenvolvi `IssueTicketSheet`: Card capacidade 3 estados (verde/âmbar ≤10% ≤5/vermelho) · Filtro inteligente portões liberados · Tratamento VIP Dourado Crown badge + gradiente âmbar
- Montei `EventTicketGateTabs`: dirty-tracking checkbox grid liberações · Search 300+ itens · Tabela ingressos 8 colunas (QR/Titular/Tipo/Portão/Assento/Preço/Emissão/Status)
- Entreguei Tema claro/escuro next-themes class sem FOUC · prefers-reduced-motion · WCAG AA contrast ratio 4.5:1 · Layout responsive até 2400px desktop
Arquitetura
Estrutura MONOREPO orquestrado scripts raiz (install:all, dev, build, lint, typecheck, test, prisma:*) — Domain-Driven Design por módulo NestJS + Repository Pattern via PrismaService singleton.
Backend Layered NestJS (6 módulos feature)
- `backend/prisma/`: schema.prisma ER · migrations SQL versionadas · seed.ts demo 1.482 ingressos · 3 locais · 20 portões · 3 eventos
- `app.module.ts` Aggregate root: auth · prisma · health · venues + assignBulkGateAllowedTicketTypes · gates · events + availability conflict · ticket-types · tickets issue transacional
- main.ts bootstrap: CORS dinâmico wildcard subdomínios PaaS · ValidationPipe global whitelist+transform · Swagger /docs · nestjs-pino bufferLogs true
- Guards + @CurrentUser: JwtAuthGuard estrito · JwtAuthOptional · Passport JWT HS256 + sub/email/name/role payload
- PrismaService onModuleInit $transaction SERIALIZABLE · pgcrypto extension · pgBouncer 6543 reads + Direct 5432 writes migrations
Frontend Next.js 14 + Analytics Monorepo
- Next App Router SSR/ISR · middleware bloqueio pré-render · Route Handlers · next/font Inter cv11
- Providers: AppHeader sticky pill + nav + perfil dropdown · Toaster shadcn · Footer · ThemeToggle next-themes class
- Client Layer: 18+ shadcn/ui (Tabs/Sheet/Dialog/Dropdown/Toaster/Table/Skeleton) + Radix headless + CVA
- Hooks domínio: useEvent · useVenue · useTickets · useDashboardQueries (cache SWR dedupe interval)
- Lib API Facade centralizada por domínio: events.fetch · tickets.issue · venues.assignBulkGateAllowedTicketTypes
- Deploy Vercel CDN Edge + Railway Nixpacks build/start command + healthcheck 300s on_failure 10 retries + Supabase Pooler 6543
Resultado
Resultados técnicos mensuráveis + qualitativos do monorepo em produção.
Métricas de engenharia
- PRODUTIVIDADE: Monorepo ~7.200 linhas TS/TSX · 5 módulos · 28 entidades UI · 7 domínios · 3 enums · 3 PK compostas
- SEED DEMO: 1.482 ingressos (distribuição realista status) · 3 locais · 20 portões · 3 eventos · 1 ADMIN seed
- NAVEGABILIDADE OPERACIONAL: Tabela ingressos 8 colunas · 3 filtros server-side ortogonais · 2 filtros client-side sync · 8 representações boolean aceitas
- ACESSIBILIDADE: WCAG 2.1 AA · OKLCH tokens claro + escuro calibrado · :focus-visible 2px offset + radius 6px · prefers-reduced-motion
- QUALIDADE: TypeScript strict mode 0 erros · Pipeline typecheck → lint → build FE+BE limpo · Vitest/Jest unitários + E2E
- DEPLOY 3 AMBIENTES: Vercel (FE Edge) · Railway.app (Nixpacks Node 20 + healthcheck 300s + 10 retries) · Supabase PostgreSQL 15 pgBouncer
- PERFORMANCE: Build backend SWC transpilação ~20x tsc · CT backend ~45s · CT frontend App Router RSC validation ~90s · cold starts <5s após warm
- ESTABILIDADE: 2 trocas estratégicas Render→Railway + Pooler→Direct porta 5432 (resolveu P1001 free tier)
- REGRAS INVIOLÁVEIS: capacidade · conflito agenda · matriz permissão sempre checkadas em escrita DENTRO $transaction mesmo tx client — impossível violar via race condition
- REPRODUTIBILIDADE: Qualquer desenvolvedor roda localmente <10 minutos com 5 comandos (clone → install:all → prisma:generate/migrate/seed → dev)