52e0f5e375
- Dockerfile for the operator app (same pattern as portal/booking). - Env-driven auth/app base URLs in nuxt.config so one build serves dev (.local) and production (.eu). - Deployment + Service + Ingress on operator.dezky.eu. - Add operator to the typecheck matrix.
109 lines
4.1 KiB
TypeScript
109 lines
4.1 KiB
TypeScript
// Nuxt 3 configuration for the Dezky operator portal.
|
|
// Separate app from apps/portal — different OAuth client, different cookies,
|
|
// different domain, stricter authorization. See docs/OPERATOR-PLAN.md.
|
|
|
|
// Base URLs are environment-driven so one build runs in dev (.local) and
|
|
// production (.eu) — same approach as apps/portal. Set at BUILD (CI) and
|
|
// RUNTIME (fleet/apps/operator.yaml + operator-secrets); the .local defaults
|
|
// keep local dev working with no env.
|
|
const AUTH_URL = (process.env.NUXT_PUBLIC_AUTH_URL || 'https://auth.dezky.local').replace(/\/$/, '')
|
|
const OPERATOR_URL = (process.env.NUXT_PUBLIC_OPERATOR_URL || 'https://operator.dezky.local').replace(/\/$/, '')
|
|
const OPERATOR_OIDC_APP_SLUG = process.env.OPERATOR_OIDC_APP_SLUG || 'dezky-operator'
|
|
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: '2026-01-01',
|
|
devtools: { enabled: true },
|
|
|
|
modules: ['nuxt-oidc-auth'],
|
|
|
|
css: ['~/assets/styles/tokens.css', '~/assets/styles/base.css'],
|
|
|
|
// Auto-import from the shared packages/ui workspace in addition to the
|
|
// app's own components/. /shared-packages is bind-mounted in
|
|
// docker-compose.yml — outside containers the same files live at
|
|
// <repo>/packages/ui/components/. The local dir keeps the default
|
|
// directory-based prefix; the shared dir uses no prefix so
|
|
// CountrySelect.vue is just <CountrySelect>.
|
|
components: [
|
|
'~/components',
|
|
{ path: '/shared-packages/ui/components', pathPrefix: false },
|
|
],
|
|
|
|
app: {
|
|
head: {
|
|
htmlAttrs: { 'data-theme': 'dark' },
|
|
link: [
|
|
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
|
|
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' },
|
|
{
|
|
rel: 'stylesheet',
|
|
href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
|
|
oidc: {
|
|
defaultProvider: 'oidc',
|
|
session: {
|
|
expirationCheck: true,
|
|
automaticRefresh: true,
|
|
},
|
|
middleware: {
|
|
globalMiddlewareEnabled: true,
|
|
customLoginPage: true,
|
|
},
|
|
providers: {
|
|
// Generic OIDC against the dezky-operator Authentik client. Same shape
|
|
// as the customer portal's config but pointed at a different provider
|
|
// and a different audience.
|
|
oidc: {
|
|
clientId: process.env.NUXT_OIDC_CLIENT_ID || '',
|
|
clientSecret: process.env.NUXT_OIDC_CLIENT_SECRET || '',
|
|
redirectUri: process.env.NUXT_OIDC_REDIRECT_URI || `${OPERATOR_URL}/auth/oidc/callback`,
|
|
authorizationUrl: `${AUTH_URL}/application/o/authorize/`,
|
|
tokenUrl: `${AUTH_URL}/application/o/token/`,
|
|
userInfoUrl: `${AUTH_URL}/application/o/userinfo/`,
|
|
logoutUrl: `${AUTH_URL}/application/o/${OPERATOR_OIDC_APP_SLUG}/end-session/`,
|
|
openIdConfiguration:
|
|
`${AUTH_URL}/application/o/${OPERATOR_OIDC_APP_SLUG}/.well-known/openid-configuration`,
|
|
scope: ['openid', 'profile', 'email', 'groups'],
|
|
userNameClaim: 'preferred_username',
|
|
responseType: 'code',
|
|
grantType: 'authorization_code',
|
|
pkce: true,
|
|
skipAccessTokenParsing: true,
|
|
exposeAccessToken: true,
|
|
// Also expose id_token so /api/auth/sign-out can pass it as
|
|
// id_token_hint to Authentik's end-session endpoint. Without it
|
|
// Authentik can't identify the session to terminate and falls back
|
|
// to its own "you've logged out" confirmation page.
|
|
exposeIdToken: true,
|
|
},
|
|
},
|
|
},
|
|
|
|
vite: {
|
|
server: {
|
|
// Vite 7 added a strict host check; allow Traefik-fronted hostnames in dev
|
|
allowedHosts: ['operator.dezky.local'],
|
|
hmr: {
|
|
protocol: 'wss',
|
|
clientPort: 443,
|
|
},
|
|
},
|
|
},
|
|
|
|
nitro: {
|
|
routeRules: {
|
|
'/api/**': { cors: true },
|
|
},
|
|
// Persist nuxt-oidc-auth's session store on disk so HMR / dev-server
|
|
// restarts don't sign operators out. The default memory driver is fine
|
|
// in prod where one long-running container holds the state.
|
|
storage: {
|
|
oidc: { driver: 'fs', base: '.nuxt/oidc-store' },
|
|
},
|
|
},
|
|
})
|