forlogic-core 2.2.1 → 2.2.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.
Files changed (33) hide show
  1. package/dist/assets/docs-BEwTKYu3.css +1 -0
  2. package/dist/assets/docs-Bgpz6ETN.js +10752 -0
  3. package/dist/assets/index-SqMwTzMJ.js +97 -0
  4. package/dist/components/ui/combobox.d.ts +2 -1
  5. package/dist/exports/ui.d.ts +1 -0
  6. package/dist/index.css +1 -1
  7. package/dist/index.css.map +1 -1
  8. package/dist/index.esm.js +1 -1
  9. package/dist/index.html +34 -0
  10. package/dist/index.js +1 -1
  11. package/dist/mind-map/components/MindMap.d.ts +23 -0
  12. package/dist/mind-map/components/MindMapConnection.d.ts +12 -0
  13. package/dist/mind-map/components/MindMapNodeView.d.ts +24 -0
  14. package/dist/mind-map/components/MindMapToolbar.d.ts +26 -0
  15. package/dist/mind-map/hooks/useMindMapKeyboard.d.ts +15 -0
  16. package/dist/mind-map/hooks/useMindMapLayout.d.ts +5 -0
  17. package/dist/mind-map/hooks/useMindMapPanZoom.d.ts +21 -0
  18. package/dist/mind-map/hooks/useMindMapState.d.ts +32 -0
  19. package/dist/mind-map/index.d.ts +4 -0
  20. package/dist/mind-map/types.d.ts +91 -0
  21. package/dist/mind-map/utils/export-image.d.ts +9 -0
  22. package/dist/mind-map/utils/layout.d.ts +15 -0
  23. package/dist/mind-map/utils/nodeOps.d.ts +66 -0
  24. package/dist/mind-map/utils/serialize.d.ts +10 -0
  25. package/dist/supabase/legacyKeyGuard.d.ts +19 -0
  26. package/docs/STORAGE_BUCKETS.md +179 -107
  27. package/docs/SUPABASE_SECRETS.md +122 -0
  28. package/docs/WORKSPACE_KNOWLEDGE.md +34 -0
  29. package/docs/design-system/README.md +2 -2
  30. package/docs/design-system/patterns/feature-flags.md +57 -0
  31. package/docs/design-system/patterns/vite-tailwind-setup.md +1 -0
  32. package/docs/design-system/selectors.md +17 -0
  33. package/package.json +3 -1
@@ -1,7 +1,7 @@
1
1
  # Supabase Storage — Inventário e mapa de consumidores
2
2
 
3
3
  > **Projeto Supabase:** `ccjfvpnndclajkleyqkc` (qualiex-db, prod)
4
- > **Snapshot:** 2026-04-21
4
+ > **Snapshot:** 2026-05-04
5
5
  > **Objetivo:** mapear todos os buckets, quem os consome, suas RLS atuais e os riscos para guiar o próximo ciclo de hardening.
6
6
  > **Escopo:** apenas documentação — nenhuma policy, bucket ou código foi alterado.
7
7
 
@@ -9,28 +9,35 @@
9
9
 
10
10
  ## 1. Visão geral
11
11
 
12
- 15 buckets ativos. Tamanho total ≈ 320 GB (dominado por `content-videos`).
12
+ 15 buckets ativos. Tamanho total ≈ 332 GB (dominado por `content-videos`).
13
13
 
14
14
  | # | Bucket | Público | Objetos | Tamanho | MIME limit | File size limit |
15
15
  |---|---|---|---:|---:|---|---|
16
16
  | 1 | `career-banners` | ✅ | 4 | 349 kB | — | — |
17
- | 2 | `certificates` | ✅ | 2.270 | 929 MB | — | — |
18
- | 3 | `content-files` | ✅ | 5.180 | 2,3 GB | lista ampla | 2 GB |
19
- | 4 | `content-videos` | ✅ | 1.856 | 317 GB | só vídeo | 3 GB |
17
+ | 2 | `certificates` | ✅ | 2.470 | 982 MB | — | — |
18
+ | 3 | `content-files` | ✅ | 5.474 | 2,7 GB | lista ampla | 2 GB |
19
+ | 4 | `content-videos` | ✅ | 1.929 | 326 GB | só vídeo | 3 GB |
20
20
  | 5 | `contracts` | 🔒 | 151 | 47 MB | — | — |
21
21
  | 6 | `imports` | 🔒 | 3 | 569 kB | — | — |
22
22
  | 7 | `knowledge-files` | 🔒 | 8 | 24 MB | — | — |
23
23
  | 8 | `library-assets` | ✅ | 10 | 105 kB | — | — |
24
- | 9 | `performance` | | 22 | 7 MB | — | — |
25
- | 10 | `performance-files` | | 33 | 6 MB | — | — |
26
- | 11 | `resumes` | 🔒 | 715 | 156 MB | | |
27
- | 12 | `thumbnails` | ✅ | 1.109 | 564 MB | — | — |
28
- | 13 | `trainings` | 🔒 | 10 | 10 MB | — | — |
29
- | 14 | `university-assets` | ✅ | 272 | 300 MB | — | — |
30
- | 15 | `user-uploads` | 🔒 | 986 | 1,4 GB | — | — |
24
+ | 9 | `pdi-uploads` | 🔒 | 8 | 14 MB | — | — |
25
+ | 10 | `performance` | 🔒 | 76 | 19 MB | — | — |
26
+ | 11 | `resumes` | 🔒 | 745 | 162 MB | pdf/doc/docx | 10 MB |
27
+ | 12 | `thumbnails` | ✅ | 1.158 | 585 MB | — | — |
28
+ | 13 | `trainings` | 🔒 | 27 | 13 MB | — | — |
29
+ | 14 | `university-assets` | ✅ | 284 | 308 MB | — | — |
30
+ | 15 | `user-uploads` | 🔒 | 1.001 | 1,5 GB | — | — |
31
31
 
32
32
  > ℹ️ A coluna **Público** indica `storage.buckets.public`. Buckets públicos liberam download anônimo via `/storage/v1/object/public/<bucket>/<path>` e, sem policy explícita, também permitem `LIST` anônimo.
33
33
 
34
+ ### Changelog
35
+
36
+ | Data | Mudança |
37
+ |------|---------|
38
+ | 2026-05-04 | `performance` tornado privado com 4 policies (SELECT/INSERT/UPDATE/DELETE) escopadas por alias. `performance-files` removido (deprecado). Snapshot atualizado. |
39
+ | 2026-04-29 | Snapshot inicial. `library-assets` INSERT anônimo removido. `thumbnails` rollback para policies permissivas. |
40
+
34
41
  ---
35
42
 
36
43
  ## 2. Matriz Bucket × Projeto
@@ -64,10 +71,10 @@ Projetos do ecossistema (Lovable):
64
71
  | `career-banners` | | | ✅ | | | | | | |
65
72
  | `resumes` | | | ✅ | | | | | (policy) | |
66
73
  | `contracts` | | | ✅ | | | | | | |
