"A feature-rich social memory platform built on the MERN stack β where every scroll is a trip down memory lane."
- πΈ What is Rewind?
- πΌοΈ UI Showcase
- π Project at a Glance
- β¨ Key Features
- ποΈ System Architecture
- ποΈ Data Model
- π οΈ Tech Stack
- π Project Structure
- π¦ Getting Started
- βοΈ Cloud Deployment
- β‘ Performance & Optimisation
- πΊοΈ Roadmap
- π€ Contributing
- β FAQ
- π Changelog
- π€ Author
- β Show Your Support
Rewind is a full-stack social memory platform built on the MERN stack. Users can create richly-tagged memory cards β complete with images, stories, and likes β and share them with the world. It demonstrates a modern decoupled architecture: the React+Redux frontend lives on Vercel's global edge network while the Express+MongoDB backend scales independently on Render.
π― Built to showcase: Full-stack MERN mastery, Redux state management, RESTful API design, cloud deployment strategy, and optimistic UI patterns.
| π | Version | π¦ Highlight |
|---|---|---|
| π | v2.0 |
Decoupled multi-cloud deploy Β· Optimistic Redux likes Β· Base64 image processing |
| π | v1.5 |
Material-UI design system Β· Tag-based filtering Β· Mongoose schema validation |
| π | v1.0 |
Initial MERN CRUD β create, read, update, delete memories |
π± Responsive grid layout β Material-UI cards auto-reflow from 4-column desktop to single-column mobile Β· Like counter updates instantly via optimistic Redux state
πΌοΈ Real-time Base64 image preview before submission Β· Tag chip input for categorisation Β· Form validates all required fields inline
β€οΈ Optimistic Like β state updates instantly before server confirmation Β· π Relative timestamps (e.g. "2 hours ago") Β· Edit / Delete controls visible to the creator
| π₯οΈ Feature | π± Mobile | π» Tablet | π₯οΈ Desktop |
|---|---|---|---|
| πΈ Memory Feed Grid | β 1-col | β 2-col | β 4-col |
| βοΈ Create / Edit Form | β | β | β |
| β€οΈ Optimistic Like | β | β | β |
| π Tag Filter | β | β | β |
| π Dark Mode (roadmap) | π | π | π |
| π Layer | π‘ Status | β±οΈ Latency | π Security |
|---|---|---|---|
| π Frontend | ~40ms |
SSL Β· Edge CDN | |
| π Backend API | ~120ms |
CORS Β· HTTPS | |
| ποΈ Database | 99.9% uptime |
AES-256 at rest |
π Live Website: https://rewind-pied.vercel.app π API Base URL: https://rewind-api-alwp.onrender.com
| π± | Fully Responsive UI | Material-UI grid adapts flawlessly across mobile, tablet, and ultra-wide desktop |
| π | Optimistic UI Updates | Redux state updates instantly on Like β UI reflects changes before the server confirms, eliminating perceived lag |
| πΌοΈ | Real-Time Image Preview | Base64 encoding renders image previews inline as soon as a file is selected β no upload round-trip needed |
| π·οΈ | Tag-Based Discovery | Multi-tag support on every memory β filter and surface related posts instantly |
| βοΈ | Decoupled Multi-Cloud | Frontend on Vercel's global edge, backend on Render β each scales and deploys independently |
| π | CORS Protection | Server-side CORS middleware restricts access to verified frontend origins only |
| ποΈ | Mongoose ODM | Type-safe, schema-validated document storage with auto-timestamps and default values |
| π¦ | 30 MB Payload Support | Custom body-parser limits handle high-resolution Base64 image uploads without request failure |
| π¨ | Material Design System | Consistent, accessible UI built entirely on Material-UI components with CSS-in-JS theming |
| β‘ | Single-Trip Data Fetching | One GET request retrieves all metadata and images, minimising TCP handshake overhead |
The application follows a Decoupled Monorepo Architecture β client and server live in the same repo but deploy to separate cloud providers and scale independently.
graph TD
U[π€ User Browser] -->|React + Redux| VF[π Vercel Frontend]
VF -->|Axios REST β HTTPS| RB[π Render Backend]
RB -->|Mongoose ODM| DB[(ποΈ MongoDB Atlas)]
DB -->|Data Response| RB
RB -->|JSON Response| VF
VF -->|Redux State Update| U
subgraph Frontend ["π VERCEL β Edge CDN"]
VF
RC[βοΈ React Components]
RX[π Redux Store]
AX[π‘ Axios Service]
VF --> RC --> RX --> AX
end
subgraph Backend ["π RENDER β Web Service"]
RB
RT[π£οΈ Express Routes]
CT[ποΈ Controllers]
MD[π Mongoose Models]
RB --> RT --> CT --> MD
end
classDef fe fill:#0a1a2e,stroke:#61DAFB,stroke-width:2px,color:#fff;
classDef be fill:#0a2e0a,stroke:#339933,stroke-width:2px,color:#fff;
classDef db fill:#0a0a2e,stroke:#47A048,stroke-width:2px,color:#fff;
classDef user fill:#000,stroke:#61DAFB,stroke-width:2px,color:#fff;
class U user;
class VF,RC,RX,AX fe;
class RB,RT,CT,MD be;
class DB db;
graph LR
subgraph Client_Side ["βοΈ CLIENT β React / Redux"]
U((π€ User)) -- "1. Form Input" --> UI[πΌοΈ UI Components]
UI -- "2. Action Dispatch" --> RD[π Redux Store]
RD -- "3. API Request" --> AX[π‘ Axios Service]
end
subgraph Server_Side ["π SERVER β Node / Express"]
AX -- "4. REST HTTPS (JSON + Base64)" --> RT[π£οΈ Express Routes]
RT -- "5. Controller Logic" --> CT[ποΈ Mongoose Controllers]
end
subgraph Storage ["ποΈ CLOUD STORAGE"]
CT -- "6. Persist document" --> DB[(MongoDB Atlas)]
DB -- "7. Return document" --> CT
end
CT -- "8. Success JSON" --> RD
RD -- "9. Re-render Feed" --> UI
DFD Level Guide:
| Level | Actor | Action |
|---|---|---|
| 0 | π€ User | Inputs Title, Message, Tags, Image via form |
| 1 | βοΈ Redux | Dispatches async action to Axios service layer |
| 2 | π‘ Axios | Transmits JSON + Base64 payload over HTTPS to Render |
| 3 | ποΈ Express | Validates payload, writes to MongoDB via Mongoose |
| 4 | π Redux | Receives success response, updates global state, triggers re-render |
sequenceDiagram
autonumber
participant U as π€ User
participant RX as π Redux
participant AX as π‘ Axios
participant EX as π Express
participant DB as ποΈ MongoDB
Note over U,RX: β€οΈ Like a Memory Post
U->>RX: dispatch(likePost(id))
RX->>RX: Optimistic update β increment likeCount in local state
RX-->>U: UI reflects +1 instantly (zero lag)
RX->>AX: PATCH /posts/:id/likePost
AX->>EX: HTTPS PATCH request
EX->>DB: findByIdAndUpdate β $inc likeCount
DB-->>EX: Updated document
EX-->>AX: 200 OK + updated post
AX-->>RX: Confirmed server state
RX-->>U: State synced β
Note over U,EX: βοΈ Create a Memory
U->>RX: dispatch(createPost(formData))
RX->>AX: POST /posts (JSON + Base64 image)
AX->>EX: HTTPS POST
EX->>DB: new PostMessage(data).save()
DB-->>EX: Saved document
EX-->>AX: 201 Created
AX-->>RX: Dispatch getPosts()
RX-->>U: Feed refreshed with new memory β
| π Field | π· Type | βοΈ Required | π·οΈ Default | π Description |
|---|---|---|---|---|
_id |
ObjectId |
Auto | β | Unique document identifier (MongoDB) |
title |
String |
β Yes | β | Headline or subject of the memory |
message |
String |
β Yes | β | Detailed story or description |
creator |
String |
β Yes | β | Name or ID of the authoring user |
tags |
[String] |
β No | [] |
Array for categorisation and tag-based search |
selectedFile |
String |
β No | "" |
Image stored as Base64-encoded string |
likeCount |
Number |
β No | 0 |
Like counter β incremented via PATCH /likePost |
createdAt |
Date |
System | Date.now |
Auto-timestamp for chronological feed sorting |
π‘ Base64 Note: The
selectedFilefield stores images as Base64 strings directly in MongoDB. This is ideal for demo-scale projects. For production at scale, migrate to a CDN (Cloudinary, AWS S3) β see Roadmap.
classDiagram
class PostMessage {
+ObjectId _id
+String title
+String message
+String creator
+String[] tags
+String selectedFile
+Number likeCount
+Date createdAt
+save() Promise
+findById() PostMessage
+findByIdAndUpdate() PostMessage
+findByIdAndRemove() void
}
note for PostMessage "selectedFile: Base64 encoded image string\nlikeCount default: 0\ncreatedAt default: Date.now"
// server/models/postMessage.js
import mongoose from 'mongoose';
const postSchema = mongoose.Schema({
title: String,
message: String,
creator: String,
tags: [String],
selectedFile: String,
likeCount: {
type: Number,
default: 0,
},
createdAt: {
type: Date,
default: new Date(),
},
});
const PostMessage = mongoose.model('PostMessage', postSchema);
export default PostMessage;| βοΈ Capability | π¬ Implementation | π Result |
|---|---|---|
| π State Management | Redux + async thunks | Optimistic UI, zero lag likes |
| πΌοΈ Image Handling | Base64 encode/decode | Instant preview, no upload roundtrip |
| π API Security | CORS middleware + HTTPS | Cross-origin requests locked to allowed origins |
| π¦ Payload Size | bodyParser 30 MB limit |
High-res images handled without 413 errors |
| βοΈ Scalability | Decoupled Vercel + Render | Frontend & backend scale and deploy independently |
πΈ Rewind/
β
βββ π» client/ # React Frontend
β βββ π public/ # Static assets & index.html
β βββ π§© src/
β βββ π‘ api/
β β βββ index.js # Axios service β base URL + all API calls
β βββ β‘ actions/
β β βββ posts.js # Redux async action creators (thunks)
β βββ π reducers/
β β βββ posts.js # Redux state reducer β handles all post actions
β βββ π¨ components/
β β βββ π Home/ # Memory feed + layout
β β βββ π Posts/ # Post grid container
β β β βββ Post/ # Individual memory card
β β βββ βοΈ Form/ # Create & Edit memory form
β βββ π¨ styles/ # CSS-in-JS (MUI makeStyles)
β βββ π App.js # Root component + routes
β βββ π¦ package.json
β
βββ π server/ # Node.js / Express Backend
β βββ ποΈ controllers/
β β βββ posts.js # CRUD logic β getPosts, createPost, updatePost, deletePost, likePost
β βββ π models/
β β βββ postMessage.js # Mongoose schema & model
β βββ π£οΈ routes/
β β βββ posts.js # Express route definitions β controller bindings
β βββ π .env # Environment secrets (git-ignored)
β βββ π index.js # Express app entry β middleware, CORS, DB connect
β
βββ πΈ screenshots/ # UI screenshots for README
β βββ π home.png
β βββ βοΈ create.png
β βββ π card.png
β
βββ π README.md
Get your own Rewind instance running locally in under 5 minutes.
| π οΈ Tool | π Version | π Link |
|---|---|---|
β₯ 16.x |
nodejs.org | |
β₯ 8.x |
Bundled with Node | |
| any | git-scm.com | |
| ποΈ MongoDB Atlas | free tier | mongodb.com/atlas |
π₯ Step 1 β Clone the repo
git clone https://github.com/salonyranjan/rewind-memories-app.git
cd rewind-memories-appπ¦ Step 2 β Install backend dependencies
cd server
npm installπ¦ Step 3 β Install frontend dependencies
cd ../client
npm install --legacy-peer-deps
# --legacy-peer-deps resolves peer dependency conflicts from Material-UI v4π Step 4 β Configure backend secrets
Create server/.env:
PORT=5000
CONNECTION_URL=mongodb+srv://<username>:<password>@cluster.mongodb.net/rewindDB
β οΈ Security note:.envis in.gitignoreβ never commit it. Use Render's Environment Variables tab for production secrets.
π Step 5 β Point frontend to local API
In client/src/api/index.js, set:
const API = axios.create({ baseURL: 'http://localhost:5000' });Remember to revert this to your Render URL before deploying.
π Step 6 β Start the backend
# Inside /server
npm start
# β API running at http://localhost:5000βοΈ Step 7 β Start the frontend (new terminal)
# Inside /client
npm start
# β App running at http://localhost:3000This project implements a Hybrid Multi-Cloud Strategy β Vercel's edge network for the frontend, Render's persistent Node.js environment for the backend.
1. Create a new Web Service on Render
2. Root Directory: server
3. Build Command: npm install
4. Start Command: node index.js
5. Environment Variables:
βββ CONNECTION_URL = your MongoDB Atlas URI
β οΈ CORS: Ensure your Render URL is whitelisted inserver/index.js:
app.use(cors({ origin: 'https://your-app.vercel.app' }));1. Import repo on vercel.com β Set Root Directory to client
2. Environment Variables:
βββ CI = false (suppresses build warnings as errors)
3. Ensure client/src/api/index.js points to your live Render URL
4. Click Deploy β
π Vercel auto-redeploys on every
git pushto main.
| π Metric | π― Value | π¬ Implementation |
|---|---|---|
| π Frontend Latency | ~40ms |
Vercel global edge CDN |
| π API Response | ~120ms |
Render persistent Node.js |
| ποΈ DB Uptime | 99.9% |
MongoDB Atlas free tier SLA |
| π¦ Payload Limit | 30 MB |
Custom bodyParser config |
| π Like UX | 0ms perceived |
Optimistic Redux state update |
| β‘ Bundle Size | Minimised | Lazy-loaded React components |
| π Re-render Control | Selective | Redux prevents unnecessary feed re-renders |
| π API Calls | Single-trip GET | All metadata + images in one request |
| Status | π Feature | π― Priority |
|---|---|---|
| β | CRUD β Create, Read, Update, Delete memories | π΄ Core |
| β | Optimistic Redux like system | π΄ Core |
| β | Base64 image handling with preview | π΄ Core |
| β | Decoupled Vercel + Render deployment | π΄ Core |
| π | Google OAuth 2.0 β secure user authentication | π‘ High |
| π | Search & Pagination β discover large memory collections | π‘ High |
| π | Cloudinary CDN β replace Base64 with dedicated image hosting | π‘ High |
| π | Dark Mode Toggle β accessibility & user preference | π’ Planned |
| π | Comment System β threaded replies per memory | π’ Planned |
| π | Memory Detail Page β full-screen single memory view | π’ Planned |
| π‘ | Stories Mode β auto-play slideshow of memories | π΅ Idea |
| π‘ | Private Collections β visibility controls per post | π΅ Idea |
All contributions are warmly welcome! πΈ
# 1. Fork the repository on GitHub
# 2. Create your feature branch
git checkout -b feature/your-feature
# 3. Commit with conventional format
git commit -m "feat: add your feature"
# Prefixes: fix: | docs: | style: | refactor: | test: | chore:
# 4. Push & open a PR
git push origin feature/your-featurePriority areas:
| π₯ Area | π What's Needed |
|---|---|
| π Auth | Google OAuth 2.0 via Passport.js or Firebase |
| πΌοΈ Images | Cloudinary SDK replacing Base64 storage |
| π Search | Server-side tag & text search with pagination |
| π§ͺ Tests | Jest + React Testing Library for components |
| π UI | Dark mode with MUI ThemeProvider |
π Why does the API take a few seconds to respond on first load?
The backend is hosted on Render's free tier, which spins down after 15 minutes of inactivity. The first request "cold-starts" the service β this takes 30β60 seconds. Subsequent requests are fast. Upgrade to Render's paid plan to eliminate cold starts in production.
πΌοΈ Why are images stored as Base64 and not uploaded to a CDN?
Base64 storage in MongoDB keeps the architecture simple for a portfolio project β no third-party image service setup required. The trade-off is document size and query performance at scale. Cloudinary integration is on the Roadmap as the recommended migration path.
β οΈ Why do I need --legacy-peer-deps for the frontend install?
The project uses Material-UI v4 which has peer dependency conflicts with newer versions of React. The --legacy-peer-deps flag tells npm to use the older dependency resolution algorithm that ignores these conflicts. Everything works correctly at runtime.
π How does CORS work between Vercel and Render?
The Express server uses the cors npm package as middleware. It's configured to whitelist the Vercel frontend origin (*.vercel.app), blocking any other cross-origin requests. This prevents unauthorised clients from hitting the API directly.
| Version | Highlights |
|---|---|
π v2.0.0 |
Decoupled multi-cloud Β· Optimistic Redux likes Β· Base64 image preview Β· CORS middleware |
v1.5.0 |
Material-UI design system Β· Tag chips Β· Mongoose schema validation Β· Render deploy |
v1.0.0 |
π Initial MERN CRUD β create, read, update, delete memories on MongoDB Atlas |
|
π§βπ» Full-Stack MERN Developer Β Β·Β π€ AI Engineer Β Β·Β π¨ UI/UX Specialist "Building full-stack experiences that feel instant, look beautiful, and scale cleanly." |
If Rewind helped you learn MERN, inspired your own project, or just made you smile β show it some love! πΈ
π‘ Pro Tip: Go to GitHub repo Settings β Social Preview and upload the home screenshot. When you share on LinkedIn, your Memory Feed UI shows instead of a generic GitHub card.
Made with πΈ by Salony Ranjan Β Β·Β Β© 2026 Rewind Β· MIT
