Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SUPABASE_URL=https://baaiifkctdlpdoctnnkn.supabase.co
SUPABASE_ANON_KEY=sb_publishable_ORZf6llaSB0kxz_xSpsFiQ_CY3ZGq0I
PORT=4000
30 changes: 30 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Backend API

Simple Node.js backend using Supabase Authentication and Gmail SMTP.

Features
- User authentication via Supabase
- Email sending using Gmail SMTP
- Weather API by city

Tech Stack
- Node.js
- Express
- Supabase Auth
- Gmail SMTP

Notes
- Supabase authentication is used for a simpler application.
- Gmail is used as the SMTP provider.
- Use a valid email address when registering.

API Endpoints

POST /api/auth/register - User registration
POST /api/auth/login - User login
GET /api/weather/{city}
Example: /api/weather/Los Angeles

Run Project
npm install
npm run dev
13 changes: 13 additions & 0 deletions backend/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const express = require('express')
const authRoutes = require('./routes/auth.routes')
const publicRoutes = require('./routes/public.routes')

const app = express()
app.use(express.json()) // must be before routes

// Mount routes
app.use('/auth', authRoutes)
app.use('/', publicRoutes) // <- this handles /public and /protected

const PORT = process.env.PORT || 4000
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
29 changes: 16 additions & 13 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const express = require("express");
const app = express();
const PORT = process.env.PORT || 4000;

// Basic route
app.get("/", (req, res) => {
res.send("Hello from Express!");
});

// Start server
app.listen(PORT, () => {
console.log(`Backend is running on http://localhost:${PORT}`);
});

// index.js
require('dotenv').config()
const express = require('express')
const authRoutes = require('./routes/auth.routes')
const publicRoutes = require('./routes/public.routes')

const app = express()
app.use(express.json())

// Routes
app.use('/api/auth', authRoutes)
app.use('/api/', publicRoutes)

const PORT = process.env.PORT || 4000
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
15 changes: 15 additions & 0 deletions backend/middleware/auth.middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const supabase = require('../supabase')

module.exports = async (req, res, next) => {
const authHeader = req.headers.authorization
if (!authHeader) return res.sendStatus(401)

const token = authHeader.replace('Bearer ', '')

const { data, error } = await supabase.auth.getUser(token)

if (error) return res.sendStatus(403)

req.user = data.user
next()
}
18 changes: 15 additions & 3 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@
"name": "backend",
"version": "1.0.0",
"scripts": {
"start": "node index.js"
"start": "node index.js",
"dev": "nodemon index.js"
},
"dependencies": {
"express": "^4.18.2"
}
"@supabase/supabase-js": "^2.96.0",
"axios": "^1.13.5",
"dotenv": "^17.3.1",
"express": "^4.22.1"
},
"devDependencies": {
"nodemon": "^3.1.11"
},
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
43 changes: 43 additions & 0 deletions backend/routes/auth.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// routes/auth.routes.js
const express = require('express')
const supabase = require('../supabase')
const router = express.Router()

// Register
router.post('/register', async (req, res) => {
const { email, password } = req.body

if (!email || !password) {
return res.status(400).json({ error: 'Email and password required' })
}

try {
const { data, error } = await supabase.auth.signUp({
email,
password
})

if (error) return res.status(400).json({ error: error.message })

res.json({ user: data.user, email })
} catch (err) {
res.status(500).json({ error: 'Server error' })
}
})

// Login
router.post('/login', async (req, res) => {
const { email, password } = req.body
if (!email || !password)
return res.status(400).json({ error: 'Email and password required' })

const { data, error } = await supabase.auth.signInWithPassword({ email, password })
if (error) return res.status(401).json({ error: error.message })

res.json({
user: data.user,
access_token: data.session ? data.session.access_token : null
})
})

module.exports = router
39 changes: 39 additions & 0 deletions backend/routes/public.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// routes/public.routes.js
const express = require('express')
const axios = require('axios')
const authMiddleware = require('../middleware/auth.middleware')
const router = express.Router()

// Public route
router.get('/public', (req, res) => {
res.json({ message: 'Public endpoint works!' })
})

// Weather route (can be public or protected)
router.get('/weather/:city', authMiddleware, async (req, res) => {
const { city } = req.params

try {
const response = await axios.get(`https://wttr.in/${city}?format=j1`)
const current = response.data.current_condition[0]

res.json({
city,
temperature_C: current.temp_C,
temperature_F: current.temp_F,
weather_desc: current.weatherDesc[0].value,
humidity: current.humidity,
wind_kmph: current.windspeedKmph,
user: req.user.email // show authenticated user
})
} catch (error) {
res.status(400).json({ error: 'City not found or API error' })
}
})

// Example protected route
router.get('/protected', authMiddleware, (req, res) => {
res.json({ message: 'Protected endpoint works!', user: req.user })
})

module.exports = router
6 changes: 6 additions & 0 deletions backend/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require('dotenv').config()
const app = require('./app')

app.listen(process.env.PORT, () => {
console.log(`Server running on port ${process.env.PORT}`)
})
8 changes: 8 additions & 0 deletions backend/supabase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const { createClient } = require('@supabase/supabase-js')

const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
)

module.exports = supabase