Files
dezky/apps/portal/components/NodeMark.vue
T
Ronni Baslund adfd9baafe chore: initial scaffold with running local stack and portal auth
Brings up Dezky's local development environment end-to-end:

Infrastructure (docker-compose):
- Traefik v3.7 reverse proxy with mkcert TLS (v3.2 couldn't speak Docker API 1.54)
- Postgres + Mongo + Redis with healthchecks and init script for per-service users
- Authentik 2025.10 (server + worker) as OIDC IdP
- Stalwart v0.16 mail server (image renamed from stalwartlabs/mail-server)
- OCIS 7.0 with PROXY_TLS=false and OCIS_CONFIG_DIR=/etc/ocis so init writes
  where the server reads
- Collabora office, plus the portal + provisioning service stubs
- Docker network aliases on Traefik so containers resolve auth.dezky.local etc.
  through the network (not host /etc/hosts)
- Docker socket mount parameterized for macOS Docker Desktop symlink path

Authentik provisioning (done via API after stack boot):
- ocis-provider (public client) + OCIS Files application
- dezky-portal provider (confidential) + Dezky Portal application
- Admin API token bound to akadmin manually since 2025.10's
  AUTHENTIK_BOOTSTRAP_TOKEN env var doesn't auto-materialize a token row

Portal (apps/portal):
- Nuxt 3 with nuxt-oidc-auth 1.0.0-beta.11 against generic 'oidc' preset
- Global auth middleware; login at /auth/oidc/login redirects to Authentik
- Visual implementation of Claude Design 'Auth' canvas: AuthShell, NodeMark,
  Auth* sub-components, design tokens as CSS custom properties
- Pages: auth/login, auth/expired, auth/disabled, index (post-login landing)
- mkcert root CA mounted into the portal so Node fetch trusts Authentik's
  self-signed cert (NODE_EXTRA_CA_CERTS) — dev only

Docs:
- AUTHENTIK-SETUP.md updated with manual token bind + portal provider scripted
  alternative
- NEXT-STEPS.md: Phase 1 and Phase 2 marked done with file locations and
  dev-mode caveats

Dev-mode shortcuts that need to be revisited before prod:
- skipAccessTokenParsing on the OIDC config
- NODE_EXTRA_CA_CERTS mkcert mount
- Bootstrap password still the generated value in .env
- Authentik admin token (dezky-bootstrap-token) is non-expiring
2026-05-23 21:25:11 +02:00

94 lines
2.5 KiB
Vue

<script setup lang="ts">
// Brand mark — a stylized "d" inside a squircle. Ported from project/logos.jsx.
// The geometry is computed so the letterform sits ~16u inside the 100x100 viewBox.
const props = withDefaults(
defineProps<{
size?: number
fg?: string
accent?: string
bowlR?: number
stemW?: number
contR?: number
dStyle?: 'donut' | 'solid' | 'outline'
dotPos?: 'corner' | 'tittle' | 'orbit' | 'none'
dotR?: number
}>(),
{
size: 22,
fg: '#0a0a0a',
accent: '#d4ff3a',
bowlR: 14,
stemW: 7,
contR: 22,
dStyle: 'donut',
dotPos: 'corner',
dotR: 4,
},
)
const geometry = computed(() => {
const overlap = props.stemW * 0.55
const cy = 52
const cx = 50 - props.stemW / 2 + overlap / 2
const stemX = cx + props.bowlR - overlap
const stemRight = stemX + props.stemW
const capR = props.stemW / 2
const stemTop = 26
const stemBottom = cy + props.bowlR
const holeR = Math.max(2.5, props.bowlR - props.stemW - 0.5)
const bowlPath =
`M ${cx - props.bowlR} ${cy} ` +
`a ${props.bowlR} ${props.bowlR} 0 1 0 ${props.bowlR * 2} 0 ` +
`a ${props.bowlR} ${props.bowlR} 0 1 0 ${-props.bowlR * 2} 0 Z`
const counterPath =
`M ${cx - holeR} ${cy} ` +
`a ${holeR} ${holeR} 0 1 0 ${holeR * 2} 0 ` +
`a ${holeR} ${holeR} 0 1 0 ${-holeR * 2} 0 Z`
const stemPath =
`M ${stemX} ${stemTop + capR} ` +
`a ${capR} ${capR} 0 0 1 ${props.stemW} 0 ` +
`L ${stemRight} ${stemBottom} ` +
`L ${stemX} ${stemBottom} Z`
const dotByPos = {
corner: { x: 74, y: 26 },
tittle: { x: stemX + props.stemW / 2, y: stemTop - props.dotR - 3 },
orbit: { x: cx - props.bowlR - props.dotR - 2, y: cy - props.bowlR - props.dotR - 2 },
none: null,
} as const
return { bowlPath, counterPath, stemPath, dot: dotByPos[props.dotPos] }
})
</script>
<template>
<svg
:width="size"
:height="size"
viewBox="0 0 100 100"
aria-label="Dezky"
role="img"
>
<rect x="8" y="8" width="84" height="84" :rx="contR" :fill="fg" />
<g v-if="dStyle === 'donut'" fill="#0a0a0a">
<path :d="geometry.bowlPath + ' ' + geometry.counterPath" fill-rule="evenodd" />
<path :d="geometry.stemPath" />
</g>
<g v-else-if="dStyle === 'solid'" fill="#0a0a0a">
<path :d="geometry.bowlPath" />
<path :d="geometry.stemPath" />
</g>
<circle
v-if="geometry.dot"
:cx="geometry.dot.x"
:cy="geometry.dot.y"
:r="dotR"
:fill="accent"
/>
</svg>
</template>