Merge branch 'agent--sigma' into agent--qualifica

This commit is contained in:
Luiz Silva 2026-09-16 23:50:58 -03:00
commit d072024532
4 changed files with 102 additions and 4 deletions

View file

@ -139,7 +139,7 @@ export const zProdutoCriar = z.object({
nome: z.string().trim().min(1),
preco: z.coerce.number().positive(),
ativo: z.boolean().default(true),
codigo: z.string().toUpperCase().optional(),
codigo: z.string().toUpperCase().nullish(),
tags: z.array(z.string()).default([]),
})
@ -149,7 +149,35 @@ produto.nome = produto.nome.trim()
produto.codigo = produto.codigo?.toUpperCase()
```
### 8. Composição e Enums Zod
### 8. Colunas e Registros que Podem ser Nulos Devem Usar `.nullish()`
Em schemas de tabelas, entidades e contratos de dados que mapeiam colunas do banco de dados ou campos de formulário/API que podem ser nulos ou omitidos, **DEVE-SE obrigatoriamente usar `.nullish()`** (nunca `.optional()` ou `.nullable()` isolados).
**Por que `.nullish()` é obrigatório?**
- **Bancos relacionais (PostgreSQL/Knex)**: colunas nulas retornam `null`.
- **Formulários e payloads parciais**: frequentemente omitem o campo (`undefined`) ou enviam `null` ao limpar.
- `.optional()` aceita apenas `undefined` — **falha** com `Expected string, received null` ao receber dados do banco ou payload com `null`.
- `.nullable()` aceita apenas `null` — **falha** com `Required` ao omitir o campo em atualizações parciais (`undefined`).
- `.nullish()` aceita ambos (`T | null | undefined`), garantindo interoperabilidade total entre banco, API e frontend sem erros de runtime.
```typescript
// ✅ CORRETO — coluna/registro opcional ou nulo com .nullish()
export const zPontosBase = z.object({
id: z.string().max(64).nullish(),
nome: z.string().min(1),
descricao: z.string().max(5000).nullish(),
codigo_empreendimento: zUUID.nullish(),
coordenadas: zCoordenadas.nullish(),
})
// ❌ ERRADO — quebra ao ler do banco quando a coluna for NULL
descricao: z.string().optional()
// ❌ ERRADO — quebra se o campo for omitido no payload (undefined)
descricao: z.string().nullable()
```
### 9. Composição e Enums Zod
```typescript
// ✅ Composição de schemas via extend/partial

View file

