A full-stack assignment submission for the Euphotic Labs Full Stack Development Internship. Displays dishes, lets an admin toggle published status, and reflects database changes in real time — including changes made outside the app itself.
- Dish list view backed by MongoDB
- Toggle published/unpublished status (atomic, race-safe update)
- Real-time sync via MongoDB Change Streams + WebSocket — the dashboard updates even when a dish is changed directly in the database, not through the UI
| Layer | Technology |
|---|---|
| Database | MongoDB (Atlas) |
| Backend | Python, FastAPI, Motor (async) |
| Frontend | React (Vite), Tailwind CSS |
| Real-time | MongoDB Change Streams, native WebSocket |
The internship listing names NoSQL explicitly as a required skill, and the seed data is already shaped as flat JSON documents, so MongoDB was the natural fit over a relational database. FastAPI's native WebSocket support made the real-time bonus straightforward without extra libraries, and it's also the framework most directly compatible with AWS Lambda deployment (via Mangum), matching the serverless work described in the role.
- Node.js v18+
- Python 3.11+
- A MongoDB Atlas cluster (free M0 tier) — required for Change Streams to work
cd backend
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# edit .env with your Atlas connection string
python -m app.seed # loads the 5 seed dishes, run once
uvicorn app.main:app --reload --port 8000cd frontend
npm install
npm run devVisit http://localhost:5173
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/dishes | List all dishes |
| PATCH | /api/dishes/{dishId}/toggle | Atomically flip isPublished |
| WS | /ws/dishes | Real-time change broadcast |
Interactive API docs: http://localhost:8000/docs
With the dashboard open, edit a dish's isPublished field directly in MongoDB Atlas's
Data Explorer (or via mongosh). The dashboard updates without a refresh — the change
stream watches the collection itself, regardless of what wrote to it.
nosh-dish-dashboard/
├── backend/
│ ├── requirements.txt
│ ├── .env.example
│ ├── data/
│ │ └── dish-assignment.json
│ └── app/
│ ├── main.py
│ ├── config.py
│ ├── database.py
│ ├── models.py
│ ├── seed.py
│ ├── websocket_manager.py
│ ├── change_stream.py
│ └── routers/
│ ├── dishes.py
│ └── ws.py
└── frontend/
├── package.json
├── tailwind.config.js
└── src/
├── main.jsx
├── App.jsx
├── api/client.js
├── hooks/useDishesSocket.js
├── components/
│ ├── DishCard.jsx
│ ├── DishGrid.jsx
│ └── ConnectionBadge.jsx
└── pages/Dashboard.jsx
No login or authentication — the assignment never asks for it, and adding it would be scope creep that doesn't answer anything the brief requires.