Skip to content
jronnomoPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

JUNEFEST 🎉

A full-stack event platform and merch store for an annual summer festival — public site, e-commerce shop, and admin CMS in a single MERN application.

JUNEFEST powers a recurring June celebration (bar crawls, golf outings, happy hours) with everything the event needs in one place: a public site with a live countdown and event RSVPs, a merchandise shop with real PayPal checkout, and a full admin panel for managing every piece of content — no code deploys required to update the site.

Live: frontend on Netlify · API on Render · data on MongoDB Atlas · images on Cloudinary · payments via PayPal


At a glance

What it is Event site + e-commerce shop + admin CMS, unified
Frontend React 18 · Redux Toolkit / RTK Query · React Router v6 · React Bootstrap
Backend Node.js · Express · Mongoose (MongoDB Atlas)
Auth JWT (bcrypt-hashed passwords) with role-based access control
Payments PayPal Orders API, verified server-side
Media Cloudinary upload pipeline via Multer
Deploy Netlify (SPA) + Render (API)

Architecture

flowchart LR
    subgraph Client["Browser — React SPA (Netlify)"]
        UI["React 18 + React Bootstrap<br/>public site · shop · admin panel"]
        RTK["Redux Toolkit / RTK Query<br/>7 API slices, tag-based cache invalidation"]
        UI --> RTK
    end

    subgraph Server["Express API (Render)"]
        MW["Middleware<br/>JWT auth · admin gate · error handler"]
        ROUTES["REST routes<br/>/api/products · /api/orders · /api/users<br/>/api/events · /api/bars · /api/carousel<br/>/api/settings · /api/upload"]
        CTRL["Controllers<br/>server-side pricing · stock control<br/>payment verification"]
        MW --> ROUTES --> CTRL
    end

    DB[("MongoDB Atlas<br/>7 Mongoose models")]
    PAYPAL["PayPal Orders API<br/>server-verified payments"]
    CLOUD["Cloudinary<br/>image hosting"]

    RTK -- "REST / Bearer JWT" --> MW
    CTRL --> DB
    CTRL -- "verify: status + amount + replay check" --> PAYPAL
    CTRL -- "Multer + CloudinaryStorage" --> CLOUD
Loading

The flow in one sentence: the React SPA talks to the Express API over REST with a Bearer JWT; the API recomputes anything money- or stock-related on the server, verifies payments directly with PayPal, and persists everything in MongoDB.

Checkout sequence (the interesting path)

sequenceDiagram
    participant U as User (React)
    participant API as Express API
    participant DB as MongoDB
    participant PP as PayPal

    U->>API: POST /api/orders (cart items)
    API->>DB: Validate stock, recompute prices server-side
    API->>DB: Atomically decrement inventory ($inc)
    API-->>U: Order created
    U->>PP: Pay via PayPal buttons
    U->>API: PUT /api/orders/:id/pay (transaction id)
    API->>PP: Verify: status COMPLETED?
    API->>PP: Verify: amount matches order total?
    API->>DB: Verify: transaction id never used before?
    API->>DB: Mark paid
    API-->>U: Receipt
Loading

Engineering highlights

Things in this codebase that go beyond the standard tutorial-grade MERN store:

  • Server-verified payments with anti-fraud checks — the backend never trusts the client's word that an order was paid. It fetches its own PayPal OAuth token and confirms three things before marking an order paid: the transaction status is COMPLETED, the captured amount exactly matches the order total, and the transaction ID has never been used on another order (replay protection). (backend/utils/paypal.js)
  • Trusted server-side pricing — item prices, 15% tax, and free-shipping-over-$100 are all recomputed from the database at order time; client-submitted prices are ignored. (backend/utils/calcPrices.js)
  • Inventory integrity — stock is validated and decremented atomically ($inc) when an order is created, and restored when an order is cancelled, with guards that prevent cancelling delivered or already-cancelled orders.
  • Role-based access control, end to end — protect (JWT) and admin middleware on the API, mirrored by PrivateRoute / AdminRoute guards in the router.
  • Event RSVP system — authenticated RSVP / un-RSVP per event with duplicate prevention, plus an admin roster view of attendees.
  • Admin CMS across six content types — products, orders, users, events, bars, and carousel images, with soft-delete (isActive) toggles and display ordering, so the whole site is content-managed.
  • Modern data layer — RTK Query with one injected API slice per resource and tag-based cache invalidation; cart and auth state persisted to localStorage.
  • Cloudinary media pipeline — admin image uploads flow through Multer with double (MIME + extension) validation into a dedicated Cloudinary folder.
  • Admin-editable countdown — the homepage countdown reads a Settings singleton, so the event date and label are changed from the admin panel, not a deploy.

