diff --git a/Dockerfile b/Dockerfile index 0375bac..5102ee0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM node:22-alpine AS builder +FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ @@ -10,7 +10,7 @@ RUN npm run build # Production stage — only the self-contained .output is needed. # bash + curl are added so Dokploy scheduled tasks (which wrap commands in # `bash -c "..."`) can run; alpine ships only ash and has no curl by default. -FROM node:22-alpine +FROM node:20-alpine RUN apk add --no-cache bash curl WORKDIR /app COPY --from=builder /app/.output .output diff --git a/nuxt.config.ts b/nuxt.config.ts index 2043abb..7757b4c 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -91,7 +91,8 @@ export default defineNuxtConfig({ }, runtimeConfig: { // Private keys (server-side only) - mongodbUri: process.env.MONGODB_URI || "", + mongodbUri: + process.env.MONGODB_URI || "mongodb://localhost:27017/ghostguild", jwtSecret: process.env.JWT_SECRET || "", resendApiKey: process.env.RESEND_API_KEY || "", helcimApiToken: process.env.HELCIM_API_TOKEN || "", diff --git a/server/api/admin/members/invite.post.js b/server/api/admin/members/invite.post.js index 710f4e1..ebd866c 100644 --- a/server/api/admin/members/invite.post.js +++ b/server/api/admin/members/invite.post.js @@ -4,7 +4,7 @@ import { Resend } from 'resend' import Member from '../../../models/member.js' import { connectDB } from '../../../utils/mongoose.js' -const resend = new Resend(useRuntimeConfig().resendApiKey) +const resend = new Resend(process.env.RESEND_API_KEY) export default defineEventHandler(async (event) => { await requireAdmin(event) diff --git a/server/api/admin/pre-registrants/invite.post.js b/server/api/admin/pre-registrants/invite.post.js index f3d46b3..3d16b88 100644 --- a/server/api/admin/pre-registrants/invite.post.js +++ b/server/api/admin/pre-registrants/invite.post.js @@ -4,7 +4,7 @@ import { Resend } from 'resend' import PreRegistration from '../../../models/preRegistration.js' import { connectDB } from '../../../utils/mongoose.js' -const resend = new Resend(useRuntimeConfig().resendApiKey) +const resend = new Resend(process.env.RESEND_API_KEY) export default defineEventHandler(async (event) => { await requireAdmin(event) diff --git a/server/plugins/validate-env.js b/server/plugins/validate-env.js index cb1c6ff..c190c4b 100644 --- a/server/plugins/validate-env.js +++ b/server/plugins/validate-env.js @@ -1,17 +1,23 @@ export default defineNitroPlugin(() => { - const config = useRuntimeConfig() - const checks = { - MONGODB_URI: config.mongodbUri, - JWT_SECRET: config.jwtSecret, - RESEND_API_KEY: config.resendApiKey, - HELCIM_API_TOKEN: config.helcimApiToken, - } + const required = [ + 'MONGODB_URI', + 'JWT_SECRET', + 'RESEND_API_KEY', + 'HELCIM_API_TOKEN', + ] - const missing = Object.entries(checks).filter(([, value]) => !value).map(([key]) => key) + const missing = required.filter((key) => { + // Check both process.env and runtime config where applicable + if (key === 'JWT_SECRET') { + const config = useRuntimeConfig() + return !config.jwtSecret + } + return !process.env[key] + }) if (missing.length > 0) { console.error(`FATAL: Missing required environment variables: ${missing.join(', ')}`) - console.error('Set these (or their NUXT_-prefixed equivalents) in your .env file or environment variables.') + console.error('Set these in your .env file or environment variables.') process.exit(1) } }) diff --git a/server/routes/oidc/interaction/login.post.ts b/server/routes/oidc/interaction/login.post.ts index a19af7b..0799a27 100644 --- a/server/routes/oidc/interaction/login.post.ts +++ b/server/routes/oidc/interaction/login.post.ts @@ -12,7 +12,7 @@ import { Resend } from "resend"; import Member from "../../../models/member.js"; import { connectDB } from "../../../utils/mongoose.js"; -const resend = new Resend(useRuntimeConfig().resendApiKey); +const resend = new Resend(process.env.RESEND_API_KEY); export default defineEventHandler(async (event) => { await connectDB(); diff --git a/server/utils/magicLink.js b/server/utils/magicLink.js index 928c7f0..9503539 100644 --- a/server/utils/magicLink.js +++ b/server/utils/magicLink.js @@ -6,7 +6,7 @@ import { randomUUID } from 'crypto' import { Resend } from 'resend' import Member from '../models/member.js' -const resend = new Resend(useRuntimeConfig().resendApiKey) +const resend = new Resend(process.env.RESEND_API_KEY) /** * Issue a 15-minute magic-link JWT for `email` and email it. diff --git a/server/utils/mongoose.js b/server/utils/mongoose.js index e75a5b4..6456191 100644 --- a/server/utils/mongoose.js +++ b/server/utils/mongoose.js @@ -7,7 +7,7 @@ export const connectDB = async () => { return; } - const MONGODB_URI = useRuntimeConfig().mongodbUri; + const MONGODB_URI = process.env.NUXT_MONGODB_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/ghostguild'; try { await mongoose.connect(MONGODB_URI, { diff --git a/server/utils/payments.js b/server/utils/payments.js index 9e529f2..bd0e984 100644 --- a/server/utils/payments.js +++ b/server/utils/payments.js @@ -2,7 +2,7 @@ import { Resend } from 'resend' import Payment from '../models/payment.js' import { paymentConfirmationEmail } from '../emails/paymentConfirmation.js' -const resend = new Resend(useRuntimeConfig().resendApiKey) +const resend = new Resend(process.env.RESEND_API_KEY) function mapStatus(helcimStatus) { if (helcimStatus === 'paid') return 'success' diff --git a/server/utils/resend.js b/server/utils/resend.js index e3cada2..24b2356 100644 --- a/server/utils/resend.js +++ b/server/utils/resend.js @@ -1,6 +1,6 @@ import { Resend } from "resend"; -const resend = new Resend(useRuntimeConfig().resendApiKey); +const resend = new Resend(process.env.RESEND_API_KEY); /** * Send event registration confirmation email