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/README.md CHANGED
@@ -1,36 +1,471 @@
1
- # 🧱 Documentação exclusiva para este projeto
1
+ # 🧱 Projeto atual
2
2
 
3
- > **Sistema empresarial com React + TypeScript + Supabase**
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'`.
6
+
7
+ ---
8
+
9
+ ## 🤖 REGRAS CRÍTICAS
10
+
11
+ ### ⚠️ TOP 3 ERROS
12
+
13
+ 1. **ESQUECER SCHEMA**
14
+ ```typescript
15
+ // ❌ ERRADO
16
+ .from('table')
17
+
18
+ // ✅ CORRETO
19
+ .schema('schema').from('table')
20
+ ```
21
+
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
+ ```
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);
37
+
38
+ -- ✅ Apenas quando solicitado explicitamente
39
+ ```
40
+
41
+ ---
42
+
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
55
+
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'
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
+ };
108
+ ```
109
+
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
+ ```
144
+
145
+ ### **5️⃣ Page + Outlet (preservar estado)**
146
+ ```typescript
147
+ // src/App.tsx
148
+ import { Outlet } from 'react-router-dom';
149
+
150
+ function App() {
151
+ return (
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>
159
+ );
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)
177
+ ```
178
+
179
+ **Componentes prontos:**
180
+ ```typescript
181
+ import { QualiexUserField, QualiexResponsibleSelectField } from 'forlogic-core';
182
+
183
+ // Select de usuários Qualiex
184
+ <QualiexResponsibleSelectField
185
+ value={form.watch('id_user')}
186
+ onChange={(userId) => form.setValue('id_user', userId)}
187
+ />
188
+ ```
189
+
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
198
+ }
199
+
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
+ ```
208
+
209
+ **Componentes customizados:**
210
+
211
+ Você pode criar e usar componentes customizados nos formulários para necessidades específicas:
212
+
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
+ ```
222
+
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' }
229
+ ```
230
+
231
+ ---
232
+
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
+ ```
275
+
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
281
+
282
+ -- SEMPRE usar 'alias'
283
+ alias = auth.uid() -- ✅ CORRETO
284
+ ```
285
+
286
+ ---
287
+
288
+ ## 🐛 TROUBLESHOOTING
289
+
290
+ ### 1️⃣ "relation does not exist"
291
+ ```typescript
292
+ // Causa: Schema ausente
293
+ .from('processes') // ❌
294
+
295
+ // Solução:
296
+ .from('processes', { schema: 'central' }) // ✅
297
+ ```
298
+
299
+ ### 2️⃣ RLS retorna vazio
300
+ ```sql
301
+ -- Causa: Sintaxe incorreta
302
+ USING (id_user = auth.uid()) -- ❌
303
+
304
+ -- Solução:
305
+ USING (alias = auth.uid()) -- ✅
306
+ ```
307
+
308
+ ### 3️⃣ Duplicação de registros
309
+ ```typescript
310
+ // Causa: ID ausente no update
311
+ await service.save({ title: 'Novo' }); // ❌ Cria duplicado
312
+
313
+ // Solução: Preservar ID
314
+ await service.save({ id: item.id, title: 'Novo' }); // ✅
315
+ ```
316
+
317
+ ### 4️⃣ Página recarrega ao editar
318
+ ```typescript
319
+ // Causa: Config sem useMemo
320
+ const config = generateCrudConfig(...); // ❌ Re-render infinito
321
+
322
+ // Solução:
323
+ const config = useMemo(() => generateCrudConfig(...), []); // ✅
324
+ ```
325
+
326
+ ### 5️⃣ Estado reseta ao navegar
327
+ ```typescript
328
+ // Causa: Outlet ausente
329
+ <Route path="/processes" element={<ProcessesPage />} /> // ❌
330
+
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)
346
+ ```
4
347
 
5
348
  ---
6
349
 
7
- ## ⚙️ Configuração deste Projeto
350
+ ## 📐 CONTROLE DE LARGURA DAS COLUNAS
351
+
352
+ O `forlogic-core` oferece três formas de definir larguras de colunas nas tabelas CRUD:
353
+
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
+ ```
370
+
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
+ }
380
+ ```
8
381
 
9
- ### 🗄️ Schema do Banco
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
+ ```
10
392
 
11
- Schema padrão deste projeto: **`central`**
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
12
397
 
13
- ## 🤖 Instruções para IA (Lovable)
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
+ ];
430
+ ```
14
431
 
15
- ⚠️ **CONSULTAR SEMPRE antes de qualquer modificação:**
432
+ ---
433
+
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';
16
445
 
17
- 1. **README.md da lib**: Acesse via `node_modules/forlogic-core/dist/README.md` - Instalação e Quick Start
18
- 2. **AI_RULES.md**: Acesse via `node_modules/forlogic-core/dist/docs/AI_RULES.md` - **REGRAS CRÍTICAS**
19
- 3. **Templates**: Acesse via `node_modules/forlogic-core/dist/docs/templates/` - Códigos prontos
20
- 4. **Hub da Docs**: Acesse via `node_modules/forlogic-core/dist/docs/README.md` - Navegação completa
446
+ // UI
447
+ import { Button, Input, Card, toast } from 'forlogic-core/ui';
21
448
 
22
- **NUNCA recriar:**
23
- - Integração Qualiex (já existe na lib)
24
- - ❌ Integração Supabase (já existe na lib)
25
- - ❌ Sistema CRUD (usar `createCrudPage` da lib)
26
- - ❌ Componentes base (importar de `forlogic-core`)
449
+ // Auth
450
+ import { useAuth, ProtectedRoute } from 'forlogic-core';
27
451
 
28
- **SEMPRE verificar:**
29
- - Schema padrão do projeto
30
- - ✅ Templates disponíveis antes de criar do zero
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
+ ```
31
464
 
32
465
  ---
33
466
 
34
467
  ## 📝 Licença
35
468
 
36
- MIT License - ForLogic © 2025
469
+ MIT License - ForLogic © 2025
470
+
471
+ **Última atualização:** 2025-10-05