@ -72,6 +72,26 @@ export const zUsuarioCriar = z.object({
| `z{Modulo}Config` | Configuração |
| `z{Modulo}Ambiente` | Variáveis de ambiente |
### 2.4. Colunas e Campos que Podem ser Nulos: Usar `.nullish()`
Toda coluna do banco de dados relacional ou campo de entidade/registro que puder ser nulo ou omitido **DEVE** utilizar `.nullish()` (nunca `.optional()` ou `.nullable()` isolados):
```typescript
// ✅ CORRETO — aceita null (do banco PostgreSQL) e undefined (payload omitido)
export const zPontoCriar = z.object({
nome: z.string().min(1),
descricao: z.string().max(5000).nullish(),
codigo_empreendimento: zUUID.nullish(),
coordenadas: zCoordenadas.nullish(),
})
// ❌ ERRADO — quebra com null retornado pelo Knex/PostgreSQL
descricao: z.string().optional(),
// ❌ ERRADO — quebra quando a chave é omitida no payload (undefined)
descricao: z.string().nullable(),
```
---
## PASSO 3 — Derivar o Tipo com `z.infer<>`
@ -175,6 +195,7 @@ Zero erros = concluído.
- [ ] A validação usa `safeParse` (exceto em boot/middleware)?
- [ ] A nomenclatura segue o padrão `z{Entidade}{Acao}`?
- [ ] Transformações (trim, coerce, default) estão no schema, não no handler?
- [ ] Colunas e campos que podem ser nulos/opcionais utilizam `.nullish()` (em vez de `.optional()` ou `.nullable()` isolados)?
- [ ] Schemas derivados usam composição (.partial, .extend, .pick), não duplicação?
- [ ] `tsc --noEmit` passa sem erros?

View file

@ -139,7 +139,7 @@ export const zProdutoCriar = z.object({
nome: z.string().trim().min(1),
preco: z.coerce.number().positive(),
ativo: z.boolean().default(true),
codigo: z.string().toUpperCase().optional(),
codigo: z.string().toUpperCase().nullish(),
tags: z.array(z.string()).default([]),
})
@ -149,7 +149,35 @@ produto.nome = produto.nome.trim()
produto.codigo = produto.codigo?.toUpperCase()
```
### 8. Composição e Enums Zod
### 8. Colunas e Registros que Podem ser Nulos Devem Usar `.nullish()`
Em schemas de tabelas, entidades e contratos de dados que mapeiam colunas do banco de dados ou campos de formulário/API que podem ser nulos ou omitidos, **DEVE-SE obrigatoriamente usar `.nullish()`** (nunca `.optional()` ou `.nullable()` isolados).
**Por que `.nullish()` é obrigatório?**
- **Bancos relacionais (PostgreSQL/Knex)**: colunas nulas retornam `null`.
- **Formulários e payloads parciais**: frequentemente omitem o campo (`undefined`) ou enviam `null` ao limpar.
- `.optional()` aceita apenas `undefined` — **falha** com `Expected string, received null` ao receber dados do banco ou payload com `null`.
- `.nullable()` aceita apenas `null` — **falha** com `Required` ao omitir o campo em atualizações parciais (`undefined`).
- `.nullish()` aceita ambos (`T | null | undefined`), garantindo interoperabilidade total entre banco, API e frontend sem erros de runtime.
```typescript
// ✅ CORRETO — coluna/registro opcional ou nulo com .nullish()
export const zPontosBase = z.object({
id: z.string().max(64).nullish(),
nome: z.string().min(1),
descricao: z.string().max(5000).nullish(),
codigo_empreendimento: zUUID.nullish(),
coordenadas: zCoordenadas.nullish(),
})
// ❌ ERRADO — quebra ao ler do banco quando a coluna for NULL
descricao: z.string().optional()
// ❌ ERRADO — quebra se o campo for omitido no payload (undefined)
descricao: z.string().nullable()
```
### 9. Composição e Enums Zod
```typescript
// ✅ Composição de schemas via extend/partial

View file

@ -72,6 +72,26 @@ export const zUsuarioCriar = z.object({
| `z{Modulo}Config` | Configuração |
| `z{Modulo}Ambiente` | Variáveis de ambiente |
### 2.4. Colunas e Campos que Podem ser Nulos: Usar `.nullish()`
Toda coluna do banco de dados relacional ou campo de entidade/registro que puder ser nulo ou omitido **DEVE** utilizar `.nullish()` (nunca `.optional()` ou `.nullable()` isolados):
```typescript
// ✅ CORRETO — aceita null (do banco PostgreSQL) e undefined (payload omitido)
export const zPontoCriar = z.object({
nome: z.string().min(1),
descricao: z.string().max(5000).nullish(),
codigo_empreendimento: zUUID.nullish(),
coordenadas: zCoordenadas.nullish(),
})
// ❌ ERRADO — quebra com null retornado pelo Knex/PostgreSQL
descricao: z.string().optional(),
// ❌ ERRADO — quebra quando a chave é omitida no payload (undefined)
descricao: z.string().nullable(),
```
---
## PASSO 3 — Derivar o Tipo com `z.infer<>`
@ -175,6 +195,7 @@ Zero erros = concluído.
- [ ] A validação usa `safeParse` (exceto em boot/middleware)?
- [ ] A nomenclatura segue o padrão `z{Entidade}{Acao}`?
- [ ] Transformações (trim, coerce, default) estão no schema, não no handler?
- [ ] Colunas e campos que podem ser nulos/opcionais utilizam `.nullish()` (em vez de `.optional()` ou `.nullable()` isolados)?
- [ ] Schemas derivados usam composição (.partial, .extend, .pick), não duplicação?
- [ ] `tsc --noEmit` passa sem erros?