forlogic-core 1.16.8 → 1.16.10

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.
Files changed (36) hide show
  1. package/.note/memory/architecture/documentation-strategy.md +59 -0
  2. package/.note/memory/patterns/core-providers-setup.md +39 -0
  3. package/.note/memory/patterns/deprecated-patterns.md +14 -0
  4. package/.note/memory/patterns/feature-flags.md +19 -0
  5. package/.note/memory/patterns/header-metadata-pattern.md +62 -0
  6. package/.note/memory/patterns/i18n-setup.md +43 -0
  7. package/.note/memory/patterns/vite-tailwind-setup.md +49 -0
  8. package/.note/memory/rules/doc-sync-rule.md +32 -0
  9. package/.note/memory/rules/i18n-import-rule.md +29 -0
  10. package/.note/memory/rules/lib-first-rule.md +42 -0
  11. package/.note/memory/rules/no-auto-index-rule.md +37 -9
  12. package/.note/memory/rules/no-delete-policy-rule.md +41 -12
  13. package/.note/memory/rules/rls-syntax-rule.md +50 -0
  14. package/.note/memory/rules/sql-naming-rule.md +23 -0
  15. package/.note/memory/rules/supabase-import-rule.md +31 -0
  16. package/.note/memory/rules/supabase-schema-rule.md +5 -4
  17. package/.note/memory/ui/components/combo-tree.md +9 -1
  18. package/.note/memory/ui/design-system/documentation-standard.md +17 -0
  19. package/README.md +78 -212
  20. package/dist/README.md +78 -212
  21. package/dist/bin/bootstrap.js +40 -0
  22. package/dist/bin/pull-docs.js +14 -22
  23. package/dist/components/ui/combo-tree.d.ts +2 -0
  24. package/dist/contexts/PageMetadataContext.d.ts +6 -1
  25. package/dist/docs/KNOWLEDGE.md +68 -167
  26. package/dist/i18n/config.d.ts +11 -0
  27. package/dist/i18n/index.d.ts +1 -1
  28. package/dist/index.css +1 -1
  29. package/dist/index.css.map +1 -1
  30. package/dist/index.d.ts +2 -1
  31. package/dist/index.esm.js +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/providers/CoreProviders.d.ts +31 -34
  34. package/docs/KNOWLEDGE.md +68 -167
  35. package/package.json +3 -4
  36. package/docs/DESIGN_SYSTEM.md +0 -12186