67
- | `user-uploads` | | | ✅ (interviews) | ✅ (training-requests, trainings, imported-evidence) | ✅ (evidence-images, evidence-attachments) | ✅ (evidences) | | | |
74
+ | `user-uploads` | | | ✅ (interviews) | ✅ (training-requests, trainings, imported-evidence) | ✅ (evidence-images, evidence-attachments) | | | | |
75
+ | `pdi-uploads` | | | | | | ✅ (evidences) | | | |
68
76
  | `trainings` | | | | ✅ | | | | | |
69
77
  | `performance` | | | | | | | ✅ (1:1) | | |
70
- | `performance-files` | | | | | | | ⚠️ órfão | | |
71
78
  | `knowledge-files` | | | | | | | | | ❓ |
72
79
 
73
80
  Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS mas sem código consumidor encontrado · ❓ a confirmar com o time.
@@ -76,18 +83,18 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
76
83
 
77
84
  ## 3. Detalhamento por bucket
78
85
 
79
- ### 3.1 `library-assets` — 🚨 prioridade alta
86
+ ### 3.1 `library-assets` — corrigido
80
87
 
81
88
  - **Finalidade:** logos, favicons e marca branca da lib (Qualiex / Saber).
82
89
  - **Consumidor:** [Admin](/projects/9dc9be11-bf85-4561-b36a-8d8f35fdbc06) — `lib/assets/index.ts`, `lib/setup/favicon.ts`. Consumido como leitura pública por todos os projetos via URL pública.
83
90
  - **Estrutura:** raiz do bucket (`logo-qualiex-white.svg`, `favicon.png`, etc.).
84
91
  - **Visibilidade:** público.
85
- - **RLS atuais:**
86
- - `Allow public upload to library assets` — **INSERT para role `public` sem qualquer condição de auth**.
92
+ - **RLS atuais:** **nenhuma policy de write** no `storage.objects` para esse bucket. SELECT continua público pelo flag de bucket público. INSERT/UPDATE/DELETE bloqueados para qualquer role (apenas service_role contorna RLS).
93
+ - **Mudança recente:** a antiga policy `Allow public upload to library assets` (INSERT anônimo sem condição) foi **removida**.
87
94
  - **Riscos:**
88
- - 🔴 Qualquer pessoa anônima pode subir arquivos (defacement, hospedagem indevida, custo).
89
- - 🟡 `LIST` anônimo (default de bucket público) expõe inventário, mas como são logos é baixo impacto.
90
- - **Recomendação:** restringir `INSERT` a `authenticated` + role admin. Avaliar mover para um bucket `brand-assets` privado com signed URLs ou simplesmente versionar os SVGs no repo da lib.
95
+ - 🟢 Upload anônimo eliminado.
96
+ - 🟡 `LIST` anônimo (default de bucket público) ainda expõe inventário, mas como são logos é baixo impacto.
97
+ - **Recomendação:** se precisar permitir upload via app, adicionar policy `TO authenticated` + checagem de admin. Caso contrário, manter como está (gerenciado via service_role/console).
91
98
 
92
99
  ---
93
100
 
@@ -97,27 +104,34 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
97
104
  - **Consumidor:** [Admin](/projects/9dc9be11-bf85-4561-b36a-8d8f35fdbc06) — `src/imports/wizard/services/importJobService.ts`.
98
105
  - **Estrutura:** `{alias}/{timestamp}_{filename}`.
99
106
  - **Visibilidade:** privado.
100
- - **RLS atuais:** SELECT/INSERT/UPDATE/DELETE escopados por `authenticated` + `(storage.foldername(name))[1] = jwt.alias`.
107
+ - **RLS atuais:**
108
+ - `imports_bucket_select` — SELECT, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
109
+ - `imports_bucket_insert` — INSERT, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
110
+ - `imports_bucket_update` — UPDATE, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
111
+ - `imports_bucket_delete` — DELETE, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
101
112
  - **Riscos:**
102
- - 🟡 Policies estão atribuídas ao role `public`, mas com `auth.role() = 'authenticated'` no body — funcional, mas inconsistente com o padrão `TO authenticated`.
113
+ - 🟡 Policies estão atribuídas ao role `public` — funcional, mas inconsistente com o padrão `TO authenticated`.
103
114
  - **Recomendação:** converter as policies para `TO authenticated` (mais explícito e linter-friendly).
104
115
 
105
116
  ---
106
117
 
107
- ### 3.3 `thumbnails` — 🚨 prioridade alta
118
+ ### 3.3 `thumbnails` — ⚠️ sem scoping por alias
108
119
 
109
120
  - **Finalidade:** miniaturas/capas de cursos e conteúdos.
110
121
  - **Consumidor:** [Educação](/projects/075796dc-6ed4-43d3-92e3-3ab7f6314db6) — `src/modules/contents/hooks/useImageUpload.ts` (default bucket).
111
- - **Estrutura:** `thumbnails/{filename}` (sem segregação por alias).
122
+ - **Estrutura atual:** sem prefixo obrigatório (uploads vão na raiz).
112
123
  - **Visibilidade:** público.
113
124
  - **RLS atuais:**
114
- - `Users can upload thumbnails` — **INSERT para `public` sem auth**.
115
- - `Authenticated users can update/delete thumbnails` — UPDATE/DELETE `authenticated`, mas sem scoping por alias.
125
+ - `Users can upload thumbnails` — INSERT `TO authenticated`, sem scoping por alias.
126
+ - `Users can update thumbnails` — UPDATE `TO authenticated`, sem scoping por alias.
127
+ - `Users can delete thumbnails` — DELETE `TO authenticated`, sem scoping por alias.
128
+ - **Histórico:**
129
+ - Hardening anterior (`thumbnails_auth_insert/update/delete` exigindo `foldername[1] = jwt.alias`) quebrou os uploads do projeto Educação, que escreve direto na raiz do bucket.
130
+ - Em 29/04/2026 fizemos rollback para o estado anterior (3 policies permissivas para `authenticated`).
116
131
  - **Riscos:**
117
- - 🔴 INSERT anônimo permite upload sem login.
118
- - 🟠 Sem segregação por `alias`: um tenant autenticado pode atualizar/deletar miniaturas de outro tenant.
119
- - 🟡 `LIST` público.
120
- - **Recomendação:** trocar `Users can upload thumbnails` por uma policy `TO authenticated` com scoping `(storage.foldername(name))[1] = jwt.alias`. Aplicar o mesmo scoping em UPDATE/DELETE.
132
+ - 🔴 Sem isolamento multi-tenant: qualquer usuário autenticado pode sobrescrever/apagar arquivos de qualquer tenant.
133
+ - 🟡 `LIST` público (bucket público) inventário visível.
134
+ - **Próximo passo (P1):** ajustar `src/modules/contents/hooks/useImageUpload.ts` para gravar em `{alias}/...` e então reaplicar as policies com scoping por alias.
121
135
 
122
136
  ---
123
137
 
@@ -127,7 +141,10 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
127
141
  - **Consumidor:** [Educação](/projects/075796dc-6ed4-43d3-92e3-3ab7f6314db6) — `src/hooks/useImageUpload.ts`, `src/modules/contents/services/aiDocsService.ts`.
128
142
  - **Estrutura:** `{alias}/...` em parte das chamadas (não obrigatório).
129
143
  - **Visibilidade:** público.
