@luanpdd/kit-mcp 1.34.0 → 1.36.0

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 (118) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +2 -2
  3. package/bin/mcp.js +6 -6
  4. package/bin/ui.js +74 -74
  5. package/gates/ai-prompt-stability.md +120 -120
  6. package/gates/budget-description.md +68 -68
  7. package/gates/confidence.md +29 -29
  8. package/gates/dependency-check.md +33 -33
  9. package/gates/dept-cycle-prevention.md +179 -179
  10. package/gates/golden-signals-coverage.md +133 -133
  11. package/gates/legacy-refactor-safety.md +178 -178
  12. package/gates/multi-tenant-rls-coverage.md +102 -102
  13. package/gates/no-personal-uuid.md +72 -72
  14. package/gates/obs-agents-mcp-supabase.md +86 -86
  15. package/gates/obs-skills-frontmatter.md +76 -76
  16. package/gates/observability-coverage.md +151 -151
  17. package/gates/omm-no-regression.md +83 -83
  18. package/gates/postmortem-template-required.md +127 -127
  19. package/gates/prr-checklist-coverage.md +128 -128
  20. package/gates/regression.md +32 -32
  21. package/gates/release-pipeline-policy.md +132 -132
  22. package/gates/secrets-scan.md +33 -33
  23. package/gates/service-role-not-in-user-facing.md +113 -113
  24. package/gates/skill-must-include.md +71 -71
  25. package/gates/sync-idempotent.md +62 -62
  26. package/gates/verify-phase-goal.md +34 -34
  27. package/kit/agents/designer-ui.md +216 -216
  28. package/kit/agents/workflow-generator.md +537 -0
  29. package/kit/commands/adicionar-backlog.md +1 -1
  30. package/kit/commands/adicionar-fase.md +1 -1
  31. package/kit/commands/adicionar-tarefa.md +1 -1
  32. package/kit/commands/auditar-observabilidade.md +103 -103
  33. package/kit/commands/auditar-toil.md +129 -129
  34. package/kit/commands/caracterizar-prompt.md +195 -195
  35. package/kit/commands/criar-workflow.md +158 -0
  36. package/kit/commands/definir-perfil.md +1 -1
  37. package/kit/commands/definir-slo.md +108 -108
  38. package/kit/commands/fio.md +1 -1
  39. package/kit/commands/golden-signals.md +142 -142
  40. package/kit/commands/instrumentar-fase.md +200 -200
  41. package/kit/commands/investigar-producao.md +162 -162
  42. package/kit/commands/observabilidade.md +118 -118
  43. package/kit/commands/postmortem.md +179 -179
  44. package/kit/commands/prr.md +205 -205
  45. package/kit/commands/publicar-rapido.md +207 -207
  46. package/kit/commands/risk-budget.md +220 -220
  47. package/kit/commands/sre.md +230 -230
  48. package/kit/file-manifest.json +5 -2
  49. package/kit/framework/references/output-style.md +22 -22
  50. package/kit/hooks/post-apply-migration.js +199 -199
  51. package/kit/hooks/sidecar-tool-publisher.js +210 -210
  52. package/kit/skills/_shared-dados-distribuidos/glossary.md +224 -224
  53. package/kit/skills/_shared-legacy/glossary.md +389 -389
  54. package/kit/skills/_shared-multi-tenant/glossary.md +186 -186
  55. package/kit/skills/_shared-observability/glossary.md +396 -396
  56. package/kit/skills/_shared-sre/glossary.md +712 -712
  57. package/kit/skills/_shared-supabase/glossary.md +234 -234
  58. package/kit/skills/blameless-postmortems/SKILL.md +340 -340
  59. package/kit/skills/burn-rate-alerting/SKILL.md +258 -258
  60. package/kit/skills/cascading-failures/SKILL.md +311 -311
  61. package/kit/skills/core-analysis-loop/SKILL.md +352 -352
  62. package/kit/skills/distributed-tracing/SKILL.md +362 -362
  63. package/kit/skills/dynamic-workflow-authoring/SKILL.md +327 -0
  64. package/kit/skills/eliminating-toil/SKILL.md +243 -243
  65. package/kit/skills/event-based-slos/SKILL.md +296 -296
  66. package/kit/skills/four-golden-signals/SKILL.md +314 -314
  67. package/kit/skills/hermetic-builds/SKILL.md +323 -323
  68. package/kit/skills/legacy-monster-methods/SKILL.md +444 -444
  69. package/kit/skills/llm-as-dependency/SKILL.md +436 -436
  70. package/kit/skills/load-shedding-graceful-degradation/SKILL.md +396 -396
  71. package/kit/skills/observability-driven-development/SKILL.md +315 -315
  72. package/kit/skills/observability-maturity-model/SKILL.md +222 -222
  73. package/kit/skills/opentelemetry-standard/SKILL.md +351 -351
  74. package/kit/skills/production-readiness-review/SKILL.md +305 -305
  75. package/kit/skills/release-engineering/SKILL.md +367 -367
  76. package/kit/skills/retry-strategies/SKILL.md +372 -372
  77. package/kit/skills/sre-risk-management/SKILL.md +221 -221
  78. package/kit/skills/structured-events/SKILL.md +265 -265
  79. package/kit/skills/supabase-cron-queues/SKILL.md +275 -275
  80. package/kit/skills/supabase-database-functions/SKILL.md +332 -332
  81. package/kit/skills/supabase-declarative-schema/SKILL.md +183 -183
  82. package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -253
  83. package/kit/skills/supabase-postgres-style/SKILL.md +138 -138
  84. package/kit/skills/supabase-storage/SKILL.md +234 -234
  85. package/kit/skills/telemetry-pipelines/SKILL.md +259 -259
  86. package/kit/skills/telemetry-sampling/SKILL.md +256 -256
  87. package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
  88. package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
  89. package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
  90. package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
  91. package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
  92. package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
  93. package/kit/skills/ui-tipografia/SKILL.md +211 -211
  94. package/package.json +1 -1
  95. package/src/cli/index.js +1114 -1114
  96. package/src/cli/render.js +194 -194
  97. package/src/cli/upgrade-check.js +135 -135
  98. package/src/core/error-redaction.js +76 -76
  99. package/src/core/failures.js +153 -153
  100. package/src/core/gate-runner.js +205 -205
  101. package/src/core/gates.js +82 -82
  102. package/src/core/logger.js +170 -170
  103. package/src/core/manifest-verify.js +174 -174
  104. package/src/core/metrics.js +268 -268
  105. package/src/core/notify.js +60 -60
  106. package/src/core/path-safety.js +141 -141
  107. package/src/core/replays.js +120 -120
  108. package/src/core/ui.js +185 -185
  109. package/src/mcp-server/install.js +149 -149
  110. package/src/mcp-server/roots.js +124 -124
  111. package/src/ui/auto-spawn.js +113 -113
  112. package/src/ui/browser.js +78 -78
  113. package/src/ui/client.js +130 -130
  114. package/src/ui/events.js +65 -65
  115. package/src/ui/lockfile.js +191 -191
  116. package/src/ui/port.js +67 -67
  117. package/src/ui/server.js +547 -547
  118. package/src/ui/wrapper.js +129 -129
