Substitui o portal Vite+Vue puro por Nuxt 3 com BFF embutido (Nitro server
routes) e fluxo de autenticação Keycloak via token-handler pattern.
Server (BFF):
- server/api/auth/{login,callback,refresh,logout,me}.ts — Keycloak PKCE
- server/api/proxy/[...path].ts — proxy autenticado pro core-api com tenant
- server/utils/{session,keycloak,pkce,redis,tenant,prefeitura}.ts
- server/middleware/csrf.ts — Origin check + header X-Requested-With
Auth (token-handler pattern):
- JWT vive só server-side em Redis; cliente recebe cookie session-id opaco
- Refresh transparente quando access_token expira
- Multi-tenant via hostname → X-Municipio/X-Dominio injetados no proxy
- Realm dedicado: modumfiscal-portal-{env}
Frontend (Nuxt):
- src/pages/** (file-based routing) substitui src/views/
- Plugins SSR: prefeitura (bootstrap pré-hidratação) + auth (hidrata user via /api/auth/me)
- Composables useAuth, useApi, useLoginModal, useFocusLoginInput
- Modal global de login quando middleware /portal/** bloqueia
- Splash overlay no boot esconde flash do preset inicial pro tema dinâmico
- DocumentoInput bloqueia campo quando user autenticado (pré-preenche em certidão/IPTU)
Removidos:
- index.html, vite.config.js, src/main.js, src/router/
- src/config/apiClient.js (substituído por \$fetch via /api/proxy)
- src/services/{auth,prefeitura}Service.js (lógica migrada pra composables/plugins)
- src/mocks/ (não mais usado)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
101 lines
2.6 KiB
TypeScript
101 lines
2.6 KiB
TypeScript
import { defineNuxtConfig } from 'nuxt/config'
|
|
import tailwindcss from '@tailwindcss/vite'
|
|
import Aura from '@primeuix/themes/aura'
|
|
import { definePreset } from '@primeuix/themes'
|
|
|
|
// Preset inicial com paleta `blue` — evita flash verde (Aura default = emerald) no SSR/boot.
|
|
// O tema dinâmico da prefeitura (via theme.config.js / applyTemplate) sobrescreve isso
|
|
// no client-side assim que o store é hidratado.
|
|
const InitialPreset = definePreset(Aura, {
|
|
semantic: {
|
|
primary: {
|
|
50: '#eff6ff',
|
|
100: '#dbeafe',
|
|
200: '#bfdbfe',
|
|
300: '#93c5fd',
|
|
400: '#60a5fa',
|
|
500: '#3b82f6',
|
|
600: '#2563eb',
|
|
700: '#1d4ed8',
|
|
800: '#1e40af',
|
|
900: '#1e3a8a',
|
|
950: '#172554',
|
|
},
|
|
},
|
|
})
|
|
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: '2025-10-01',
|
|
ssr: true,
|
|
srcDir: 'src',
|
|
serverDir: 'server',
|
|
devtools: { enabled: true },
|
|
|
|
modules: [
|
|
'@pinia/nuxt',
|
|
'pinia-plugin-persistedstate/nuxt',
|
|
'@primevue/nuxt-module',
|
|
],
|
|
|
|
// Auto-import de components sem prefix de diretório (AccessibilityWidget em vez de CommonAccessibilityWidget).
|
|
components: [
|
|
{ path: '~/components', pathPrefix: false },
|
|
],
|
|
|
|
css: [
|
|
'~/assets/main.css',
|
|
'~/assets/layout/layout.scss',
|
|
],
|
|
|
|
vite: {
|
|
plugins: [tailwindcss()],
|
|
},
|
|
|
|
primevue: {
|
|
options: {
|
|
theme: {
|
|
preset: InitialPreset,
|
|
options: { darkModeSelector: '.app-dark' },
|
|
},
|
|
},
|
|
autoImport: true,
|
|
},
|
|
|
|
runtimeConfig: {
|
|
// Servidor only — disponível em useRuntimeConfig() no server/
|
|
keycloakUrl: '',
|
|
keycloakRealm: '',
|
|
keycloakClientId: '',
|
|
keycloakClientSecret: '',
|
|
coreApiUrl: '',
|
|
redisUrl: '',
|
|
cookieSecret: '',
|
|
sessionTtlSeconds: 28800,
|
|
pkceTtlSeconds: 300,
|
|
|
|
public: {
|
|
// Disponível no cliente — sem segredos
|
|
appName: 'Portal Modum Fiscal',
|
|
},
|
|
},
|
|
|
|
app: {
|
|
head: {
|
|
htmlAttrs: { lang: 'pt-BR' },
|
|
title: 'Portal do Contribuinte',
|
|
meta: [
|
|
{ charset: 'utf-8' },
|
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
|
],
|
|
link: [
|
|
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
|
|
],
|
|
},
|
|
pageTransition: { name: 'page', mode: 'out-in' },
|
|
},
|
|
|
|
typescript: {
|
|
strict: false,
|
|
},
|
|
})
|