forlogic-core 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/README.md CHANGED
@@ -1,248 +1,628 @@
1
- # ForLogic Core
1
+ # 🧱 Projeto atual
2
2
 
3
- > **Biblioteca empresarial com React + TypeScript + Supabase**
4
- > Sistema CRUD completo, autenticação, integração Qualiex e componentes UI prontos.
3
+ **Schema padrão:** `central`
4
+
5
+ > **Nota sobre schemas:** O schema padrão é `central`, mas módulos podem usar schemas diferentes quando necessário para organização ou isolamento de dados. Por exemplo, o módulo de treinamentos usa o schema `trainings`. Você pode especificar o schema no service usando `schemaName: 'nome_do_schema'`.
5
6
 
6
7
  ---
7
8
 
8
- ## 📦 Instalação
9
+ ## 🤖 REGRAS CRÍTICAS
10
+
11
+ ### ⚠️ TOP 3 ERROS
12
+
13
+ 1. **ESQUECER SCHEMA**
14
+ ```typescript
15
+ // ❌ ERRADO
16
+ .from('table')
9
17
 
10
- ```bash
11
- npm install forlogic-core
18
+ // ✅ CORRETO
19
+ .schema('schema').from('table')
12
20
  ```
13
21
 
14
- ### Peer Dependencies
22
+ 2. **RLS COM `id` (sem alias)**
23
+ ```sql
24
+ -- ❌ ERRADO
25
+ CREATE POLICY "Users view own" ON schema.table
26
+ FOR SELECT USING (id_user = auth.uid());
27
+
28
+ -- ✅ CORRETO
29
+ CREATE POLICY "Users view own" ON schema.table
30
+ FOR SELECT USING (alias = auth.uid());
31
+ ```
15
32
 
16
- A biblioteca requer as seguintes dependências (geralmente já presentes em projetos React):
33
+ 3. **NÃO CRIAR ÍNDICES AUTOMATICAMENTE**
34
+ ```sql
35
+ -- ❌ PROIBIDO criar índices sem aprovação
36
+ CREATE INDEX idx_table_user ON schema.table(id_user);
17
37
 
18
- ```bash
19
- npm install react react-dom react-router-dom @tanstack/react-query
38
+ -- ✅ Apenas quando solicitado explicitamente
20
39
  ```
21
40
 
22
41
  ---
23
42
 
24
- ## 🚀 Quick Start
43
+ ### CHECKLIST (antes de implementar)
25
44
 
26
- ### 1. Configuração Inicial
45
+ - [ ] Schema `schema` especificado em queries e service?
46
+ - [ ] RLS usando `alias` (nunca `id_user`)?
47
+ - [ ] Preservar `item.id` no update?
48
+ - [ ] Config gerado com `useMemo()`?
49
+ - [ ] `<Outlet />` no componente pai?
50
+ - [ ] Qualiex header `un-alias` configurado?
27
51
 