@@ -0,0 +1,59 @@
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`)
@@ -0,0 +1,39 @@
1
+ # Padrão: CoreProviders Setup
2
+
3
+ ## Providers incluídos
4
+
5
+ | Provider | Descrição |
6
+ |----------|-----------|
7
+ | ErrorBoundary | Captura erros de renderização React |
8
+ | I18nextProvider | Sistema de internacionalização |
9
+ | QueryClientProvider | Cache e queries (React Query) |
10
+ | AuthProvider | Autenticação e sessão |
11
+ | LocaleProvider | Idioma, timezone, formato de data |
12
+ | ModuleProvider | Configuração de módulo ativo |
13
+ | ModuleAccessGuard | Bloqueio de acesso por módulo |
14
+
15
+ ## Uso básico
16
+
17
+ ```tsx
18
+ <CoreProviders moduleAlias="performance" appTranslations={{ 'pt-BR': ptBR }}>
19
+ <BrowserRouter>
20
+ <Routes />
21
+ </BrowserRouter>
22
+ </CoreProviders>
23
+ ```
24
+
25
+ ## Props
26
+
27
+ | Prop | Tipo | Obrigatório | Descrição |
28
+ |------|------|-------------|-----------|
29
+ | children | ReactNode | Sim | Componentes filhos |
30
+ | queryClient | QueryClient | Não | Instância customizada (default criado automaticamente) |
31
+ | moduleAlias | string | Não | Alias do módulo para verificação de acesso |
32
+ | moduleAccessGuardProps | object | Não | Props para o ModuleAccessGuard |
33
+ | appTranslations | Record<string, Record<string, string>> | Não | Traduções por idioma no namespace 'app' |
34
+
35
+ ## QueryClient default
36
+
37
+ ```ts
38
+ { defaultOptions: { queries: { staleTime: 5 * 60 * 1000, retry: 1 } } }
39
+ ```
@@ -0,0 +1,14 @@
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 |
@@ -0,0 +1,19 @@
1
+ # Padrão: Feature Flags (Variáveis de Ambiente)
2
+
3
+ ## Variáveis disponíveis
4
+
5
+ | Variável | Descrição | Padrão |
6
+ |----------|-----------|--------|
7
+ | `VITE_SHOW_USER_PREFERENCES` | Exibe "Preferências" no menu do usuário (idioma, timezone, formato de data) | Não exibe |
8
+ | `VITE_I18N_DEBUG_MODE` | Modo debug de i18n (mostra chaves ao invés de traduções) | `"false"` |
9
+ | `VITE_IS_QUALIEX` | Usa logos Qualiex ao invés de Forlogic | `"false"` |
10
+
11
+ ## Uso
12
+
13
+ ```env
14
+ VITE_SHOW_USER_PREFERENCES=true
15
+ VITE_I18N_DEBUG_MODE=false
16
+ VITE_IS_QUALIEX=true
17
+ ```
18
+
19
+ Variáveis Vite precisam do prefixo `VITE_` para serem expostas ao cliente.
@@ -0,0 +1,62 @@
1
+ # Padrão: Título, Subtítulo e Breadcrumbs via Header (usePageMetadata)
2
+
3
+ ## Regra
4
+
5
+ **O padrão da aplicação é exibir título, subtítulo e breadcrumbs no header** usando `usePageMetadata()`.
6
+
7
+ - **NÃO** usar `BodyContent` ou `ContentContainer` com título/subtítulo internos por padrão.
8
+ - Breadcrumbs, títulos e subtítulos internos ao conteúdo são **exceções** e devem ser usados **somente quando explicitamente solicitados** pelo usuário.
9
+
10
+ ## Uso Padrão
11
+
12
+ ```tsx
13
+ import { usePageMetadata } from 'forlogic-core';
14
+
15
+ export function MinhaPage() {
16
+ usePageMetadata({ title: 'Título', subtitle: 'Subtítulo descritivo' });
17
+
18
+ return (
19
+ <div className="flex flex-col h-full p-4 gap-4">
20
+ {/* conteúdo direto, sem BodyContent/ContentContainer */}
21
+ </div>
22
+ );
23
+ }
24
+ ```
25
+
26
+ ## Com Breadcrumbs
27
+
28
+ ```tsx
29
+ usePageMetadata({
30
+ title: 'Editar Usuário',
31
+ subtitle: 'Atualize os dados cadastrais',
32
+ breadcrumbs: [
33
+ { label: 'Usuários', href: '/users' },
34
+ { label: 'João Silva' }
35
+ ]
36
+ });
37
+ ```
38
+
39
+ ## Subtitle com ReactNode
40
+
41
+ ```tsx
42
+ usePageMetadata({
43
+ title: 'Detalhes',
44
+ subtitle: <span>Veja a <Link to="/docs">documentação</Link></span>
45
+ });
46
+ ```
47
+
48
+ ## ❌ Evitar (exceto quando pedido)
49
+
50
+ ```tsx
51
+ // NÃO fazer por padrão:
52
+ <BodyContent breadcrumbs={[{ label: 'Página' }]}>
53
+ <ContentContainer title="Título" subtitle="Subtítulo">
54
+ ...
55
+ </ContentContainer>
56
+ </BodyContent>
57
+ ```
58
+
59
+ ## Quando usar breadcrumbs/título interno
60
+
61
+ - Apenas quando o usuário **pedir explicitamente** breadcrumbs ou título dentro do conteúdo.
62
+ - Páginas com navegação hierárquica profunda podem justificar breadcrumbs, mas sempre confirmar antes.
@@ -0,0 +1,43 @@
1
+ # Padrão: Setup de Traduções (i18n)
2
+
3
+ ## Arquitetura de namespaces
4
+
5
+ - `core` — traduções base da lib (save, cancel, delete, etc.)
6
+ - `app` — traduções do projeto consumidor (injetadas via `CoreProviders`)
7
+ - Resolução: `app` → `core` → fallback `pt-BR`
8
+
9
+ ## Setup em projetos consumidores
10
+
11
+ 1. Criar JSONs flat em `src/i18n/pt-BR.json`: `{ "key": "value" }` (sem nesting)
12
+ 2. Passar para CoreProviders:
13
+
14
+ ```tsx
15
+ <CoreProviders appTranslations={{ 'pt-BR': ptBR, 'en-US': enUS }}>
16
+ ```
17
+
18
+ 3. Usar `useTranslation` de `forlogic-core` (nunca de `react-i18next`)
19
+
20
+ ## Resolução de chaves
21
+
22
+ ```
23
+ t('save') → app: não encontra → core: "Salvar"
24
+ t('objective') → app: "Objetivo"
25
+ t('save') com override no app → app: "Gravar" (sobrescreve core)
26
+ ```
27
+
28
+ ## Debug
29
+
30
+ ```ts
31
+ import { i18n } from 'forlogic-core';
32
+ console.log('Resources:', i18n.store.data);
33
+ // { 'pt-BR': { core: {...}, app: {...} } }
34
+ ```
35
+
36
+ ## Troubleshooting
37
+
38
+ | Causa | Solução |
39
+ |-------|---------|
40
+ | Chaves aparecem ao invés de traduções | Instalar peer deps `i18next` e `react-i18next` |
41
+ | Import de `react-i18next` direto | Usar import de `forlogic-core` |
42
+ | `appTranslations` não passado | Adicionar prop no CoreProviders |
43
+ | JSON com formato errado | Deve ser flat, sem nesting |
@@ -0,0 +1,49 @@
1
+ # Padrão: Setup Vite + Tailwind para Projetos Consumidores
2
+
3
+ ## Vite — Security Headers
4
+
5
+ ```ts
6
+ import { createSecurityHeadersPlugin } from 'forlogic-core/vite';
7
+
8
+ export default defineConfig(({ mode }) => ({
9
+ plugins: [
10
+ react(),
11
+ createSecurityHeadersPlugin(mode === 'development', {
12
+ supabaseUrls: ['https://SEU_PROJETO.supabase.co'],
13
+ additionalConnectSrc: ['https://*.qualiex.com'],
14
+ }),
15
+ ],
16
+ resolve: {
17
+ alias: { '@': path.resolve(__dirname, './src') }, // DEVE ser absoluto
18
+ },
19
+ optimizeDeps: { force: true }, // Força re-bundle ao atualizar forlogic-core
20
+ publicDir: false,
21
+ esbuild: { sourcemap: true, target: 'es2020' },
22
+ build: { chunkSizeWarningLimit: 4000 },
23
+ }));
24
+ ```
25
+
26
+ Opções do plugin: `supabaseUrls`, `trustedOrigins`, `additionalScriptSrc`, `additionalStyleSrc`, `additionalConnectSrc`, `cspReportUri`, `enableTrustedTypes` (default true), `upgradeInsecureRequests` (default true).
27
+
28
+ Alternativa: `createForlogicViteConfig()` factory que retorna config completa (ver README).
29
+
30
+ ## Tailwind
31
+
32
+ ```ts
33
+ import { forlogicTailwindPreset, forlogicContentPaths } from 'forlogic-core/tailwind';
34
+
35
+ export default {
36
+ presets: [forlogicTailwindPreset],
37
+ content: [...forlogicContentPaths],
38
+ } satisfies Config;
39
+ ```
40
+
41
+ `forlogicContentPaths` inclui: `./src/**/*.{ts,tsx}`, `./lib/**/*.{ts,tsx}`, `./node_modules/forlogic-core/dist/**/*.{js,ts,jsx,tsx}`, etc.
42
+
43
+ ## Checklist
44
+
45
+ - [ ] `createSecurityHeadersPlugin` no vite.config.ts com URLs do Supabase
46
+ - [ ] `resolve.alias` usa `path.resolve(__dirname, ...)`
47
+ - [ ] `forlogicTailwindPreset` no tailwind.config.ts
48
+ - [ ] `forlogicContentPaths` no content
49
+ - [ ] Variáveis CSS definidas no index.css (--primary, --background, etc.)
@@ -0,0 +1,32 @@
1
+ # Regra: Sincronização Automática de Documentação
2
+
3
+ ## Gatilho
4
+
5
+ Sempre que modificar qualquer arquivo em `lib/`, verificar se existe documentação correspondente em `src/design-system/docs/`.
6
+
7
+ ## Ações obrigatórias
8
+
9
+ ### 1. Componente/hook existente com doc existente
10
+ - Atualizar props, exemplos e descrições no `*Doc.tsx` correspondente para refletir a mudança
11
+
12
+ ### 2. Componente/hook novo sem doc
13
+ - Criar `*Doc.tsx` usando `ComponentDocTemplate` (com prop `usage` obrigatória)
14
+ - Registrar no `src/design-system/config/docRegistry.ts` (lazy import)
15
+ - Registrar no `src/design-system/config/sections.ts` (sidebar + breadcrumb)
16
+
17
+ ### 3. Mudanças arquiteturais
18
+ - Atualizar `docs/KNOWLEDGE.md` se afetar regras, mapa de módulos ou convenções
19
+ - Atualizar `.note/memory/` se afetar padrões documentados
20
+
21
+ ## Mapeamento de referência
22
+
23
+ ```
24
+ lib/components/ui/<comp>.tsx → src/design-system/docs/components/<Comp>Doc.tsx
25
+ lib/crud/components/<comp>.tsx → src/design-system/docs/components/crud/<Comp>Doc.tsx
26
+ lib/contexts/<Context>.tsx → src/design-system/docs/ContextsDoc.tsx
27
+ lib/hooks/<hook>.ts → src/design-system/docs/HooksDoc.tsx
28
+ lib/services/<Service>.ts → src/design-system/docs/ServicesDoc.tsx
29
+ lib/components/layout/<comp>.tsx → src/design-system/docs/components/layout/<Comp>Doc.tsx
30
+ ```
31
+
32
+ Consultar `.note/memory/documentation/consolidated-components-registry.md` para componentes agrupados sob uma única doc.
@@ -0,0 +1,29 @@
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`.
@@ -0,0 +1,42 @@
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,20 +1,48 @@
1
- # Memory: rules/no-auto-index-rule
2
- Updated: now
1
+ # Regra: Sem índices automáticos
3
2
 
