Day-of-launch deep-dive audit and remediation. 11 issues fixed across security, correctness, and reliability. Tests: 698 → 758 passing (+60), 0 failing, 2 skipped. CRITICAL (security) Fix #1 — HELCIM_API_TOKEN removed from runtimeConfig.public; dead useHelcim.js deleted. Production token MUST BE ROTATED post-deploy (was previously exposed in window.__NUXT__ payload). Fix #2 — /api/helcim/customer gated with origin check + per-IP/email rate limit + magic-link email verification (replaces unauthenticated setAuthCookie). Adds payment-bridge token for paid-tier signup so users can complete Helcim checkout before email verify. New utils: server/utils/{magicLink,rateLimit}.js. UX: signup success copy now prompts user to check email. Fix #3 — /api/events/[id]/payment deleted (dead code with unauth member-spoof bypass — processHelcimPayment was a permanent stub). Removes processHelcimPayment export and eventPaymentSchema. Fix #4 — /api/helcim/initialize-payment re-derives ticket amount server-side via calculateTicketPrice and calculateSeriesTicketPrice. Adds new series_ticket metadata type (was being shoved through event_ticket with seriesId in metadata.eventId). Fix #5 — /api/helcim/customer upgrades existing status:guest members in place rather than rejecting with 409. Lowercases email at lookup; preserves _id so prior event registrations stay linked. HIGH (correctness / reliability) Fix #6 — Daily reconciliation cron via Netlify scheduled function (@daily). New: netlify.toml, netlify/functions/reconcile-payments.mjs, server/api/internal/reconcile-payments.post.js. Shared-secret auth via NUXT_RECONCILE_TOKEN env var. Inline 3-retry exponential backoff on Helcim transactions API. Fix #7 — validateBeforeSave: false on event subdoc saves (waitlist endpoints) to dodge legacy location validators. Fix #8 — /api/series/[id]/tickets/purchase always upserts a guest Member when caller is unauthenticated, mirrors event-ticket flow byte-for-byte. SeriesPassPurchase.vue adds guest-account hint and client auth refresh on signedIn:true response. Fix #9 — /api/members/cancel-subscription leaves status active per ratified bylaws (was pending_payment). Adds lastCancelledAt audit field on Member model. Indirectly fixes false-positive detectStuckPendingPayment admin alert for cancelled members. Fix #10 — /api/auth/verify uses validateBody with strict() Zod schema (verifyMagicLinkSchema, max 2000 chars). Fix #11 — 8 vitest cases for cancel-subscription handler (was uncovered). Specs and audit at docs/superpowers/specs/2026-04-25-fix-*.md and docs/superpowers/plans/2026-04-25-launch-readiness-fixes.md. LAUNCH_READINESS.md updated with new test count, 3 deploy-time tasks (rotate Helcim token, set NUXT_RECONCILE_TOKEN, verify Netlify scheduled function), and Fixed-2026-04-25 fix log.
121 lines
3.5 KiB
TypeScript
121 lines
3.5 KiB
TypeScript
// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: "2025-07-15",
|
|
devtools: { enabled: false },
|
|
modules: ["@nuxt/eslint", "@nuxt/ui", "@nuxtjs/plausible"],
|
|
fonts: {
|
|
providers: {
|
|
google: false,
|
|
fontsource: false,
|
|
},
|
|
},
|
|
colorMode: {
|
|
preference: "system",
|
|
fallback: "light",
|
|
classSuffix: "",
|
|
},
|
|
app: {
|
|
head: {
|
|
htmlAttrs: { lang: "en" },
|
|
title: "Ghost Guild",
|
|
titleTemplate: "%s · Ghost Guild",
|
|
link: [
|
|
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
|
{
|
|
rel: "preconnect",
|
|
href: "https://fonts.gstatic.com",
|
|
crossorigin: "",
|
|
},
|
|
{
|
|
rel: "stylesheet",
|
|
href: "https://fonts.googleapis.com/css2?family=Brygada+1918:ital,wght@0,400..700;1,400..700&family=Commit+Mono&display=swap",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
build: {
|
|
transpile: ["vue-cal"],
|
|
},
|
|
routeRules: {
|
|
"/policies/code-of-conduct": {
|
|
redirect: {
|
|
to: "https://publish.obsidian.md/baby-ghosts-corp-docs/Public/Policies/Code+of+Conduct",
|
|
statusCode: 302,
|
|
},
|
|
},
|
|
"/policies/conflict-resolution": {
|
|
redirect: {
|
|
to: "https://publish.obsidian.md/baby-ghosts-corp-docs/Public/Policies/Conflict+Resolution+Policy",
|
|
statusCode: 302,
|
|
},
|
|
},
|
|
},
|
|
plausible: {
|
|
domain: "ghostguild.org",
|
|
},
|
|
css: ["~/assets/css/main.css"],
|
|
vite: {
|
|
optimizeDeps: {
|
|
include: ["@plausible-analytics/tracker"],
|
|
},
|
|
server: {
|
|
allowedHosts: [".trycloudflare.com", ".ngrok-free.app", ".ngrok.io"],
|
|
hmr: {
|
|
port: 24678,
|
|
},
|
|
watch: {
|
|
ignored: [
|
|
"**/.git/**",
|
|
"**/.nuxt/**",
|
|
"**/.output/**",
|
|
"**/node_modules/**",
|
|
"**/dist/**",
|
|
"**/e2e/**",
|
|
"**/coverage/**",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
nitro: {
|
|
watchOptions: {
|
|
ignored: [
|
|
"**/.git/**",
|
|
"**/.nuxt/**",
|
|
"**/.output/**",
|
|
"**/node_modules/**",
|
|
"**/dist/**",
|
|
"**/e2e/**",
|
|
"**/coverage/**",
|
|
],
|
|
},
|
|
},
|
|
runtimeConfig: {
|
|
// Private keys (server-side only)
|
|
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 || "",
|
|
slackBotToken: process.env.SLACK_BOT_TOKEN || "",
|
|
slackAdminBotToken: process.env.SLACK_ADMIN_BOT_TOKEN || "",
|
|
slackSigningSecret: process.env.SLACK_SIGNING_SECRET || "",
|
|
slackVettingChannelId: process.env.SLACK_VETTING_CHANNEL_ID || "",
|
|
oidcClientId: process.env.OIDC_CLIENT_ID || "outline-wiki",
|
|
oidcClientSecret: process.env.OIDC_CLIENT_SECRET || "",
|
|
oidcCookieSecret: process.env.OIDC_COOKIE_SECRET || "",
|
|
outlineApiKey: process.env.OUTLINE_API_KEY || "",
|
|
helcimMonthlyPlanId: process.env.NUXT_HELCIM_MONTHLY_PLAN_ID || "",
|
|
helcimAnnualPlanId: process.env.NUXT_HELCIM_ANNUAL_PLAN_ID || "",
|
|
reconcileToken: process.env.NUXT_RECONCILE_TOKEN || "",
|
|
|
|
// Public keys (available on client-side)
|
|
public: {
|
|
helcimAccountId: process.env.NUXT_PUBLIC_HELCIM_ACCOUNT_ID || "",
|
|
cloudinaryCloudName:
|
|
process.env.NUXT_PUBLIC_CLOUDINARY_CLOUD_NAME || "divzuumlr",
|
|
appUrl: process.env.NUXT_PUBLIC_APP_URL || "http://localhost:3000",
|
|
comingSoon: process.env.NUXT_PUBLIC_COMING_SOON || "false",
|
|
helcimPortalUrl: process.env.NUXT_PUBLIC_HELCIM_PORTAL_URL || "",
|
|
},
|
|
},
|
|
});
|