130
- - **RLS atuais:** INSERT/UPDATE/DELETE só `authenticated` exigindo `jwt.alias IS NOT NULL`. Sem scoping por pasta.
144
+ - **RLS atuais:**
145
+ - `university_assets_auth_insert` — INSERT `TO authenticated`, `jwt.alias IS NOT NULL`. Sem scoping por pasta.
146
+ - `university_assets_auth_update` — UPDATE `TO authenticated`, `jwt.alias IS NOT NULL`. Sem scoping por pasta.
147
+ - `university_assets_auth_delete` — DELETE `TO authenticated`, `jwt.alias IS NOT NULL`. Sem scoping por pasta.
131
148
  - **Riscos:**
132
149
  - 🟠 Qualquer usuário autenticado de qualquer tenant pode sobrescrever/excluir arquivos de qualquer outro tenant.
133
150
  - 🟡 `LIST` público.
@@ -143,7 +160,10 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
143
160
  - [Treinamentos](/projects/e02280e1-3f95-4114-8d83-80d3e8ced304) — `src/training/utils/evidenceUrlResolver.ts` (leitura via `getPublicUrl`).
144
161
  - **Estrutura:** sem padrão por alias (arquivos no root).
145
162
  - **Visibilidade:** público (mesmo o código gerando signed URLs — ou seja, a privacidade pretendida não é real).
146
- - **RLS atuais:** INSERT/UPDATE/DELETE só `authenticated`. Sem scoping por alias. SELECT público (bucket público).
163
+ - **RLS atuais:**
164
+ - `Authenticated users can upload certificates` — INSERT `TO authenticated`, sem scoping.
165
+ - `Authenticated users can update certificates` — UPDATE `TO authenticated`, sem scoping.
166
+ - `Authenticated users can delete certificates` — DELETE `TO authenticated`, sem scoping.
147
167
  - **Riscos:**
148
168
  - 🔴 Certificados são **PII** (nome do aluno, curso, datas). Bucket público + sem scoping = qualquer URL adivinhada/descoberta vaza dados pessoais.
149
169
  - 🟠 `LIST` anônimo expõe inventário com nomes de arquivo.
@@ -157,7 +177,10 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
157
177
  - **Consumidor:** [Educação](/projects/075796dc-6ed4-43d3-92e3-3ab7f6314db6) — `src/modules/contents/hooks/useFileUpload.ts`, `docs/SCORM_IMPLEMENTATION.md`.
158
178
  - **Estrutura:** `{packageFolder}/...` (SCORM); demais sem padrão claro.
159
179
  - **Visibilidade:** público.
160
- - **RLS atuais:** INSERT/UPDATE/DELETE só `authenticated`. Sem scoping por alias.
180
+ - **RLS atuais:**
181
+ - `Authenticated users can upload content-files` — INSERT `TO authenticated`, sem scoping.
182
+ - `Authenticated users can update content-files` — UPDATE `TO authenticated`, sem scoping.
183
+ - `Authenticated users can delete content-files` — DELETE `TO authenticated`, sem scoping.
161
184
  - **Riscos:**
162
185
  - 🟠 Materiais de treinamento de um cliente podem estar acessíveis publicamente para quem tiver a URL/listar o bucket.
163
186
  - 🟡 `LIST` público.
@@ -171,10 +194,13 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
171
194
  - **Consumidor:** [Educação](/projects/075796dc-6ed4-43d3-92e3-3ab7f6314db6) — `src/contexts/UploadQueueContext.tsx`, `src/modules/contents/hooks/useVideoUpload.ts`.
172
195
  - **Estrutura:** `{alias}/{filename}`.
173
196
  - **Visibilidade:** público.
174
- - **RLS atuais:** INSERT/UPDATE/DELETE só `authenticated` com **scoping por alias** (`(storage.foldername(name))[1] = jwt.alias`). SELECT público.
197
+ - **RLS atuais:**
198
+ - `content_videos_auth_insert` — INSERT `TO authenticated`, `foldername[1] = jwt.alias`.
199
+ - `content_videos_auth_update` — UPDATE `TO authenticated`, `foldername[1] = jwt.alias`.
200
+ - `content_videos_auth_delete` — DELETE `TO authenticated`, `foldername[1] = jwt.alias`.
175
201
  - **Riscos:**
176
202
  - 🟠 Vídeos premium acessíveis por URL pública direta.
177
- - 🟡 `LIST` público (alto volume — 317 GB).
203
+ - 🟡 `LIST` público (alto volume — 326 GB).
178
204
  - **Recomendação:** considerar privado + signed URLs (igual a Vimeo/Mux). Custo: rever player e CDN.
179
205
 
180
206
  ---
@@ -185,10 +211,13 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
185
211
  - **Consumidor:** [Colaboradores](/projects/37cdf18f-3d54-4af2-a02b-9f7e2d94e654).
186
212
  - **Estrutura:** raiz.
187
213
  - **Visibilidade:** público.
188
- - **RLS atuais:** INSERT/DELETE só `authenticated`. SELECT público (esperado).
214
+ - **RLS atuais:**
215
+ - `career_banners_upload` — INSERT, role `public`, `auth.role() = 'authenticated'`.
216
+ - `career_banners_delete` — DELETE, role `public`, `auth.role() = 'authenticated'`.
189
217
  - **Riscos:**
190
218
  - 🟡 Sem scoping por alias — qualquer admin de qualquer tenant pode deletar banners de outro.
191
- - **Recomendação:** scoping por alias se houver mais de um cliente usando.
219
+ - 🟡 Policies em role `public` em vez de `TO authenticated`.
220
+ - **Recomendação:** scoping por alias se for multi-tenant. Padronizar para `TO authenticated`.
192
221
 
193
222
  ---
194
223
 
@@ -201,11 +230,13 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
201
230
  - **Estrutura:** `{alias}/{filename}` (Colaboradores) e `{auth.uid()}/...` (Cockpit) — **dois esquemas convivendo**.
202
231
  - **Visibilidade:** privado.
203
232
  - **RLS atuais:**
204
- - `resumes_alias_select`, `resumes_auth_upload`escopados por `jwt.alias`, exigem extensões `pdf|doc|docx|jpg|jpeg|png`.
233
+ - `resumes_alias_select` — SELECT `TO authenticated`, `foldername[1] = jwt.alias`.
234
+ - `resumes_auth_upload` — INSERT `TO authenticated`, `foldername[1] = jwt.alias` + extensões `pdf|doc|docx|jpg|jpeg|png`.
235
+ - **⚠️ Incongruência MIME:** o bucket aceita apenas `pdf/doc/docx` (configuração `allowed_mime_types`), mas a policy `resumes_auth_upload` lista também `jpg|jpeg|png`. Na prática o bucket rejeitaria imagens pelo MIME antes da policy ser avaliada, mas a policy está desatualizada.
205
236
  - **Riscos:**
206
237
  - 🟠 Há duas convenções de path conflitantes (alias vs uid). Pode haver arquivos "órfãos" que não casam com nenhuma policy.
207
238
  - 🟠 Não há policy explícita de UPDATE/DELETE listada.
208
- - **Recomendação:** alinhar uma única convenção (`{alias}/{auth.uid()}/{file}` cobre os dois) e adicionar UPDATE/DELETE.
239
+ - **Recomendação:** alinhar uma única convenção (`{alias}/{auth.uid()}/{file}` cobre os dois) e adicionar UPDATE/DELETE. Remover extensões de imagem da policy para casar com o bucket.
209
240
 
