Configured Azure AD and Dockerfile
This commit is contained in:
parent
85f20147ed
commit
ad262a315c
@ -1,36 +1,47 @@
|
||||
# 1. Stage: Abhängigkeiten installieren
|
||||
FROM node:20-alpine AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm ci
|
||||
|
||||
# 2. Stage: Builder (Der Code wird kompiliert)
|
||||
# 2. Stage: Builder (Code kompilieren)
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
# Hier werden auch die Environment Variables für den Build gebraucht
|
||||
# (In Dokploy setzt du diese später, aber für den Build ignorieren wir ESLint Fehler oft)
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# 3. Stage: Runner (Das eigentliche Image für Dokploy - winzig klein)
|
||||
# 3. Stage: Runner (Production Image)
|
||||
FROM node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV production
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
# Wir kopieren nur das Nötigste aus dem Builder
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Set correct permissions for prerender cache
|
||||
RUN mkdir .next
|
||||
RUN chown nextjs:nodejs .next
|
||||
|
||||
# Kopiere den Standalone-Build und Static-Files
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
ENV PORT 3000
|
||||
ENV HOSTNAME "0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
@ -1,76 +1,80 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--color-background: hsl(0 0% 100%);
|
||||
--color-foreground: hsl(0 0% 3.9%);
|
||||
--color-card: hsl(0 0% 100%);
|
||||
--color-card-foreground: hsl(0 0% 3.9%);
|
||||
--color-popover: hsl(0 0% 100%);
|
||||
--color-popover-foreground: hsl(0 0% 3.9%);
|
||||
--color-primary: hsl(0 0% 9%);
|
||||
--color-primary-foreground: hsl(0 0% 98%);
|
||||
--color-secondary: hsl(0 0% 96.1%);
|
||||
--color-secondary-foreground: hsl(0 0% 9%);
|
||||
--color-muted: hsl(0 0% 96.1%);
|
||||
--color-muted-foreground: hsl(0 0% 45.1%);
|
||||
--color-accent: hsl(0 0% 96.1%);
|
||||
--color-accent-foreground: hsl(0 0% 9%);
|
||||
--color-destructive: hsl(0 84.2% 60.2%);
|
||||
--color-destructive-foreground: hsl(0 0% 98%);
|
||||
--color-border: hsl(0 0% 89.8%);
|
||||
--color-input: hsl(0 0% 89.8%);
|
||||
--color-ring: hsl(0 0% 3.9%);
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
* {
|
||||
@apply border-border;
|
||||
border-color: hsl(var(--border));
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
background-color: hsl(var(--background));
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
|
||||
@ -3,14 +3,15 @@ import { DrizzleAdapter } from "@auth/drizzle-adapter";
|
||||
import { DefaultSession, getServerSession, NextAuthOptions } from "next-auth";
|
||||
import { Adapter } from "next-auth/adapters";
|
||||
import { redirect } from "next/navigation";
|
||||
import { env } from "@/lib/env.mjs"
|
||||
|
||||
import { z } from "zod";
|
||||
import AzureADProvider from "next-auth/providers/azure-ad";
|
||||
|
||||
declare module "next-auth" {
|
||||
interface Session {
|
||||
user: DefaultSession["user"] & {
|
||||
id: string;
|
||||
};
|
||||
accessToken?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,16 +25,43 @@ export type AuthSession = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
const envSchema = z.object({
|
||||
AZURE_AD_CLIENT_ID: z.string().min(1),
|
||||
AZURE_AD_CLIENT_SECRET: z.string().min(1),
|
||||
});
|
||||
|
||||
export const env = envSchema.parse(process.env);
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: DrizzleAdapter(db) as Adapter,
|
||||
callbacks: {
|
||||
session: ({ session, user }) => {
|
||||
session.user.id = user.id;
|
||||
jwt: async ({ token, account }) => {
|
||||
if (account) {
|
||||
token.accessToken = account.access_token;
|
||||
}
|
||||
return token;
|
||||
},
|
||||
session: ({ session, token, user }) => {
|
||||
if (user) {
|
||||
session.user.id = user.id;
|
||||
}
|
||||
if (token?.accessToken) {
|
||||
session.accessToken = token.accessToken as string;
|
||||
}
|
||||
return session;
|
||||
},
|
||||
},
|
||||
providers: [
|
||||
|
||||
AzureADProvider({
|
||||
clientId: env.AZURE_AD_CLIENT_ID,
|
||||
clientSecret: env.AZURE_AD_CLIENT_SECRET,
|
||||
tenantId: "common", // Multi-Tenancy Support
|
||||
authorization: {
|
||||
params: {
|
||||
scope: "openid profile email offline_access User.Read",
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
22
lib/env.mjs
22
lib/env.mjs
@ -11,7 +11,7 @@ export const env = createEnv({
|
||||
|
||||
NEXTAUTH_SECRET: process.env.NODE_ENV === "production"
|
||||
? z.string().min(1)
|
||||
: z.string().min(1).optional(),
|
||||
: z.string().optional(),
|
||||
NEXTAUTH_URL: z.preprocess(
|
||||
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
|
||||
// Since NextAuth.js automatically uses the VERCEL_URL if present.
|
||||
@ -19,15 +19,21 @@ export const env = createEnv({
|
||||
// VERCEL_URL doesn't include `https` so it cant be validated as a URL
|
||||
process.env.VERCEL_URL ? z.string().min(1) : z.string().url()
|
||||
),
|
||||
RESEND_API_KEY: z.string().min(1),
|
||||
STRIPE_SECRET_KEY: z.string().min(1),
|
||||
STRIPE_WEBHOOK_SECRET: z.string().min(1),
|
||||
|
||||
// Azure AD (Microsoft Entra ID) - optional in development
|
||||
AZURE_AD_CLIENT_ID: z.string().optional(),
|
||||
AZURE_AD_CLIENT_SECRET: z.string().optional(),
|
||||
|
||||
// Optional in development
|
||||
RESEND_API_KEY: z.string().optional(),
|
||||
STRIPE_SECRET_KEY: z.string().optional(),
|
||||
STRIPE_WEBHOOK_SECRET: z.string().optional(),
|
||||
},
|
||||
client: {
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
|
||||
NEXT_PUBLIC_STRIPE_PRO_PRICE_ID: z.string().min(1),
|
||||
NEXT_PUBLIC_STRIPE_MAX_PRICE_ID: z.string().min(1),
|
||||
NEXT_PUBLIC_STRIPE_ULTRA_PRICE_ID: z.string().min(1), // NEXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1),
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().optional(),
|
||||
NEXT_PUBLIC_STRIPE_PRO_PRICE_ID: z.string().optional(),
|
||||
NEXT_PUBLIC_STRIPE_MAX_PRICE_ID: z.string().optional(),
|
||||
NEXT_PUBLIC_STRIPE_ULTRA_PRICE_ID: z.string().optional(),
|
||||
},
|
||||
// If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually
|
||||
// runtimeEnv: {
|
||||
|
||||
@ -2,6 +2,7 @@ import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
output: "standalone", // Erforderlich für Docker-Deployment
|
||||
reactCompiler: true,
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user