forlogic-core 1.4.15 → 1.5.1

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.
@@ -0,0 +1,712 @@
1
+ # 🎫 Arquitetura de Tokens - Documentação Atualizada
2
+
3
+ ## 📋 Visão Geral
4
+
5
+ Este projeto implementa um **sistema de autenticação tripla** que integra Qualiex OAuth 2.0 com backend Supabase, proporcionando autenticação robusta e controle de acesso multi-tenant.
6
+
7
+ ## 🔑 Sistema de Três Tokens
8
+
9
+ ### 1. **Qualiex Access Token** (`access_token`)
10
+
11
+ - **Origem**: Servidor OAuth 2.0 Qualiex
12
+ - **Formato**: JWT assinado pelo Qualiex
13
+ - **Propósito**: Valida identidade e autorização com serviços Qualiex
14
+ - **Armazenamento**: `localStorage` como `qualiex_access_token`
15
+ - **Validade**: Configurada pelo Qualiex (tipicamente 1-2 horas)
16
+
17
+ #### Estrutura do Payload:
18
+ ```json
19
+ {
20
+ "default": "empresa_principal",
21
+ "co0": "empresa1;;;Nome Empresa 1;status",
22
+ "co1": "empresa2;;;Nome Empresa 2;status",
23
+ "co2": "empresa3;;;Nome Empresa 3;status",
24
+ "iat": 1234567890,
25
+ "exp": 1234567890
26
+ }
27
+ ```
28
+
29
+ #### Campos de Empresa (`co*`):
30
+ ```
31
+ Formato: alias;;;nome_empresa;status;;;;;;;company_id
32
+ Posições:
33
+ - [0]: alias da empresa
34
+ - [3]: nome da empresa
35
+ - [4]: status
36
+ - [7]: company_id (para RLS)
37
+ ```
38
+
39
+ ### 2. **Qualiex ID Token** (`id_token`)
40
+
41
+ - **Origem**: Servidor OpenID Connect Qualiex
42
+ - **Formato**: JWT com informações do perfil do usuário
43
+ - **Propósito**: Contém dados de identidade e perfil detalhado
44
+ - **Armazenamento**: `localStorage` como `qualiex_id_token`
45
+ - **Validade**: Mesmo período do access token
46
+
47
+ #### Estrutura do Payload:
48
+ ```json
49
+ {
50
+ "subNewId": "user_unique_id_123",
51
+ "email": "usuario@empresa.com",
52
+ "name": "Nome Completo do Usuário",
53
+ "identifier": "identificador_usuario",
54
+ "photo-date": "timestamp_foto",
55
+ "default": "empresa_principal",
56
+ "co0": "empresa1;;;Nome Empresa 1;status;;;;;;;id_empresa_1",
57
+ "co1": "empresa2;;;Nome Empresa 2;status;;;;;;;id_empresa_2",
58
+ "iat": 1234567890,
59
+ "exp": 1234567890
60
+ }
61
+ ```
62
+
63
+ ### 3. **Supabase Token** (`supabase_token`)
64
+
65
+ - **Origem**: Gerado pela Edge Function `validate-token`
66
+ - **Formato**: JWT assinado com secret do Supabase
67
+ - **Propósito**: Autentica usuário com backend Supabase e habilita RLS
68
+ - **Armazenamento**: `localStorage` como `supabase_token`
69
+ - **Validade**: 24 horas (renovação automática)
70
+
71
+ #### Estrutura do Payload:
72
+ ```json
73
+ {
74
+ "sub": "user_unique_id_123",
75
+ "email": "usuario@empresa.com",
76
+ "alias": "empresa_selecionada",
77
+ "company_id": "id_empresa_extraido",
78
+ "user_metadata": {
79
+ "name": "Nome Completo do Usuário",
80
+ "identifier": "identificador_usuario"
81
+ },
82
+ "aud": "authenticated",
83
+ "role": "authenticated",
84
+ "iat": 1234567890,
85
+ "exp": 1234567890
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 🔄 Fluxo de Autenticação
92
+
93
+ ### Diagrama do Fluxo Completo
94
+
95
+ ```mermaid
96
+ sequenceDiagram
97
+ participant U as Usuário
98
+ participant A as App Frontend
99
+ participant Q as Qualiex OAuth
100
+ participant E as Edge Function
101
+ participant S as Supabase
102
+ participant DB as PostgreSQL
103
+
104
+ Note over U,DB: Fluxo de Produção
105
+
106
+ U->>A: 1. Clique em "Login"
107
+ A->>Q: 2. Redirect para OAuth Qualiex
108
+ Q->>U: 3. Tela de login Qualiex
109
+ U->>Q: 4. Credenciais válidas
110
+ Q->>A: 5. Callback com tokens (access + id)
111
+
112
+ A->>A: 6. Extrai empresas do ID token
113
+ A->>A: 7. Usuário seleciona empresa
114
+
115
+ A->>E: 8. POST /validate-token
116
+ Note right of A: { access_token, alias }
117
+
118
+ E->>Q: 9. Valida access token
119
+ Q->>E: 10. Token válido ✓
120
+
121
+ E->>E: 11. Extrai company_id do token
122
+ E->>E: 12. Gera Supabase JWT
123
+
124
+ E->>A: 13. Retorna supabase_token
125
+
126
+ A->>A: 14. Armazena todos os tokens
127
+ A->>A: 15. Atualiza estado auth
128
+
129
+ A->>S: 16. Requests com supabase_token
130
+ S->>DB: 17. Query com RLS
131
+ Note right of S: WHERE alias = JWT.alias
132
+ DB->>S: 18. Dados filtrados
133
+ S->>A: 19. Resposta autorizada
134
+
135
+ Note over U,DB: Fluxo de Desenvolvimento
136
+
137
+ U->>A: 1. Login (Dev Mode)
138
+ A->>E: 2. POST /dev-tokens
139
+ E->>E: 3. Gera tokens mock
140
+ E->>A: 4. Retorna todos tokens
141
+ A->>A: 5. Mesmo fluxo de produção
142
+ ```
143
+
144
+ ### Estados do Fluxo
145
+
146
+ ```mermaid
147
+ stateDiagram-v2
148
+ [*] --> Unauthenticated
149
+
150
+ Unauthenticated --> OAuth_Redirect: Login Click
151
+ OAuth_Redirect --> Token_Validation: Callback Received
152
+
153
+ Token_Validation --> Company_Selection: Tokens Valid
154
+ Token_Validation --> Unauthenticated: Tokens Invalid
155
+
156
+ Company_Selection --> Supabase_Auth: Company Selected
157
+ Company_Selection --> Unauthenticated: User Cancels
158
+
159
+ Supabase_Auth --> Authenticated: Success
160
+ Supabase_Auth --> Unauthenticated: Supabase Error
161
+
162
+ Authenticated --> Token_Refresh: Token Expiring
163
+ Token_Refresh --> Authenticated: Refresh Success
164
+ Token_Refresh --> Unauthenticated: Refresh Failed
165
+
166
+ Authenticated --> Unauthenticated: Logout
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 🏗️ Arquitetura de Arquivos
172
+
173
+ ### Frontend (src/auth/)
174
+
175
+ ```
176
+ src/auth/
177
+ ├── components/
178
+ │ ├── ProtectedRoute.tsx # Proteção de rotas
179
+ │ └── UserInfo.tsx # Exibição de dados do usuário
180
+ ├── contexts/
181
+ │ └── AuthContext.tsx # Estado global de autenticação
182
+ ├── pages/
183
+ │ └── CallbackPage.tsx # Processamento do callback OAuth
184
+ └── services/
185
+ ├── AuthService.ts # Lógica de negócio de auth
186
+ └── TokenManager.ts # Gestão de armazenamento de tokens
187
+ ```
188
+
189
+ ### Backend (supabase/functions/)
190
+
191
+ ```
192
+ supabase/functions/
193
+ ├── validate-token/ # Validação em produção
194
+ │ └── index.ts # Valida Qualiex + gera Supabase token
195
+ ├── dev-tokens/ # Desenvolvimento
196
+ │ └── index.ts # Gera tokens mock para dev
197
+ └── secure-cors-middleware/ # Middleware CORS
198
+ └── index.ts # Configurações CORS seguras
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 🔧 Implementação Detalhada
204
+
205
+ ### AuthContext.tsx (Estado Global)
206
+
207
+ ```typescript
208
+ interface AuthState {
209
+ isAuthenticated: boolean;
210
+ isLoading: boolean;
211
+ user: UserInfo | null;
212
+ alias: string | null;
213
+ companies: Company[];
214
+ tokens: {
215
+ accessToken: string | null;
216
+ idToken: string | null;
217
+ supabaseToken: string | null;
218
+ };
219
+ }
220
+
221
+ const AuthContext = createContext<{
222
+ ...AuthState;
223
+ login: () => void;
224
+ logout: () => void;
225
+ switchUnit: (alias: string) => Promise<void>;
226
+ refreshData: () => void;
227
+ }>({});
228
+ ```
229
+
230
+ ### TokenManager.ts (Gestão de Tokens)
231
+
232
+ ```typescript
233
+ export class TokenManager {
234
+ // Armazenamento
235
+ static setAccessToken(token: string): void;
236
+ static setIdToken(token: string): void;
237
+ static setSupabaseToken(token: string): void;
238
+
239
+ // Recuperação
240
+ static getAccessToken(): string | null;
241
+ static getIdToken(): string | null;
242
+ static getSupabaseToken(): string | null;
243
+
244
+ // Validação
245
+ static isTokenExpired(token: string): boolean;
246
+ static isTokenValid(token: string): boolean;
247
+
248
+ // Limpeza
249
+ static clearTokens(): void;
250
+ static clearOAuthState(): void;
251
+
252
+ // Decodificação
253
+ static decodeJWT(token: string): any;
254
+ }
255
+ ```
256
+
257
+ ### AuthService.ts (Lógica de Negócio)
258
+
259
+ ```typescript
260
+ export class AuthService {
261
+ // OAuth Flow
262
+ static initiateLogin(): void;
263
+ static handleCallback(url: string): Promise<AuthResult>;
264
+
265
+ // Company Management
266
+ static extractCompanies(idToken: string): Company[];
267
+ static switchCompany(alias: string): Promise<void>;
268
+
269
+ // Token Operations
270
+ static validateTokens(accessToken: string, alias: string): Promise<string>;
271
+ static refreshSupabaseToken(): Promise<void>;
272
+
273
+ // State Management
274
+ static getCurrentUser(): UserInfo | null;
275
+ static isAuthenticated(): boolean;
276
+ static logout(): void;
277
+ }
278
+ ```
279
+
280
+ ---
281
+
282
+ ## 🌍 Ambientes: Desenvolvimento vs Produção
283
+
284
+ ### Desenvolvimento (`dev-tokens` function)
285
+
286
+ ```typescript
287
+ // Edge Function: supabase/functions/dev-tokens/index.ts
288
+ const isDev = origin.includes('localhost') ||
289
+ origin.includes('sandbox.lovable.dev') ||
290
+ Deno.env.get('DENO_DEPLOYMENT_ID') === undefined;
291
+
292
+ if (isDev) {
293
+ return {
294
+ access_token: DEV_ACCESS_TOKEN, // Token mock Qualiex
295
+ id_token: DEV_ID_TOKEN // Token mock com dados de teste
296
+ };
297
+ }
298
+ ```
299
+
300
+ **Características do Ambiente de Desenvolvimento:**
301
+ - ✅ Tokens mock pré-configurados
302
+ - ✅ Sem dependência de OAuth real
303
+ - ✅ Dados de teste realistas
304
+ - ✅ Múltiplas empresas de exemplo
305
+ - ✅ Fluxo completo simulado
306
+
307
+ ### Produção (`validate-token` function)
308
+
309
+ ```typescript
310
+ // Edge Function: supabase/functions/validate-token/index.ts
311
+ async function validateToken(accessToken: string, alias: string) {
312
+ // 1. Validar token com servidor Qualiex
313
+ const validation = await fetch(QUALIEX_VALIDATE_ENDPOINT, {
314
+ headers: {
315
+ 'Authorization': `Bearer ${accessToken}`,
316
+ 'un-alias': alias
317
+ }
318
+ });
319
+
320
+ // 2. Extrair company_id do token
321
+ const companyId = extractCompanyId(accessToken, alias);
322
+
323
+ // 3. Gerar Supabase JWT
324
+ const supabaseToken = await createJWT({
325
+ sub: userId,
326
+ alias: alias,
327
+ company_id: companyId,
328
+ // ... outros claims
329
+ }, SUPABASE_JWT_SECRET);
330
+
331
+ return supabaseToken;
332
+ }
333
+ ```
334
+
335
+ **Características do Ambiente de Produção:**
336
+ - ✅ OAuth real com Qualiex
337
+ - ✅ Validação de tokens em tempo real
338
+ - ✅ Dados reais de empresas
339
+ - ✅ Segurança completa
340
+ - ✅ Logs de auditoria
341
+
342
+ ---
343
+
344
+ ## 📦 Storage Strategy (Armazenamento)
345
+
346
+ ### LocalStorage Mapping
347
+
348
+ | Token | Key | Conteúdo | Persistência |
349
+ |-------|-----|----------|--------------|
350
+ | Access Token | `qualiex_access_token` | JWT Qualiex para API | Até logout |
351
+ | ID Token | `qualiex_id_token` | Dados do usuário + empresas | Até logout |
352
+ | Supabase Token | `supabase_token` | JWT para RLS Supabase | Até logout |
353
+
354
+ ### SessionStorage (Temporário)
355
+
356
+ | Item | Key | Conteúdo | Persistência |
357
+ |------|-----|----------|--------------|
358
+ | OAuth State | `oauth_state` | CSRF protection | Apenas sessão |
359
+ | Redirect URI | `qualiex_redirect_uri` | URL de retorno | Até uso |
360
+
361
+ ### Estratégia de Limpeza
362
+
363
+ ```typescript
364
+ // Limpeza automática em diferentes cenários
365
+ class TokenManager {
366
+ // Logout explícito
367
+ static logout(): void {
368
+ localStorage.removeItem('qualiex_access_token');
369
+ localStorage.removeItem('qualiex_id_token');
370
+ localStorage.removeItem('supabase_token');
371
+ sessionStorage.clear();
372
+ }
373
+
374
+ // Token expirado
375
+ static cleanExpiredTokens(): void {
376
+ Object.keys(localStorage).forEach(key => {
377
+ if (key.includes('token') && this.isTokenExpired(localStorage.getItem(key))) {
378
+ localStorage.removeItem(key);
379
+ }
380
+ });
381
+ }
382
+
383
+ // Mudança de empresa
384
+ static switchCompany(alias: string): void {
385
+ // Manter access_token e id_token
386
+ // Limpar apenas supabase_token (será regenerado)
387
+ localStorage.removeItem('supabase_token');
388
+ }
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## 🐛 Debugging e Troubleshooting
395
+
396
+ ### Logs Estruturados
397
+
398
+ ```typescript
399
+ // Habilitação de debug
400
+ const DEBUG_AUTH = import.meta.env.DEV || localStorage.getItem('debug_auth');
401
+
402
+ class AuthDebugger {
403
+ static logTokenDecoding(token: string, type: string): void {
404
+ if (DEBUG_AUTH) {
405
+ console.group(`[TokenDecoder] ${type}`);
406
+ console.log('Raw Token:', token.substring(0, 50) + '...');
407
+ console.log('Decoded:', this.decodeToken(token));
408
+ console.groupEnd();
409
+ }
410
+ }
411
+
412
+ static logAuthFlow(step: string, data: any): void {
413
+ if (DEBUG_AUTH) {
414
+ console.log(`[AuthFlow] ${step}:`, data);
415
+ }
416
+ }
417
+
418
+ static logRLSContext(): void {
419
+ if (DEBUG_AUTH) {
420
+ console.group('[RLS Context]');
421
+ console.log('Current alias:', this.getCurrentAlias());
422
+ console.log('JWT Claims:', this.getJWTClaims());
423
+ console.groupEnd();
424
+ }
425
+ }
426
+ }
427
+ ```
428
+
429
+ ### Problemas Comuns e Soluções
430
+
431
+ #### 1. **Token Parsing Errors**
432
+
433
+ ```typescript
434
+ // Problema: Erro ao decodificar JWT
435
+ // Causa: Base64 mal formado ou token corrompido
436
+ // Solução:
437
+ function safeDecodeJWT(token: string): any | null {
438
+ try {
439
+ const parts = token.split('.');
440
+ if (parts.length !== 3) throw new Error('Invalid JWT format');
441
+
442
+ const payload = parts[1];
443
+ const paddedPayload = payload + '='.repeat((4 - payload.length % 4) % 4);
444
+ const decoded = atob(paddedPayload.replace(/-/g, '+').replace(/_/g, '/'));
445
+
446
+ return JSON.parse(decoded);
447
+ } catch (error) {
448
+ console.error('[AuthService] Token decode failed:', error);
449
+ return null;
450
+ }
451
+ }
452
+ ```
453
+
454
+ #### 2. **Company Extraction Failures**
455
+
456
+ ```typescript
457
+ // Problema: Não encontra company_id no token
458
+ // Causa: Formato incorreto ou campo faltando
459
+ // Solução:
460
+ function extractCompanyId(token: string, alias: string): string | null {
461
+ const payload = this.safeDecodeJWT(token);
462
+ if (!payload) return null;
463
+
464
+ // Buscar em todos os campos co* dinamicamente
465
+ for (const key in payload) {
466
+ if (key.startsWith('co') && /^co\d+$/.test(key)) {
467
+ const coField = payload[key];
468
+ if (typeof coField === 'string') {
469
+ const parts = coField.split(';');
470
+ // Verificar se tem alias na posição 0 e company_id na posição 7
471
+ if (parts.length > 7 && parts[0] === alias && parts[7]) {
472
+ return parts[7];
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ console.warn(`[AuthService] Company ID not found for alias: ${alias}`);
479
+ return null;
480
+ }
481
+ ```
482
+
483
+ #### 3. **RLS Access Denied**
484
+
485
+ ```typescript
486
+ // Problema: Usuário não consegue acessar dados
487
+ // Causa: JWT não tem claims corretos ou RLS mal configurado
488
+ // Diagnóstico:
489
+ async function debugRLSAccess(): Promise<void> {
490
+ const supabaseToken = TokenManager.getSupabaseToken();
491
+ if (!supabaseToken) {
492
+ console.error('[RLS Debug] No Supabase token found');
493
+ return;
494
+ }
495
+
496
+ const claims = TokenManager.decodeJWT(supabaseToken);
497
+ console.group('[RLS Debug] Token Analysis');
498
+ console.log('Token alias:', claims.alias);
499
+ console.log('Token company_id:', claims.company_id);
500
+ console.log('Token expiry:', new Date(claims.exp * 1000));
501
+ console.log('Is expired:', claims.exp < Date.now() / 1000);
502
+ console.groupEnd();
503
+
504
+ // Testar acesso direto
505
+ try {
506
+ const { data, error } = await supabase
507
+ .from('examples')
508
+ .select('id, alias, title')
509
+ .limit(1);
510
+
511
+ if (error) {
512
+ console.error('[RLS Debug] Query failed:', error);
513
+ } else {
514
+ console.log('[RLS Debug] Query success:', data);
515
+ }
516
+ } catch (err) {
517
+ console.error('[RLS Debug] Query exception:', err);
518
+ }
519
+ }
520
+ ```
521
+
522
+ #### 4. **Token Refresh Issues**
523
+
524
+ ```typescript
525
+ // Problema: Token não renova automaticamente
526
+ // Causa: Lógica de refresh não executando
527
+ // Solução:
528
+ class TokenRefreshManager {
529
+ private static refreshTimer: NodeJS.Timeout | null = null;
530
+
531
+ static scheduleRefresh(token: string): void {
532
+ this.clearRefreshTimer();
533
+
534
+ const decoded = TokenManager.decodeJWT(token);
535
+ if (!decoded) return;
536
+
537
+ // Renovar 5 minutos antes de expirar
538
+ const expiryTime = decoded.exp * 1000;
539
+ const refreshTime = expiryTime - (5 * 60 * 1000);
540
+ const timeUntilRefresh = refreshTime - Date.now();
541
+
542
+ if (timeUntilRefresh > 0) {
543
+ this.refreshTimer = setTimeout(async () => {
544
+ try {
545
+ await AuthService.refreshSupabaseToken();
546
+ console.log('[TokenRefresh] Auto-refresh successful');
547
+ } catch (error) {
548
+ console.error('[TokenRefresh] Auto-refresh failed:', error);
549
+ // Forçar re-login
550
+ AuthService.logout();
551
+ }
552
+ }, timeUntilRefresh);
553
+ }
554
+ }
555
+
556
+ static clearRefreshTimer(): void {
557
+ if (this.refreshTimer) {
558
+ clearTimeout(this.refreshTimer);
559
+ this.refreshTimer = null;
560
+ }
561
+ }
562
+ }
563
+ ```
564
+
565
+ ---
566
+
567
+ ## 🔒 Considerações de Segurança
568
+
569
+ ### Tokens em localStorage
570
+
571
+ **Riscos:**
572
+ - ❌ Vulnerável a XSS (Cross-Site Scripting)
573
+ - ❌ Persistente entre sessões do browser
574
+ - ❌ Acessível via JavaScript
575
+
576
+ **Mitigações:**
577
+ - ✅ CSP (Content Security Policy) rigoroso
578
+ - ✅ HTTPS obrigatório em produção
579
+ - ✅ Validação de origem nas Edge Functions
580
+ - ✅ Tokens com TTL curto (24h max)
581
+ - ✅ Limpeza automática na logout
582
+
583
+ ### CSRF Protection
584
+
585
+ ```typescript
586
+ // Estado OAuth para prevenir CSRF
587
+ function generateOAuthState(): string {
588
+ const state = crypto.randomUUID();
589
+ sessionStorage.setItem('oauth_state', state);
590
+ return state;
591
+ }
592
+
593
+ function validateOAuthState(receivedState: string): boolean {
594
+ const storedState = sessionStorage.getItem('oauth_state');
595
+ sessionStorage.removeItem('oauth_state');
596
+ return storedState === receivedState;
597
+ }
598
+ ```
599
+
600
+ ### Token Validation
601
+
602
+ ```typescript
603
+ // Validação robusta de tokens
604
+ class TokenValidator {
605
+ static isValid(token: string): boolean {
606
+ if (!token) return false;
607
+
608
+ try {
609
+ const decoded = TokenManager.decodeJWT(token);
610
+ if (!decoded) return false;
611
+
612
+ // Verificar expiração
613
+ if (decoded.exp && decoded.exp < Date.now() / 1000) {
614
+ return false;
615
+ }
616
+
617
+ // Verificar campos obrigatórios
618
+ if (!decoded.sub || !decoded.aud) {
619
+ return false;
620
+ }
621
+
622
+ return true;
623
+ } catch {
624
+ return false;
625
+ }
626
+ }
627
+
628
+ static validateClaims(token: string, requiredClaims: string[]): boolean {
629
+ const decoded = TokenManager.decodeJWT(token);
630
+ if (!decoded) return false;
631
+
632
+ return requiredClaims.every(claim => decoded[claim] !== undefined);
633
+ }
634
+ }
635
+ ```
636
+
637
+ ---
638
+
639
+ ## 📊 Monitoramento e Métricas
640
+
641
+ ### Edge Functions Analytics
642
+
643
+ ```typescript
644
+ // Logging estruturado nas Edge Functions
645
+ function logAuthEvent(event: string, data: any): void {
646
+ console.log(JSON.stringify({
647
+ timestamp: new Date().toISOString(),
648
+ event: event,
649
+ data: data,
650
+ environment: Deno.env.get('DENO_DEPLOYMENT_ID') ? 'production' : 'development'
651
+ }));
652
+ }
653
+
654
+ // Métricas de uso
655
+ logAuthEvent('token_validation_start', { alias });
656
+ logAuthEvent('token_validation_success', { userId, alias });
657
+ logAuthEvent('token_validation_error', { error: error.message });
658
+ ```
659
+
660
+ ### Frontend Analytics
661
+
662
+ ```typescript
663
+ // Tracking de eventos de auth
664
+ class AuthAnalytics {
665
+ static trackLogin(method: 'oauth' | 'dev'): void {
666
+ // Implementar com seu analytics favorito
667
+ console.log('[Analytics] Login attempt:', method);
668
+ }
669
+
670
+ static trackCompanySwitch(fromAlias: string, toAlias: string): void {
671
+ console.log('[Analytics] Company switch:', { fromAlias, toAlias });
672
+ }
673
+
674
+ static trackTokenRefresh(success: boolean): void {
675
+ console.log('[Analytics] Token refresh:', { success });
676
+ }
677
+ }
678
+ ```
679
+
680
+ ---
681
+
682
+ ## 🚀 Próximos Passos e Melhorias
683
+
684
+ ### Roadmap de Melhorias
685
+
686
+ 1. **Segurança Avançada**
687
+ - [ ] Implementar httpOnly cookies para tokens
688
+ - [ ] Adicionar refresh token rotation
689
+ - [ ] Implementar device fingerprinting
690
+ - [ ] Rate limiting nas Edge Functions
691
+
692
+ 2. **Performance**
693
+ - [ ] Cache de validação de tokens
694
+ - [ ] Preload de dados de empresas
695
+ - [ ] Lazy loading de módulos auth
696
+ - [ ] Service Worker para token refresh
697
+
698
+ 3. **Monitoramento**
699
+ - [ ] Dashboard de métricas de auth
700
+ - [ ] Alertas de falhas de login
701
+ - [ ] Auditoria de mudanças de empresa
702
+ - [ ] Detecção de tentativas de ataque
703
+
704
+ 4. **Developer Experience**
705
+ - [ ] CLI para gerar tokens de dev
706
+ - [ ] Interface visual para debug de tokens
707
+ - [ ] Documentação interativa
708
+ - [ ] Testes automatizados de auth
709
+
710
+ ---
711
+
712
+ **🎫 Arquitetura robusta e escalável para autenticação multi-tenant segura.**