forlogic-core 1.16.10 → 1.16.12
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/.note/memory/features/crud-defaults-batteries-included.md +14 -0
- package/.note/memory/patterns/alias-url-resolution.md +39 -0
- package/.note/memory/{rules → patterns}/doc-sync-rule.md +1 -1
- package/.note/memory/patterns/dynamic-supabase-config.md +4 -0
- package/.note/memory/patterns/environment-detection-logic.md +35 -0
- package/dist/auth/components/AliasRouteGuard.d.ts +25 -0
- package/dist/auth/services/AuthService.d.ts +1 -1
- package/dist/auth/services/TokenManager.d.ts +6 -0
- package/dist/bin/pull-docs.js +106 -28
- package/dist/config/index.d.ts +8 -0
- package/dist/crud/components/ColumnSettingsPopover.d.ts +2 -1
- package/dist/crud/components/CrudTable.d.ts +3 -1
- package/dist/crud/hooks/useColumnManager.d.ts +2 -0
- package/dist/crud/primitives/TreeTable.d.ts +1 -1
- package/dist/crud/primitives/types.d.ts +11 -0
- package/dist/docs/KNOWLEDGE.md +9 -7
- package/dist/hooks/useAliasFromUrl.d.ts +33 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/leadership/components/LeadershipPage.d.ts +12 -1
- package/dist/leadership/index.d.ts +0 -1
- package/dist/leadership/types.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/linkHelpers.d.ts +5 -0
- package/docs/KNOWLEDGE.md +9 -7
- package/package.json +2 -2
- package/.note/memory/architecture/documentation-strategy.md +0 -59
- package/.note/memory/patterns/deprecated-patterns.md +0 -14
- package/.note/memory/patterns/spa-navigation-pattern.md +0 -19
- package/.note/memory/rules/i18n-import-rule.md +0 -29
- package/.note/memory/rules/lib-first-rule.md +0 -42
- package/.note/memory/rules/no-auto-index-rule.md +0 -48
- package/.note/memory/rules/no-delete-policy-rule.md +0 -52
- package/.note/memory/rules/no-env-modification-rule.md +0 -19
- package/.note/memory/rules/rls-syntax-rule.md +0 -50
- package/.note/memory/rules/sql-naming-rule.md +0 -23
- package/.note/memory/rules/supabase-import-rule.md +0 -31
- package/.note/memory/rules/supabase-schema-rule.md +0 -20
- /package/.note/memory/{ui/components → components}/combo-tree.md +0 -0
- /package/.note/memory/{documentation/consolidated-components-registry.md → patterns/components-registry.md} +0 -0
- /package/.note/memory/{ui/design-system → patterns}/documentation-standard.md +0 -0
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { UnassociatedUser } from '../types';
|
|
2
|
+
export interface LeadershipPageProps {
|
|
3
|
+
/** Lista de usuários não associados à hierarquia (fornecida pelo consumidor) */
|
|
4
|
+
unassociatedUsers?: UnassociatedUser[];
|
|
5
|
+
/** Callback quando um usuário não associado é movido para a hierarquia */
|
|
6
|
+
onAssociateUser?: (userId: string, targetLeaderId: string | null) => void;
|
|
7
|
+
/** Callback para movimentação customizada (default: usa useUpdateLeaderMutation) */
|
|
8
|
+
onMoveNode?: (draggedId: string, targetId: string | null) => void;
|
|
9
|
+
/** Callback para movimentação em lote customizada */
|
|
10
|
+
onMoveNodes?: (draggedIds: string[], targetId: string | null) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function LeadershipPage({ unassociatedUsers, onAssociateUser, onMoveNode: customMoveNode, onMoveNodes: customMoveNodes, }?: LeadershipPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,6 +9,5 @@ export * from './utils/leadershipUtils';
|
|
|
9
9
|
export * from './hooks/useLeadershipApi';
|
|
10
10
|
export * from './hooks/useLeadershipMutations';
|
|
11
11
|
export * from './components/LeadershipPage';
|
|
12
|
-
export * from './components/LeaderRow';
|
|
13
12
|
export * from './components/LeadershipDialog';
|
|
14
13
|
export * from './components/LeadershipForm';
|
|
@@ -10,6 +10,12 @@ export interface Leader {
|
|
|
10
10
|
name?: string;
|
|
11
11
|
email?: string;
|
|
12
12
|
subordinatesCount?: number;
|
|
13
|
+
subordinateNames?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface UnassociatedUser {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
email: string;
|
|
13
19
|
}
|
|
14
20
|
export interface LeaderNode extends Leader {
|
|
15
21
|
children: LeaderNode[];
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ export { formatDatetime, formatDate } from './formatters/dateFormatters';
|
|
|
5
5
|
export { formatCurrency } from './formatters/currencyFormatters';
|
|
6
6
|
export declare const debounce: <T extends (...args: any[]) => any>(func: T, wait: number) => ((...args: Parameters<T>) => void);
|
|
7
7
|
export declare const slugify: (text: string) => string;
|
|
8
|
-
export { handleExternalLink } from './linkHelpers';
|
|
8
|
+
export { handleExternalLink, buildModuleUrl } from './linkHelpers';
|
|
@@ -2,3 +2,8 @@
|
|
|
2
2
|
* Abre link externo em nova aba ou copia para clipboard se bloqueado pelo navegador
|
|
3
3
|
*/
|
|
4
4
|
export declare function handleExternalLink(url: string, e?: React.MouseEvent): void;
|
|
5
|
+
/**
|
|
6
|
+
* Substitui placeholders `{alias}` em uma URL de módulo pelo alias ativo.
|
|
7
|
+
* Se alias não fornecido, retorna a URL original.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildModuleUrl(urlTemplate: string, alias?: string): string;
|
package/docs/KNOWLEDGE.md
CHANGED
|
@@ -98,10 +98,12 @@ supabase.from('tabela').select('*');
|
|
|
98
98
|
|
|
99
99
|
## 6. Fontes de Contexto
|
|
100
100
|
|
|
101
|
-
| Fonte | Caminho |
|
|
102
|
-
|
|
103
|
-
| Memory
|
|
104
|
-
| Memory patterns | `.note/memory/patterns/` |
|
|
105
|
-
| Memory
|
|
106
|
-
| Código-fonte da lib | Cross-project → projeto **Admin** (forlogic-core) |
|
|
107
|
-
| Design System (visual) | Rota `/ds` no app do projeto **Admin** |
|
|
101
|
+
| Fonte | Caminho | Conteúdo |
|
|
102
|
+
|-------|---------|----------|
|
|
103
|
+
| Memory components | `.note/memory/components/` | Props, variantes e exemplos de componentes |
|
|
104
|
+
| Memory patterns | `.note/memory/patterns/` | Layouts, setup, convenções, regras do projeto |
|
|
105
|
+
| Memory features | `.note/memory/features/` | Contexto de features específicas do projeto |
|
|
106
|
+
| Código-fonte da lib | Cross-project → projeto **Admin** (forlogic-core) | Props, tipos, implementação |
|
|
107
|
+
| Design System (visual) | Rota `/ds` no app do projeto **Admin** | Documentação interativa |
|
|
108
|
+
|
|
109
|
+
> ℹ️ `.note/memory/` usa 3 pastas padronizadas: `components/`, `patterns/`, `features/`. `KNOWLEDGE.md` é a fonte única de verdade para regras e convenções.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forlogic-core",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@radix-ui/react-toggle": "^1.1.9",
|
|
75
75
|
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
76
76
|
"@radix-ui/react-tooltip": "^1.2.7",
|
|
77
|
-
"@supabase/supabase-js": "^2.
|
|
77
|
+
"@supabase/supabase-js": "^2.100.0",
|
|
78
78
|
"@tanstack/react-query": "^5.83.0",
|
|
79
79
|
"@tiptap/extension-color": "^3.14.0",
|
|
80
80
|
"@tiptap/extension-highlight": "^3.14.0",
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Estratégia de Documentação
|
|
2
|
-
|
|
3
|
-
## Fonte de verdade
|
|
4
|
-
|
|
5
|
-
| Tipo | Local | Sincronizado via `lib-update` |
|
|
6
|
-
|------|-------|-------------------------------|
|
|
7
|
-
| Regras críticas | `docs/KNOWLEDGE.md` | Sim |
|
|
8
|
-
| Regras da IA | `.note/memory/rules/` | Sim |
|
|
9
|
-
| Padrões de layout | `.note/memory/patterns/` | Não (cross-project) |
|
|
10
|
-
| Componentes/UI | `.note/memory/components/` | Não (cross-project) |
|
|
11
|
-
| Arquitetura | `.note/memory/architecture/` | Não (cross-project) |
|
|
12
|
-
| Design System visual | Rota `/ds` no app | — |
|
|
13
|
-
| Props e tipos | Código-fonte da lib | Cross-project |
|
|
14
|
-
|
|
15
|
-
## Memórias por categoria
|
|
16
|
-
|
|
17
|
-
### Rules (sincronizadas)
|
|
18
|
-
- `supabase-schema-rule` — Schema obrigatório em queries
|
|
19
|
-
- `supabase-import-rule` — Usar getSupabaseClient() da lib
|
|
20
|
-
- `no-delete-policy-rule` — Soft delete, sem FOR DELETE
|
|
21
|
-
- `no-auto-index-rule` — Sem índices preventivos
|
|
22
|
-
- `no-env-modification-rule` — Sem alterar .env
|
|
23
|
-
- `rls-syntax-rule` — Sintaxe RLS por operação
|
|
24
|
-
- `sql-naming-rule` — Nomenclatura de tabelas, FKs, booleans
|
|
25
|
-
- `lib-first-rule` — Priorizar forlogic-core
|
|
26
|
-
- `i18n-import-rule` — Import de forlogic-core, não react-i18next
|
|
27
|
-
- `doc-sync-rule` — Como funciona o lib-update
|
|
28
|
-
|
|
29
|
-
### Patterns (cross-project)
|
|
30
|
-
- `vite-tailwind-setup` — Config de build e preset
|
|
31
|
-
- `feature-flags` — Variáveis de ambiente disponíveis
|
|
32
|
-
- `i18n-setup` — Namespaces core/app
|
|
33
|
-
- `core-providers-setup` — Hierarquia de providers
|
|
34
|
-
- `header-metadata-pattern` — usePageMetadata
|
|
35
|
-
- `spa-navigation-pattern` — Navegação SPA
|
|
36
|
-
- `crud-toolbar-layout` — Layout 3 zonas
|
|
37
|
-
- `crud-action-bar-3-zone-layout` — ActionBar zones
|
|
38
|
-
- `crud-bulk-actions-dropdown-standard` — Ações em lote
|
|
39
|
-
- `single-scroll-pattern` — Scroll único
|
|
40
|
-
- `dialog-body-scroll-pattern` — Scroll em dialogs
|
|
41
|
-
- `body-content-scroll-usage` — BodyContent
|
|
42
|
-
- `deprecated-patterns` — Mapa de substituição
|
|
43
|
-
|
|
44
|
-
### Components (cross-project)
|
|
45
|
-
- `action-button-for-tables` — ActionButton em tabelas
|
|
46
|
-
- `alertdialog-permanent-deletion` — AlertDialog
|
|
47
|
-
- `baseform-custom-fields` — Campos customizados
|
|
48
|
-
- `baseform-usage` — Uso do BaseForm
|
|
49
|
-
- `delete-confirmation-dialog` — Dialog destrutivo
|
|
50
|
-
- `dialog-sizes-and-structure` — Tamanhos de dialog
|
|
51
|
-
- `dialog-variants` — Variantes de dialog
|
|
52
|
-
- `pagination-usage` — CrudPrimitivePagination
|
|
53
|
-
|
|
54
|
-
## O que NÃO é sincronizado
|
|
55
|
-
|
|
56
|
-
- `docs/PUBLISH.md` — Operacional
|
|
57
|
-
- `lib/media/README.md` — Coberto pelo DS
|
|
58
|
-
- Templates Vite completos — Coberto por patterns
|
|
59
|
-
- Referência de API de componentes — Coberto pelo DS (`/ds`)
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Padrões Deprecated
|
|
2
|
-
|
|
3
|
-
## Mapa de substituição
|
|
4
|
-
|
|
5
|
-
| Não usar | Usar | Motivo |
|
|
6
|
-
|----------|------|--------|
|
|
7
|
-
| `BulkActionBar` separado | Dropdown integrado no `CrudActionBar` | Consolidação de toolbar |
|
|
8
|
-
| `<MoreHorizontal>` genérico | `ActionButton` da lib | Padrão consistente de ações |
|
|
9
|
-
| Paginação manual | `CrudPrimitivePagination` com `variant="full"` | API unificada |
|
|
10
|
-
| `StatusSelect` | `Combobox` | Componente mais flexível |
|
|
11
|
-
| `DeleteConfirmationDialog` | `Dialog` com variant destrutiva | Componente padrão da lib |
|
|
12
|
-
| `Searchbar` | `Input` com ícone de busca | Simplificação |
|
|
13
|
-
| Schema `public` | `.schema('common')` | Schema customizado do projeto |
|
|
14
|
-
| `import { supabase }` local | `getSupabaseClient()` de `forlogic-core` | Auth headers automáticos |
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Memory: patterns/spa-navigation-pattern
|
|
2
|
-
Updated: now
|
|
3
|
-
|
|
4
|
-
Navegação SPA deve usar componentes do React Router, nunca `<a href>` ou `window.location`.
|
|
5
|
-
|
|
6
|
-
```tsx
|
|
7
|
-
// ❌ ERRADO - recarrega página inteira
|
|
8
|
-
<a href="/dashboard">Dashboard</a>
|
|
9
|
-
window.location.href = '/page';
|
|
10
|
-
|
|
11
|
-
// ✅ CORRETO - navegação SPA sem reload
|
|
12
|
-
import { Link, useNavigate } from 'react-router-dom';
|
|
13
|
-
|
|
14
|
-
<Link to="/dashboard">Dashboard</Link>
|
|
15
|
-
const navigate = useNavigate();
|
|
16
|
-
navigate('/page');
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
**Exceção**: Links externos devem usar `<a>` com `target="_blank"` e `rel="noopener noreferrer"`.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Regra: Import de i18n
|
|
2
|
-
|
|
3
|
-
## Regra
|
|
4
|
-
|
|
5
|
-
Sempre importar `useTranslation` de `forlogic-core`, nunca de `react-i18next`.
|
|
6
|
-
|
|
7
|
-
## Motivo
|
|
8
|
-
|
|
9
|
-
Importar de `react-i18next` cria uma instância separada do i18next, causando erro `NO_I18NEXT_INSTANCE` e traduções não funcionam.
|
|
10
|
-
|
|
11
|
-
## Correto
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { useTranslation } from 'forlogic-core';
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Errado
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { useTranslation } from 'react-i18next';
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Aplica-se a
|
|
24
|
-
|
|
25
|
-
- `useTranslation`
|
|
26
|
-
- `i18n` (instância)
|
|
27
|
-
- Qualquer hook/utilidade de i18n
|
|
28
|
-
|
|
29
|
-
Todos devem vir de `forlogic-core` para compartilhar a mesma instância configurada pelo `CoreProviders`.
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Regra: Lib-First (forlogic-core)
|
|
2
|
-
|
|
3
|
-
## Regra
|
|
4
|
-
|
|
5
|
-
Antes de criar qualquer componente, serviço ou utilitário no projeto, verificar se já existe na `forlogic-core`.
|
|
6
|
-
|
|
7
|
-
## Checklist obrigatório
|
|
8
|
-
|
|
9
|
-
1. Pesquisar se o componente existe na forlogic-core (`lib/index.ts`, `lib/exports/`)
|
|
10
|
-
2. Verificar documentação do Design System (`/ds`)
|
|
11
|
-
3. Confirmar que a funcionalidade não pode ser alcançada com props/variantes existentes
|
|
12
|
-
|
|
13
|
-
## Correto
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { Button, Dialog, Combobox, createCrudPage, cn, formatDatetime } from 'forlogic-core';
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Proibido (se existe na lib)
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
src/components/ui/button.tsx // Existe na lib
|
|
23
|
-
src/components/ui/dialog.tsx // Existe na lib
|
|
24
|
-
src/lib/utils.ts // cn() existe na lib
|
|
25
|
-
src/components/SplitButton.tsx // Existe na lib
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Exceções (quando PODE criar localmente)
|
|
29
|
-
|
|
30
|
-
1. Componente específico de negócio (ex: `InvoiceCard`, `UserProfileWidget`)
|
|
31
|
-
2. Composição de componentes da lib (ex: wrapper que combina Dialog + Form)
|
|
32
|
-
3. Componente temporário (protótipo que será migrado para a lib)
|
|
33
|
-
4. Funcionalidade não generalizável
|
|
34
|
-
|
|
35
|
-
## Quando precisa de customização
|
|
36
|
-
|
|
37
|
-
| Cenário | Ação correta |
|
|
38
|
-
|---------|-------------|
|
|
39
|
-
| Componente não existe na lib | Criar localmente E solicitar inclusão na lib |
|
|
40
|
-
| Precisa de variante nova | Solicitar variante na lib |
|
|
41
|
-
| Precisa de comportamento específico | Usar composição/wrapper |
|
|
42
|
-
| Bug no componente da lib | Reportar e corrigir na lib, não criar cópia local |
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Regra: Sem índices automáticos
|
|
2
|
-
|
|
3
|
-
**NUNCA** criar índices automaticamente em migrations.
|
|
4
|
-
|
|
5
|
-
## Errado
|
|
6
|
-
|
|
7
|
-
```sql
|
|
8
|
-
-- ❌ Índice "por precaução"
|
|
9
|
-
CREATE INDEX idx_subprocess_process ON common.subprocesses(id_process);
|
|
10
|
-
CREATE INDEX idx_process_title ON common.processes(title);
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Correto
|
|
14
|
-
|
|
15
|
-
```sql
|
|
16
|
-
-- ✅ Criar tabela SEM índices
|
|
17
|
-
CREATE TABLE common.processes (
|
|
18
|
-
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
19
|
-
title TEXT NOT NULL,
|
|
20
|
-
id_process UUID REFERENCES common.processes(id),
|
|
21
|
-
created_at TIMESTAMPTZ DEFAULT now()
|
|
22
|
-
);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Quando criar índices
|
|
26
|
-
|
|
27
|
-
APENAS quando:
|
|
28
|
-
1. Solicitado explicitamente pelo usuário
|
|
29
|
-
2. Análise de performance comprovou necessidade (`EXPLAIN ANALYZE`)
|
|
30
|
-
3. Aprovação prévia do usuário
|
|
31
|
-
|
|
32
|
-
## Template (quando aprovado)
|
|
33
|
-
|
|
34
|
-
```sql
|
|
35
|
-
-- Migration: add_index_<table>_<column>
|
|
36
|
-
-- Motivo: [justificativa com dados de EXPLAIN ANALYZE]
|
|
37
|
-
-- Aprovado por: [usuário]
|
|
38
|
-
CREATE INDEX idx_<table>_<column> ON common.<table>(<column>);
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Checklist de migration
|
|
42
|
-
|
|
43
|
-
- [ ] Tabela criada sem índices extras
|
|
44
|
-
- [ ] RLS habilitado (`ALTER TABLE ... ENABLE ROW LEVEL SECURITY`)
|
|
45
|
-
- [ ] Policies criadas (SELECT, INSERT, UPDATE — nunca DELETE)
|
|
46
|
-
- [ ] Soft delete configurado (`deleted_at` column)
|
|
47
|
-
|
|
48
|
-
**Motivo**: Índices custam espaço, impactam escrita e 99% dos "preventivos" nunca são usados.
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Regra: Sem DELETE físico
|
|
2
|
-
|
|
3
|
-
**NUNCA** criar política RLS de DELETE. Usar soft delete com UPDATE.
|
|
4
|
-
|
|
5
|
-
## Implementação
|
|
6
|
-
|
|
7
|
-
```sql
|
|
8
|
-
-- 1. Adicionar coluna de soft delete
|
|
9
|
-
ALTER TABLE common.tabela ADD COLUMN deleted_at TIMESTAMP WITH TIME ZONE;
|
|
10
|
-
|
|
11
|
-
-- 2. Policy SELECT filtrando deletados
|
|
12
|
-
CREATE POLICY "table_select" ON common.tabela
|
|
13
|
-
FOR SELECT USING (
|
|
14
|
-
deleted_at IS NULL
|
|
15
|
-
AND ((SELECT auth.jwt()) ->> 'alias'::text) = alias
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
-- 3. Policy UPDATE para permitir soft delete
|
|
19
|
-
CREATE POLICY "table_update" ON common.tabela
|
|
20
|
-
FOR UPDATE
|
|
21
|
-
USING (((SELECT auth.jwt()) ->> 'alias'::text) = alias)
|
|
22
|
-
WITH CHECK (((SELECT auth.jwt()) ->> 'alias'::text) = alias);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Errado
|
|
26
|
-
|
|
27
|
-
```sql
|
|
28
|
-
-- ❌ PROIBIDO
|
|
29
|
-
CREATE POLICY "table_delete" ON common.tabela
|
|
30
|
-
FOR DELETE USING (...);
|
|
31
|
-
|
|
32
|
-
-- ❌ DELETE físico no código
|
|
33
|
-
await supabase.schema('common').from('tabela').delete().eq('id', id);
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Correto no código
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// ✅ Soft delete via UPDATE
|
|
40
|
-
await supabase.schema('common')
|
|
41
|
-
.from('tabela')
|
|
42
|
-
.update({ deleted_at: new Date().toISOString() })
|
|
43
|
-
.eq('id', id);
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Sintaxe RLS
|
|
47
|
-
|
|
48
|
-
- `SELECT` → `USING`
|
|
49
|
-
- `INSERT` → `WITH CHECK`
|
|
50
|
-
- `UPDATE` → `USING` + `WITH CHECK`
|
|
51
|
-
|
|
52
|
-
**Motivo**: Soft delete preserva histórico e evita problemas de integridade referencial.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Memory: rules/no-env-modification-rule
|
|
2
|
-
Updated: now
|
|
3
|
-
|
|
4
|
-
**NUNCA** modificar o arquivo `.env` sem autorização EXPLÍCITA do usuário.
|
|
5
|
-
|
|
6
|
-
```bash
|
|
7
|
-
# ❌ PROIBIDO sem autorização
|
|
8
|
-
VITE_SUPABASE_URL="..."
|
|
9
|
-
VITE_QUALIEX_API_URL="..."
|
|
10
|
-
|
|
11
|
-
# ✅ CORRETO - perguntar antes
|
|
12
|
-
"Posso modificar o .env para alterar X?"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
**Quando modificar?** APENAS quando:
|
|
16
|
-
1. Solicitado explicitamente pelo usuário
|
|
17
|
-
2. Usuário aprovou a mudança de ambiente (dev/prod)
|
|
18
|
-
|
|
19
|
-
**Motivo**: O .env controla ambiente (dev/prod) e contém credenciais sensíveis.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Regra: Sintaxe RLS
|
|
2
|
-
|
|
3
|
-
## Sintaxe por operação
|
|
4
|
-
|
|
5
|
-
| Operação | Cláusula |
|
|
6
|
-
|----------|----------|
|
|
7
|
-
| SELECT | `USING` |
|
|
8
|
-
| INSERT | `WITH CHECK` |
|
|
9
|
-
| UPDATE | `USING` + `WITH CHECK` |
|
|
10
|
-
| DELETE | **PROIBIDO** (usar soft delete) |
|
|
11
|
-
|
|
12
|
-
## Padrão JWT com parênteses
|
|
13
|
-
|
|
14
|
-
Sempre usar `(SELECT auth.jwt())` com parênteses para evitar re-execução por linha:
|
|
15
|
-
|
|
16
|
-
```sql
|
|
17
|
-
-- ✅ Correto
|
|
18
|
-
CREATE POLICY "table_select" ON common.tabela
|
|
19
|
-
FOR SELECT USING (
|
|
20
|
-
((SELECT auth.jwt()) ->> 'alias'::text) = alias
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
-- ❌ Errado — re-executa por linha
|
|
24
|
-
CREATE POLICY "table_select" ON common.tabela
|
|
25
|
-
FOR SELECT USING (
|
|
26
|
-
(auth.jwt() ->> 'alias'::text) = alias
|
|
27
|
-
);
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Erros comuns
|
|
31
|
-
|
|
32
|
-
```sql
|
|
33
|
-
-- ❌ WITH CHECK em SELECT
|
|
34
|
-
FOR SELECT WITH CHECK (...);
|
|
35
|
-
|
|
36
|
-
-- ❌ USING em INSERT
|
|
37
|
-
FOR INSERT USING (...);
|
|
38
|
-
|
|
39
|
-
-- ❌ Parênteses extras no JWT
|
|
40
|
-
((SELECT (auth.jwt()) ->> 'alias'::text))
|
|
41
|
-
|
|
42
|
-
-- ❌ Policy DELETE
|
|
43
|
-
FOR DELETE USING (...);
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Padrões multi-tenant
|
|
47
|
-
|
|
48
|
-
- **Por alias**: `((SELECT auth.jwt()) ->> 'alias'::text) = alias`
|
|
49
|
-
- **Por user**: `auth.uid() = id_user`
|
|
50
|
-
- **Por company**: `company_id = ((SELECT auth.jwt()) -> 'user_metadata' ->> 'company_id')::uuid`
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Regra: Nomenclatura SQL
|
|
2
|
-
|
|
3
|
-
## Convenções
|
|
4
|
-
|
|
5
|
-
| Tipo | Padrão | Exemplo |
|
|
6
|
-
|------|--------|---------|
|
|
7
|
-
| Tabelas | plural, snake_case | `processes`, `user_roles` |
|
|
8
|
-
| FK | `id_<tabela_singular>` | `id_process`, `id_user` |
|
|
9
|
-
| Boolean | `is_` ou `has_` | `is_active`, `has_access` |
|
|
10
|
-
| Timestamps | sufixo `_at` | `created_at`, `updated_at`, `deleted_at` |
|
|
11
|
-
|
|
12
|
-
## Errado
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
-- ❌ FK sem prefixo id_
|
|
16
|
-
process_id, userId, fk_process
|
|
17
|
-
|
|
18
|
-
-- ❌ Boolean sem prefixo
|
|
19
|
-
active, verified, access
|
|
20
|
-
|
|
21
|
-
-- ❌ Tabela singular ou camelCase
|
|
22
|
-
process, userRole, UserRoles
|
|
23
|
-
```
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Regra: Import do Supabase
|
|
2
|
-
|
|
3
|
-
## Regra
|
|
4
|
-
|
|
5
|
-
Sempre usar `getSupabaseClient()` ou `getPublicSupabaseClient()` de `forlogic-core`. Nunca importar de `@/integrations/supabase/client` nem criar instâncias com `createClient`.
|
|
6
|
-
|
|
7
|
-
## Correto
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import { getSupabaseClient } from 'forlogic-core';
|
|
11
|
-
const supabase = getSupabaseClient();
|
|
12
|
-
|
|
13
|
-
// Para operações sem autenticação
|
|
14
|
-
import { getPublicSupabaseClient } from 'forlogic-core';
|
|
15
|
-
const publicClient = getPublicSupabaseClient();
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Errado
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
// ❌ Cliente local sem token do usuário
|
|
22
|
-
import { supabase } from '@/integrations/supabase/client';
|
|
23
|
-
|
|
24
|
-
// ❌ Instância manual sem headers de auth
|
|
25
|
-
import { createClient } from '@supabase/supabase-js';
|
|
26
|
-
const supabase = createClient(url, key);
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Motivo
|
|
30
|
-
|
|
31
|
-
O `getSupabaseClient()` injeta automaticamente o `supabase_token` do usuário nos headers, garantindo que as policies RLS funcionem. Clientes criados manualmente usam apenas a chave anônima, causando falhas silenciosas de permissão em schemas protegidos.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Memory: rules/supabase-schema-rule
|
|
2
|
-
Updated: now
|
|
3
|
-
|
|
4
|
-
**SEMPRE** use `.schema()` com o schema definido em `docs/KNOWLEDGE.md` (seção 0).
|
|
5
|
-
Leia o valor de lá antes de escrever qualquer query Supabase.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
// ✅ CORRETO — schema vem da seção 0 do KNOWLEDGE.md
|
|
9
|
-
const { data } = await supabase
|
|
10
|
-
.schema('<SCHEMA do KNOWLEDGE.md>')
|
|
11
|
-
.from('tabela')
|
|
12
|
-
.select('*');
|
|
13
|
-
|
|
14
|
-
// ❌ ERRADO - vai falhar em produção
|
|
15
|
-
const { data } = await supabase
|
|
16
|
-
.from('tabela')
|
|
17
|
-
.select('*');
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Motivo**: O projeto usa schema customizado (não o `public` padrão do Supabase). O valor exato está centralizado em `docs/KNOWLEDGE.md` seção 0.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|