Skip to content

Commit f276985

Browse files
authored
Merge pull request #1 from parsa-faraji/feat/sandbox-ui-port
Port full study-spot/group UI from huddle-sandbox
2 parents 53fa5ec + ff10b74 commit f276985

57 files changed

Lines changed: 6061 additions & 656 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ build/
1111
.env.local
1212
.env.*.local
1313

14+
# Firebase service account key (never commit!)
15+
**/serviceAccountKey.json
16+
1417
# logs
1518
npm-debug.log*
1619
yarn-debug.log*
@@ -26,3 +29,4 @@ pnpm-debug.log*
2629
# firebase local state
2730
.firebase/
2831
firebase-debug.log
32+
.vercel

BACKEND_SLIDES_PASTE.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
PASTE THIS INTO YOUR HUDDLE MID-SEMESTER PRESENTATION
2+
====================================================
3+
4+
Find these slides and add the text below (or replace placeholder text).
5+
6+
--- SLIDE: "Backend" (under PROGRESS 01) ---
7+
Add these bullets:
8+
9+
• Express server + Firebase Admin; health & profile endpoints live
10+
• Auth (verifyToken) with Firebase ID tokens for protected routes
11+
• Backend Playground: in-repo course + 3 activities so the team can learn & test the API
12+
• Deployed to Vercel — everyone can do the activities on the live URL
13+
14+
--- SLIDE: "BACKEND" (under CHALLENGES 02) ---
15+
Backend challenges (add or keep):
16+
17+
• Learning Node, Express, Firebase Admin
18+
• Coordinating with frontend while building in parallel
19+
• Personalizing recommendations / determining available data
20+
21+
--- SLIDE: "NEXT STEPS" (Backend section) ---
22+
Backend next steps:
23+
24+
• Add study-spots API (GET/POST /api/spots, then ratings)
25+
• User preferences & groups endpoints
26+
• Keep using the Playground + WORKSHOP.md for pair programming
27+
28+
---
29+
Tip: In Google Slides or PowerPoint, click the text box on each slide and paste or type the bullets above.