4
3
  **NUNCA** criar índices automaticamente em migrations.
5
4
 
5
+ ## Errado
6
+
6
7
  ```sql
7
- -- ❌ PROIBIDO - índice "por precaução"
8
- CREATE INDEX idx_subprocess_process ON subprocesses(id_process);
9
- CREATE INDEX idx_process_title ON processes(title);
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
10
14
 
11
- -- ✅ CORRETO - criar tabela SEM índices
12
- CREATE TABLE common.processes (...);
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
+ );
13
23
  ```
14
24
 
15
- **Quando criar índices?** APENAS quando:
25
+ ## Quando criar índices
26
+
27
+ APENAS quando:
16
28
  1. Solicitado explicitamente pelo usuário
17
- 2. Análise de performance comprovou necessidade (EXPLAIN ANALYZE)
29
+ 2. Análise de performance comprovou necessidade (`EXPLAIN ANALYZE`)
18
30
  3. Aprovação prévia do usuário
19
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
+
20
48
  **Motivo**: Índices custam espaço, impactam escrita e 99% dos "preventivos" nunca são usados.
@@ -1,23 +1,52 @@
1
- # Memory: rules/no-delete-policy-rule
2
- Updated: now
1
+ # Regra: Sem DELETE físico
3
2
 
4
3
  **NUNCA** criar política RLS de DELETE. Usar soft delete com UPDATE.
