diff --git a/apps/bot/src/env.ts b/apps/bot/src/env.ts index 4f41376..5311677 100644 --- a/apps/bot/src/env.ts +++ b/apps/bot/src/env.ts @@ -3,11 +3,14 @@ import { z } from 'zod'; config(); +const emptyToUndefined = (value: unknown) => + value === '' || value === undefined || value === null ? undefined : value; + const EnvSchema = z.object({ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), BOT_TOKEN: z.string().min(1), BOT_CLIENT_ID: z.string().min(1), - BOT_GUILD_ID: z.string().min(1).optional(), + BOT_GUILD_ID: z.preprocess(emptyToUndefined, z.string().min(1).optional()), DATABASE_URL: z.string().url(), REDIS_URL: z.string().url(), LOG_LEVEL: z.string().default('info'), @@ -15,11 +18,11 @@ const EnvSchema = z.object({ BACKUP_RETENTION_DAYS: z.coerce.number().int().positive().default(14), BACKUP_CRON: z.string().default('0 3 * * *'), BACKUP_DIR: z.string().default('/backups'), - METRICS_TOKEN: z.string().optional(), + METRICS_TOKEN: z.preprocess(emptyToUndefined, z.string().min(1).optional()), HEALTH_PORT: z.coerce.number().int().positive().default(8080), PUBLIC_BASE_URL: z.string().url().default('http://localhost:8080'), - TWITCH_CLIENT_ID: z.string().min(1).optional(), - TWITCH_CLIENT_SECRET: z.string().min(1).optional() + TWITCH_CLIENT_ID: z.preprocess(emptyToUndefined, z.string().min(1).optional()), + TWITCH_CLIENT_SECRET: z.preprocess(emptyToUndefined, z.string().min(1).optional()) }); export const env = EnvSchema.parse(process.env); diff --git a/apps/webui/Dockerfile b/apps/webui/Dockerfile index cf300c1..34c40ce 100644 --- a/apps/webui/Dockerfile +++ b/apps/webui/Dockerfile @@ -40,6 +40,8 @@ RUN pnpm --filter @nexumi/webui build FROM base AS runner ENV NODE_ENV=production +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 COPY --from=build /app/apps/webui/.next/standalone ./ COPY --from=build /app/apps/webui/.next/static ./apps/webui/.next/static COPY --from=build /app/apps/webui/public ./apps/webui/public diff --git a/docs/PHASE-TRACKING.md b/docs/PHASE-TRACKING.md index 795da88..5d42162 100644 --- a/docs/PHASE-TRACKING.md +++ b/docs/PHASE-TRACKING.md @@ -220,12 +220,17 @@ Dieses Dokument hält den aktuellen Implementierungsstand fest. Es wird bei jede ### Manuelle Tests (noch offen) -- Discord Developer Portal: OAuth2-Redirect `http://localhost:3000/api/auth/callback` (bzw. `https://nexumi.de/api/auth/callback` in Produktion) unter „OAuth2 → Redirects" eintragen; Scopes `identify guilds` sind Standard-OAuth2-Scopes, keine Extra-Freigabe nötig -- Login-Flow Ende-zu-Ende gegen echten Discord-Account testen (`/login` → Discord-Consent → `/dashboard`) -- Dashboard-Zugriff mit einem Account ohne „Server verwalten"-Recht prüfen (muss auf `/dashboard` zurückspringen) -- Modul-Toggles je Modul speichern und in der Bot-DB/Redis verifizieren (insbesondere Fun `enabled` und den neuen Redis-Hash `dashboard:modules:{guildId}`) -- Access-Rules anlegen/löschen und Dashboard-Audit-Log-Einträge in der DB prüfen -- `docker compose up -d --build webui` gegen laufenden Postgres/Redis-Stack verifizieren +- Discord Developer Portal: OAuth2-Redirect `http://localhost:3000/api/auth/callback` (bzw. `https://nexumi.de/api/auth/callback` in Produktion) unter „OAuth2 → Redirects" eintragen +- Login-Flow Ende-zu-Ende (`http://localhost:3000/login` → Discord → `/dashboard`) +- Zugriff ohne „Server verwalten" prüfen +- Modul-Toggles + Access-Rules speichern; Audit-Log prüfen + +### Deploy-Verifikation (automatisiert) + +- `docker compose up -d --build bot webui` OK +- Migration `20260722180000_phase6_webui` angewendet (`DashboardAccessRule`, `DashboardAuditLog`, `GuildSettings.timezone`) +- Bot healthy + ready; WebUI healthy (`/api/health` → `{"ok":true}`), Login-Seite erreichbar +- Checks: shared tests 23, webui typecheck/lint/test grün ## Nächster geplanter Schritt