diff --git a/REBUILD.md b/REBUILD.md new file mode 100644 index 0000000..2afdc7c --- /dev/null +++ b/REBUILD.md @@ -0,0 +1,57 @@ +# Rebuild Scripts + +## Quick Start + +### Production Mode (Recommended for testing) +```bash +./rebuild.sh prod +# or just +./rebuild.sh +``` + +### Development Mode (Hot reload) +```bash +./rebuild.sh dev +``` + +## What it does + +1. **Kills all processes** - Stops any running Node/Next.js processes +2. **Frees ports** - Ensures ports 3000 and 3003 are available +3. **Cleans build artifacts** - Removes `.next`, cache files, etc. +4. **Rebuilds** (production only) - Runs `npm run build` +5. **Starts server** - Runs in foreground (dev) or background (prod) + +## Viewing Logs + +### Production Mode +```bash +tail -f /tmp/mirrormatch-server.log +``` + +### Development Mode +Logs appear directly in the terminal (foreground mode) + +## Manual Commands + +If you prefer to run commands manually: + +```bash +# Kill everything +sudo fuser -k 3000/tcp +killall -9 node +pkill -f "next" +sleep 2 + +# Clean +cd /home/beast/Code/mirrormatch +rm -rf .next node_modules/.cache + +# Rebuild (production) +npm run build + +# Start +NODE_ENV=production npm run start > /tmp/server.log 2>&1 & +# or for dev +NODE_ENV=development npm run dev +``` diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 866b2be..58272dd 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -1,3 +1,4 @@ import { handlers } from "@/lib/auth" +// No wrapper needed - Auth.js now handles cookies correctly via useSecureCookies export const { GET, POST } = handlers diff --git a/app/layout.tsx b/app/layout.tsx index acac771..bee8b53 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,6 +3,7 @@ import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import Providers from "@/components/Providers"; import Navigation from "@/components/Navigation"; +import HelpModal from "@/components/HelpModal"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -32,6 +33,7 @@ export default function RootLayout({
{children}
+
diff --git a/components/HelpModal.tsx b/components/HelpModal.tsx new file mode 100644 index 0000000..5a13006 --- /dev/null +++ b/components/HelpModal.tsx @@ -0,0 +1,285 @@ +"use client" + +import { useState, useEffect } from "react" + +export default function HelpModal() { + const [isOpen, setIsOpen] = useState(false) + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + // Check for Shift+? (Shift+/ produces "?") + // Also check for event.key === "?" as fallback for some keyboard layouts + const isQuestionMark = + (event.shiftKey && event.key === "/") || + event.key === "?" || + (event.code === "Slash" && event.shiftKey) + + // Only trigger if Shift is pressed (not Ctrl/Cmd) + if (event.shiftKey && isQuestionMark && !event.ctrlKey && !event.metaKey) { + event.preventDefault() + setIsOpen((prev) => !prev) + } + // Also close on Escape key + if (event.key === "Escape" && isOpen) { + setIsOpen(false) + } + } + + window.addEventListener("keydown", handleKeyDown) + return () => window.removeEventListener("keydown", handleKeyDown) + }, [isOpen]) + + if (!isOpen) return null + + return ( + <> + {/* Overlay */} +
setIsOpen(false)} + > + {/* Modal */} +
e.stopPropagation()} + > + {/* Header */} +
+

Welcome to MirrorMatch

+ +
+ + {/* Content */} +
+ {/* What is MirrorMatch */} +
+

+ + + + What is MirrorMatch? +

+

+ MirrorMatch is a fun and engaging photo guessing game where you can upload photos + and challenge other players to guess who is in the picture. Test your knowledge of + friends, family, or colleagues while competing for points on the leaderboard! +

+
+ + {/* How to Play */} +
+

+ + + + + How to Play +

+
    +
  1. + Upload Photos: Go to the Upload page and add photos with answer + names. You can upload files or use image URLs. +
  2. +
  3. + Guess Photos: Browse the Photos page and click on any photo to + make your guess. Enter the name of the person you think is in the picture. +
  4. +
  5. + Earn Points: Get points for each correct guess! The more you + guess correctly, the higher you'll climb on the leaderboard. +
  6. +
  7. + Compete: Check the Leaderboard to see how you rank against other + players. +
  8. +
+
+ + {/* Features */} +
+

+ + + + Key Features +

+
    +
  • + + + Photo Upload: Share photos via file upload or URL + +
  • +
  • + + + Guessing System: Submit guesses and get instant feedback + +
  • +
  • + + + Email Notifications: Get notified when new photos are + uploaded + +
  • +
  • + + + Leaderboard: Track rankings and compete with others + +
  • +
  • + + + Profile Management: View your points and manage your account + +
  • +
+
+ + {/* Keyboard Shortcuts */} +
+

+ + + + Keyboard Shortcuts +

+
+
+ + + Shift + + {" + "} + + ? + + + Open/Close this help window +
+
+ + + Esc + + + Close help window +
+
+
+ + {/* Tips */} +
+

+ + + + Tips +

+
    +
  • + 💡 + Guesses are case-insensitive, so don't worry about capitalization +
  • +
  • + 💡 + You can't guess your own photos, but you can still view them +
  • +
  • + 💡 + + You'll receive email notifications when other users upload new photos + +
  • +
  • + 💡 + Check the leaderboard regularly to see your ranking +
  • +
+
+
+ + {/* Footer */} +
+

+ Press Esc or click outside to close +

