From ef8d281b2b088c56f4a0385736b2870667bb7907 Mon Sep 17 00:00:00 2001 From: friday-bot Date: Wed, 27 May 2026 16:23:12 -0600 Subject: [PATCH] v2: MongoDB backend + /manage dashboard - Replace Express 4 backend with Express 5 + Mongoose 8 + TypeScript 5.8 - Add MongoDB 8.0 container via docker-compose - Add JWT auth (jose), argon2 password hashing, zod validation, multer uploads - Models: BoardMember, Event, GalleryItem, Sponsor, Minute, Member, User - Full CRUD REST API for all content types - Seed script to populate MongoDB from hardcoded data - Wire all frontend components to fetch from API (no JSX changes) - Add /manage dashboard: login + tabs for Board, Events, Gallery, Sponsors, Minutes, Members - Uploads volume for persistent file storage across deploys --- Dockerfile | 65 ++- client/src/App.tsx | 44 +- client/src/components/Calendar.tsx | 9 +- client/src/components/Gallery.tsx | 64 +-- client/src/components/Home.tsx | 16 +- client/src/components/Manage.tsx | 590 ++++++++++++++++++++++++++ client/src/components/Meet-Board.tsx | 34 +- client/src/components/Minutes.tsx | 51 +-- client/src/components/Sponsors.tsx | 42 +- docker-compose.yml | 43 +- server/package.json | 47 +- server/src/db.ts | 9 + server/src/index.ts | 70 +-- server/src/middleware/auth.ts | 27 ++ server/src/middleware/errorHandler.ts | 24 ++ server/src/middleware/upload.ts | 33 ++ server/src/models/BoardMember.ts | 21 + server/src/models/Event.ts | 25 ++ server/src/models/GalleryItem.ts | 15 + server/src/models/Member.ts | 27 ++ server/src/models/Minute.ts | 17 + server/src/models/Sponsor.ts | 23 + server/src/models/User.ts | 20 + server/src/routes/auth.ts | 48 +++ server/src/routes/board.ts | 45 ++ server/src/routes/email.ts | 35 ++ server/src/routes/events.ts | 42 ++ server/src/routes/gallery.ts | 37 ++ server/src/routes/members.ts | 43 ++ server/src/routes/minutes.ts | 33 ++ server/src/routes/sponsors.ts | 46 ++ server/src/seed.ts | 89 ++++ server/tsconfig.json | 14 +- stack.env | 11 + 34 files changed, 1478 insertions(+), 281 deletions(-) create mode 100644 client/src/components/Manage.tsx create mode 100644 server/src/db.ts create mode 100644 server/src/middleware/auth.ts create mode 100644 server/src/middleware/errorHandler.ts create mode 100644 server/src/middleware/upload.ts create mode 100644 server/src/models/BoardMember.ts create mode 100644 server/src/models/Event.ts create mode 100644 server/src/models/GalleryItem.ts create mode 100644 server/src/models/Member.ts create mode 100644 server/src/models/Minute.ts create mode 100644 server/src/models/Sponsor.ts create mode 100644 server/src/models/User.ts create mode 100644 server/src/routes/auth.ts create mode 100644 server/src/routes/board.ts create mode 100644 server/src/routes/email.ts create mode 100644 server/src/routes/events.ts create mode 100644 server/src/routes/gallery.ts create mode 100644 server/src/routes/members.ts create mode 100644 server/src/routes/minutes.ts create mode 100644 server/src/routes/sponsors.ts create mode 100644 server/src/seed.ts diff --git a/Dockerfile b/Dockerfile index 0b9e7ab..b4ad5a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,71 +1,62 @@ # Build stage -FROM node:14 AS build +FROM node:22-alpine AS build -# Add a cache busting argument ARG CACHEBUST=1 RUN echo "Cache bust: $CACHEBUST" +# Build tools needed for argon2 native compilation +RUN apk add --no-cache python3 make g++ + WORKDIR /app - -# Copy package.json and package-lock.json + +# Install dependencies first (cache layer) COPY .env ./.env COPY package*.json ./ COPY client/package*.json ./client/ COPY server/package*.json ./server/ -# Install dependencies -RUN cd client && npm cache clean --force && rm -rf node_modules && npm install +RUN cd client && npm install RUN cd server && npm install -# Copy the entire client directory structure +# Copy static assets COPY client/public/headshots ./client/public/headshots -COPY client/public/logos ./client/public/logos -COPY client/public/photos ./client/public/photos -COPY client/public/sponsors ./client/public/sponsors -COPY client/public/videos ./client/public/videos -COPY client/public/minutes ./client/public/minutes +COPY client/public/logos ./client/public/logos +COPY client/public/photos ./client/public/photos +COPY client/public/sponsors ./client/public/sponsors +COPY client/public/videos ./client/public/videos +COPY client/public/minutes ./client/public/minutes COPY client/public/*.* ./client/public/ - -# Copy source code -COPY client/src ./client/src -COPY client/*.js ./client/ +# Copy source +COPY client/src ./client/src +COPY client/*.js ./client/ COPY client/*.json ./client/ -COPY server ./server - -# Install required packages -RUN npm install nodemailer dotenv date-fns react-icons +COPY server/src ./server/src +COPY server/tsconfig.json ./server/ # Build client RUN cd client && npm run build -# Install all dependencies including devDependencies -RUN cd server && npm install - # Build server -RUN cd server && npm run build - -# Remove devDependencies -RUN cd server && npm prune --production +RUN cd server && npm run build && npm prune --production # Production stage -FROM node:14-alpine +FROM node:22-alpine + +RUN apk add --no-cache python3 make g++ WORKDIR /app -# Copy built assets and static files from build stage COPY --from=build /app/client/build ./client/build -COPY --from=build /app/server ./server +COPY --from=build /app/server/dist ./server/dist +COPY --from=build /app/server/node_modules ./server/node_modules +COPY --from=build /app/server/package.json ./server/package.json COPY --from=build /app/.env ./.env -# Set working directory to server +RUN mkdir -p uploads/headshots uploads/photos uploads/sponsors uploads/minutes + WORKDIR /app/server -# Install production dependencies -RUN npm install --only=production - -# Expose port EXPOSE 801 -# Start the server -CMD ["npm", "start"] +CMD ["node", "dist/index.js"] diff --git a/client/src/App.tsx b/client/src/App.tsx index f96ff9a..36b0132 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -14,29 +14,35 @@ import VideoGallery from './components/VideoGallery'; import Resources from './components/Resources'; /* import ComingSoon from './components/ComingSoon'; */ import JoinMCDi from './components/JoinMCDi'; +import Manage from './components/Manage'; const App: React.FC = () => { return ( -
-
-
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
-
-
+ + } /> + +
+
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+