Fullstack · Civic Tech · Bogotá

EcoRewards

Recycle. Earn points. Track your impact.

The problem

Bogotá has dozens of recycling centers, but no digital infrastructure connecting residents to them. There's no way to know which centers are nearby, what materials they accept, or how much impact you're actually having. I built EcoRewards to fill that gap — a fullstack app that maps 27 real recycling centers, tracks user impact (CO₂ avoided, items recycled, streak), and rewards consistent behavior with points.

How it works

1

Auth

Clerk handles authentication with Google OAuth and email. A webhook syncs the new user profile into Supabase automatically on signup.

2

Database

Supabase PostgreSQL stores users, recycling centers, and impact records. RLS policies ensure users can only read and write their own data.

3

Map

Leaflet renders 27 real Bogotá recycling centers with custom markers. Center data is seeded directly in the DB — no third-party API dependency.

4

Rewards

Impact metrics (CO₂ avoided, items recycled, streak, equivalent trees) are calculated server-side and exposed via auth-gated API routes.

5

Deploy

Vercel handles deployment with GitHub Actions for CI. Environment variables manage Supabase and Clerk keys across environments.

Architecture decisions

01

Security at the database layer

Row-Level Security policies in Supabase mean user data isolation isn't just enforced in application code — it's guaranteed at the database level. Even if an API route had a bug, a user could never access another user's records.

02

27 real centers, not placeholder data

I manually researched and seeded 27 actual recycling centers in Bogotá. The decision to use real data instead of fake seeds makes the app immediately useful and demo-ready — it also tests the map rendering under realistic conditions.

03

Clerk → Supabase via webhook

Rather than creating user records on first login in the app, a Clerk webhook fires on signup and creates the Supabase profile automatically. This keeps the auth flow clean and ensures the DB is always in sync with Clerk without polling or manual triggers.

Stack

FrontendNext.js 14, TypeScript, React
AuthClerk (Google OAuth + email, webhook sync)
DatabaseSupabase PostgreSQL with RLS policies
MapLeaflet.js, 27 seeded real centers
CI/CDGitHub Actions, Vercel