DEV Community

Cover image for Building DumpTrade a peer-to-peer waste redistribution platform
Edward Odero
Edward Odero

Posted on

Building DumpTrade a peer-to-peer waste redistribution platform

The problem

Households and businesses generate waste that still has value — offcuts, e-waste, packaging, furniture, organic scraps — but most of it ends up dumped or burned simply because there's no easy channel to get it to someone who could reuse it.

At GreenTechHackathon
 , my team set out to fix that with DumpTrade: a platform where anyone can post something they don't need, and anyone nearby who could use it can claim it free, fast, and dead simple.

This post walks through how we designed and built it, the trade-offs we made under a hackathon deadline, and a few implementation details I think are worth sharing.

The core idea

The loop is intentionally small:

Post → Browse → Claim → Collect

Every other feature exists to support that loop, not distract from it. We deliberately left out things like in-app chat, payments, and admin moderation for the MVP contact info is exchanged directly once something's claimed, and a report/flag button covers moderation for now.

Tech stack: why plain HTML/CSS/JS

We built the frontend in vanilla HTML, CSS, and JavaScript — no React, no build step. For a hackathon with a five person team and a tight deadline, that turned out to be the right call:

Zero tooling to configure or debug when someone's laptop acts up at 2am
Every page (index.html, browse.html, listing.html, post.html, login.html, register.html) is just... a file. Anyone on the team could open and edit any page without stepping on a bundler config.
A small shared api.js module simulates the backend for now — same function names/shapes we'll use once the real backend exists, so swapping in fetch() calls later should be mechanical rather than a rewrite.
dumptrade-frontend/
├── index.html / browse.html / listing.html / post.html / login.html / register.html
├── css/styles.css
└── js/
├── api.js # mock data layer — future home of real API calls
├── listings.js # shared rendering (cards, detail view, toast)
├── claim.js # claim / collect button logic
├── auth.js # login/register form handling
└── post.js # photo upload + post form
Claim logic: the one part that actually needed care

Everything else in the MVP is straightforward CRUD, but the claim flow has a real race condition: what happens if two people click "Claim" on the same listing at nearly the same time?

We handle it with a simple guard — check the status is still available right before flipping it:

js
function apiClaimListing(id) {
const l = apiGetListingById(id);
if (!l) return { ok: false, message: "Listing not found." };
if (l.status !== "available") {
return { ok: false, message: "Sorry — this was just claimed by someone else." };
}
l.status = "claimed";
return { ok: true, message: "Claimed!", listing: l };
}

In a real backend this becomes an atomic conditional update (UPDATE ... WHERE status = 'available', checking rows affected), but the logic is the same shape either way — check-then-set needs to be a single indivisible step, or you'll get double-claims.

Estimating environmental impact without a scale

One thing judges tend to respond well to: a number. "We helped the environment" is vague; "~340kg diverted from landfill" is a pitch. But we don't have IoT scales at a weekend hackathon.

Our answer: category-average weight estimates, applied when an item is marked collected.

Category Avg weight estimate
Furniture (large) 25kg
E-waste (large) 8kg
Textiles (per bag) 3kg
Construction offcuts 10kg
Organic waste 2kg

We're upfront about this being an estimate, not a measurement — methodology transparency mattered more to us than a falsely precise number.

Location filtering

Since "nearby" matters a lot for something people physically have to go pick up, Browse includes a location filter built from the cities already present in the listings data (parsed from a "City, Area" string) — not full geolocation yet, but enough to make results actually relevant:

js
function cityOf(location) { return location.split(",")[0].trim(); }

function apiGetListings(filters = {}) {
return _listings.filter(l => {
if (filters.city && cityOf(l.location) !== filters.city) return false;
// ...other filters
return true;
});
}

Real geolocation/maps is on the roadmap once there's a backend to store coordinates.

What's next
Wire up a real backend (Go or Node — still deciding) and a database
Real auth instead of the current mock login/register screens
Push notifications when something you'd want gets listed nearby
Recurring listings for businesses with regular byproducts (a cafe's daily coffee grounds, a workshop's weekly offcuts)
Try it / see the code
Live demo: [link]
GitHub: [link]

Built by [Name], [Name], [Name], [Name], and me at [Hackathon Name]. If you're working on something similar or have thoughts on the claim-race-condition approach, I'd love to hear them in the comments.

Top comments (0)