28
- ```tsx
29
- // src/main.tsx
30
- import { setupQualiexCore } from 'forlogic-core';
31
- import 'forlogic-core/index.css';
52
+ ---
53
+
54
+ ## 🚀 QUICK START - Criar CRUD Completo
32
55
 
33
- setupQualiexCore({
34
- supabaseUrl: import.meta.env.VITE_SUPABASE_URL,
35
- supabaseAnonKey: import.meta.env.VITE_SUPABASE_ANON_KEY
56
+ ### **1️⃣ Type**
57
+ ```typescript
58
+ // src/processes/process.ts
59
+ export interface Process {
60
+ id: string;
61
+ id_user: string | null;
62
+ title: string;
63
+ description?: string;
64
+ status: 'draft' | 'active' | 'completed';
65
+ created_at?: string;
66
+ updated_at?: string;
67
+ deleted?: boolean;
68
+ }
69
+
70
+ export type ProcessInsert = Omit<Process, 'id' | 'created_at' | 'updated_at'>;
71
+ export type ProcessUpdate = Partial<ProcessInsert>;
72
+ ```
73
+
74
+ ### **2️⃣ Service**
75
+ ```typescript
76
+ // src/processes/processService.ts
77
+ import { createSimpleService } from 'forlogic-core';
78
+ import { Process, ProcessInsert, ProcessUpdate } from './process';
79
+
80
+ export const { service: processService, useCrudHook: useProcesses } =
81
+ createSimpleService<Process, ProcessInsert, ProcessUpdate>({
82
+ tableName: 'processes',
83
+ entityName: 'processo',
84
+ schemaName: 'central', // ⚠️ OBRIGATÓRIO
85
+ searchFields: ['title', 'description'],
86
+ enableQualiexEnrichment: true
87
+ });
88
+ ```
89
+
90
+ ### **3️⃣ Save Handler**
91
+ ```typescript
92
+ // src/processes/ProcessesPage.tsx
93
+ import { createSimpleSaveHandler } from 'forlogic-core';
94
+ import { processService } from './processService';
95
+
96
+ const handleSave = createSimpleSaveHandler({
97
+ service: processService,
98
+ entityName: 'processo'
36
99
  });
100
+
101
+ // ⚠️ CRÍTICO: Preservar ID no update
102
+ const handleUpdate = async (item: Process) => {
103
+ await handleSave({
104
+ ...item,
105
+ id: item.id // ⚠️ OBRIGATÓRIO para update
106
+ });
107
+ };
37
108
  ```
38
109
 
39
- ### 2. Estrutura de Providers
110
+ ### **4️⃣ Config (com useMemo)**
111
+ ```typescript
112
+ // src/processes/ProcessesPage.tsx
113
+ import { useMemo } from 'react';
114
+ import { generateCrudConfig } from 'forlogic-core';
115
+
116
+ export default function ProcessesPage() {
117
+ const crud = useProcesses();
118
+
119
+ // ⚠️ OBRIGATÓRIO useMemo para evitar re-renders
120
+ const config = useMemo(() =>
121
+ generateCrudConfig<Process>({
122
+ entity: 'processo',
123
+ columns: [
124
+ { key: 'title', label: 'Título', type: 'text', required: true },
125
+ { key: 'status', label: 'Status', type: 'select',
126
+ options: [
127
+ { value: 'draft', label: 'Rascunho' },
128
+ { value: 'active', label: 'Ativo' },
129
+ { value: 'completed', label: 'Concluído' }
130
+ ]
131
+ },
132
+ { key: 'description', label: 'Descrição', type: 'textarea' }
133
+ ]
134
+ }),
135
+ []);
136
+
137
+ return createCrudPage({
138
+ config,
139
+ crud,
140
+ saveHandler: handleSave
141
+ });
142
+ }
143
+ ```
40
144
 
41
- ```tsx
145
+ ### **5️⃣ Page + Outlet (preservar estado)**
146
+ ```typescript
42
147
  // src/App.tsx
43
- import { ErrorBoundary, QueryClientProvider, AuthProvider } from 'forlogic-core';
44
- import { BrowserRouter } from 'react-router-dom';
148
+ import { Outlet } from 'react-router-dom';
45
149
 
46
150
  function App() {
47
151
  return (
48
- <ErrorBoundary>
49
- <QueryClientProvider client={queryClient}>
50
- <AuthProvider>
51
- <BrowserRouter>
52
- {/* Suas rotas aqui */}
53
- </BrowserRouter>
54
- </AuthProvider>
55
- </QueryClientProvider>
56
- </ErrorBoundary>
152
+ <Routes>
153
+ <Route path="/processes" element={<ProcessLayout />}>
154
+ <Route index element={<ProcessesPage />} />
155
+ <Route path="new" element={<ProcessesPage />} />
156
+ <Route path=":id/edit" element={<ProcessesPage />} />
157
+ </Route>
158
+ </Routes>
57
159
  );
58
160
  }
161
+
162
+ // ⚠️ OBRIGATÓRIO: Outlet preserva estado
163
+ function ProcessLayout() {
164
+ return <Outlet />; // Evita reload do componente
165
+ }
59
166
  ```
