marketplace-mvp/ β”œβ”€ backend/ β”‚ β”œβ”€ package.json β”‚ β”œβ”€ .env β”‚ β”œβ”€ server.js β”‚ β”œβ”€ models/ β”‚ β”‚ β”œβ”€ User.js β”‚ β”‚ β”œβ”€ Listing.js β”‚ β”‚ └─ Message.js β”‚ β”œβ”€ routes/ β”‚ β”‚ β”œβ”€ auth.js β”‚ β”‚ β”œβ”€ listings.js β”‚ β”‚ └─ messages.js β”‚ β”œβ”€ middleware/ β”‚ β”‚ └─ auth.js β”‚ └─ uploads/ (images stored here in dev) └─ frontend/ β”œβ”€ package.json β”œβ”€ src/ β”‚ β”œβ”€ App.js β”‚ β”œβ”€ api.js β”‚ β”œβ”€ pages/ β”‚ β”‚ β”œβ”€ Listings.js β”‚ β”‚ β”œβ”€ ListingDetail.js β”‚ β”‚ β”œβ”€ CreateListing.js β”‚ β”‚ └─ Auth.js β”‚ └─ components/ β”‚ └─ ListingCard.js └─ public/

{ "name": "marketplace-backend", "version": "1.0.0", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js", "seed": "node seed.js" }, "dependencies": { "bcryptjs": "^2.4.3", "cors": "^2.8.5", "dotenv": "^16.0.0", "express": "^4.18.2", "jsonwebtoken": "^9.0.0", "mongoose": "^7.0.0", "multer": "^1.4.5" }, "devDependencies": { "nodemon": "^2.0.22" } }

PORT=5000 MONGO_URI=mongodb://localhost:27017/marketplace JWT_SECRET=supersecret_jwt_key_change_me

require('dotenv').config(); const express = require('express'); const mongoose = require('mongoose'); const cors = require('cors'); const path = require('path');

const authRoutes = require('./routes/auth'); const listingsRoutes = require('./routes/listings'); const messagesRoutes = require('./routes/messages');

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

// Serve uploaded images app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

app.use('/api/auth', authRoutes); app.use('/api/listings', listingsRoutes); app.use('/api/messages', messagesRoutes);

const PORT = process.env.PORT || 5000;

mongoose.connect(process.env.MONGO_URI, { }) .then(() => { console.log('Mongo connected'); app.listen(PORT, () => console.log('Server running on', PORT)); }) .catch(err => { console.error('Mongo connection error', err); });

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, passwordHash: { type: String, required: true }, createdAt: { type: Date, default: Date.now } });

module.exports = mongoose.model('User', userSchema);

const mongoose = require('mongoose');

const listingSchema = new mongoose.Schema({ title: { type: String, required: true }, description: String, price: { type: Number, required: true }, category: String, images: [String], // store URLs like /uploads/... location: String, seller: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, createdAt: { type: Date, default: Date.now }, active: { type: Boolean, default: true } });

module.exports = mongoose.model('Listing', listingSchema);

const mongoose = require('mongoose');

const messageSchema = new mongoose.Schema({ listing: { type: mongoose.Schema.Types.ObjectId, ref: 'Listing', required: true }, from: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, to: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, text: { type: String, required: true }, createdAt: { type: Date, default: Date.now } });

module.exports = mongoose.model('Message', messageSchema);

const jwt = require('jsonwebtoken'); const User = require('../models/User');

module.exports = async function (req, res, next) { const token = req.header('Authorization')?.replace('Bearer ', ''); if (!token) return res.status(401).send({ error: 'Auth required' });

try { const payload = jwt.verify(token, process.env.JWT_SECRET); const user = await User.findById(payload.id).select('-passwordHash'); if (!user) return res.status(401).send({ error: 'Invalid token' }); req.user = user; next(); } catch (err) { return res.status(401).send({ error: 'Invalid token' }); } }

const express = require('express'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const User = require('../models/User'); const router = express.Router();

// Register router.post('/register', async (req, res) => { try { const { name, email, password } = req.body; if (!email || !password || !name) return res.status(400).json({ error: 'Missing fields' });

if (await User.findOne({ email })) return res.status(400).json({ error: 'Email already used' });

const passwordHash = await bcrypt.hash(password, 10);
const user = new User({ name, email, passwordHash });
await user.save();

const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });
res.json({ token, user: { id: user._id, name: user.name, email: user.email } });

} catch (err) { res.status(500).json({ error: err.message }); } });

// Login router.post('/login', async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ email }); if (!user) return res.status(400).json({ error: 'Invalid credentials' });

const ok = await bcrypt.compare(password, user.passwordHash);
if (!ok) return res.status(400).json({ error: 'Invalid credentials' });