5
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
+
6
27
  ```sql
7
28
  -- ❌ PROIBIDO
8
- CREATE POLICY "table_delete" ON common.table
29
+ CREATE POLICY "table_delete" ON common.tabela
9
30
  FOR DELETE USING (...);
10
31
 
11
- -- CORRETO - adicionar coluna deleted_at
12
- ALTER TABLE common.table ADD COLUMN deleted_at TIMESTAMP WITH TIME ZONE;
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
13
37
 
14
- CREATE POLICY "table_update" ON common.table
15
- FOR UPDATE USING (...) WITH CHECK (...);
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);
16
44
  ```
17
45
 
18
- **Motivo**: Soft delete preserva histórico e evita problemas de integridade referencial.
46
+ ## Sintaxe RLS
47
+
48
+ - `SELECT` → `USING`
49
+ - `INSERT` → `WITH CHECK`
50
+ - `UPDATE` → `USING` + `WITH CHECK`
19
51
 
20
- **Sintaxe RLS**:
21
- - `SELECT` → usa `USING`
22
- - `INSERT` → usa `WITH CHECK`
23
- - `UPDATE` → usa `USING` E `WITH CHECK`
52
+ **Motivo**: Soft delete preserva histórico e evita problemas de integridade referencial.
@@ -0,0 +1,50 @@
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`
@@ -0,0 +1,23 @@
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
+ ```
@@ -0,0 +1,31 @@
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,12 +1,13 @@
1
1
  # Memory: rules/supabase-schema-rule
