feat: portal redesign, pricing catalog, partner-staff invites

- portal: new admin/ and partner/ surfaces with full component library
  (AppLauncher, Avatar, Badge, Card, Modal, Tabs, etc.), composables,
  layouts, partner-routing middleware, and supporting server APIs
- pricing: Price schema/module with operator CRUD, pricing.vue catalog UI,
  Subscription extended with cycle/currency/perSeatAmount/seats snapshots
  for stable MRR aggregation
- partner staff: User.partnerId, invite-partner-user DTO and flow,
  /partners/:slug/users endpoints, InvitePartnerUserModal, shared
  dezky-partner-staff Authentik group
- /me: partner-aware endpoint returning user + partner context so portal
  can route between end-user and partner-admin surfaces
- tenant: seats field for portfolio displays and future MRR calculations
- operator: pricing page, signed-out page, useMe/useToast composables,
  ToastStack
This commit is contained in:
Ronni Baslund
2026-05-28 20:00:33 +02:00
parent be430179d9
commit 0bd4e5498e
144 changed files with 22110 additions and 209 deletions
@@ -183,7 +183,16 @@ services:
image: ghcr.io/goauthentik/server:2025.10
container_name: dezky-authentik
restart: unless-stopped
command: server
# Override the image's entrypoint to run rebrand-web.sh first, then
# chain to dumb-init -- ak (the image's normal entrypoint). The script
# patches "Powered by authentik" → "Powered by Dezky" in the served
# web bundles on every container start, since those filenames are
# version-stamped and can't be safely bind-mounted across upgrades.
# Runs as root (user "0") so the sed can write to /web/dist; the script
# drops privileges back to uid 1000 before exec'ing ak.
user: "0"
entrypoint: ["/lifecycle/rebrand-web.sh"]
command: ["server"]
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_REDIS__PASSWORD: ${REDIS_PASSWORD}
@@ -202,6 +211,7 @@ services:
- authentik_certs:/certs
- authentik_templates:/templates
- ./configs/authentik/blueprints:/blueprints/custom:ro
- ./configs/authentik/rebrand-web.sh:/lifecycle/rebrand-web.sh:ro
networks: [dezky]
depends_on:
postgres:
@@ -213,6 +223,17 @@ services:
- traefik.http.routers.authentik.rule=Host(`auth.dezky.local`)
- traefik.http.routers.authentik.tls=true
- traefik.http.services.authentik.loadbalancer.server.port=9000
# Hide Authentik's end-user dashboard. Anything hitting
# auth.dezky.local/ (root) or /if/user/* gets bounced to
# app.dezky.local. Login flow paths (/flows/, /application/o/,
# /api/, /static/, /if/flow/) and the admin UI (/if/admin/) keep
# working. After OIDC sign-in the relying party callback fires
# first, so users never land on /if/user/ during a normal flow —
# this only matters for users who type auth.dezky.local directly.
- "traefik.http.middlewares.authentik-hide-dashboard.redirectregex.regex=^https://auth\\.dezky\\.local(/|/if/user(/.*)?)$"
- "traefik.http.middlewares.authentik-hide-dashboard.redirectregex.replacement=https://app.dezky.local/"
- "traefik.http.middlewares.authentik-hide-dashboard.redirectregex.permanent=false"
- traefik.http.routers.authentik.middlewares=authentik-hide-dashboard
authentik-worker:
image: ghcr.io/goauthentik/server:2025.10
@@ -440,6 +461,10 @@ services:
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
volumes:
- ../../apps/portal:/app
# Read-only mount of the monorepo's shared packages so Nuxt's
# components.dirs entry (/shared-packages/ui/components) resolves
# inside this container. Same mount is added to the operator service.
- ../../packages:/shared-packages:ro
- portal_node_modules:/app/node_modules
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
networks: [dezky]
@@ -484,6 +509,8 @@ services:
NODE_EXTRA_CA_CERTS: /etc/ssl/mkcert-root.pem
volumes:
- ../../apps/operator:/app
# Shared packages — see portal service for explanation.
- ../../packages:/shared-packages:ro
- operator_node_modules:/app/node_modules
- ./certs/mkcert-root.pem:/etc/ssl/mkcert-root.pem:ro
networks: [dezky]