@@ -1,253 +1,253 @@
1
- ---
2
- name: supabase-pgvector-rag
3
- description: Use ao implementar RAG com pgvector — create extension vector, dim consistente, HNSW vs IVFFlat, operadores <=>/<#>, RAG with permissions via RLS, chunking.
4
- ---
5
-
6
- # Supabase — pgvector + RAG
7
-
8
- ## Quando usar
9
-
10
- LLM carrega esta skill quando implementar embeddings, similarity search ou RAG (Retrieval-Augmented Generation) com Supabase. Trigger phrases:
11
-
12
- - "pgvector", "vector embeddings"
13
- - "RAG Supabase", "retrieval augmented generation"
14
- - "semantic search Postgres"
15
- - "HNSW vs IVFFlat"
16
- - "embedding dimension"
17
- - "match_documents function"
18
-
19
- ## Regras absolutas
20
-
21
- - **Setup:** `create extension if not exists vector;` em migration ou `supabase/schemas/`.
22
- - **Dimension fixa por modelo** — defina `embedding vector(N)` com N = dim do modelo: 1536 (OpenAI ada-002), 768 (nomic-embed-text), 384 (all-MiniLM-L6-v2). Mismatch = silent fail ou matches aleatórios.
23
- - **Index obrigatório** — sem index, similarity search faz full scan e degrada drasticamente em > 10k linhas.
24
- - **`HNSW`** = default em 2026 — recall melhor, queries mais rápidas com mais data. Build mais lento.
25
- - **`IVFFlat`** = alternativa quando build time domina (datasets dinâmicos com re-build frequente). Recall menor.
26
- - **Distance operators canônicos:**
27
- - **`<=>`** — cosine distance (mais comum em embeddings normalizados)
28
- - **`<#>`** — negative inner product
29
- - **`<->`** — L2 (euclidean) distance
30
- - **`RAG with permissions`** — combine similarity search com RLS na tabela source. Sem isso, retrieval vaza documents entre tenants.
31
- - **Chunking:** 200-500 tokens com overlap 10-20%. Chunks > 1k tokens degradam embeddings; < 100 perdem contexto.
32
- - **Embedding generation server-side** — geração via Edge Function ou worker (model API key não vai para client).
33
-
34
- ## Patterns canônicos
35
-
36
- ### Schema com RLS + HNSW index
37
-
38
- ```sql
39
- -- PT-BR: extension uma vez por projeto
40
- create extension if not exists vector;
41
-
42
- -- PT-BR: documents com embedding e user_id para RAG with permissions
43
- create table public.documents (
44
- id uuid primary key default gen_random_uuid(),
45
- user_id uuid not null references auth.users (id) on delete cascade,
46
- content text not null, -- PT-BR: chunk de texto (200-500 tokens)
47
- embedding vector(1536) not null, -- PT-BR: dim casa com modelo
48
- metadata jsonb default '{}'::jsonb,
49
- created_at timestamptz default now()
50
- );
51
-
52
- -- PT-BR: HNSW com cosine distance (default 2026)
53
- create index documents_embedding_hnsw_idx
54
- on public.documents
55
- using hnsw (embedding vector_cosine_ops);
56
-
57
- -- PT-BR: RLS — RAG with permissions
58
- alter table public.documents enable row level security;
59
-
60
- create policy "users_read_own_docs"
61
- on public.documents for select to authenticated
62
- using ((select auth.uid()) = user_id);
63
-
64
- create policy "users_insert_own_docs"
65
- on public.documents for insert to authenticated
66
- with check ((select auth.uid()) = user_id);
67
-
68
- create index documents_user_id_idx on public.documents (user_id);
69
- ```
70
-
71
- ### Função `match_documents` — RAG with permissions
72
-
73
- ```sql
74
- create or replace function public.match_documents(
75
- query_embedding vector(1536),
76
- match_threshold float,
77
- match_count int
78
- )
79
- returns table (
80
- id uuid,
81
- content text,
82
- similarity float,
83
- metadata jsonb
84
- )
85
- language plpgsql
86
- security invoker -- PT-BR: invoker → respeita RLS do caller
87
- set search_path = ''
88
- stable
89
- as $$
90
- begin
91
- return query
92
- select
93
- d.id,
94
- d.content,
95
- 1 - (d.embedding <=> query_embedding) as similarity,
96
- d.metadata
97
- from public.documents as d
98
- where 1 - (d.embedding <=> query_embedding) > match_threshold
99
- order by d.embedding <=> query_embedding
100
- limit match_count;
101
- end;
102
- $$;
103
- ```
104
-
105
- **Por que `security invoker`:** garante que a função só retorna documentos que o caller (usuário autenticado) tem permissão de ver via RLS. Sem RLS, qualquer caller via similarity recupera documents de outros tenants.
106
-
107
- ### Uso da função do client
108
-
109
- ```ts
110
- // PT-BR: gerar embedding (em Edge Function, server-side) e chamar match_documents
111
- const queryEmbedding = await embedQuery(userQuestion) // dim 1536
112
-
113
- const { data: matches } = await supabase.rpc('match_documents', {
114
- query_embedding: queryEmbedding,
115
- match_threshold: 0.78,
116
- match_count: 10,
117
- })
118
-
119
- // matches: [{ id, content, similarity, metadata }, ...] já filtrado por RLS
120
- const context = matches.map((m) => m.content).join('\n\n')
121
- const answer = await llmComplete({ context, question: userQuestion })
122
- ```
123
-
124
- ### IVFFlat alternativa
125
-
126
- ```sql
127
- -- PT-BR: usar IVFFlat quando build time importa (dataset dinâmico)
128
- -- lists = sqrt(N) é heurística para N total de linhas
129
- create index documents_embedding_ivfflat_idx
130
- on public.documents
131
- using ivfflat (embedding vector_cosine_ops)
132
- with (lists = 100); -- ajustar conforme volume
133
- ```
134
-
135
- ### Geração de embeddings em Edge Function
136
-
137
- ```ts
138
- // supabase/functions/embed-document/index.ts
139
- // PT-BR: chunking + embedding + insert
140
- import { createClient } from 'npm:@supabase/supabase-js@2'
141
- import OpenAI from 'npm:openai@4'
142
-
143
- Deno.serve(async (req) => {
144
- const { user_id, document } = await req.json()
145
- const openai = new OpenAI({ apiKey: Deno.env.get('OPENAI_API_KEY') })
146
- const supabase = createClient(
147
- Deno.env.get('SUPABASE_URL')!,
148
- Deno.env.get('SUPABASE_SECRET_KEYS')!
149
- )
150
-
151
- // PT-BR: chunk em pedaços de ~400 tokens com overlap 20%
152
- const chunks = chunkText(document, { size: 400, overlap: 80 })
153
-
154
- for (const chunk of chunks) {
155
- const embedRes = await openai.embeddings.create({
156
- model: 'text-embedding-3-small', // dim 1536
157
- input: chunk,
158
- })
159
- await supabase.from('documents').insert({
160
- user_id,
161
- content: chunk,
162
- embedding: embedRes.data[0].embedding,
163
- })
164
- }
165
-
166
- return new Response('embedded')
167
- })
168
- ```
169
-
170
- ## Anti-patterns
171
-
172
- ### Anti-pattern 1: Dim mismatch entre modelo e coluna
173
-
174
- **Errado:**
175
- ```sql
176
- create table documents (embedding vector(1536) not null);
177
- ```
178
- ```ts
179
- // PT-BR: usa nomic-embed-text que retorna dim 768
180
- const embedding = await nomicEmbed(text) // 768
181
- await supabase.from('documents').insert({ embedding }) // ⚠ insert falha
182
- ```
183
-
184
- **Por quê:** Postgres rejeita insert com dim mismatch (`expected 1536 dimensions, got 768`). Em pior caso, se aceito, similarity retorna ranking aleatório.
185
-
186
- **Certo:** alinhe dim:
187
- ```sql
188
- create table documents (embedding vector(768) not null);
189
- ```
190
- ou troque o modelo para um que retorne 1536.
191
-
192
- ### Anti-pattern 2: Similarity search sem RLS — vazamento RAG
193
-
194
- **Errado:**
195
- ```sql
196
- -- PT-BR: tabela documents sem RLS
197
- create table public.documents (
198
- id uuid primary key,
199
- content text,
200
- embedding vector(1536)
201
- );
202
- ```
203
-
204
- **Por quê:** qualquer authenticated chama `match_documents` e recupera documents de outros usuários. Em apps multi-tenant, é vazamento crítico — RAG do tenant A vê docs do tenant B.
205
-
206
- **Certo:** habilite RLS + policies por `user_id`/`org_id` + use `security invoker` em funções de match (ver pattern canônico).
207
-
208
- ### Anti-pattern 3: Chunks gigantes (> 1k tokens)
209
-
210
- **Errado:**
211
- ```ts
212
- // PT-BR: chunk inteiro de documento (5k tokens)
213
- const chunks = [fullDocument]
214
- const embedding = await embed(fullDocument)
215
- ```
216
-
217
- **Por quê:** embeddings perdem detalhe semântico em chunks muito grandes. O modelo média muitos conceitos em um único vetor, similarity vira ruidosa. Ranking RAG fica ruim.
218
-
219
- **Certo:** chunks de 200-500 tokens com overlap:
220
- ```ts
221
- const chunks = chunkText(fullDocument, { size: 400, overlap: 80 })
222
- for (const chunk of chunks) {
223
- await embed(chunk).then(insert)
224
- }
225
- ```
226
-
227
- ### Anti-pattern 4: Sem index em coluna `embedding`
228
-
229
- **Errado:**
230
- ```sql
231
- create table documents (embedding vector(1536) not null);
232
- -- (esqueceu create index)
233
- ```
234
-
235
- **Por quê:** sem index, similarity search vira sequential scan. Em > 10k linhas, queries levam segundos a minutos. Em produção, app fica inviável.
236
-
237
- **Certo:**
238
- ```sql
239
- create index documents_embedding_hnsw_idx on documents using hnsw (embedding vector_cosine_ops);
240
- ```
241
-
242
- ## Notas de futuro
243
-
244
- - **Hybrid search** (FTS + vector com RRF — Reciprocal Rank Fusion) está coberto em skill `supabase-fts` (defer v1.9 — full-text search standalone).
245
- - **Vector Buckets** e **Analytics Buckets** ainda em alpha em 2026 — mencione como existência mas não detalhe (pattern canônico evoluindo).
246
-
247
- ## Ver também
248
-
249
- - [supabase-rls-policies](../supabase-rls-policies/SKILL.md) — RLS é base de RAG with permissions
250
- - [supabase-database-functions](../supabase-database-functions/SKILL.md) — função `match_documents` com `security invoker` + `set search_path = ''`
251
- - [supabase-edge-functions](../supabase-edge-functions/SKILL.md) — geração de embeddings server-side
252
- - [supabase-migrations](../supabase-migrations/SKILL.md) — schema com `vector` extension
253
- - [glossário](../_shared-supabase/glossary.md) — operadores `<=>`/`<#>`/`<->`
1
+ ---
2
+ name: supabase-pgvector-rag
3
+ description: Use ao implementar RAG com pgvector — create extension vector, dim consistente, HNSW vs IVFFlat, operadores <=>/<#>, RAG with permissions via RLS, chunking.
4
+ ---
5
+
6
+ # Supabase — pgvector + RAG
7
+
8
+ ## Quando usar
9
+
10
+ LLM carrega esta skill quando implementar embeddings, similarity search ou RAG (Retrieval-Augmented Generation) com Supabase. Trigger phrases:
11
+
12
+ - "pgvector", "vector embeddings"
13
+ - "RAG Supabase", "retrieval augmented generation"
14
+ - "semantic search Postgres"
15
+ - "HNSW vs IVFFlat"
16
+ - "embedding dimension"
17
+ - "match_documents function"
18
+
19
+ ## Regras absolutas
20
+
21
+ - **Setup:** `create extension if not exists vector;` em migration ou `supabase/schemas/`.
22
+ - **Dimension fixa por modelo** — defina `embedding vector(N)` com N = dim do modelo: 1536 (OpenAI ada-002), 768 (nomic-embed-text), 384 (all-MiniLM-L6-v2). Mismatch = silent fail ou matches aleatórios.
23
+ - **Index obrigatório** — sem index, similarity search faz full scan e degrada drasticamente em > 10k linhas.
24
+ - **`HNSW`** = default em 2026 — recall melhor, queries mais rápidas com mais data. Build mais lento.
25
+ - **`IVFFlat`** = alternativa quando build time domina (datasets dinâmicos com re-build frequente). Recall menor.
26
+ - **Distance operators canônicos:**
27
+ - **`<=>`** — cosine distance (mais comum em embeddings normalizados)
28
+ - **`<#>`** — negative inner product
29
+ - **`<->`** — L2 (euclidean) distance
30
+ - **`RAG with permissions`** — combine similarity search com RLS na tabela source. Sem isso, retrieval vaza documents entre tenants.
31
+ - **Chunking:** 200-500 tokens com overlap 10-20%. Chunks > 1k tokens degradam embeddings; < 100 perdem contexto.
32
+ - **Embedding generation server-side** — geração via Edge Function ou worker (model API key não vai para client).
33
+
34
+ ## Patterns canônicos
35
+
36
+ ### Schema com RLS + HNSW index
37
+
38
+ ```sql
39
+ -- PT-BR: extension uma vez por projeto
40
+ create extension if not exists vector;
41
+
42
+ -- PT-BR: documents com embedding e user_id para RAG with permissions
43
+ create table public.documents (
44
+ id uuid primary key default gen_random_uuid(),
45
+ user_id uuid not null references auth.users (id) on delete cascade,
46
+ content text not null, -- PT-BR: chunk de texto (200-500 tokens)
47
+ embedding vector(1536) not null, -- PT-BR: dim casa com modelo
48
+ metadata jsonb default '{}'::jsonb,
49
+ created_at timestamptz default now()
50
+ );
51
+
52
+ -- PT-BR: HNSW com cosine distance (default 2026)
53
+ create index documents_embedding_hnsw_idx
54
+ on public.documents
55
+ using hnsw (embedding vector_cosine_ops);
56
+
57
+ -- PT-BR: RLS — RAG with permissions
58
+ alter table public.documents enable row level security;
59
+
60
+ create policy "users_read_own_docs"
61
+ on public.documents for select to authenticated
62
+ using ((select auth.uid()) = user_id);
63
+
64
+ create policy "users_insert_own_docs"
65
+ on public.documents for insert to authenticated
66
+ with check ((select auth.uid()) = user_id);
67
+
68
+ create index documents_user_id_idx on public.documents (user_id);
69
+ ```
70
+
71
+ ### Função `match_documents` — RAG with permissions
72
+
73
+ ```sql
74
+ create or replace function public.match_documents(
75
+ query_embedding vector(1536),
76
+ match_threshold float,
77
+ match_count int
78
+ )
79
+ returns table (
80
+ id uuid,
81
+ content text,
82
+ similarity float,
83
+ metadata jsonb
84
+ )
85
+ language plpgsql
86
+ security invoker -- PT-BR: invoker → respeita RLS do caller
87
+ set search_path = ''
88
+ stable
89
+ as $$
90
+ begin
91
+ return query
92
+ select
93
+ d.id,
94
+ d.content,
95
+ 1 - (d.embedding <=> query_embedding) as similarity,
96
+ d.metadata
97
+ from public.documents as d
98
+ where 1 - (d.embedding <=> query_embedding) > match_threshold
99
+ order by d.embedding <=> query_embedding
100
+ limit match_count;
101
+ end;
102
+ $$;
103
+ ```
104
+
105
+ **Por que `security invoker`:** garante que a função só retorna documentos que o caller (usuário autenticado) tem permissão de ver via RLS. Sem RLS, qualquer caller via similarity recupera documents de outros tenants.
106
+
107
+ ### Uso da função do client
108
+
109
+ ```ts
110
+ // PT-BR: gerar embedding (em Edge Function, server-side) e chamar match_documents
111
+ const queryEmbedding = await embedQuery(userQuestion) // dim 1536
112
+
113
+ const { data: matches } = await supabase.rpc('match_documents', {
114
+ query_embedding: queryEmbedding,
115
+ match_threshold: 0.78,
116
+ match_count: 10,
117
+ })
118
+
119
+ // matches: [{ id, content, similarity, metadata }, ...] já filtrado por RLS
120
+ const context = matches.map((m) => m.content).join('\n\n')
121
+ const answer = await llmComplete({ context, question: userQuestion })
122
+ ```
123
+
124
+ ### IVFFlat alternativa
125
+
126
+ ```sql
127
+ -- PT-BR: usar IVFFlat quando build time importa (dataset dinâmico)
128
+ -- lists = sqrt(N) é heurística para N total de linhas
129
+ create index documents_embedding_ivfflat_idx
130
+ on public.documents
131
+ using ivfflat (embedding vector_cosine_ops)
132
+ with (lists = 100); -- ajustar conforme volume
133
+ ```
134
+
135
+ ### Geração de embeddings em Edge Function
136
+
137
+ ```ts
138
+ // supabase/functions/embed-document/index.ts
139
+ // PT-BR: chunking + embedding + insert
140
+ import { createClient } from 'npm:@supabase/supabase-js@2'
141
+ import OpenAI from 'npm:openai@4'
142
+
143
+ Deno.serve(async (req) => {
144
+ const { user_id, document } = await req.json()
145
+ const openai = new OpenAI({ apiKey: Deno.env.get('OPENAI_API_KEY') })
146
+ const supabase = createClient(
147
+ Deno.env.get('SUPABASE_URL')!,
148
+ Deno.env.get('SUPABASE_SECRET_KEYS')!
149
+ )
150
+
151
+ // PT-BR: chunk em pedaços de ~400 tokens com overlap 20%
152
+ const chunks = chunkText(document, { size: 400, overlap: 80 })
153
+
154
+ for (const chunk of chunks) {
155
+ const embedRes = await openai.embeddings.create({
156
+ model: 'text-embedding-3-small', // dim 1536
157
+ input: chunk,
158
+ })
159
+ await supabase.from('documents').insert({
160
+ user_id,
161
+ content: chunk,
162
+ embedding: embedRes.data[0].embedding,
163
+ })
164
+ }
165
+
166
+ return new Response('embedded')
167
+ })
168
+ ```
169
+
170
+ ## Anti-patterns
171
+
172
+ ### Anti-pattern 1: Dim mismatch entre modelo e coluna
173
+
174
+ **Errado:**
175
+ ```sql
176
+ create table documents (embedding vector(1536) not null);
177
+ ```
178
+ ```ts
179
+ // PT-BR: usa nomic-embed-text que retorna dim 768
180
+ const embedding = await nomicEmbed(text) // 768
181
+ await supabase.from('documents').insert({ embedding }) // ⚠ insert falha
182
+ ```
183
+
184
+ **Por quê:** Postgres rejeita insert com dim mismatch (`expected 1536 dimensions, got 768`). Em pior caso, se aceito, similarity retorna ranking aleatório.
185
+
186
+ **Certo:** alinhe dim:
187
+ ```sql
188
+ create table documents (embedding vector(768) not null);
189
+ ```
190
+ ou troque o modelo para um que retorne 1536.
191
+
192
+ ### Anti-pattern 2: Similarity search sem RLS — vazamento RAG
193
+
194
+ **Errado:**
195
+ ```sql
196
+ -- PT-BR: tabela documents sem RLS
197
+ create table public.documents (
198
+ id uuid primary key,
199
+ content text,
200
+ embedding vector(1536)
201
+ );
202
+ ```
203
+
204
+ **Por quê:** qualquer authenticated chama `match_documents` e recupera documents de outros usuários. Em apps multi-tenant, é vazamento crítico — RAG do tenant A vê docs do tenant B.
205
+
206
+ **Certo:** habilite RLS + policies por `user_id`/`org_id` + use `security invoker` em funções de match (ver pattern canônico).
207
+
208
+ ### Anti-pattern 3: Chunks gigantes (> 1k tokens)
209
+
210
+ **Errado:**
211
+ ```ts
212
+ // PT-BR: chunk inteiro de documento (5k tokens)
213
+ const chunks = [fullDocument]
214
+ const embedding = await embed(fullDocument)
215
+ ```
216
+
217
+ **Por quê:** embeddings perdem detalhe semântico em chunks muito grandes. O modelo média muitos conceitos em um único vetor, similarity vira ruidosa. Ranking RAG fica ruim.
218
+
219
+ **Certo:** chunks de 200-500 tokens com overlap:
220
+ ```ts
221
+ const chunks = chunkText(fullDocument, { size: 400, overlap: 80 })
222
+ for (const chunk of chunks) {
223
+ await embed(chunk).then(insert)
224
+ }
225
+ ```
226
+
227
+ ### Anti-pattern 4: Sem index em coluna `embedding`
228
+
229
+ **Errado:**
230
+ ```sql
231
+ create table documents (embedding vector(1536) not null);
232
+ -- (esqueceu create index)
233
+ ```
234
+
235
+ **Por quê:** sem index, similarity search vira sequential scan. Em > 10k linhas, queries levam segundos a minutos. Em produção, app fica inviável.
236
+
237
+ **Certo:**
238
+ ```sql
239
+ create index documents_embedding_hnsw_idx on documents using hnsw (embedding vector_cosine_ops);
240
+ ```
241
+
242
+ ## Notas de futuro
243
+
244
+ - **Hybrid search** (FTS + vector com RRF — Reciprocal Rank Fusion) está coberto em skill `supabase-fts` (defer v1.9 — full-text search standalone).
245
+ - **Vector Buckets** e **Analytics Buckets** ainda em alpha em 2026 — mencione como existência mas não detalhe (pattern canônico evoluindo).
246
+
247
+ ## Ver também
248
+
249
+ - [supabase-rls-policies](../supabase-rls-policies/SKILL.md) — RLS é base de RAG with permissions
250
+ - [supabase-database-functions](../supabase-database-functions/SKILL.md) — função `match_documents` com `security invoker` + `set search_path = ''`
251
+ - [supabase-edge-functions](../supabase-edge-functions/SKILL.md) — geração de embeddings server-side
252
+ - [supabase-migrations](../supabase-migrations/SKILL.md) — schema com `vector` extension
253
+ - [glossário](../_shared-supabase/glossary.md) — operadores `<=>`/`<#>`/`<->`