03 · Projeto autoral · ERP Full StackEm desenvolvimento

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.

Papel
Arquitetura end-to-end + modelagem ER · NestJS 10 + Prisma 5 (6 RN core) · Next.js 14 App Router + TanStack Query 5
Período
Em desenvolvimento
Código
Público
Tipo
Projeto autoral
Stack
TypeScript 5.3 strict (SWC)NestJS 10 + Passport JWTNext.js 14 App Router (SSR/ISR)Prisma ORM 5.10 schema-firstPostgreSQL 15 (Supabase) SERIALIZABLETailwind CSS 3.4 + OKLCH tokensshadcn/ui · Radix UI · CVATanStack Query 5 + TanStack Table 8React Hook Form 7 + Zod 3.22class-validator + class-transformernestjs-pino (Pino HTTP JSON logs)bcrypt 10 rounds saltNestJS Swagger OpenAPI 3.0Vitest + Supertest (BE)Jest + Testing Library (FE)Vercel · Railway Nixpacks · Supabase

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)