Backend/SETUP_FIREBASE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Backend Firebase setup (one-time)
2+
3+
The backend needs **Firebase service account** credentials so it can verify users and use Firestore. You only do this once.
4+
5+
## Easiest: use the JSON file
6+
7+
1. Open [Firebase Console](https://console.firebase.google.com/) → your **huddle-5ae58** project.
8+
2. Click the **gear****Project settings**.
9+
3. Go to the **Service accounts** tab.
10+
4. Click **Generate new private key****Generate key**. A JSON file downloads.
11+
5. Move that file into this folder (**Backend**).
12+
6. Rename it to **`serviceAccountKey.json`** (exactly that name).
13+
7. Restart the server: `npm start`.
14+
15+
Done. The backend will load it automatically. Do not commit this file (it’s in .gitignore).
16+
17+
---
18+
19+
If you prefer using `.env` instead of the JSON file, copy `.env.example` to `.env` and fill in the three values from the same JSON file.

Backend/WORKSHOP.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Huddle Backend Workshop – Pair Programming Guide
2+
3+
A step-by-step guide for your team to learn and build the Huddle backend together.
4+
5+
---
6+
7+
## Before You Start
8+
9+
1. **Open the Playground** – In your browser, open `playground.html` (double-click it or drag into browser).
10+
2. **Start the backend** – In a terminal: `cd Backend && npm start`
11+
3. **Share your screen** – For pair programming, one person shares; switch driver every 10–15 min.
12+
13+
---
14+
15+
## Session 1: Your First Endpoint (30–45 min)
16+
17+
**Goal:** Understand request → server → response, and add a new endpoint.
18+
19+
### Step 1: Test what’s already there
20+
- In the Playground, click **Home** preset, then **Send request**
21+
- You should see: `Backend is running!`
22+
- Click **Health** preset, then **Send request**
23+
- You should see: `{ "ok": true, "message": "Backend is healthy!" }`
24+
25+
### Step 2: Add a new endpoint
26+
Open `server.js` and add:
27+
28+
```javascript
29+
app.get('/api/hello', (req, res) => {
30+
res.json({ message: 'Hello from the backend!' });
31+
});
32+
```
33+
34+
Restart the server (Ctrl+C, then `npm start`). In the Playground, set path to `/api/hello`, click Send. You should see your message.
35+
36+
**Discuss:** What does `res.json()` do? Why do we use it instead of `res.send()`?
37+
38+
---
39+
40+
## Session 2: Protected Routes & Auth (45–60 min)
41+
42+
**Goal:** Understand how `verifyToken` works and test a protected route.
43+
44+
### Step 1: See what happens without a token
45+
- Click **Profile** preset, leave the token field empty, click Send
46+
- You should get `401` and `{ "error": "No token provided" }`
47+
48+
### Step 2: Get a token
49+
1. Sign in on the Huddle frontend (http://localhost:5173)
50+
2. Go to the Dashboard and click **Fetch My Profile from Backend**
51+
3. Open DevTools (F12) → **Network** tab
52+
4. Click the request to `profile`**Headers** → find **Request Headers** → copy the value of `Authorization` (everything after `Bearer `)
53+
5. Paste that into the Playground’s “Auth token” field
54+
55+
### Step 3: Call /profile with the token
56+
- Click **Profile** preset, then Send
57+
- You should get `200` and `{ "message": "Hello user <your-uid>" }`
58+
59+
**Discuss:** What does `verifyToken` do? Where does `req.user` come from?
60+
61+
---
62+
63+
## Session 3: Study Spots – Read from Firestore (60 min)
64+
65+
**Goal:** Create study spots in Firestore and return them via an API.
66+
67+
### Step 1: Plan the data
68+
Decide what a “study spot” looks like, e.g.:
69+
70+
```json
71+
{
72+
"id": "spot1",
73+
"name": "Main Library 3F",
74+
"noise": "quiet",
75+
"hasOutlets": true,
76+
"openLate": false
77+
}
78+
```
79+
80+
### Step 2: Add test data in Firestore
81+
In [Firebase Console](https://console.firebase.google.com/) → Firestore → start a `spots` collection and add 1–2 documents.
82+
83+
### Step 3: Add the endpoint
84+
In `server.js`:
85+
86+
```javascript
87+
const { db } = require('./firebase');
88+
89+
app.get('/api/spots', async (req, res) => {
90+
try {
91+
const snapshot = await db.collection('spots').get();
92+
const spots = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
93+
res.json({ spots });
94+
} catch (err) {
95+
res.status(500).json({ error: err.message });
96+
}
97+
});
98+
```
99+
100+
Restart, add a preset in the Playground for `GET /api/spots`, and test.
101+
102+
**Discuss:** What is `snapshot.docs`? Why do we use `doc.id` and `doc.data()`?
103+
104+
---
105+
106+
## Session 4: Create a Spot (POST) (45 min)
107+
108+
**Goal:** Accept JSON in the request body and write to Firestore.
109+
110+
Add:
111+
112+
```javascript
113+
app.post('/api/spots', verifyToken, async (req, res) => {
114+
try {
115+
const { name, noise, hasOutlets, openLate } = req.body;
116+
const ref = await db.collection('spots').add({
117+
name,
118+
noise: noise || 'unknown',
119+
hasOutlets: !!hasOutlets,
120+
openLate: !!openLate,
121+
createdBy: req.user.uid,
122+
createdAt: new Date(),
123+
});
124+
res.status(201).json({ id: ref.id, message: 'Spot created!' });
125+
} catch (err) {
126+
res.status(500).json({ error: err.message });
127+
}
128+
});
129+
```
130+
131+
In the Playground: Method `POST`, path `/api/spots`, Body:
132+
133+
```json
134+
{
135+
"name": "Coffee Shop Study",
136+
"noise": "moderate",
137+
"hasOutlets": true,
138+
"openLate": true
139+
}
140+
```
141+
142+
Add your token and Send.
143+
144+
---
145+
146+
## Session 5: Filtering (Query params) (30 min)
147+
148+
**Goal:** Filter spots with `?noise=quiet` etc.
149+
150+
```javascript
151+
app.get('/api/spots', async (req, res) => {
152+
try {
153+
let query = db.collection('spots');
154+
if (req.query.noise) {
155+
query = query.where('noise', '==', req.query.noise);
156+
}
157+
const snapshot = await query.get();
158+
const spots = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
159+
res.json({ spots });
160+
} catch (err) {
161+
res.status(500).json({ error: err.message });
162+
}
163+
});
164+
```
165+
166+
Test in Playground: path `/api/spots?noise=quiet`
167+
168+
---
169+
170+
## What to Build Next
171+
172+
| Feature | Suggested endpoint | HTTP |
173+
|------------------|----------------------------------|--------|
174+
| Get one spot | `GET /api/spots/:id` | GET |
175+
| Add rating | `POST /api/spots/:id/ratings` | POST |
176+
| User preferences | `GET /api/profile/preferences` | GET |
177+
| Update prefs | `PATCH /api/profile/preferences`| PATCH |
178+
| Create group | `POST /api/groups` | POST |
179+
| Join group | `POST /api/groups/:id/join` | POST |
180+
181+
Add presets in the Playground for each new endpoint as you build them.
182+
183+
---
184+
185+
## Pair Programming Roles
186+
187+
- **Driver** – Types code, runs requests, shares screen
188+
- **Navigator** – Reads this guide, suggests next step, asks “what if we…?”
189+
- Switch every 10–15 minutes.
190+
191+
---
192+
193+
## Tips
194+
195+
- Keep the Playground and this guide open side by side.
196+
- When something breaks, read the error in the response – it usually tells you what’s wrong.
197+
- Use `console.log(req.body)` or `console.log(req.query)` to debug.
198+
- Have fun and ask lots of questions!

0 commit comments

Comments
 (0)