210
241
  ---
211
242
 
@@ -215,17 +246,21 @@ Legenda: ✅ uso confirmado em código · 🔎 só leitura · (policy) tem RLS m
215
246
  - **Consumidor:** [Colaboradores](/projects/37cdf18f-3d54-4af2-a02b-9f7e2d94e654) — `src/contracts/contractService.ts`, edge function `contract-processor`.
216
247
  - **Estrutura:** `{templates|generated}/{alias}/{filename}`.
217
248
  - **Visibilidade:** privado.
218
- - **RLS atuais:** SELECT/INSERT/UPDATE/DELETE escopados por pasta + alias.
249
+ - **RLS atuais:**
250
+ - `contracts_select` — SELECT, role `public`, `foldername[1] IN ('templates','generated')` + `foldername[2] = jwt.alias`.
251
+ - `contracts_insert` — INSERT, role `public`, mesma condição.
252
+ - `contracts_update` — UPDATE, role `public`, mesma condição.
253
+ - `contracts_delete` — DELETE `TO authenticated`, mesma condição.
219
254
  - **Riscos:**
220
- - 🟢 Bem segregado.
221
- - 🟡 Policies estão em role `public` com `auth.role() = 'authenticated'` implícito via `jwt`. Funcional mas inconsistente.
255
+ - 🟢 Bem segregado por alias.
256
+ - 🟡 SELECT/INSERT/UPDATE em role `public` (funcional mas inconsistente).
222
257
  - **Recomendação:** padronizar para `TO authenticated`.
223
258
 
224
259
  ---
225
260
 
226
261
  ### 3.11 `user-uploads` — 🚨 alta complexidade
227
262
 
228
- Bucket multi-projeto, segregado por subpasta. **Usado por 4 projetos** (Colaboradores, Treinamentos, Matriz de Foco, PDI).
263
+ Bucket multi-projeto, segregado por subpasta. **Usado por 3 projetos** (Colaboradores, Treinamentos, Matriz de Foco).
229
264
 
230
265
  - **Visibilidade:** privado.
231
266
  - **Estrutura por consumidor:**