+
+
+
+ + ) +} diff --git a/lib/auth.ts b/lib/auth.ts index be1b102..499bc44 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -3,16 +3,41 @@ import Credentials from "next-auth/providers/credentials" import { prisma } from "./prisma" import bcrypt from "bcryptjs" import { logger } from "./logger" -import { SESSION_COOKIE_NAME } from "./constants" const nextAuthSecret = process.env.NEXTAUTH_SECRET if (!nextAuthSecret) { throw new Error("NEXTAUTH_SECRET is not set. Define it to enable authentication.") } +// Determine if we should use secure cookies based on AUTH_URL/NEXTAUTH_URL +// Auth.js v5 derives this from the origin it detects, so we need to be explicit +const authUrl = process.env.AUTH_URL || process.env.NEXTAUTH_URL || "http://localhost:3000" +const isDev = process.env.NODE_ENV === "development" +const isHttp = authUrl.startsWith("http://") + +// Explicitly control useSecureCookies - only true when URL is https:// +// This prevents Auth.js from auto-detecting HTTPS and adding prefixes on HTTP +const useSecureCookies = !isHttp + +// Log cookie configuration for debugging (only in development) +if (isDev) { + logger.debug("NextAuth cookie configuration", { + authUrl, + isDev, + isHttp, + useSecureCookies, + nodeEnv: process.env.NODE_ENV, + hasVercelEnv: !!process.env.VERCEL, + hasAuthTrustHost: !!process.env.AUTH_TRUST_HOST, + }) +} + export const { handlers, auth, signIn, signOut } = NextAuth({ + // trustHost must be true for NextAuth v5 to work, even on localhost + // We control HTTPS detection via cookie configuration instead trustHost: true, debug: process.env.NODE_ENV !== "production", + basePath: "/api/auth", providers: [ Credentials({ name: "Credentials", @@ -115,16 +140,39 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ strategy: "jwt", maxAge: 30 * 24 * 60 * 60, // 30 days }, - cookies: { - sessionToken: { - name: SESSION_COOKIE_NAME, - options: { - httpOnly: true, - sameSite: "lax", - path: "/", - secure: true, // Always secure in production (HTTPS required) - }, - }, - }, + // Explicitly configure cookies for HTTP (localhost) + // For HTTPS, let Auth.js defaults handle it (prefixes + Secure) + cookies: isHttp + ? { + // localhost / pure HTTP: no prefixes, no Secure + sessionToken: { + name: "authjs.session-token", + options: { + httpOnly: true, + sameSite: "lax", + path: "/", + secure: false, + }, + }, + csrfToken: { + name: "authjs.csrf-token", + options: { + httpOnly: true, + sameSite: "lax", + path: "/", + secure: false, + }, + }, + callbackUrl: { + name: "authjs.callback-url", + options: { + httpOnly: true, + sameSite: "lax", + path: "/", + secure: false, + }, + }, + } + : undefined, // Let Auth.js defaults handle HTTPS envs (prefixes + Secure) secret: nextAuthSecret, }) diff --git a/lib/constants.ts b/lib/constants.ts index cdd1ff5..4ff933d 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -5,5 +5,6 @@ /** * NextAuth session cookie name * Must match the cookie name defined in lib/auth.ts + * For HTTP (localhost), no prefix. For HTTPS, Auth.js will add __Secure- prefix automatically. */ -export const SESSION_COOKIE_NAME = "__Secure-authjs.session-token" +export const SESSION_COOKIE_NAME = "authjs.session-token" diff --git a/rebuild.sh b/rebuild.sh new file mode 100755 index 0000000..e309d69 --- /dev/null +++ b/rebuild.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# Complete clean rebuild and start script for MirrorMatch +# Usage: ./rebuild.sh [dev|prod] +# dev - Development mode (hot reload, foreground) +# prod - Production mode (optimized, background with logging) + +set -e + +MODE=${1:-prod} + +echo "=========================================" +echo "MirrorMatch - Clean Rebuild & Start" +echo "Mode: ${MODE}" +echo "=========================================" + +# Step 1: Kill everything +echo "" +echo "Step 1: Killing all processes..." +sudo fuser -k 3000/tcp 2>/dev/null || true +killall -9 node 2>/dev/null || true +pkill -f "next" 2>/dev/null || true +sleep 2 +echo "✓ All processes killed" + +# Step 2: Free ports +echo "" +echo "Step 2: Freeing ports..." +lsof -ti:3000 | xargs kill -9 2>/dev/null || true +lsof -ti:3003 | xargs kill -9 2>/dev/null || true +sleep 1 +echo "✓ Ports freed" + +# Step 3: Clean build artifacts +echo "" +echo "Step 3: Cleaning build artifacts..." +cd /home/beast/Code/mirrormatch +rm -rf .next node_modules/.cache .next/cache .next/dev/lock 2>/dev/null || true +echo "✓ Build artifacts cleaned" + +# Step 4: Rebuild (only for production) +if [ "$MODE" = "prod" ]; then + echo "" + echo "Step 4: Rebuilding application..." + npm run build + echo "✓ Build complete" +fi + +# Step 5: Start server +echo "" +echo "Step 5: Starting server..." +echo "=========================================" + +if [ "$MODE" = "dev" ]; then + echo "Development mode - logs will appear below:" + echo "Press Ctrl+C to stop" + echo "=========================================" + echo "" + export NODE_ENV=development + unset AUTH_TRUST_HOST + npm run dev +else + echo "Production mode - server running in background" + echo "View logs: tail -f /tmp/mirrormatch-server.log" + echo "=========================================" + echo "" + export NODE_ENV=production + unset AUTH_TRUST_HOST + npm run start > /tmp/mirrormatch-server.log 2>&1 & + echo "Server PID: $!" + echo "" + sleep 3 + if curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 | grep -q "200\|307"; then + echo "✓ Server is running on http://localhost:3000" + else + echo "⚠ Server may still be starting. Check logs: tail -f /tmp/mirrormatch-server.log" + fi +fi