60
167
 
61
- ### 3. Criar uma Página CRUD Completa
168
+ ---
62
169
 
63
- ```tsx
64
- // src/employees/EmployeesPage.tsx
65
- import { createCrudPage, createSimpleService, useCrud } from 'forlogic-core';
170
+ ## 🎯 AÇÕES EM LOTE (Bulk Actions)
66
171
 
67
- // 1. Definir tipo
68
- interface Employee {
69
- id?: string;
70
- name: string;
71
- email: string;
72
- role: string;
73
- }
172
+ O sistema CRUD suporta seleção múltipla e ações em lote usando checkboxes.
74
173
 
75
- // 2. Criar service
76
- const service = createSimpleService<Employee>('employees', {
77
- schemaName: 'central' // Usar schema do seu projeto
78
- });
174
+ ### **Habilitar Bulk Actions**
79
175
 
80
- // 3. Criar hook
81
- const useEmployeesCrud = () => useCrud({
82
- service,
83
- queryKey: 'employees'
84
- });
176
+ Adicione `enableBulkActions: true` na configuração:
85
177
 
86
- // 4. Configurar colunas e formulário
87
- const columns = [
88
- { key: 'name', label: 'Nome' },
89
- { key: 'email', label: 'Email' },
90
- { key: 'role', label: 'Cargo' }
91
- ];
178
+ ```typescript
179
+ const config = useMemo((): CrudPageConfig<Process> => ({
180
+ entityName: "Processo",
181
+ entityNamePlural: "Processos",
182
+ enableBulkActions: true, // 🆕 Habilita checkboxes e ações em lote
183
+ columns: [...],
184
+ formSections: [...]
185
+ }), []);
186
+ ```
92
187
 
93
- const formSections = [
94
- {
95
- title: 'Dados do Funcionário',
96
- fields: [
97
- { name: 'name', label: 'Nome', type: 'text', required: true },
98
- { name: 'email', label: 'Email', type: 'email', required: true },
99
- { name: 'role', label: 'Cargo', type: 'text', required: true }
100
- ]
101
- }
102
- ];
188
+ ### **Ações Padrão Disponíveis**
103
189
 
104
- // 5. Exportar página
105
- export default createCrudPage({
106
- useCrud: useEmployeesCrud,
107
- columns,
108
- formSections,
109
- title: 'Funcionários'
110
- });
190
+ Quando `enableBulkActions: true`, as seguintes ações ficam disponíveis automaticamente:
191
+
192
+ - ✅ **Deletar em lote**: Deleta múltiplos itens selecionados (usa a mesma função do delete individual)
193
+ - ✅ **Checkbox "Selecionar Todos"**: No header da tabela para selecionar/deselecionar todos os itens da página
194
+ - ✅ **Indicador Visual**: Linhas/cards selecionados têm background destacado
195
+ - ✅ **Barra de Ações**: Aparece no topo quando há itens selecionados
196
+
197
+ ### **Ações Customizadas**
198
+
199
+ Você pode adicionar ações customizadas além do delete padrão:
200
+
201
+ ```typescript
202
+ import { Download, Archive } from 'lucide-react';
203
+ import type { BulkAction } from 'forlogic-core';
204
+
205
+ const config: CrudPageConfig<Process> = {
206
+ entityName: "Processo",
207
+ entityNamePlural: "Processos",
208
+ enableBulkActions: true,
209
+ bulkActions: [
210
+ {
211
+ label: "Exportar Selecionados",
212
+ icon: Download,
213
+ variant: "outline", // 'default' | 'destructive' | 'outline'
214
+ action: async (items) => {
215
+ // Sua lógica de exportação
216
+ const selectedItems = manager.entities.filter(
217
+ e => manager.selectedIds.includes(e.id)
218
+ );
219
+ await exportToExcel(selectedItems);
220
+ }
221
+ },
222
+ {
223
+ label: "Arquivar",
224
+ icon: Archive,
225
+ confirmMessage: "Tem certeza que deseja arquivar os itens selecionados?",
226
+ action: async (items) => {
227
+ const selectedItems = manager.entities.filter(
228
+ e => manager.selectedIds.includes(e.id)
229
+ );
230
+ await bulkArchive(selectedItems.map(i => i.id));
231
+ }
232
+ }
233
+ ],
234
+ columns: [...]
235
+ };
111
236
  ```
112
237
 
113
- ---
238
+ ### **Comportamento**
114
239
 
115
- ## 📚 Documentação Completa
240
+ **Desktop (Tabela):**
241
+ - Checkbox na primeira coluna (50px de largura)
242
+ - Checkbox no header para "Selecionar Todos"
243
+ - Click na linha NÃO abre o form quando bulk actions está ativo (evita edição acidental)
116
244
 
117
- A documentação detalhada está disponível em:
245
+ **Mobile (Cards):**
246
+ - Checkbox no canto superior esquerdo de cada card
247
+ - Mesmo comportamento de seleção que desktop
118
248
 
119
- - **[Regras para IA](dist/docs/AI_RULES.md)** - Checklist crítico para desenvolvimento assistido por IA
120
- - **[Troubleshooting](dist/docs/TROUBLESHOOTING.md)** - Soluções para problemas comuns
121
- - **[Templates Prontos](dist/docs/templates/)** - Códigos completos para copiar e usar
122
- - **[Navegação da Docs](dist/docs/README.md)** - Hub central da documentação
249
+ **Barra de Ações:**
250
+ - Aparece automaticamente quando itens selecionados
251
+ - Mostra quantidade de itens selecionados
252
+ - Botão "Limpar" para deselecionar todos
253
+ - Botões de ações (Delete + customizadas)
123
254
 
124
- ---
255
+ ### **Propriedades do Manager**
256
+
257
+ Quando bulk actions está habilitado, o `manager` retornado pelo `useCrud` inclui:
258
+
259
+ ```typescript
260
+ manager.selectedIds // string[] - IDs dos itens selecionados
261
+ manager.selectItem(id) // Seleciona/desseleciona um item
262
+ manager.selectAll() // Seleciona/desseleciona todos
263
+ manager.clearSelection() // Limpa seleção
264
+ manager.isAllSelected // boolean - Todos selecionados?
265
+ manager.bulkDelete(ids) // Deleta múltiplos IDs
266
+ manager.isBulkDeleting // boolean - Loading do bulk delete
267
+ ```
125
268
 
126
- ## 🎯 Recursos Principais
269
+ ### **Exemplo Completo**
127
270
 
128
- ### ✅ Sistema CRUD Completo
129
- - Tabelas com paginação, filtros e ordenação
130
- - Formulários automáticos com validação
131
- - Cards responsivos para mobile
132
- - Ações em lote (deletar múltiplos)
271
+ ```typescript
272
+ // src/processes/ProcessesPage.tsx
273
+ import { useMemo } from 'react';
274
+ import { createCrudPage, createSimpleSaveHandler, type BulkAction } from 'forlogic-core';
275
+ import { Download, Archive } from 'lucide-react';
276
+ import { Process } from './process';
277
+ import { useProcessCrud } from './processService';
278
+ import { exportToExcel } from '@/utils/export';
133
279
 
134
- ### 🔐 Autenticação
135
- - Login/logout automático
136
- - Proteção de rotas
137
- - Integração com Supabase Auth
138
- - Gerenciamento de tokens
280
+ export function ProcessesPage() {
281
+ const manager = useProcessCrud();
139
282
 
140
- ### 🎨 Componentes UI
141
- - 50+ componentes prontos (shadcn/ui)
142
- - Design system completo
143
- - Dark mode nativo
144
- - Totalmente customizável
283
+ const bulkActions: BulkAction<Process>[] = useMemo(() => [
284
+ {
285
+ label: "Exportar",
286
+ icon: Download,
287
+ variant: "outline",
288
+ action: async () => {
289
+ const selected = manager.entities.filter(
290
+ e => manager.selectedIds.includes(e.id)
291
+ );
292
+ await exportToExcel(selected);
293
+ }
294
+ }
295
+ ], [manager.entities, manager.selectedIds]);
296
+
297
+ const config = useMemo(() => ({
298
+ entityName: "Processo",
299
+ entityNamePlural: "Processos",
300
+ enableBulkActions: true,
301
+ bulkActions,
302
+ columns: [
303
+ { key: 'title', header: 'Título', sortable: true },
304
+ { key: 'status', header: 'Status', className: 'w-24 text-center' },
305
+ ],
306
+ formSections: [...]
307
+ }), [bulkActions]);
308
+
309
+ const handleSave = createSimpleSaveHandler(
310
+ manager,
311
+ (data) => ({ ...data }),
312
+ (data) => ({ ...data })
313
+ );
145
314
 
146
- ### 🔗 Integrações
147
- - **Qualiex**: Componentes para seleção de usuários
148
- - **Supabase**: Cliente configurado automaticamente
149
- - **React Query**: Cache e sincronização de dados
315
+ const CrudPage = createCrudPage({
316
+ manager,
317
+ config,
318
+ onSave: handleSave
319
+ });
320
+
321
+ return <CrudPage />;
322
+ }
323
+ ```
150
324
 
151
325
  ---
152
326
 
153
- ## 💡 Exemplo de Uso Completo
327
+ ### 🔗 Integração Qualiex (opcional)
154
328
 
155
- ```tsx
156
- import {
157
- createCrudPage,
158
- createSimpleService,
159
- useCrud,
160
- QualiexUserField
161
- } from 'forlogic-core';
329
+ **Auto-enrichment** (já configurado no BaseService):
330
+ ```typescript
331
+ // ✅ Automático - dados enriquecidos com nome do usuário
332
+ const processes = await processService.getAll();
333
+ // processes[0].usuario_nome = "João Silva" (se enableQualiexEnrichment: true)
334
+ ```
162
335
 
163
- interface Task {
164
- id?: string;
165
- title: string;
166
- description: string;
167
- responsible_id: string;
168
- status: 'pending' | 'in_progress' | 'done';
336
+ **Componentes prontos:**
337
+ ```typescript
338
+ import { QualiexUserField, QualiexResponsibleSelectField } from 'forlogic-core';
339
+
340
+ // Select de usuários Qualiex
341
+ <QualiexResponsibleSelectField
342
+ value={form.watch('id_user')}
343
+ onChange={(userId) => form.setValue('id_user', userId)}
344
+ />
345
+ ```
346
+
347
+ **Componentes em formulários CRUD:**
348
+ ```typescript
349
+ // Para seleção de usuário
350
+ {
351
+ name: 'responsible_id',
352
+ label: 'Responsável',
353
+ type: 'simple-qualiex-user-field' as const,
354
+ required: true
169
355
  }
170
356
 
171
- const service = createSimpleService<Task>('tasks', {
172
- schemaName: 'central'
173
- });
357
+ // Para seleção de responsável
358
+ {
359
+ name: 'responsible_id',
360
+ label: 'Responsável',
361
+ type: 'single-responsible-select' as const,
362
+ required: true
363
+ }
364
+ ```
174
365
 
175
- const useTasksCrud = () => useCrud({ service, queryKey: 'tasks' });
366
+ **Componentes customizados:**
176
367
 
177
- export default createCrudPage({
178
- useCrud: useTasksCrud,
179
- columns: [
180
- { key: 'title', label: 'Título' },
181
- { key: 'status', label: 'Status' },
182
- ],
183
- formSections: [
184
- {
185
- title: 'Dados da Tarefa',
186
- fields: [
187
- { name: 'title', label: 'Título', type: 'text', required: true },
188
- { name: 'description', label: 'Descrição', type: 'textarea' },
189
- {
190
- name: 'responsible_id',
191
- label: 'Responsável',
192
- type: 'custom',
193
- component: QualiexUserField
194
- },
195
- {
196
- name: 'status',
197
- label: 'Status',
198
- type: 'select',
199
- options: [
200
- { value: 'pending', label: 'Pendente' },
201
- { value: 'in_progress', label: 'Em Progresso' },
202
- { value: 'done', label: 'Concluído' }
203
- ]
204
- }
205
- ]
206
- }
207
- ],
208
- title: 'Tarefas'
209
- });
368
+ Você pode criar e usar componentes customizados nos formulários para necessidades específicas:
369
+
370
+ ```typescript
371
+ // Exemplo de campo customizado
372
+ {
373
+ name: 'custom_field',
374
+ label: 'Campo Customizado',
375
+ type: 'my-custom-component' as const,
376
+ required: true
377
+ }
378
+ ```
379
+
380
+ > **Nota:** Componentes customizados devem ser registrados no `BaseForm.tsx` para funcionarem corretamente nos formulários CRUD.
381
+
382
+ **⚠️ CRÍTICO:** Requests Qualiex exigem header `un-alias`:
383
+ ```typescript
384
+ // Já configurado no BaseService automaticamente
385
+ headers: { 'un-alias': 'true' }
210
386
  ```
211
387
 
212
388
  ---
213
389
 
214
- ## 🔧 Configuração Avançada
390
+ ## 🗃️ MIGRATIONS + RLS
391
+
392
+ ### Template SQL Completo
393
+ ```sql
394
+ -- 1️⃣ Criar tabela
395
+ CREATE TABLE central.processes (
396
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
397
+ id_user UUID, -- ⚠️ NUNCA foreign key para auth.users
398
+ title TEXT NOT NULL,
399
+ description TEXT,
400
+ status TEXT DEFAULT 'draft',
401
+ created_at TIMESTAMPTZ DEFAULT now(),
402
+ updated_at TIMESTAMPTZ DEFAULT now(),
403
+ deleted BOOLEAN DEFAULT false
404
+ );
405
+
406
+ -- 2️⃣ Habilitar RLS
407
+ ALTER TABLE central.processes ENABLE ROW LEVEL SECURITY;
408
+
409
+ -- 3️⃣ Políticas RLS (usar 'alias', nunca 'id_user')
410
+ CREATE POLICY "Users view own processes"
411
+ ON central.processes FOR SELECT
412
+ USING (alias = auth.uid()); -- ⚠️ 'alias', não 'id_user'
413
+
414
+ CREATE POLICY "Users insert own processes"
415
+ ON central.processes FOR INSERT
416
+ WITH CHECK (alias = auth.uid());
417
+
418
+ CREATE POLICY "Users update own processes"
419
+ ON central.processes FOR UPDATE
420
+ USING (alias = auth.uid());
421
+
422
+ -- 4️⃣ Trigger updated_at
423
+ CREATE TRIGGER set_updated_at
424
+ BEFORE UPDATE ON central.processes
425
+ FOR EACH ROW
426
+ EXECUTE FUNCTION public.set_updated_at();
427
+
428
+ -- 5️⃣ Índices (apenas se necessário)
429
+ -- ⚠️ NÃO criar automaticamente - solicitar aprovação
430
+ -- CREATE INDEX idx_processes_user ON central.processes(id_user);
431
+ ```
432
+
433
+ ### ❌ Sintaxes Proibidas RLS
434
+ ```sql
435
+ -- NUNCA usar 'id' ou 'id_user' direto
436
+ id_user = auth.uid() -- ❌ ERRADO
437
+ id = auth.uid() -- ❌ ERRADO
438
+
439
+ -- SEMPRE usar 'alias'
440
+ alias = auth.uid() -- ✅ CORRETO
441
+ ```
442
+
443
+ ---
444
+
445
+ ## 🐛 TROUBLESHOOTING
446
+
447
+ ### 1️⃣ "relation does not exist"
448
+ ```typescript
449
+ // Causa: Schema ausente
450
+ .from('processes') // ❌
451
+
452
+ // Solução:
453
+ .from('processes', { schema: 'central' }) // ✅
454
+ ```
455
+
456
+ ### 2️⃣ RLS retorna vazio
457
+ ```sql
458
+ -- Causa: Sintaxe incorreta
459
+ USING (id_user = auth.uid()) -- ❌
460
+
461
+ -- Solução:
462
+ USING (alias = auth.uid()) -- ✅
463
+ ```
464
+
465
+ ### 3️⃣ Duplicação de registros
466
+ ```typescript
467
+ // Causa: ID ausente no update
468
+ await service.save({ title: 'Novo' }); // ❌ Cria duplicado
469
+
470
+ // Solução: Preservar ID
471
+ await service.save({ id: item.id, title: 'Novo' }); // ✅
472
+ ```
473
+
474
+ ### 4️⃣ Página recarrega ao editar
475
+ ```typescript
476
+ // Causa: Config sem useMemo
477
+ const config = generateCrudConfig(...); // ❌ Re-render infinito
478
+
479
+ // Solução:
480
+ const config = useMemo(() => generateCrudConfig(...), []); // ✅
481
+ ```
482
+
483
+ ### 5️⃣ Estado reseta ao navegar
484
+ ```typescript
485
+ // Causa: Outlet ausente
486
+ <Route path="/processes" element={<ProcessesPage />} /> // ❌
215
487
 
216
- ### Import Modular (Tree-shaking)
488
+ // Solução: Layout com Outlet
489
+ <Route path="/processes" element={<ProcessLayout />}>
490
+ <Route index element={<ProcessesPage />} />
491
+ </Route>
492
+ // ProcessLayout: return <Outlet />; // ✅
493
+ ```
217
494
 
218
- Para bundles menores, use imports específicos:
495
+ ### 6️⃣ Qualiex retorna 401
496
+ ```typescript
497
+ // Causa: Header ausente
498
+ fetch(url); // ❌
219
499
 
220
- ```tsx
221
- import { Button, Input, Card } from 'forlogic-core/modular';
500
+ // Solução: Adicionar header
501
+ fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
502
+ // (BaseService já faz automaticamente)
222
503
  ```
223
504
 
224
- ### Customização de Tema
505
+ ---
506
+
507
+ ## 📐 CONTROLE DE LARGURA DAS COLUNAS
225
508
 
226
- Edite `index.css` no seu projeto:
509
+ O `forlogic-core` oferece três formas de definir larguras de colunas nas tabelas CRUD:
510
+
511
+ ### **1️⃣ Via `className` (Recomendado)**
512
+ Use classes do Tailwind para larguras fixas ou responsivas:
513
+ ```typescript
514
+ const columns = [
515
+ {
516
+ key: 'status',
517
+ header: 'Status',
518
+ className: 'w-24 text-center', // Largura fixa: 96px
519
+ },
520
+ {
521
+ key: 'updated_at',
522
+ header: 'Atualizado em',
523
+ className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
524
+ },
525
+ ];
526
+ ```
227
527
 
228
- ```css
229
- :root {
230
- --primary: 220 70% 50%;
231
- --secondary: 210 40% 96.1%;
232
- /* ... outros tokens */
528
+ ### **2️⃣ Via `width` (Fixo em pixels)**
529
+ Especifique largura fixa diretamente:
530
+ ```typescript
531
+ {
532
+ key: 'order',
533
+ header: 'Ordem',
534
+ width: 60, // Largura fixa: 60px
535
+ className: 'text-center',
233
536
  }
234
537
  ```
235
538
 
539
+ ### **3️⃣ Via `minWidth` + `weight` (Flexível)**
540
+ Para colunas que crescem proporcionalmente:
541
+ ```typescript
542
+ {
543
+ key: 'description',
544
+ header: 'Descrição',
545
+ minWidth: 200, // Mínimo: 200px
546
+ weight: 2, // 2x mais espaço que colunas padrão (weight: 1)
547
+ }
548
+ ```
549
+
550
+ ### **⚠️ Importante**
551
+ - A tabela usa `table-auto` para respeitar essas configurações
552
+ - Para truncar textos longos, use: `className: "max-w-[200px] truncate"`
553
+ - Combine `whitespace-nowrap` com largura fixa para evitar quebras
554
+
555
+ ### **📋 Exemplo Completo**
556
+ ```typescript
557
+ const columns: CrudColumn<MyEntity>[] = [
558
+ {
559
+ key: 'order',
560
+ header: 'Ordem',
561
+ width: 60, // Fixo: 60px
562
+ className: 'text-center',
563
+ },
564
+ {
565
+ key: 'title',
566
+ header: 'Título',
567
+ minWidth: 200, // Mínimo: 200px, cresce conforme espaço disponível
568
+ weight: 3, // 3x mais espaço que colunas padrão
569
+ },
570
+ {
571
+ key: 'status',
572
+ header: 'Status',
573
+ className: 'w-24 text-center', // Tailwind: 96px
574
+ },
575
+ {
576
+ key: 'progress',
577
+ header: 'Nível & Progresso',
578
+ className: 'w-40 text-center', // Tailwind: 160px
579
+ },
580
+ {
581
+ key: 'updated_at',
582
+ header: 'Atualizado em',
583
+ className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
584
+ render: (item) => formatDate(item.updated_at)
585
+ },
586
+ ];
587
+ ```
588
+
236
589
  ---
237
590
 
238
- ## 📖 Links Úteis
591
+ ## 📚 REFERÊNCIA RÁPIDA
592
+
593
+ ### Imports Essenciais
594
+ ```typescript
595
+ // CRUD
596
+ import {
597
+ createSimpleService,
598
+ createCrudPage,
599
+ generateCrudConfig,
600
+ createSimpleSaveHandler
601
+ } from 'forlogic-core';
602
+
603
+ // UI
604
+ import { Button, Input, Card, toast } from 'forlogic-core/ui';
605
+
606
+ // Auth
607
+ import { useAuth, ProtectedRoute } from 'forlogic-core';
608
+
609
+ // Qualiex
610
+ import { QualiexUserField, useQualiexUsers } from 'forlogic-core';
611
+ ```
239
612
 
240
- - **GitHub**: [forlogic-core](https://github.com/forlogic/forlogic-core)
241
- - **NPM**: [forlogic-core](https://www.npmjs.com/package/forlogic-core)
242
- - **Suporte**: [Issues](https://github.com/forlogic/forlogic-core/issues)
613
+ ### Estrutura de Arquivos
614
+ ```
615
+ src/
616
+ ├── processes/
617
+ │ ├── process.ts # Types
618
+ │ ├── processService.ts # Service + Hook
619
+ │ └── ProcessesPage.tsx # Page + Config
620
+ ```
243
621
 
244
622
  ---
245
623
 
246
624
  ## 📝 Licença
247
625
 
248
626
  MIT License - ForLogic © 2025
627
+
628
+ **Última atualização:** 2025-10-05