feat: partner enrichment, mutations, settings & branding + operator quick-wins

Backend (platform-api): computed tenant health plus industry/brandColor; partner-scoped tenant update/suspend/resume guarded by assertPartnerOwnsTenant; enriched partner users (MFA + access level) with invite/remove; partner settings and whitelabel branding persistence; Authentik authenticator counting and group removal. Audit on every mutation.

Frontend (portal): all five partner pages on real data — dashboard alerts, customers edit/suspend, team MFA/access with invite/remove, editable settings, branding fetch/save.

Operator: dashboard and infrastructure service health driven by real liveness probes; fabricated uptime/p95/error-rate removed.
This commit is contained in:
Ronni Baslund
2026-05-30 08:03:07 +02:00
parent a51dc9a732
commit 89691626f4
33 changed files with 1753 additions and 198 deletions
@@ -0,0 +1,23 @@
// Resume a suspended partner-owned customer tenant. Forwards to platform-api
// POST /me/partner/tenants/:slug/resume (ownership enforced server-side).
import { getUserSession } from 'nuxt-oidc-auth/runtime/server/utils/session.js'
export default defineEventHandler(async (event) => {
const session = await getUserSession(event).catch(() => null)
const accessToken = (session as { accessToken?: string } | null)?.accessToken
if (!accessToken) {
throw createError({ statusCode: 401, statusMessage: 'Not signed in' })
}
const slug = getRouterParam(event, 'slug')
const base = process.env.PLATFORM_API_INTERNAL_URL ?? 'http://platform-api:3001'
try {
return await $fetch(`${base}/me/partner/tenants/${slug}/resume`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
})
} catch (err: unknown) {
const e = err as { statusCode?: number; data?: unknown }
throw createError({ statusCode: e.statusCode ?? 500, data: e.data })
}
})
@@ -0,0 +1,23 @@
// Suspend a partner-owned customer tenant. Forwards to platform-api
// POST /me/partner/tenants/:slug/suspend (ownership enforced server-side).
import { getUserSession } from 'nuxt-oidc-auth/runtime/server/utils/session.js'
export default defineEventHandler(async (event) => {
const session = await getUserSession(event).catch(() => null)
const accessToken = (session as { accessToken?: string } | null)?.accessToken
if (!accessToken) {
throw createError({ statusCode: 401, statusMessage: 'Not signed in' })
}
const slug = getRouterParam(event, 'slug')
const base = process.env.PLATFORM_API_INTERNAL_URL ?? 'http://platform-api:3001'
try {
return await $fetch(`${base}/me/partner/tenants/${slug}/suspend`, {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
})
} catch (err: unknown) {
const e = err as { statusCode?: number; data?: unknown }
throw createError({ statusCode: e.statusCode ?? 500, data: e.data })
}
})