Skip to content

Instantly share code, notes, and snippets.

@vedovelli
Created March 10, 2026 18:39
Show Gist options
  • Select an option

  • Save vedovelli/743c83acb3c4924e481cff3f037e72bd to your computer and use it in GitHub Desktop.

Select an option

Save vedovelli/743c83acb3c4924e481cff3f037e72bd to your computer and use it in GitHub Desktop.
Você é um arquiteto de software especializado em React SPAs modernas. Preciso que você crie um
plano completo de instalação e configuração de uma SPA com a seguinte arquitetura. O plano deve
incluir: (1) comandos de instalação, (2) conteúdo de cada arquivo de configuração, (3) explicação
da função de cada elemento, e (4) QA gates com Git hooks.
---
## STACK TÉCNICA
### Runtime & Build
- **Node.js** ≥ 24
- **pnpm** como package manager (usar `packageManager` field no package.json)
- **Vite 8** como bundler com Rolldown
- **TypeScript 5.9+** com configuração strict máxima
### Framework & UI
- **React 19** com React Compiler (babel-plugin-react-compiler)
- **TanStack Router** com file-based routing e auto code splitting
- **TanStack Query** para server state management
- **TanStack Form** com **Valibot** para validação de formulários
- **TanStack Table** para tabelas de dados
- **TanStack Virtual** para virtualização de listas
- **Tailwind CSS v4** via @tailwindcss/vite plugin
- **CVA (cva@1.0.0-beta.4)** com **tailwind-merge** para component variants
- **Base UI (@base-ui/react)** como primitivos de UI acessíveis
- **Lucide React** para ícones
- **Motion** para animações
- **Sonner** para toast notifications
- **cmdk** para command palette
### Utilitários
- **ts-pattern** para pattern matching (OBRIGATÓRIO em vez de switch/if-else chains)
- **Remeda** para utility functions funcionais
- **date-fns** para manipulação de datas
- **nanoid** para IDs únicos
- **Immer** para imutabilidade
- **Zustand** para estado global do cliente (mínimo, preferir TanStack Query)
### Testing (3 camadas)
- **Vitest 4** como test runner com 3 projetos:
- `unit`: testes unitários (`*.spec.ts(x)`)
- `browser`: testes de componente com Playwright (`*.browser.spec.ts(x)`)
- `integration`: testes de integração (`*.integration.spec.ts(x)`)
- **Testing Library** (React + DOM + user-event)
- **MSW 2** para mock de APIs em testes de integração
- **jsdom** como ambiente padrão para testes unitários
- **@vitest/browser-playwright** para browser tests
- **@vitest/coverage-v8** para cobertura de código
### Linting & Formatting (alta velocidade)
- **oxlint** como linter principal (Rust-based, extremamente rápido)
- **oxfmt** como formatter (Rust-based)
- **ESLint 10** apenas para regras que oxlint não cobre:
- **eslint-plugin-boundaries** para enforcement de arquitetura modular
- **typescript-eslint** para regras TypeScript avançadas
- **eslint-plugin-oxlint** para desabilitar regras duplicadas
- **markdownlint-cli2** para documentação
### DevTools (só em dev)
- **@tanstack/devtools-vite** (injetado condicionalmente)
- **@tanstack/react-devtools**, **react-query-devtools**, **react-form-devtools**, **react-router-devtools**
- **react-scan** para detectar re-renders desnecessários
### Git Hooks
- **Husky 9** para Git hooks
---
## ESTRUTURA DE DIRETÓRIOS
```text
src/
├── core/ # Utilitários core, API client, query keys, hooks compartilhados
│ ├── api.ts # API client (fetch wrapper)
│ ├── keys.ts # Query key factory (@lukemorales/query-key-factory)
│ ├── queries.ts # Query options centralizadas
│ ├── hooks.ts # Hooks reutilizáveis
│ ├── i18n.ts # Provider e config de i18n
│ ├── storage.ts # Utilitários de localStorage
│ └── locales/ # Catálogos de tradução por idioma
├── ui/ # Design system (componentes reutilizáveis sem lógica de negócio)
│ ├── Button.tsx
│ ├── Form.tsx
│ ├── variants.ts # Configuração CVA com tailwind-merge
│ └── ...
├── pattern/ # Componentes compostos de nível mais alto (usam ui/)
├── layouts/ # Componentes de layout puros
├── features/ # Lógica de negócio por domínio
│ └── {domain}/
│ ├── pages/
│ ├── components/
│ ├── hooks/ # Mutations do domínio
│ ├── types/
│ └── schemas/ # Schemas Valibot
├── routes/ # File-based routing (TanStack Router)
│ ├── __root.tsx
│ ├── _auth/ # Grupo de rotas autenticadas
│ └── ...
├── mocks/ # MSW handlers e setup
│ ├── handlers/
│ └── setup-specs.ts
└── main.tsx # Entry point
```
---
## PATH ALIASES (tsconfig.json + vite resolve)
```json
{
"@*": ["./src/*"],
"@core/*": ["./src/core/*"],
"@features/*": ["./src/features/*"],
"@layouts/*": ["./src/layouts/*"],
"@pattern/*": ["./src/pattern/*"],
"@routes/*": ["./src/routes/*"],
"@ui/*": ["./src/ui/*"],
"@mocks/*": ["./src/mocks/*"]
}
```
---
## TSCONFIG.JSON — CONFIGURAÇÃO STRICT MÁXIMA
```json
{
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules", "dist", "build"],
"compilerOptions": {
"target": "ES2024",
"module": "ESNext",
"lib": ["ES2024", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"types": ["vite/client", "vitest/globals", "msw"],
"allowJs": true,
"moduleResolution": "bundler",
"esModuleInterop": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true,
"baseUrl": ".",
"paths": {
"@*": ["./src/*"],
"@core/*": ["./src/core/*"],
"@features/*": ["./src/features/*"],
"@mocks/*": ["./src/mocks/*"],
"@layouts/*": ["./src/layouts/*"],
"@pattern/*": ["./src/pattern/*"],
"@routes/*": ["./src/routes/*"],
"@ui/*": ["./src/ui/*"]
},
"sourceMap": true,
"declaration": false,
"skipLibCheck": true,
"noEmit": true,
"erasableSyntaxOnly": true,
"strict": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUncheckedSideEffectImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true
}
}
```
---
## OXLINT CONFIGURAÇÃO (.oxlintrc.json)
Plugins habilitados: unicorn, typescript, oxc, react, react-perf, import, vitest
Categorias em nível "error": correctness, perf, restriction, suspicious, pedantic
Regras importantes:
- `eslint/max-depth`: máximo 3
- `eslint/max-nested-callbacks`: máximo 3
- `import/consistent-type-specifier-style`: "prefer-inline"
- `typescript/array-type`: "array" (não `Array<T>`)
- Relaxar regras em arquivos de teste (`*.spec.ts`)
Forneça o conteúdo completo do `.oxlintrc.json` com os seguintes overrides:
- Arquivos gerais `**/*.{js,ts,tsx}`: permitir async/await, optional chaining, rest/spread
- Arquivos TS `**/*.{ts,tsx}`: max-depth 3, max-nested-callbacks 3, inline type imports
- Arquivos JSX `**/*.{jsx,tsx}`: permitir stateless multi-comp, permitir constant-only exports
- Arquivos de teste `**/*.spec.{ts,tsx}`: relaxar regras de console, any, non-null assertion, etc.
- Arquivos de mock `**/mocks/**`: permitir parent imports relativos
---
## ESLINT — APENAS PARA BOUNDARIES
ESLint 10 configurado APENAS para eslint-plugin-boundaries que enforça regras de importação:
| Camada | Pode importar de |
| ---------- | ------------------------------------------------ |
| core | core, mocks |
| ui | ui |
| layout | core, ui, layout |
| pattern | core, ui, pattern |
| features | core, ui, pattern, components, features |
| components | core, ui, pattern, components, features |
| routes | core, ui, pattern, layout, features, components |
| mocks | core, mocks, features |
Usar eslint-plugin-oxlint para desabilitar regras que oxlint já cobre.
Forneça o conteúdo completo do `eslint.config.js` com:
- Ignores para dist, routeTree.gen.ts, specs, mocks, locales
- typescript-eslint recommended
- boundaries plugin com todas as regras acima
- oxlint integration
---
## VITE CONFIG
Plugins (em ordem):
1. `@tanstack/devtools-vite` (apenas em dev)
2. `@tanstack/router-plugin/vite` com `autoCodeSplitting: true`
3. `@vitejs/plugin-react` com babel plugins: lingui-macro + react-compiler
4. `@tailwindcss/vite`
5. `@lingui/vite-plugin`
6. `rollup-license-plugin`
7. `rollup-plugin-visualizer` (condicional via env var)
Build config:
- Code splitting: separar react e react-dom em chunk "react"
- Drop console e debugger em produção
- Nomear chunks: `lazy-[name]-[hash].js`
Feature flags via `define`:
```js
__APP_VERSION__: git short SHA
__APP_ENV__: mode (development/production)
__FEATURE_FLAG_*__: boolean flags de env vars
```
Forneça o conteúdo completo do `vite.config.ts`.
---
## VITEST CONFIG
3 projetos de teste no mesmo config:
- **unit**: `src/**/*.spec.ts(x)` excluindo integration e browser
- **integration**: `src/**/*.integration.spec.ts(x)` com timeout 15s
- **browser**: config separado (`vitest.browser.config.ts`) com Playwright
Coverage excluindo: `*.d.ts`, types, specs, config, generated, routes, mocks, entry points
Forneça o conteúdo completo do `vite.config.ts` (seção test) e do `vitest.browser.config.ts`.
---
## GIT HOOKS (Husky)
### Pre-commit
```bash
pnpm fmt # oxfmt auto-format
pnpm lint:docs:fix # markdownlint auto-fix
```
### Pre-push
```bash
pnpm lint # oxlint + ESLint (ambos devem passar)
pnpm build # build de produção deve compilar
```
Forneça os arquivos `.husky/pre-commit` e `.husky/pre-push` completos com verificação de exit code.
---
## SCRIPTS DO PACKAGE.JSON
```json
{
"dev": "vite --port 3000",
"build": "vite build",
"serve": "vite preview",
"check": "pnpm fmt && pnpm lint:oxlint:fix",
"fmt": "oxfmt",
"fmt:ci": "oxfmt --check",
"lint": "oxlint && eslint",
"lint:oxlint:fix": "oxlint --fix",
"lint:ts": "tsc --noEmit",
"lint:docs": "markdownlint-cli2 'docs/**/*.md'",
"lint:docs:fix": "markdownlint-cli2 --fix 'docs/**/*.md'",
"test": "pnpm test:unit && pnpm test:browser:headless && pnpm test:integration",
"test:unit": "vitest run --project unit",
"test:unit:watch": "vitest --project unit",
"test:integration": "vitest run --project integration",
"test:integration:watch": "vitest --project integration",
"test:browser": "vitest --config=vitest.browser.config.ts",
"test:browser:headless": "vitest run --config=vitest.browser.config.ts --browser.headless",
"test:watch": "vitest",
"i18n:extract": "lingui extract",
"i18n:compile": "lingui compile",
"prepare": "husky",
"build:stats": "VITE_BUNDLE_STATS=true vite build",
"bump": "pnpx npm-check-updates --upgrade && pnpm i && pnpm audit",
"bump:check": "pnpx npm-check-updates"
}
```
---
## QA GATES (checklist obrigatório antes de considerar qualquer tarefa completa)
```text
✅ pnpm fmt → Formatting (oxfmt)
✅ pnpm lint → oxlint + ESLint boundaries
✅ pnpm lint:ts → TypeScript strict compilation
✅ pnpm test → Todas as 3 camadas de teste
✅ pnpm build → Build de produção
```
---
## CONVENÇÕES OBRIGATÓRIAS
1. **`type` em vez de `interface`** para todas as definições de tipo
2. **Inline type imports**: `import { type Foo }` não `import type { Foo }`
3. **Named exports apenas** — sem default exports
4. **Sem barrel exports** (index.ts re-exportando) — imports diretos sempre
5. **ts-pattern** obrigatório para qualquer lógica condicional com 3+ branches, sempre com `.returnType<T>()`
6. **Sem useCallback/useMemo** para otimização — React Compiler cuida disso
7. **TanStack Query** para todo estado de servidor — nunca useEffect para fetch
8. **Path aliases** em todos os imports — nunca caminhos relativos com `../`
### ts-pattern — Padrão obrigatório
```typescript
// SEMPRE usar .returnType<T>() para declarar o tipo de retorno
const getStatus = (status: string) => {
return match(status)
.returnType<BadgeVariant>()
.with("pending", () => "orange")
.with("active", "granted", () => "success")
.otherwise(() => "indigo")
}
// Usar .exhaustive() quando todos os casos devem ser cobertos
// Usar .otherwise() quando há um fallback padrão
```
---
## ENTREGÁVEL ESPERADO
Gere o plano completo com:
1. Comandos de instalação agrupados por categoria (dependencies, devDependencies)
2. Conteúdo completo de cada arquivo de configuração (tsconfig, vite, oxlint, eslint, lingui, vitest)
3. Arquivo de setup de testes (`setup-specs.ts`)
4. Estrutura de diretórios com arquivos iniciais
5. Um componente exemplo usando a stack completa (route + query + form + ui com CVA)
6. Documentação em markdown explicando cada decisão arquitetural
7. Git hooks configurados e testáveis
8. Arquivo `vite-env.d.ts` com declarações de feature flags
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment