forlogic-core 1.5.2 → 1.5.3

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,471 @@
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());
15
27
 
16
- A biblioteca requer as seguintes dependências (geralmente já presentes em projetos React):
28
+ -- CORRETO
29
+ CREATE POLICY "Users view own" ON schema.table
30
+ FOR SELECT USING (alias = auth.uid());
31
+ ```
32
+
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)
44
+
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?
51
+
52
+ ---
53
+
54
+ ## 🚀 QUICK START - Criar CRUD Completo
25
55
 
26
- ### 1. Configuração Inicial
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
+ }
27
69
 
28
- ```tsx
29
- // src/main.tsx
30
- import { setupQualiexCore } from 'forlogic-core';
31
- import 'forlogic-core/index.css';
70
+ export type ProcessInsert = Omit<Process, 'id' | 'created_at' | 'updated_at'>;
71
+ export type ProcessUpdate = Partial<ProcessInsert>;
72
+ ```
32
73
 
33
- setupQualiexCore({
34
- supabaseUrl: import.meta.env.VITE_SUPABASE_URL,
35
- supabaseAnonKey: import.meta.env.VITE_SUPABASE_ANON_KEY
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
+ }
166
+ ```
167
+
168
+ ---
169
+
170
+ ### 🔗 Integração Qualiex (opcional)
171
+
172
+ **Auto-enrichment** (já configurado no BaseService):
173
+ ```typescript
174
+ // ✅ Automático - dados enriquecidos com nome do usuário
175
+ const processes = await processService.getAll();
176
+ // processes[0].usuario_nome = "João Silva" (se enableQualiexEnrichment: true)
59
177
  ```
60
178
 
61
- ### 3. Criar uma Página CRUD Completa
179
+ **Componentes prontos:**
180
+ ```typescript
181
+ import { QualiexUserField, QualiexResponsibleSelectField } from 'forlogic-core';
62
182
 
63
- ```tsx
64
- // src/employees/EmployeesPage.tsx
65
- import { createCrudPage, createSimpleService, useCrud } from 'forlogic-core';
183
+ // Select de usuários Qualiex
184
+ <QualiexResponsibleSelectField
185
+ value={form.watch('id_user')}
186
+ onChange={(userId) => form.setValue('id_user', userId)}
187
+ />
188
+ ```
66
189
 
67
- // 1. Definir tipo
68
- interface Employee {
69
- id?: string;
70
- name: string;
71
- email: string;
72
- role: string;
190
+ **Componentes em formulários CRUD:**
191
+ ```typescript
192
+ // Para seleção de usuário
193
+ {
194
+ name: 'responsible_id',
195
+ label: 'Responsável',
196
+ type: 'simple-qualiex-user-field' as const,
197
+ required: true
73
198
  }
74
199
 
75
- // 2. Criar service
76
- const service = createSimpleService<Employee>('employees', {
77
- schemaName: 'central' // Usar schema do seu projeto
78
- });
200
+ // Para seleção de responsável
201
+ {
202
+ name: 'responsible_id',
203
+ label: 'Responsável',
204
+ type: 'single-responsible-select' as const,
205
+ required: true
206
+ }
207
+ ```
79
208
 
80
- // 3. Criar hook
81
- const useEmployeesCrud = () => useCrud({
82
- service,
83
- queryKey: 'employees'
84
- });
209
+ **Componentes customizados:**
85
210
 
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
- ];
211
+ Você pode criar e usar componentes customizados nos formulários para necessidades específicas:
92
212
 
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
- ];
213
+ ```typescript
214
+ // Exemplo de campo customizado
215
+ {
216
+ name: 'custom_field',
217
+ label: 'Campo Customizado',
218
+ type: 'my-custom-component' as const,
219
+ required: true
220
+ }
221
+ ```
103
222
 
104
- // 5. Exportar página
105
- export default createCrudPage({
106
- useCrud: useEmployeesCrud,
107
- columns,
108
- formSections,
109
- title: 'Funcionários'
110
- });
223
+ > **Nota:** Componentes customizados devem ser registrados no `BaseForm.tsx` para funcionarem corretamente nos formulários CRUD.
224
+
225
+ **⚠️ CRÍTICO:** Requests Qualiex exigem header `un-alias`:
226
+ ```typescript
227
+ // ✅ Já configurado no BaseService automaticamente
228
+ headers: { 'un-alias': 'true' }
111
229
  ```
112
230
 
113
231
  ---
114
232
 
115
- ## 📚 Documentação Completa
233
+ ## 🗃️ MIGRATIONS + RLS
234
+
235
+ ### Template SQL Completo
236
+ ```sql
237
+ -- 1️⃣ Criar tabela
238
+ CREATE TABLE central.processes (
239
+ id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
240
+ id_user UUID, -- ⚠️ NUNCA foreign key para auth.users
241
+ title TEXT NOT NULL,
242
+ description TEXT,
243
+ status TEXT DEFAULT 'draft',
244
+ created_at TIMESTAMPTZ DEFAULT now(),
245
+ updated_at TIMESTAMPTZ DEFAULT now(),
246
+ deleted BOOLEAN DEFAULT false
247
+ );
248
+
249
+ -- 2️⃣ Habilitar RLS
250
+ ALTER TABLE central.processes ENABLE ROW LEVEL SECURITY;
251
+
252
+ -- 3️⃣ Políticas RLS (usar 'alias', nunca 'id_user')
253
+ CREATE POLICY "Users view own processes"
254
+ ON central.processes FOR SELECT
255
+ USING (alias = auth.uid()); -- ⚠️ 'alias', não 'id_user'
256
+
257
+ CREATE POLICY "Users insert own processes"
258
+ ON central.processes FOR INSERT
259
+ WITH CHECK (alias = auth.uid());
260
+
261
+ CREATE POLICY "Users update own processes"
262
+ ON central.processes FOR UPDATE
263
+ USING (alias = auth.uid());
264
+
265
+ -- 4️⃣ Trigger updated_at
266
+ CREATE TRIGGER set_updated_at
267
+ BEFORE UPDATE ON central.processes
268
+ FOR EACH ROW
269
+ EXECUTE FUNCTION public.set_updated_at();
270
+
271
+ -- 5️⃣ Índices (apenas se necessário)
272
+ -- ⚠️ NÃO criar automaticamente - solicitar aprovação
273
+ -- CREATE INDEX idx_processes_user ON central.processes(id_user);
274
+ ```
116
275
 
117
- A documentação detalhada está disponível em:
276
+ ### Sintaxes Proibidas RLS
277
+ ```sql
278
+ -- NUNCA usar 'id' ou 'id_user' direto
279
+ id_user = auth.uid() -- ❌ ERRADO
280
+ id = auth.uid() -- ❌ ERRADO
118
281
 
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
282
+ -- SEMPRE usar 'alias'
283
+ alias = auth.uid() -- CORRETO
284
+ ```
123
285
 
124
286
  ---
125
287
 
126
- ## 🎯 Recursos Principais
288
+ ## 🐛 TROUBLESHOOTING
127
289
 
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)
290
+ ### 1️⃣ "relation does not exist"
291
+ ```typescript
292
+ // Causa: Schema ausente
293
+ .from('processes') //
133
294
 
134
- ### 🔐 Autenticação
135
- - Login/logout automático
136
- - Proteção de rotas
137
- - Integração com Supabase Auth
138
- - Gerenciamento de tokens
295
+ // Solução:
296
+ .from('processes', { schema: 'central' }) // ✅
297
+ ```
139
298
 
140
- ### 🎨 Componentes UI
141
- - 50+ componentes prontos (shadcn/ui)
142
- - Design system completo
143
- - Dark mode nativo
144
- - Totalmente customizável
299
+ ### 2️⃣ RLS retorna vazio
300
+ ```sql
301
+ -- Causa: Sintaxe incorreta
302
+ USING (id_user = auth.uid()) -- ❌
145
303
 
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
304
+ -- Solução:
305
+ USING (alias = auth.uid()) --
306
+ ```
150
307
 
151
- ---
308
+ ### 3️⃣ Duplicação de registros
309
+ ```typescript
310
+ // Causa: ID ausente no update
311
+ await service.save({ title: 'Novo' }); // ❌ Cria duplicado
152
312
 
153
- ## 💡 Exemplo de Uso Completo
313
+ // Solução: Preservar ID
314
+ await service.save({ id: item.id, title: 'Novo' }); // ✅
315
+ ```
154
316
 
155
- ```tsx
156
- import {
157
- createCrudPage,
158
- createSimpleService,
159
- useCrud,
160
- QualiexUserField
161
- } from 'forlogic-core';
317
+ ### 4️⃣ Página recarrega ao editar
318
+ ```typescript
319
+ // Causa: Config sem useMemo
320
+ const config = generateCrudConfig(...); // ❌ Re-render infinito
162
321
 
163
- interface Task {
164
- id?: string;
165
- title: string;
166
- description: string;
167
- responsible_id: string;
168
- status: 'pending' | 'in_progress' | 'done';
169
- }
322
+ // Solução:
323
+ const config = useMemo(() => generateCrudConfig(...), []); // ✅
324
+ ```
170
325
 
171
- const service = createSimpleService<Task>('tasks', {
172
- schemaName: 'central'
173
- });
326
+ ### 5️⃣ Estado reseta ao navegar
327
+ ```typescript
328
+ // Causa: Outlet ausente
329
+ <Route path="/processes" element={<ProcessesPage />} /> // ❌
174
330
 
175
- const useTasksCrud = () => useCrud({ service, queryKey: 'tasks' });
176
-
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
- });
331
+ // Solução: Layout com Outlet
332
+ <Route path="/processes" element={<ProcessLayout />}>
333
+ <Route index element={<ProcessesPage />} />
334
+ </Route>
335
+ // ProcessLayout: return <Outlet />; // ✅
336
+ ```
337
+
338
+ ### 6️⃣ Qualiex retorna 401
339
+ ```typescript
340
+ // Causa: Header ausente
341
+ fetch(url); //
342
+
343
+ // Solução: Adicionar header
344
+ fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
345
+ // (BaseService já faz automaticamente)
210
346
  ```
211
347
 
212
348
  ---
213
349
 
214
- ## 🔧 Configuração Avançada
350
+ ## 📐 CONTROLE DE LARGURA DAS COLUNAS
215
351
 
216
- ### Import Modular (Tree-shaking)
352
+ O `forlogic-core` oferece três formas de definir larguras de colunas nas tabelas CRUD:
217
353
 
218
- Para bundles menores, use imports específicos:
354
+ ### **1️⃣ Via `className` (Recomendado)**
355
+ Use classes do Tailwind para larguras fixas ou responsivas:
356
+ ```typescript
357
+ const columns = [
358
+ {
359
+ key: 'status',
360
+ header: 'Status',
361
+ className: 'w-24 text-center', // Largura fixa: 96px
362
+ },
363
+ {
364
+ key: 'updated_at',
365
+ header: 'Atualizado em',
366
+ className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
367
+ },
368
+ ];
369
+ ```
219
370
 
220
- ```tsx
221
- import { Button, Input, Card } from 'forlogic-core/modular';
371
+ ### **2️⃣ Via `width` (Fixo em pixels)**
372
+ Especifique largura fixa diretamente:
373
+ ```typescript
374
+ {
375
+ key: 'order',
376
+ header: 'Ordem',
377
+ width: 60, // Largura fixa: 60px
378
+ className: 'text-center',
379
+ }
222
380
  ```
223
381
 
224
- ### Customização de Tema
382
+ ### **3️⃣ Via `minWidth` + `weight` (Flexível)**
383
+ Para colunas que crescem proporcionalmente:
384
+ ```typescript
385
+ {
386
+ key: 'description',
387
+ header: 'Descrição',
388
+ minWidth: 200, // Mínimo: 200px
389
+ weight: 2, // 2x mais espaço que colunas padrão (weight: 1)
390
+ }
391
+ ```
225
392
 
226
- Edite `index.css` no seu projeto:
393
+ ### **⚠️ Importante**
394
+ - A tabela usa `table-auto` para respeitar essas configurações
395
+ - Para truncar textos longos, use: `className: "max-w-[200px] truncate"`
396
+ - Combine `whitespace-nowrap` com largura fixa para evitar quebras
227
397
 
228
- ```css
229
- :root {
230
- --primary: 220 70% 50%;
231
- --secondary: 210 40% 96.1%;
232
- /* ... outros tokens */
233
- }
398
+ ### **📋 Exemplo Completo**
399
+ ```typescript
400
+ const columns: CrudColumn<MyEntity>[] = [
401
+ {
402
+ key: 'order',
403
+ header: 'Ordem',
404
+ width: 60, // Fixo: 60px
405
+ className: 'text-center',
406
+ },
407
+ {
408
+ key: 'title',
409
+ header: 'Título',
410
+ minWidth: 200, // Mínimo: 200px, cresce conforme espaço disponível
411
+ weight: 3, // 3x mais espaço que colunas padrão
412
+ },
413
+ {
414
+ key: 'status',
415
+ header: 'Status',
416
+ className: 'w-24 text-center', // Tailwind: 96px
417
+ },
418
+ {
419
+ key: 'progress',
420
+ header: 'Nível & Progresso',
421
+ className: 'w-40 text-center', // Tailwind: 160px
422
+ },
423
+ {
424
+ key: 'updated_at',
425
+ header: 'Atualizado em',
426
+ className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
427
+ render: (item) => formatDate(item.updated_at)
428
+ },
429
+ ];
234
430
  ```
235
431
 
236
432
  ---
237
433
 
238
- ## 📖 Links Úteis
434
+ ## 📚 REFERÊNCIA RÁPIDA
435
+
436
+ ### Imports Essenciais
437
+ ```typescript
438
+ // CRUD
439
+ import {
440
+ createSimpleService,
441
+ createCrudPage,
442
+ generateCrudConfig,
443
+ createSimpleSaveHandler
444
+ } from 'forlogic-core';
445
+
446
+ // UI
447
+ import { Button, Input, Card, toast } from 'forlogic-core/ui';
239
448
 
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)
449
+ // Auth
450
+ import { useAuth, ProtectedRoute } from 'forlogic-core';
451
+
452
+ // Qualiex
453
+ import { QualiexUserField, useQualiexUsers } from 'forlogic-core';
454
+ ```
455
+
456
+ ### Estrutura de Arquivos
457
+ ```
458
+ src/
459
+ ├── processes/
460
+ │ ├── process.ts # Types
461
+ │ ├── processService.ts # Service + Hook
462
+ │ └── ProcessesPage.tsx # Page + Config
463
+ ```
243
464
 
244
465
  ---
245
466
 
246
467
  ## 📝 Licença
247
468
 
248
469
  MIT License - ForLogic © 2025
470
+
471
+ **Última atualização:** 2025-10-05