@@ -238,26 +273,31 @@ Bucket multi-projeto, segregado por subpasta. **Usado por 4 projetos** (Colabora
238
273
  | `trainings/.../{alias}/...` | Treinamentos | Evidências de treinamento (alias na 3ª pasta) |
239
274
  | `evidence-images/...` | Matriz de Foco | Imagens coladas no rich-text editor |
240
275
  | `evidence-attachments/{evidenceId}/...` | Matriz de Foco | Anexos de evidências |
241
- | `evidences/...` | PDI | Anexos de planos de ação |
242
276
 
243
- - **RLS atuais:**
244
- - `interview_scoped_select` — SELECT escopado.
245
- - `training_requests_attachments_select/insert/delete` escopados.
246
- - `imported_evidence_select/insert` — escopados.
247
- - `trainings_bucket_*` escopados (mas no bucket `trainings`, não no `user-uploads`).
248
- - `Authenticated users can update user-uploads` — **UPDATE genérico para qualquer authenticated, sem scoping**.
249
- - `authenticated_interview_upload` INSERT genérico no bucket sem scoping (legado da Matriz de Foco antes da migração `20260328223532`).
250
- - **Não vejo policies SELECT/INSERT explícitas para `evidence-images/`, `evidence-attachments/` e `evidences/`** provavelmente estão dependendo da policy genérica `authenticated` existente em outra migração.
277
+ - **RLS atuais (05/05/2026):**
278
+
279
+ | Policy | Cmd | Role | Scoping |
280
+ |--------|-----|------|---------|
281
+ | `interview_scoped_select` | SELECT | `public` | `foldername[1] = 'interviews'` + `foldername[2] = jwt.alias` |
282
+ | `authenticated_interview_upload` | INSERT | `public` | `auth.role() = 'authenticated'` — **sem scoping por subpasta/alias** ⚠️ |
283
+ | `training_requests_attachments_select` | SELECT | `public` | `foldername[1] = 'training-requests'` + `foldername[2] = jwt.alias` |
284
+ | `training_requests_attachments_insert` | INSERT | `public` | `foldername[1] = 'training-requests'` + `foldername[2] = jwt.alias` |
285
+ | `training_requests_attachments_delete` | DELETE | `public` | `foldername[1] = 'training-requests'` + `foldername[2] = jwt.alias` |
286
+ | `imported_evidence_select` | SELECT | `public` | `foldername[1] = 'imported-evidence'` + `foldername[2] = jwt.alias` |
287
+ | `imported_evidence_insert` | INSERT | `public` | `foldername[1] = 'imported-evidence'` + `foldername[2] = jwt.alias` |
288
+ | `evidence_uploads_select` | SELECT | `authenticated` | `foldername[1] IN ('evidence-images','evidence-attachments')` + `jwt.alias IS NOT NULL` — **sem checagem de alias** ⚠️ |
289
+ | `evidence_uploads_delete` | DELETE | `authenticated` | `foldername[1] IN ('evidence-images','evidence-attachments')` + `jwt.alias IS NOT NULL` — **sem checagem de alias** ⚠️ |
290
+ | `Authenticated users can update user-uploads` | UPDATE | `authenticated` | `foldername[2] = jwt.alias` (cobre `*/{alias}/...`, mas não `evidence-images/` nem `evidences/`) |
251
291
 
252
292
  - **Riscos:**
253
- - 🔴 UPDATE genérico permite que qualquer authenticated sobrescreva arquivos de outros tenants e outros projetos.
254
- - 🔴 Sem policies específicas para Matriz de Foco / PDI, a leitura/insert pode estar usando uma policy genérica `authenticated_select/insert` (precisa verificar) se sim, **vazamento cross-tenant**.
293
+ - 🔴 `authenticated_interview_upload` continua permitindo que qualquer authenticated grave em qualquer subpasta do bucket (cross-tenant + cross-projeto).
294
+ - 🔴 `evidence_uploads_select/delete` não checam alias qualquer authenticated lê/deleta evidências da Matriz de Foco de outros tenants.
255
295
  - 🟠 Padrão de path inconsistente entre projetos (uns usam alias na 1ª pasta, outros na 3ª, outros não usam).
256
296
 
257
297
  - **Recomendação:**
258
298
  - Padronizar para `{projeto}/{alias}/...`.
259
- - Substituir UPDATE genérico por policies por subpasta + alias.
260
- - Auditar e adicionar policies específicas para `evidence-images`, `evidence-attachments`, `evidences`.
299
+ - Substituir `authenticated_interview_upload` por INSERT por subpasta + alias.
300
+ - Adicionar checagem de alias em `evidence_uploads_select/delete` (Matriz de Foco).
261
301
 
262
302
  ---
263
303
 
@@ -267,87 +307,117 @@ Bucket multi-projeto, segregado por subpasta. **Usado por 4 projetos** (Colabora
267
307
  - **Consumidor:** [Treinamentos](/projects/e02280e1-3f95-4114-8d83-80d3e8ced304) — `LeaderResolveModal`, `LeaderPendingSelectModal`.
268
308
  - **Estrutura:** `.../.../{alias}/...` (alias na 3ª pasta — esquisito).
269
309
  - **Visibilidade:** privado.
270
- - **RLS atuais:** SELECT/INSERT escopados por `(storage.foldername(name))[2] = jwt.alias`.
310
+ - **RLS atuais:**
311
+ - `trainings_bucket_select` — SELECT, role `public`, `foldername[2] = jwt.alias`.
312
+ - `trainings_bucket_insert` — INSERT, role `public`, `foldername[2] = jwt.alias`.
271
313
  - **Riscos:**
272
314
  - 🟡 Discrepância: a policy usa pasta `[2]`, mas o resolver de evidências em `evidenceUrlResolver.ts` aceita o bucket. Validar se o path real bate.
273
315
  - 🟠 Sem policy explícita de UPDATE/DELETE.
274
- - **Recomendação:** confirmar convenção de path e adicionar UPDATE/DELETE escopados.
316
+ - 🟡 Policies em role `public` (funcional mas inconsistente).
317
+ - **Recomendação:** confirmar convenção de path, adicionar UPDATE/DELETE escopados e padronizar para `TO authenticated`.
275
318
 
276
319
  ---
277
320
 
278
- ### 3.13 `performance` — média/alta
321
+ ### 3.13 `performance` — ✅ corrigido (05/2026)
279
322
 
280
- - **Finalidade:** anexos do módulo de **One-on-One** dentro de Desempenho — evidências de tarefas e relatórios de tarefa.
323
+ - **Finalidade:** anexos do módulo de **One-on-One** dentro de Desempenho — evidências de tarefas e relatórios.
281
324
  - **Consumidor:** [Desempenho](/projects/7c73eab6-bf0a-4cb5-93b3-e1809d1363d7)
282
325
  - `src/one-on-ones/services/evidenceService.ts` → pasta `evidences/`
283
326
  - `src/one-on-ones/services/taskReportService.ts` → pasta `task-reports/`
284
- - Ambos usam `getPublicUrl` (ou seja, dependem do bucket ser público para servir os arquivos).
285
- - **Estrutura real:** `evidences/...` e `task-reports/...` no root (sem segregação por `alias` ou `auth.uid()`).
286
- - **Visibilidade:** público.
287
- - **RLS atuais:** apenas `performance_authenticated_insert` (INSERT escopado por `(storage.foldername(name))[1] = jwt.alias`). **Sem SELECT/UPDATE/DELETE explícitos** — caem no default do bucket público.
327
+ - **Estrutura:** `{alias}/evidences/...` e `{alias}/task-reports/...`.
328
+ - **Visibilidade:** 🔒 **privado** (alterado de público para privado).
329
+ - **RLS atuais (pós-hardening):**
330
+ - `performance_authenticated_select` SELECT `TO authenticated`, `jwt.alias = foldername[1]`.
331
+ - `performance_authenticated_insert` — INSERT, role `public`, `jwt.alias = foldername[1]`.
332
+ - `performance_authenticated_update` — UPDATE, role `public`, `jwt.alias = foldername[1]`.
333
+ - `performance_authenticated_delete` — DELETE, role `public`, `jwt.alias = foldername[1]`.
334
+ - **Mudança recente:** bucket tornado privado + 4 policies com scoping por alias na 1ª pasta. Resolve os riscos P0 apontados anteriormente.
288
335
  - **Riscos:**
289
- - 🔴 Policy de INSERT exige alias na 1ª pasta, mas o **código grava em `evidences/{file}` e `task-reports/{file}`** ou seja, a policy **não bate com o path real** e o INSERT só funciona porque… provavelmente está funcionando via outra policy genérica ou os arquivos foram criados antes da policy. Precisa investigar (22 objetos, último em 20/04).
290
- - 🔴 Bucket público + sem segregação por tenant = qualquer URL adivinhada vaza evidências de qualquer cliente.
291
- - 🟠 `LIST` anônimo expõe inventário.
292
- - **Recomendação:**
293
- 1. Realinhar o código para `{alias}/evidences/...` e `{alias}/task-reports/...` (ou alterar a policy para casar com o path atual).
294
- 2. Tornar privado e migrar o front para signed URLs.
295
- 3. Adicionar SELECT/UPDATE/DELETE escopados por alias + autor.
336
+ - 🟢 Isolamento multi-tenant via alias — resolvido.
337
+ - 🟡 INSERT/UPDATE/DELETE em role `public` (funcional mas inconsistente com o padrão `TO authenticated`).
338
+ - 🟡 O código de Desempenho pode precisar migrar de `getPublicUrl` para `createSignedUrl` (bucket agora privado).
339
+ - **Recomendação:** padronizar policies para `TO authenticated`. Confirmar que o front de Desempenho já usa signed URLs.
296
340
 
297
341
  ---
298
342
 
299
- ### 3.14 `performance-files` — ⚠️ órfão (candidato a deprecar)
300
-
301
- - **Origem:** criado pela migração `20260203114103_ffecc964-7e28-4605-8516-b851f62d0433.sql` no projeto Desempenho ("bucket dedicado para o módulo de desempenho").
302
- - **Consumidor atual:** **nenhum** — busca em todo o projeto Desempenho (e nos demais 13 projetos do ecossistema) não encontra nenhuma referência ao nome `performance-files` fora da própria migração. Os 33 objetos existentes parecem ser de testes manuais ou de uma implementação anterior que foi substituída por `performance`.
303
- - **Estrutura:** `{auth.uid()}/...` (assumido pela policy de DELETE).
304
- - **Visibilidade:** público.
305
- - **RLS atuais:**
306
- - `performance_files_public_read` — SELECT para `public` sem condição.
307
- - `performance_files_authenticated_insert` — INSERT só `authenticated`, sem scoping por alias.
308
- - `performance_files_owner_delete` — DELETE só pelo dono via `auth.uid()`.
309
- - **Riscos:**
310
- - 🟠 Bucket sem código consumidor: nenhum hardening é prioridade, mas mantê-lo aberto é superfície de ataque desnecessária.
311
- - 🔴 Bucket público + INSERT sem scoping por alias = qualquer authenticated pode poluir o bucket.
312
- - **Recomendação:** **deprecar**. Backup dos 33 objetos atuais, migrar (se algum for relevante) para `performance`, depois remover o bucket. Confirmar com o time de Desempenho antes de deletar.
313
-
314
- ---
315
-
316
- ### 3.15 `knowledge-files` — ❓ a confirmar
343
+ ### 3.14 `knowledge-files` — a confirmar
317
344
 
318
345
  - **Finalidade provável:** base de conhecimento para IA / chatbot.
319
346
  - **Consumidor:** sem uso direto encontrado em nenhum dos 14 projetos. 8 objetos, último em março/2026.
320
347
  - **Estrutura:** `{alias}/...`.
321
348
  - **Visibilidade:** privado.
322
- - **RLS atuais:** SELECT/INSERT escopados por `authenticated` + alias.
349
+ - **RLS atuais:**
350
+ - `knowledge_files_select` — SELECT, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
351
+ - `knowledge_files_upload` — INSERT, role `public`, `auth.role() = 'authenticated'` + `foldername[1] = jwt.alias`.
323
352
  - **Riscos:**
324
353
  - 🟡 Sem UPDATE/DELETE explícitos.
325
354
  - 🟡 Provavelmente consumido por uma edge function (não por front) — confirmar.
355
+ - 🟡 Policies em role `public` (funcional mas inconsistente).
326
356
  - **Recomendação:** identificar consumidor e validar fluxo antes de mexer.
327
357
 
328
358
  ---
329
359
 
360
+ ### 3.15 `pdi-uploads` — ✅ novo (05/2026)
361
+
362
+ - **Finalidade:** evidências de ações nos Planos de Desenvolvimento Individual (PDI).
363
+ - **Consumidor:** exclusivamente [PDI](/projects/7269db93-bd03-4b7d-842a-cd74404d2606)
364
+ - `src/modules/plans/utils/evidenceStorage.ts` — helper centralizado (`uploadEvidence`, `resolveEvidenceUrl`, `getEvidenceSignedUrl`)
365
+ - `src/modules/plans/components/tracking/EvidenceModal.tsx` — upload de evidências no acompanhamento
366
+ - `src/modules/plans/components/ActionManagementModal.tsx` — upload/edição de evidências em ações
367
+ - **Estrutura:** `{alias}/evidences/{timestamp}_{sanitized_filename}`.
368
+ - **Visibilidade:** 🔒 **privado** — acesso via signed URLs (1h de validade).
369
+ - **Limites:** sem restrição de MIME type ou tamanho no bucket (validação no front: 10 MB max).
370
+ - **RLS atuais (3 policies, todas `TO authenticated` com scoping por alias):**
371
+ - `pdi_uploads_select` — SELECT, `bucket_id = 'pdi-uploads' AND foldername[1] = jwt.alias`.
372
+ - `pdi_uploads_insert` — INSERT, mesma condição em `WITH CHECK`.
373
+ - `pdi_uploads_update` — UPDATE, mesma condição em `USING` e `WITH CHECK`.
374
+ - **Sem policy de DELETE** — alinhado com a regra de soft delete do projeto (evidências são desvinculadas no registro, não apagadas do storage).
375
+ - **Origem:** bucket criado durante migração de evidências do PDI, que antes usava `user-uploads/evidences/`. Migração concluída em 05/2026 (ver `docs/pdi-storage-migration-plan.md`).
376
+ - **Riscos:**
377
+ - 🟢 Isolamento multi-tenant via alias — correto desde a criação.
378
+ - 🟢 Todas as policies usam `TO authenticated` (padrão correto).
379
+ - 🟢 Signed URLs no front (bucket privado desde o início).
380
+ - **Recomendação:** nenhuma ação necessária — bucket exemplar.
381
+
382
+ ---
383
+
330
384
  ## 4. Padrões de policies (síntese)
331
385
 
332
- Boas práticas observadas no projeto:
386
+ ### 4.1 Boas práticas observadas
333
387
 
334
388
  | Padrão | Onde aparece | Recomendar generalizar |
335
389
  |---|---|---|
336
- | `(storage.foldername(name))[1] = ((SELECT auth.jwt()) ->> 'alias')` | content-videos, contracts, imports, knowledge-files, training-requests, imported-evidence, resumes | ✅ sim — virar padrão |
337
- | `TO authenticated` explícito | thumbnails, certificates, content-files, university-assets, content-videos, resumes | ✅ sim — converter as policies em role `public` |
390
+ | `(storage.foldername(name))[1] = ((SELECT auth.jwt()) ->> 'alias')` | content-videos, contracts, imports, knowledge-files, training-requests, imported-evidence, resumes, performance, **pdi-uploads** | ✅ sim — virar padrão |
391
+ | `TO authenticated` explícito | thumbnails, certificates, content-files, university-assets, content-videos, resumes, evidence_uploads, **pdi-uploads** | ✅ sim — converter as policies em role `public` |
338
392
  | `(SELECT auth.jwt())` (e não `auth.jwt()`) | a maioria das policies novas | ✅ obrigatório (linter) |
339
- | Bucket privado + signed URLs | certificates (Educação), contracts | ✅ aplicar a thumbnails, content-files, content-videos |
393
+ | Bucket privado + signed URLs | certificates (Educação), contracts, performance, **pdi-uploads** | ✅ aplicar a thumbnails, content-files, content-videos |
394
+
395
+ ### 4.2 Policies com role `public` (debt técnico)
396
+
397
+ As seguintes policies usam `roles: {public}` com `auth.role() = 'authenticated'` no body em vez do mais correto `TO authenticated`. Funcionam, mas geram warnings no linter e são inconsistentes com o padrão:
398
+
399
+ | Bucket | Policies afetadas |
400
+ |--------|-------------------|
401
+ | `career-banners` | `career_banners_upload`, `career_banners_delete` |
402
+ | `contracts` | `contracts_select`, `contracts_insert`, `contracts_update` |
403
+ | `imports` | `imports_bucket_select`, `imports_bucket_insert`, `imports_bucket_update`, `imports_bucket_delete` |
404
+ | `knowledge-files` | `knowledge_files_select`, `knowledge_files_upload` |
405
+ | `performance` | `performance_authenticated_insert`, `performance_authenticated_update`, `performance_authenticated_delete` |
406
+ | `trainings` | `trainings_bucket_select`, `trainings_bucket_insert` |
407
+ | `user-uploads` | `authenticated_interview_upload`, `interview_scoped_select`, `training_requests_*`, `imported_evidence_*` |
408
+
409
+ **Recomendação:** migrar todas para `TO authenticated` em uma migration batch (P2 — sem mudança funcional).
340
410
 
341
411
  ---
342
412
 
343
413
  ## 5. Itens em aberto (a confirmar com o time)
344
414
 
345
415
  1. **`knowledge-files`**: quem consome? É edge function?
346
- 2. **`performance-files`**: confirmar com o time de Desempenho que pode ser deprecado (não código consumidor; 33 objetos de origem desconhecida).
347
- 3. **`performance`**: alinhar path do código (`evidences/`, `task-reports/`) com a policy (que exige alias na pasta) atualmente são incompatíveis.
348
- 4. **`certificates` precisa ser público?** O código de Educação gera signed URLs, então não.
349
- 5. **`content-videos` privado?** Avaliar custo (player) vs benefício (proteger PII e propriedade intelectual).
350
- 6. **`user-uploads` para Matriz de Foco e PDI**: existem policies dedicadas ou tudo cai numa policy genérica `authenticated`?
416
+ 2. **`performance`**: confirmar que o front de Desempenho migrou de `getPublicUrl` para signed URLs após o bucket ser tornado privado.
417
+ 3. **`certificates` precisa ser público?** O código de Educação gera signed URLs, então não.
418
+ 4. **`content-videos` privado?** Avaliar custo (player) vs benefício (proteger PII e propriedade intelectual).
419
+ 5. **`user-uploads` para Matriz de Foco**: `evidence_uploads_select/delete` não checam alias — risco cross-tenant confirmado. (PDI migrou para `pdi-uploads`).
420
+ 6. **`resumes`**: policy permite `jpg/jpeg/png` mas bucket aceita `pdf/doc/docx` limpar policy.
351
421
 
352
422
  ---
353
423
 
@@ -357,18 +427,20 @@ Boas práticas observadas no projeto:
357
427
 
358
428
  | Prioridade | Bucket | Ação |
359
429
  |---|---|---|
360
- | 🔴 P0 | `library-assets` | Remover `Allow public upload to library assets` (INSERT anônimo). |
361
- | 🔴 P0 | `thumbnails` | Trocar `Users can upload thumbnails` por policy `TO authenticated` + scoping por alias. |
362
- | 🔴 P0 | `user-uploads` | Substituir UPDATE genérico por policies por subpasta + alias; auditar Matriz de Foco e PDI. |
430
+ | done | `library-assets` | INSERT anônimo removido (sem policies de write). |
431
+ | done | `thumbnails` | INSERT/UPDATE/DELETE `TO authenticated` (sem scoping pendente ajuste no front). |
432
+ | done | `performance` | Tornado privado + 4 policies com scoping por alias. |
433
+ | ✅ done | `performance-files` | Bucket deprecado e removido. |
434
+ | ✅ done | `pdi-uploads` | Bucket criado (privado) + 3 policies `TO authenticated` com scoping por alias. Migração de `user-uploads` concluída. |
435
+ | 🔴 P0 | `user-uploads` | Substituir `authenticated_interview_upload` (INSERT genérico) por INSERT por subpasta + alias; adicionar checagem de alias em `evidence_uploads_select/delete` (Matriz de Foco). |
363
436
  | 🔴 P0 | `certificates` | Tornar privado + migrar Treinamentos para signed URLs. |
437
+ | 🟠 P1 | `thumbnails` | Ajustar front de Educação para gravar em `{alias}/...` e reaplicar scoping por alias. |
364
438
  | 🟠 P1 | `university-assets`, `content-files` | Adicionar scoping por alias em UPDATE/DELETE/INSERT. |
365
- | 🔴 P0 | `performance` | Realinhar path do código (`evidences/`, `task-reports/`) com a policy de INSERT (que exige `{alias}/...`); tornar privado; adicionar SELECT escopado. |
366
- | 🟠 P1 | `performance-files` | Deprecar bucket nenhum código consumidor encontrado; backup dos 33 objetos e remover. |
367
- | 🟠 P1 | `resumes` | Unificar convenção de path (alias + uid) e adicionar UPDATE/DELETE. |
368
- | 🟡 P2 | `contracts`, `imports` | Padronizar `TO authenticated` (limpeza, sem mudança funcional). |
439
+ | 🟠 P1 | `resumes` | Unificar convenção de path (alias + uid), adicionar UPDATE/DELETE, remover extensões de imagem da policy. |
440
+ | 🟡 P2 | Múltiplos | Padronizar ~20 policies de role `public` para `TO authenticated` (limpeza, sem mudança funcional). Ver seção 4.2. |
441
+ | 🟡 P2 | `contracts`, `imports` | Padronizar `TO authenticated` (limpeza). |
369
442
  | 🟡 P2 | `career-banners` | Scoping por alias se for multi-tenant. |
370
443
  | 🟡 P2 | `content-videos` | Avaliar privado + signed URLs (impacto no player). |
371
- | 🟡 P2 | Todos públicos | Substituir SELECT default por SELECT `TO authenticated` (ou `TO public` apenas para os realmente públicos como `library-assets` e `career-banners`) — alinha com plano já existente em [Cockpit `.lovable/plan.md`](/projects/e6853fb4-67f9-4776-b427-7768a9136f10). |
372
444
 
373
445
  ---
374
446
 
@@ -0,0 +1,122 @@
1
+ # Supabase Secrets — Inventário
2
+
3
+ > **Projeto Supabase:** `ccjfvpnndclajkleyqkc`
4
+ >
5
+ > Todas as secrets são compartilhadas entre os projetos Lovable que apontam para este mesmo projeto Supabase.
6
+ > Última atualização: 2026-05-04
7
+
8
+ ---
9
+
10
+ ## Infraestrutura Supabase (automáticas)
11
+
12
+ Secrets gerenciadas automaticamente pelo Supabase. **Não editar manualmente.**
13
+
14
+ | Secret | Finalidade | Projetos |
15
+ |--------|-----------|----------|
16
+ | `SUPABASE_URL` | URL do projeto Supabase | Todos com edge functions |
17
+ | `SUPABASE_SERVICE_ROLE_KEY` | Chave admin — bypass de RLS em edge functions | Todos com edge functions |
18
+ | `SUPABASE_ANON_KEY` | Chave pública anon (usada em `createClient` server-side) | Cockpit, Educação, PDI, Competências, Colaboradores |
19
+ | `SUPABASE_DB_URL` | Connection string PostgreSQL | Infraestrutura interna Supabase |
20
+
21
+ ---
22
+
23
+ ## Autenticação e JWT
24
+
25
+ | Secret | Finalidade | Projetos | Observações |
26
+ |--------|-----------|----------|-------------|
27
+ | `JWT_SECRET` | Verificação de assinatura HMAC-SHA256 dos JWTs customizados | **Admin** (validate-token, azure-blob-upload, clicksign, d4sign, send-email), **Cockpit** (_shared/auth), **Colaboradores** (sensitive-data, entra-id-sync, collaborator-webhook, contract-*), **PDI** (dev-tokens) | Crítica — usada para validar tokens em todas as edge functions protegidas |
28
+ | `VALIDATE_JWT_ENDPOINT` | URL de endpoint externo para validação de JWT (Qualiex API) | **Admin** (validate-token), **Treinamentos** (docs-documents-used, docs-process-outdated, notify-leader) | Fallback quando JWT_SECRET não é usado diretamente |
29
+ | `SUPABASE_PUBLISHABLE_KEY` | Chave pública do projeto (alias da anon key) | **Admin** (validate-token) | Usada para validar tokens de projetos consumidores |
30
+ | `SUPABASE_PUBLISHABLE_KEYS` | Lista de chaves públicas de múltiplos projetos | **Admin** (validate-token) | Suporte multi-projeto na validação |
31
+ | `SUPABASE_SECRET_KEYS` | Lista de chaves secretas de múltiplos projetos | **Admin** (validate-token) | Suporte multi-projeto na validação |
32
+ | `SUPABASE_JWKS` | JSON Web Key Set para validação de tokens | **Admin** (validate-token) | Padrão JWKS para rotação de chaves |
33
+
34
+ ---
35
+
36
+ ## Desenvolvimento e Preview
37
+
38
+ | Secret | Finalidade | Projetos | Observações |
39
+ |--------|-----------|----------|-------------|
40
+ | `DEV_ACCESS_TOKEN` | Token OAuth pré-configurado para ambiente de preview | **Admin**, **Cockpit** (sync-completed, view-pendencias), **Documentos**, **PDI** | Permite autenticação no preview Lovable sem fluxo OAuth |
41
+ | `DEV_ID_TOKEN` | ID token pré-configurado para ambiente de preview | **Admin**, **Cockpit**, **Documentos**, **PDI** | Par do DEV_ACCESS_TOKEN |
42
+ | `DEV_TOKENS_SECRET` | Secret de autenticação da edge function `dev-tokens` | **Admin** | Protege o endpoint que retorna os tokens de dev |
43
+ | `CRON_SECRET` | Header de autenticação do cron job `audit-ship` | **Admin** | Enviado como `x-cron-secret` pelo pg_cron |
44
+
45
+ ---
46
+
47
+ ## E-mail (AWS SES)
48
+
49
+ | Secret | Finalidade | Projetos |
50
+ |--------|-----------|----------|
51
+ | `AWS_ACCESS_KEY_ID` | Credencial IAM para AWS SES | **Admin** (send-email), **Cockpit** (notify-suggestion), **Treinamentos** (docs-process-outdated) |
52
+ | `AWS_SECRET_ACCESS_KEY` | Credencial IAM para AWS SES | **Admin** (send-email), **Cockpit** (notify-suggestion), **Treinamentos** (docs-process-outdated) |
53
+ | `AWS_SES_REGION` | Região do SES (default: `us-east-1`) | **Admin**, **Cockpit**, **Treinamentos** |
54
+ | `AWS_SES_FROM_EMAIL` | Endereço de e-mail remetente | **Admin**, **Cockpit**, **Treinamentos** |
55
+ | `AWS_SES_FROM_NAME` | Nome exibido como remetente | **Admin**, **Cockpit**, **Treinamentos** |
56
+ | `SUGGESTION_NOTIFY_EMAIL` | E-mail destino para notificações de sugestões do Cockpit | **Cockpit** (notify-suggestion) |
57
+
58
+ ---
59
+
60
+ ## Azure
61
+
62
+ | Secret | Finalidade | Projetos | Observações |
63
+ |--------|-----------|----------|-------------|
64
+ | `AZURE_BLOB_ACCOUNT_URL` | URL da conta Azure Blob Storage | **Admin** (azure-blob-upload) | Upload de arquivos para Azure |
65
+ | `AZURE_BLOB_ACCOUNT_KEY` | SharedKey da conta Azure Blob | **Admin** (azure-blob-upload) | Método preferido de autenticação |
66
+ | `AZURE_BLOB_SAS_TOKEN` | SAS Token para Azure Blob | **Admin** (azure-blob-upload) | ⚠️ **Deprecated** — fallback do `AZURE_BLOB_ACCOUNT_KEY` |
67
+ | `AZURE_TENANT_ID` | Tenant ID do Azure AD (Entra ID) | **Colaboradores** (entra-id-sync) | Sincronização de usuários via Microsoft Graph |
68
+ | `AZURE_CLIENT_ID` | Client ID do app Azure AD | **Colaboradores** (entra-id-sync) | Par do AZURE_TENANT_ID |
69
+
70
+ > **Nota:** Existia uma secret `AZURE_CLIENT_SECRET` que era recriada indevidamente. Nenhum projeto no workspace a referencia no código — a origem da recriação não foi identificada.
71
+
72
+ ---
73
+
74
+ ## Integrações de IA
75
+
76
+ | Secret | Finalidade | Projetos |
77
+ |--------|-----------|----------|
78
+ | `OPENAI_API_KEY` | Chave da API OpenAI (GPT) | **Educação** (generate-block-content, generate-course-structure, process-document, extract-certificate-data, generate-quiz-from-document), **Desempenho** (generate-questions-ai, performance-generate-*), **PDI** (generate-pdi-actions, generate-strategic-plan), **Competências** (generate-questions-ai), **Pulso** (analyze-comments, analyze-survey-data, generate-action-plan, refine-action-plan, analyze-custom-survey, generate-survey-action-plan), **Treinamentos** (generate-quiz-from-document, suggest-evaluation-criteria, validate-certificate) |
79
+ | `OPENROUTER_API_KEY` | Chave do OpenRouter (modelo: `google/gemini-2.5-flash`) | **Matriz de Foco** (generic-app-scan, manager-chat, outlook-calendar, redundancy-hunter, smart-assistant) |
80
+ | `LOVABLE_API_KEY` | Chave da API Lovable (AI Gateway) | **Educação** (generate-questions-ai) |
81
+
82
+ ---
83
+
84
+ ## Integrações Externas
85
+
86
+ | Secret | Finalidade | Projetos | Observações |
87
+ |--------|-----------|----------|-------------|
88
+ | `CLICKSIGN_SANDBOX_API_KEY` | API Key do Clicksign (ambiente sandbox) | **Admin** (clicksign) | Assinatura eletrônica de documentos |
89
+ | `ELASTIC_URL` | URL do cluster Elasticsearch | **Admin** (audit-ship) | Destino dos logs de auditoria |
90
+ | `ELASTIC_API_KEY` | API Key do Elasticsearch | **Admin** (audit-ship) | Autenticação no cluster |
91
+ | `HUBSPOT_PRIVATE_APP_TOKEN` | Token de app privado do HubSpot | **Cockpit** (hubspot-tickets) | No código é lido como `HUBSPOT_ACCESS_TOKEN` via `Deno.env.get()` |
92
+ | `SENSITIVE_DATA_KEY` | Chave AES-GCM para criptografia de dados sensíveis (CPF, etc.) | **Colaboradores** (sensitive-data, api-export-sensitive-data, entra-id-sync), **Matriz de Foco** (generic-app-scan, generic-app-secrets, migrate-legacy-tokens) | Chave hex de 256 bits |
93
+ | `VITE_QUALIEX_API_URL` | URL da API Qualiex | **Admin** (validate-token), **Cockpit** (_shared/auth), **Treinamentos** (docs-process-outdated, notify-leader) | Configuração de ambiente (prod vs dev) |
94
+
95
+ ---
96
+
97
+ ## Secrets sem Referência no Código
98
+
99
+ | Secret | Status | Recomendação |
100
+ |--------|--------|-------------|
101
+ | `VITE_BUILDER_API_KEY` | Nenhuma edge function ou código frontend referencia esta secret | ⚠️ Candidata a remoção — verificar se algum serviço externo a utiliza antes de deletar |
102
+
103
+ ---
104
+
105
+ ## Secrets Específicas de Projetos (não listadas acima)
106
+
107
+ Estas secrets são usadas apenas por projetos específicos mas vivem no mesmo projeto Supabase:
108
+
109
+ | Secret (no código) | Projeto | Finalidade |
110
+ |---------------------|---------|-----------|
111
+ | `TRAININGS_SERVICE_API_KEY` | **Treinamentos** | Auth service-to-service entre edge functions |
112
+ | `HUBSPOT_ACCESS_TOKEN` | **Cockpit** | Mesmo valor de `HUBSPOT_PRIVATE_APP_TOKEN` (nome diferente no `Deno.env.get`) |
113
+
114
+ > **Nota:** Estas secrets podem não estar na lista do dashboard se foram adicionadas diretamente ou por outro projeto. Verifique no [painel de secrets](https://supabase.com/dashboard/project/ccjfvpnndclajkleyqkc/settings/functions).
115
+
116
+ ---
117
+
118
+ ## Referências
119
+
120
+ - [Painel de Secrets do Supabase](https://supabase.com/dashboard/project/ccjfvpnndclajkleyqkc/settings/functions)
121
+ - [Plano de Segurança (Fase 2)](./../.lovable/plan.md)
122
+ - [Inventário de Storage Buckets](./STORAGE_BUCKETS.md)