feat: Initial commit of backend services and AGENTS.md

This commit is contained in:
William Valentin
2025-10-29 13:12:30 -07:00
commit 999d37babb
25 changed files with 3881 additions and 0 deletions

23
backend/routes/ai.js Normal file
View File

@@ -0,0 +1,23 @@
const express = require("express");
const auth = require("../middleware/auth");
const router = express.Router();
// Get AI task suggestions
router.get("/task-suggestions", auth, async (req, res) => {
try {
// In a real application, you would use a more sophisticated AI model to generate task suggestions.
// For this example, we'll just return some mock data.
const suggestions = [
{ street: "Main St", description: "Clean up litter" },
{ street: "Elm St", description: "Remove graffiti" },
{ street: "Oak Ave", description: "Mow the lawn" },
];
res.json(suggestions);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

98
backend/routes/auth.js Normal file
View File

@@ -0,0 +1,98 @@
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
const auth = require("../middleware/auth");
const router = express.Router();
// Get user
router.get("/", auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select("-password");
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Register
router.post("/register", async (req, res) => {
const { name, email, password } = req.body;
try {
let user = await User.findOne({ email });
if (user) {
return res.status(400).json({ msg: "User already exists" });
}
user = new User({
name,
email,
password,
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: 3600 },
(err, token) => {
if (err) throw err;
res.json({ token });
},
);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Login
router.post("/login", async (req, res) => {
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ msg: "Invalid credentials" });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ msg: "Invalid credentials" });
}
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: 3600 },
(err, token) => {
if (err) throw err;
res.json({ token });
},
);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

66
backend/routes/events.js Normal file
View File

@@ -0,0 +1,66 @@
const express = require("express");
const Event = require("../models/Event");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all events
router.get("/", async (req, res) => {
try {
const events = await Event.find();
res.json(events);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create an event
router.post("/", auth, async (req, res) => {
const { title, description, date, location } = req.body;
try {
const newEvent = new Event({
title,
description,
date,
location,
});
const event = await newEvent.save();
res.json(event);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// RSVP to an event
router.put("/rsvp/:id", auth, async (req, res) => {
try {
const event = await Event.findById(req.params.id);
if (!event) {
return res.status(404).json({ msg: "Event not found" });
}
// Check if the user has already RSVPed
if (
event.participants.filter(
(participant) => participant.toString() === req.user.id,
).length > 0
) {
return res.status(400).json({ msg: "Already RSVPed" });
}
event.participants.unshift(req.user.id);
await event.save();
res.json(event.participants);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

View File

@@ -0,0 +1,27 @@
const express = require("express");
const auth = require("../middleware/auth");
const User = require("../models/User");
const router = express.Router();
// Handle premium subscription
router.post("/subscribe", auth, async (req, res) => {
try {
// In a real application, you would integrate with a payment gateway like Stripe.
// For this example, we'll just mock a successful payment.
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ msg: "User not found" });
}
user.isPremium = true;
await user.save();
res.json({ msg: "Subscription successful" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

63
backend/routes/posts.js Normal file
View File

@@ -0,0 +1,63 @@
const express = require("express");
const Post = require("../models/Post");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all posts
router.get("/", async (req, res) => {
try {
const posts = await Post.find().populate("user", ["name"]);
res.json(posts);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create a post
router.post("/", auth, async (req, res) => {
const { content, imageUrl } = req.body;
try {
const newPost = new Post({
user: req.user.id,
content,
imageUrl,
});
const post = await newPost.save();
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Like a post
router.put("/like/:id", auth, async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ msg: "Post not found" });
}
// Check if the post has already been liked by this user
if (
post.likes.filter((like) => like.toString() === req.user.id).length > 0
) {
return res.status(400).json({ msg: "Post already liked" });
}
post.likes.unshift(req.user.id);
await post.save();
res.json(post.likes);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

58
backend/routes/reports.js Normal file
View File

@@ -0,0 +1,58 @@
const express = require("express");
const Report = require("../models/Report");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all reports
router.get("/", async (req, res) => {
try {
const reports = await Report.find()
.populate("street", ["name"])
.populate("user", ["name"]);
res.json(reports);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create a report
router.post("/", auth, async (req, res) => {
const { street, issue } = req.body;
try {
const newReport = new Report({
street,
user: req.user.id,
issue,
});
const report = await newReport.save();
res.json(report);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Resolve a report
router.put("/:id", auth, async (req, res) => {
try {
const report = await Report.findById(req.params.id);
if (!report) {
return res.status(404).json({ msg: "Report not found" });
}
report.status = "resolved";
await report.save();
res.json(report);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

70
backend/routes/rewards.js Normal file
View File

@@ -0,0 +1,70 @@
const express = require("express");
const Reward = require("../models/Reward");
const User = require("../models/User");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all rewards
router.get("/", async (req, res) => {
try {
const rewards = await Reward.find();
res.json(rewards);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create a reward
router.post("/", auth, async (req, res) => {
const { name, description, cost, isPremium } = req.body;
try {
const newReward = new Reward({
name,
description,
cost,
isPremium,
});
const reward = await newReward.save();
res.json(reward);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Redeem a reward
router.post("/redeem/:id", auth, async (req, res) => {
try {
const reward = await Reward.findById(req.params.id);
if (!reward) {
return res.status(404).json({ msg: "Reward not found" });
}
const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ msg: "User not found" });
}
if (user.points < reward.cost) {
return res.status(400).json({ msg: "Not enough points" });
}
if (reward.isPremium && !user.isPremium) {
return res.status(403).json({ msg: "Premium reward not available" });
}
user.points -= reward.cost;
await user.save();
res.json({ msg: "Reward redeemed successfully" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

74
backend/routes/streets.js Normal file
View File

@@ -0,0 +1,74 @@
const express = require("express");
const Street = require("../models/Street");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all streets
router.get("/", async (req, res) => {
try {
const streets = await Street.find();
res.json(streets);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Get single street
router.get("/:id", async (req, res) => {
try {
const street = await Street.findById(req.params.id);
if (!street) {
return res.status(404).json({ msg: "Street not found" });
}
res.json(street);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create a street
router.post("/", auth, async (req, res) => {
const { name, location } = req.body;
try {
const newStreet = new Street({
name,
location,
});
const street = await newStreet.save();
res.json(street);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Adopt a street
router.put("/adopt/:id", auth, async (req, res) => {
try {
const street = await Street.findById(req.params.id);
if (!street) {
return res.status(404).json({ msg: "Street not found" });
}
if (street.status === "adopted") {
return res.status(400).json({ msg: "Street already adopted" });
}
street.adoptedBy = req.user.id;
street.status = "adopted";
await street.save();
res.json(street);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

56
backend/routes/tasks.js Normal file
View File

@@ -0,0 +1,56 @@
const express = require("express");
const Task = require("../models/Task");
const auth = require("../middleware/auth");
const router = express.Router();
// Get all tasks for user
router.get("/", auth, async (req, res) => {
try {
const tasks = await Task.find({ completedBy: req.user.id });
res.json(tasks);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create a task
router.post("/", auth, async (req, res) => {
const { street, description } = req.body;
try {
const newTask = new Task({
street,
description,
});
const task = await newTask.save();
res.json(task);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Complete a task
router.put("/:id", auth, async (req, res) => {
try {
const task = await Task.findById(req.params.id);
if (!task) {
return res.status(404).json({ msg: "Task not found" });
}
task.completedBy = req.user.id;
task.status = "completed";
await task.save();
res.json(task);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
module.exports = router;

21
backend/routes/users.js Normal file
View File

@@ -0,0 +1,21 @@
const express = require('express');
const User = require('../models/User');
const auth = require('../middleware/auth');
const router = express.Router();
// Get user by ID
router.get('/:id', auth, async (req, res) => {
try {
const user = await User.findById(req.params.id).populate('adoptedStreets');
if (!user) {
return res.status(404).json({ msg: 'User not found' });
}
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
module.exports = router;