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 +455 -20
- package/dist/README.md +394 -171
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/docs/AI_RULES.md +0 -213
- package/dist/docs/README.md +0 -102
- package/dist/docs/TROUBLESHOOTING.md +0 -473
- package/dist/docs/architecture/TOKENS_ARCHITECTURE.md +0 -712
- package/dist/docs/templates/app-layout.tsx +0 -192
- package/dist/docs/templates/basic-crud-page.tsx +0 -97
- package/dist/docs/templates/basic-crud-working.tsx +0 -182
- package/dist/docs/templates/complete-crud-example.tsx +0 -307
- package/dist/docs/templates/custom-form.tsx +0 -99
- package/dist/docs/templates/custom-service.tsx +0 -194
- package/dist/docs/templates/permission-check-hook.tsx +0 -275
- package/dist/docs/templates/qualiex-config.ts +0 -137
- package/dist/docs/templates/qualiex-integration-example.tsx +0 -430
- package/dist/docs/templates/quick-start-example.tsx +0 -96
- package/dist/docs/templates/rls-policies.sql +0 -80
- package/dist/docs/templates/sidebar-config.tsx +0 -145
package/README.md
CHANGED
|
@@ -1,36 +1,471 @@
|
|
|
1
|
-
# 🧱
|
|
1
|
+
# 🧱 Projeto atual
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
##
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|