2
2
  Updated: now
3
3
 
4
- **SEMPRE** especifique o schema `common` em TODA query Supabase:
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.
5
6
 
6
7
  ```typescript
7
- // ✅ CORRETO
8
+ // ✅ CORRETO — schema vem da seção 0 do KNOWLEDGE.md
8
9
  const { data } = await supabase
9
- .schema('common')
10
+ .schema('<SCHEMA do KNOWLEDGE.md>')
10
11
  .from('tabela')
11
12
  .select('*');
12
13
 
@@ -16,4 +17,4 @@ const { data } = await supabase
16
17
  .select('*');
17
18
  ```
18
19
 
19
- **Motivo**: O projeto usa schema customizado `common`, não o `public` padrão do Supabase.
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.
@@ -1,11 +1,19 @@
1
1
  # Memory: ui/components/combo-tree
2
2
  Updated: today
3
3
 
4
- O componente `ComboTree` permite a seleção de dados hierárquicos com busca recursiva e separação entre expansão (chevron) e seleção (label). Suporta ícones customizados por nó:
4
+ O componente `ComboTree` permite a seleção de dados hierárquicos com busca recursiva e separação entre expansão (chevron) e seleção (label).
5
+
6
+ ## Layout
7
+ - O **chevron** (▶/▼) fica no **final da linha** (à direita), indicando que o nó tem filhos
8
+ - O **check** (✓) e o **ícone** ficam no início, seguidos pelo label
9
+ - Nós sem filhos não exibem chevron
10
+
11
+ ## Ícones customizados por nó
5
12
 
6
13
  - `icon` — ícone padrão (nó colapsado e não selecionado)
7
14
  - `iconOpen` — ícone quando o nó está **expandido** (fallback para `icon`)
8
15
  - `iconSelected` — ícone quando o nó está **selecionado** (fallback para `iconOpen` se expandido, senão `icon`)
16
+ - `iconClassName` — classe CSS para cor/estilo do ícone (fallback: `text-muted-foreground`)
9
17
 
10
18
  Prioridade de resolução:
11
19
  - Selecionado + Expandido → `iconSelected ?? iconOpen ?? icon`