const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' });
res.json({ token, user: { id: user._id, name: user.name, email: user.email } });

} catch (err) { res.status(500).json({ error: err.message }); } });

module.exports = router;

const express = require('express'); const multer = require('multer'); const path = require('path'); const Listing = require('../models/Listing'); const auth = require('../middleware/auth');

const router = express.Router();

// multer local storage const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, path.join(__dirname, '..', 'uploads')), filename: (req, file, cb) => { const name = Date.now() + '-' + file.originalname.replace(/\s+/g, '-'); cb(null, name); } }); const upload = multer({ storage });

// Create listing router.post('/', auth, upload.array('images', 6), async (req, res) => { try { const { title, description, price, category, location } = req.body; const images = (req.files || []).map(f => /uploads/${f.filename}); const listing = new Listing({ title, description, price: Number(price), category, location, images, seller: req.user._id }); await listing.save(); res.json(listing); } catch (err) { res.status(500).json({ error: err.message }); } });

// Update listing (owner only) router.put('/:id', auth, async (req, res) => { try { const listing = await Listing.findById(req.params.id); if (!listing) return res.status(404).json({ error: 'Not found' }); if (!listing.seller.equals(req.user._id)) return res.status(403).json({ error: 'Forbidden' });

Object.assign(listing, req.body);
await listing.save();
res.json(listing);

} catch (err) { res.status(500).json({ error: err.message }); } });

// Delete listing (owner only) router.delete('/:id', auth, async (req, res) => { try { const listing = await Listing.findById(req.params.id); if (!listing) return res.status(404).json({ error: 'Not found' }); if (!listing.seller.equals(req.user._id)) return res.status(403).json({ error: 'Forbidden' }); await listing.deleteOne(); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } });

// Get listing by id router.get('/:id', async (req, res) => { try { const listing = await Listing.findById(req.params.id).populate('seller', 'name email'); if (!listing) return res.status(404).json({ error: 'Not found' }); res.json(listing); } catch (err) { res.status(500).json({ error: err.message }); } });

// Query listings with basic search and filters router.get('/', async (req, res) => { try { const { q, category, minPrice, maxPrice, page = 1, limit = 20 } = req.query; const filter = { active: true }; if (q) filter.$text = { $search: q }; // requires text index if (category) filter.category = category; if (minPrice) filter.price = Object.assign(filter.price || {}, { $gte: Number(minPrice) }); if (maxPrice) filter.price = Object.assign(filter.price || {}, { $lte: Number(maxPrice) });

const listings = await Listing.find(filter)
  .populate('seller', 'name')
  .sort({ createdAt: -1 })
  .skip((page - 1) * limit)
  .limit(Number(limit));
res.json(listings);

} catch (err) { res.status(500).json({ error: err.message }); } });

module.exports = router;

db.listings.createIndex({ title: "text", description: "text", category: "text" })

const express = require('express'); const Message = require('../models/Message'); const Listing = require('../models/Listing'); const auth = require('../middleware/auth'); const router = express.Router();

// Send message about a listing router.post('/', auth, async (req, res) => { try { const { listingId, text } = req.body; const listing = await Listing.findById(listingId); if (!listing) return res.status(404).json({ error: 'Listing not found' });

const msg = new Message({
  listing: listing._id,
  from: req.user._id,
  to: listing.seller,
  text
});
await msg.save();
res.json(msg);

} catch (err) { res.status(500).json({ error: err.message }); } });

// Get messages for user router.get('/', auth, async (req, res) => { try { const msgs = await Message.find({ $or: [{ to: req.user._id }, { from: req.user._id }] }) .populate('from', 'name email') .populate('to', 'name email') .populate('listing', 'title'); res.json(msgs); } catch (err) { res.status(500).json({ error: err.message }); } });

module.exports = router;

require('dotenv').config(); const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const User = require('./models/User'); const Listing = require('./models/Listing');

async function seed() { await mongoose.connect(process.env.MONGO_URI); await User.deleteMany({}); await Listing.deleteMany({});

const pw = await bcrypt.hash('password', 10); const u1 = await new User({ name: 'Alice', email: 'alice@example.com', passwordHash: pw }).save(); const u2 = await new User({ name: 'Bob', email: 'bob@example.com', passwordHash: pw }).save();

const l1 = new Listing({ title: 'Vintage Coffee Table', description: 'Solid wood, great condition.', price: 120, category: 'Furniture', images: [], location: 'Chicago, IL', seller: u1._id }); const l2 = new Listing({ title: 'iPhone 12 - 128GB', description: 'Unlocked, minor scratches.', price: 350, category: 'Electronics', images: [], location: 'Chicago, IL', seller: u2._id }); await l

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support