Adicionada compressão Brotli/Gzip, auto-import de Vue e PrimeVue, e análise visual do bundle para otimização de produção e Remove AppLayout duplicado de cada área (therapist, admin, configuracoes, account, supervisor, billing, features) e consolida sob um único pai no router/index.js. Adiciona RouterPassthrough para grupos de rota sem layout intermediário. Remove debug ativo (console.trace em router.push e queries Supabase em todo watch de rota) que degradava performance para todos os usuários.

This commit is contained in:
Leonardo
2026-03-25 12:14:43 -03:00
parent bfe148ef12
commit 0658e2e9bf
18 changed files with 979 additions and 991 deletions
+4 -114
View File
@@ -19,7 +19,6 @@ import { onMounted, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { supabase } from '@/lib/supabase/client';
import { useTenantStore } from '@/stores/tenantStore';
import { useEntitlementsStore } from '@/stores/entitlementsStore';
import { fetchDocsForPath } from '@/composables/useAjuda';
import AjudaDrawer from '@/components/AjudaDrawer.vue';
@@ -28,25 +27,14 @@ import AppOfflineOverlay from '@/components/AppOfflineOverlay.vue';
const route = useRoute();
const router = useRouter();
const tenantStore = useTenantStore();
const entStore = useEntitlementsStore();
function isTenantArea(path = '') {
return path.startsWith('/admin') || path.startsWith('/therapist');
}
function isPortalArea(path = '') {
return path.startsWith('/portal');
}
function isSaasArea(path = '') {
return path.startsWith('/saas');
return path.startsWith('/admin') || path.startsWith('/therapist') || path.startsWith('/configuracoes');
}
// ── Setup Wizard redirect ────────────────────────────────────────
async function checkSetupWizard() {
// Só verifica em área de tenant
if (!isTenantArea(route.path)) return;
// Não redireciona se já está no setup
if (route.path.includes('/setup')) return;
const uid = tenantStore.user?.id;
@@ -56,7 +44,6 @@ async function checkSetupWizard() {
if (!data) return;
// Determina o kind do tenant ativo para saber qual flag checar
const activeMembership = tenantStore.memberships?.find((m) => m.id === tenantStore.activeTenantId);
const kind = activeMembership?.kind ?? tenantStore.activeRole ?? '';
const isClinic = kind.startsWith('clinic');
@@ -68,113 +55,16 @@ async function checkSetupWizard() {
}
}
async function debugSnapshot(label = 'snapshot') {
console.group(`🧭 [APP DEBUG] ${label}`);
try {
// 0) rota + meta
console.log('route.fullPath:', route.fullPath);
console.log('route.path:', route.path);
console.log('route.name:', route.name);
console.log('route.meta:', route.meta);
// 1) storage
console.groupCollapsed('📦 Storage');
console.log('localStorage.tenant_id:', localStorage.getItem('tenant_id'));
console.log('localStorage.currentTenantId:', localStorage.getItem('currentTenantId'));
console.log('localStorage.tenant:', localStorage.getItem('tenant'));
console.log('sessionStorage.redirect_after_login:', sessionStorage.getItem('redirect_after_login'));
console.log('sessionStorage.intended_area:', sessionStorage.getItem('intended_area'));
console.groupEnd();
// 2) sessão auth (fonte real)
const { data: authData, error: authErr } = await supabase.auth.getUser();
if (authErr) console.warn('[auth.getUser] error:', authErr);
const user = authData?.user || null;
console.log('auth.user:', user ? { id: user.id, email: user.email } : null);
// 3) profiles.role (identidade global)
let profileRole = null;
if (user?.id) {
const { data: profile, error: pErr } = await supabase.from('profiles').select('role').eq('id', user.id).single();
if (pErr) console.warn('[profiles] error:', pErr);
profileRole = profile?.role || null;
}
console.log('profiles.role (global):', profileRole);
// 4) memberships via RPC (fonte de verdade do tenantStore)
let rpcTenants = null;
if (user?.id) {
const { data: rpcData, error: rpcErr } = await supabase.rpc('my_tenants');
if (rpcErr) console.warn('[rpc my_tenants] error:', rpcErr);
rpcTenants = rpcData ?? null;
}
console.log('rpc.my_tenants():', rpcTenants);
// 5) stores (sempre logar)
console.groupCollapsed('🏪 Stores (before optional loads)');
console.log('tenantStore.activeTenantId:', tenantStore.activeTenantId);
console.log('tenantStore.activeRole:', tenantStore.activeRole);
console.log('tenantStore.memberships:', tenantStore.memberships);
console.log('entStore.loaded:', entStore.loaded);
console.log('entStore.tenantId:', entStore.activeTenantId || entStore.tenantId);
console.groupEnd();
// 6) IMPORTANTÍSSIMO: não carregar tenant fora da área tenant
const path = route.path || '';
if (isTenantArea(path)) {
console.log('✅ Tenant area detected → will loadSessionAndTenant + entitlements');
await tenantStore.loadSessionAndTenant();
if (tenantStore.activeTenantId) {
await entStore.loadForTenant(tenantStore.activeTenantId);
}
console.groupCollapsed('🏪 Stores (after tenant loads)');
console.log('tenantStore.activeTenantId:', tenantStore.activeTenantId);
console.log('tenantStore.activeRole:', tenantStore.activeRole);
console.log('tenantStore.memberships:', tenantStore.memberships);
console.log("entStore.can('online_scheduling.manage'):", entStore.can?.('online_scheduling.manage'));
console.groupEnd();
// Redireciona para o wizard se setup não foi concluído
await checkSetupWizard();
} else if (isPortalArea(path)) {
console.log('🟣 Portal area detected → SKIP tenantStore.loadSessionAndTenant()');
} else if (isSaasArea(path)) {
console.log('🟠 SaaS area detected → SKIP tenantStore.loadSessionAndTenant()');
} else {
console.log('⚪ Other/public area detected → SKIP tenantStore.loadSessionAndTenant()');
}
} catch (e) {
console.error('[APP DEBUG] snapshot error:', e);
} finally {
console.groupEnd();
}
}
onMounted(async () => {
// 🔥 PRIMEIRO LOG — TENANT ID BRUTO (mantive sua ideia)
console.log('[SEU_TENANT_ID]', localStorage.getItem('tenant_id'));
// snapshot inicial
await debugSnapshot('mounted');
// Carrega docs de ajuda para a rota inicial
onMounted(() => {
fetchDocsForPath(route.path);
});
// snapshot a cada navegação (isso é o que vai te salvar)
watch(
() => route.fullPath,
async (to, from) => {
await debugSnapshot(`route change: ${from} -> ${to}`);
// Atualiza docs de ajuda ao navegar
() => {
fetchDocsForPath(route.path);
// Verifica setup sempre que entrar em área tenant
if (isTenantArea(route.path) && tenantStore.loaded) {
await checkSetupWizard();
checkSetupWizard();
}
}
);