Feature tour

Area What's there
Public site Homepage (countdown, photo carousel, team), bar-crawl listings, event pages with RSVP
Shop Paginated + searchable catalog, product reviews & ratings, cart, multi-step checkout, PayPal payment, order history
Account Register / login, profile management, my orders, my RSVPs
Admin Dashboard + management screens for carousel, bars, events (with photos & RSVP rosters), products, orders (pay / deliver / cancel), and users

Key routes

Path Description
/ Homepage — countdown, carousel, team
/bars · /events · /events/:id Listings + event detail with RSVP
/shop · /product/:id · /cart Merch catalog through checkout
/profile Orders + RSVPs
/admin/* Dashboard, carousel, bars, events, products, orders, users

Data model

Seven Mongoose models, all timestamped:

Model Purpose
User Auth identity — bcrypt-hashed password (pre('save') hook), isAdmin role flag
Product Catalog item with embedded reviews subdocuments, rating aggregates, stock count
Order Price-snapshot line items, shipping, payment result, paid / delivered / cancelled lifecycle
Event Typed events (bar-crawl / golf / happy-hour) with embedded photos and RSVPs
Bar Bar-crawl venue — featured drink, website, display order
CarouselImage Homepage carousel entries with ordering and active flag
Settings Singleton config driving the countdown date/label

Project structure

junefest-main/
├── backend/
│   ├── server.js            Express app: CORS, routers, static, error handling
│   ├── seeder.js            DB seed / destroy scripts
│   ├── config/              Mongo connection
│   ├── controllers/         One per resource (products, orders, users, events, bars, carousel, settings)
│   ├── middleware/          JWT auth, admin gate, asyncHandler, ObjectId check, error handler
│   ├── models/              7 Mongoose schemas
│   ├── routes/              REST routers, incl. Cloudinary upload
│   └── utils/               calcPrices · generateToken · paypal (server-side verification)
├── frontend/
│   └── src/
│       ├── screens/         Public, checkout, and Admin/ screens
│       ├── components/      CountdownTimer, carousels, Rating, Paginate, route guards…
│       ├── slices/          RTK Query API slices per resource + auth/cart slices
│       └── assets/          Custom Bootstrap theme
└── netlify.toml             SPA build + redirect config

Running locally

# 1. Install
npm install
npm install --prefix frontend

# 2. Configure — copy example.env to .env and fill in:
#    NODE_ENV, PORT, MONGO_URI, JWT_SECRET, PAGINATION_LIMIT
#    PAYPAL_CLIENT_ID, PAYPAL_APP_SECRET, PAYPAL_API_URL
#    CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET

# 3. Seed the database (bars, events, products, users)
npm run data:import        # npm run data:destroy to clear
# Default admin: admin@email.com / 123456

# 4. Run both servers
npm run dev                # backend :8000 + frontend :3000, concurrently

Other scripts: npm run server (API only, nodemon) · npm run client (SPA only) · npm run build (production build) · npm run debug (Node inspector).


Deployment

Netlify (frontend) — build settings live in netlify.toml (base frontend, SPA catch-all redirect). Set REACT_APP_API_URL to the backend URL.

Render (backend) — build npm install, start node backend/server.js, with all .env vars configured (including the three CLOUDINARY_* vars).

Images — uploads go straight to Cloudinary in every environment via multer-storage-cloudinary; nothing is stored on the app server's disk.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages