Smart. Secure. Automated.
Privacy-first campus lost & found platform with intelligent heuristic matching and fraud-proof ownership verification.
π Live Demo Β Β·Β βοΈ API Health Β Β·Β π¦ Installation Β Β·Β π€ Contributing Β Β·Β π‘ API
- What is ReclaimX?
- β¨ Key Features
- πΈ Screenshots
- π Tech Stack
- π Project Structure
- π§ How the Matching Engine Works
- π Ownership Verification (Anti-Fraud)
- π Trust Score System
- π Database Schema
- π‘ API Reference
- π¦ Getting Started
- π Deployment
- π Security
- π§ͺ Testing & CI
- πΊ Roadmap
- π₯ Team
- π€ Contributing
- π License
ReclaimX replaces the traditional campus lost & found notice board with an automated, privacy-first system. Students report lost or found items, and a custom weighted scoring engine matches them in real time based on text similarity, image presence, location overlap, and time proximity.
| Goal | Description |
|---|---|
| Privacy First | Only the item name is publicly visible. Descriptions, photos, and verification details are encrypted and private |
| Fraud Prevention | Ownership verified via 3 secret questions only the real owner could answer. 3 failed attempts = account suspended |
| Trust System | Users earn Bronze β Silver β Gold status for successful returns |
| Works Offline | Full PWA with service worker caching and offline submission queue |
- Real-time Matching Engine β Custom heuristic scoring (Jaccard similarity + location + time decay)
- Privacy-First Design β Sensitive data encrypted, only item names public
- Fraud-Proof Verification β 3 secret questions with server-side answer scoring
- Trust Score System β Bronze β Silver β Gold progression with points for successful returns
- PWA Support β Installable, works offline with service worker caching
- Multi-Auth Providers β Email/Password, Google, GitHub via Firebase
- Image Upload β Cloudinary integration for item photos
- Multi-Campus Support β Island-based matching by campus_id
- Rate Limiting β 100 requests/15 min per IP to prevent abuse
- Sensitive Data Filter β Blocks Aadhaar, PAN, card numbers in descriptions
| Home Page | Login Page | Signup Page |
|---|---|---|
![]() |
![]() |
![]() |
| Dashboard | Browse Items |
|---|---|
![]() |
![]() |
| My Matches | Report Lost Item |
|---|---|
![]() |
![]() |
| Report Found Item | Profile |
|---|---|
![]() |
![]() |
π Full-resolution screenshots live in docs/screenshots/.
| Layer | Technology |
|---|---|
| Frontend | Vanilla HTML5, CSS3, JavaScript (ES Modules) |
| PWA | Service Worker + Web App Manifest |
| Auth | Firebase Auth (Email/Password, Google, GitHub) |
| Backend | Node.js + Express.js |
| Database | Supabase (PostgreSQL) |
| Image Storage | Cloudinary v2 |
| Matching Engine | Custom heuristic scoring (Jaccard similarity + location + time decay) |
| Security | Helmet.js, express-rate-limit, Firebase ID token verification |
| Frontend Hosting | Vercel |
| Backend Hosting | Render |
RECLAIMX/
βββ frontend/ β Deployed on Vercel (root dir: frontend/)
β βββ index.html β Public landing page
β βββ manifest.json β PWA manifest
β βββ service-worker.js β Offline caching
β βββ vercel.json β Clean URL rewrites + cache headers
β βββ .env.example β No secrets needed for frontend
β β
β βββ pages/
β β βββ login.html
β β βββ register.html
β β βββ dashboard.html β Stats, recent activity, my reports
β β βββ browse.html β Public browse with search/filter
β β βββ report-lost.html β Hidden verification attributes
β β βββ report-found.html
β β βββ matches.html β Score ring, verify claim flow
β β βββ profile.html β Avatar, trust score, activity
β β βββ 404.html
β β
β βββ assets/
β β βββ css/global.css β Full design system (dark theme)
β β βββ js/
β β β βββ main.js β API_BASE, toast, sidebar init
β β β βββ auth-guard.js β Back/forward button bypass (bfcache)
β β β βββ auth.js β Session guard, token refresh
β β β βββ firebase-config.js β Loads config from backend
β β β βββ pwa.js β SW registration, offline queue
β β βββ icons/
β β
β βββ components/
β βββ sidebar.html β Injected via fetch() on every page
β βββ toast.html β Rich toast with progress bar
β
βββ backend/ β Deployed on Render (root dir: backend/)
βββ server.js β Express entry point (port 5000)
βββ package.json
βββ .env β Secrets β never commit
βββ .env.example
β
βββ config/
β βββ firebase.js β Firebase Admin SDK
β βββ supabase.js β Supabase service_role client
β βββ cloudinary.js β Cloudinary v2 + multer memoryStorage
β βββ serviceAccountKey.json β Firebase key β never commit
β
βββ middleware/
β βββ authMiddleware.js β Firebase token verification
β βββ errorHandler.js β Global error + 404 handler
β
βββ routes/
β βββ authRoutes.js β /api/auth/*
β βββ itemRoutes.js β /api/items/*
β βββ matchRoutes.js β /api/matches/*
β βββ configRoutes.js β /api/config/firebase
β
βββ ai/
β βββ matchingEngine.js β Heuristic scoring engine
β
βββ utils/
βββ verificationEngine.js β Ownership answer scoring
βββ sensitiveDataFilter.js β Blocks Aadhaar, PAN, card numbers
βββ emailService.js β Resend email notifications (planned)
| Component | Port | Entry Point | Hosting |
|---|---|---|---|
| Frontend | 3000 (local) | frontend/index.html |
Vercel |
| Backend | 5000 (local) | backend/server.js |
Render |
| API Root | http://localhost:5000/api |
β | β |
When a lost or found item is submitted, the engine queries all open opposing items on the same campus with the same category, then scores each pair:
[ \text{Final Score} = (\text{Text} \times 40%) + (\text{Image} \times 30%) + (\text{Location} \times 20%) + (\text{Time} \times 10%) ]
| Signal | Method |
|---|---|
| Text | Jaccard similarity on item name (70%) + description (30%) |
| Image | Presence score β 65 if both have images, 40 if one, 20 if neither |
| Location | Token overlap between last-seen and found locations |
| Time decay | Linear decay over 72 hours β older reports score lower |
A claim is created only if score β₯ 40 and campus + category both match exactly.
β οΈ Note: Image signal is a presence placeholder. Vector embedding similarity (MobileNet + pgvector) is planned for v2.
After a match is created, the claimer answers 3 questions drawn from private hidden attributes:
- Interior colour / lining
- Unique marks, scratches, stickers, or engravings
- What the item contains
Answers checked server-side using Jaccard word similarity:
- Score β₯ 60% β verified
- Below 60% β strike logged
- 3 strikes β account suspended
| Level | Points | Notes |
|---|---|---|
| π₯ Bronze Helper | 0β49 pts | Default on signup |
| π₯ Silver Helper | 50β99 pts | Trusted member |
| π₯ Gold Hero | 100+ pts | Campus hero |
+10 points awarded to both parties on each successful item return.
Run this SQL in your Supabase SQL Editor:
CREATE TABLE users (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
firebase_uid TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
campus_id TEXT DEFAULT 'campus_a',
photo TEXT DEFAULT '',
trust_score INTEGER DEFAULT 0,
trust_level TEXT DEFAULT 'Bronze',
failed_claims INTEGER DEFAULT 0,
is_suspended BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE lost_items (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES users(id),
campus_id TEXT NOT NULL,
item_name TEXT NOT NULL, -- PUBLIC
description TEXT, -- PRIVATE
category TEXT,
last_seen_location TEXT, -- PUBLIC
image_urls TEXT[] DEFAULT '{}', -- PRIVATE
hidden_color_inside TEXT, -- PRIVATE (verification)
hidden_unique_marks TEXT, -- PRIVATE (verification)
hidden_contains TEXT, -- PRIVATE (verification)
status TEXT DEFAULT 'Lost', -- Lost \[|\] Pending \[|\] Resolved
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE found_items (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES users(id),
campus_id TEXT NOT NULL,
item_name TEXT NOT NULL, -- PUBLIC
description TEXT, -- PRIVATE
category TEXT,
found_location TEXT, -- PUBLIC
image_url TEXT DEFAULT '', -- PRIVATE
status TEXT DEFAULT 'Found', -- Found \[|\] Resolved
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE claims (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
lost_item_id UUID REFERENCES lost_items(id),
found_item_id UUID REFERENCES found_items(id),
claimant_id UUID REFERENCES users(id),
match_score FLOAT DEFAULT 0,
answer_1 TEXT, answer_2 TEXT, answer_3 TEXT,
verification_score FLOAT DEFAULT 0,
loster_confirmed BOOLEAN DEFAULT false,
founder_confirmed BOOLEAN DEFAULT false,
status TEXT DEFAULT 'Pending', -- Pending \[|\] Verified \[|\] Rejected \[|\] Resolved
created_at TIMESTAMPTZ DEFAULT NOW()
);
β οΈ Use the service_role key in your backend.env, not the anon key. The anon key will be blocked by Row Level Security.
Base URL: https://reclaimx.onrender.com/api (production) or http://localhost:5000/api (local)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /session |
β | Verify Firebase token + upsert user |
| GET | /me |
β | Get current user profile |
| PUT | /profile |
β | Update display name / clear photo |
| POST | /avatar |
β | Upload profile photo to Cloudinary |
| POST | /forgot-password |
β | Send Firebase password reset email |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
β | Browse open lost & found items |
| GET | /me |
β | Get current user's reports |
| POST | /lost |
β | Report a lost item (triggers matching) |
| POST | /found |
β | Report a found item (triggers matching) |
| DELETE | /lost/:id |
β | Delete own lost report |
| DELETE | /found/:id |
β | Delete own found report |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / |
β | Get all claims for current user |
| POST | /verify |
β | Submit ownership verification answers |
| POST | /confirm-handover/:id |
β | Confirm physical handover |
| POST | /dismiss/:id |
β | Dismiss a match |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/config/firebase |
β | Firebase client config (safe to expose) |
| GET | /api/health |
β | Server health check |
curl -X POST https://reclaimx.onrender.com/api/auth/session \
-H "Content-Type: application/json" \
-d '{
"firebaseToken": "YOUR_FIREBASE_ID_TOKEN_HERE"
}'Response:
{
"success": true,
"user": {
"id": "uuid-here",
"firebase_uid": "firebase-uid",
"name": "John Doe",
"email": "john@example.com",
"campus_id": "campus_a",
"trust_score": 0,
"trust_level": "Bronze"
}
}curl -X GET https://reclaimx.onrender.com/api/auth/me \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE"Response:
{
"success": true,
"user": {
"id": "uuid-here",
"firebase_uid": "firebase-uid",
"name": "John Doe",
"email": "john@example.com",
"campus_id": "campus_a",
"photo": "",
"trust_score": 10,
"trust_level": "Bronze",
"failed_claims": 0,
"is_suspended": false
}
}curl -X POST https://reclaimx.onrender.com/api/items/lost \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE" \
-d '{
"campus_id": "campus_a",
"item_name": "iPhone 13 Pro",
"description": "Midnight green, 128GB, has a crack on the back",
"category": "Electronics",
"last_seen_location": "Library Floor 2",
"hidden_color_inside": "Black leather lining",
"hidden_unique_marks": "Crack on back near camera, Apple sticker on case",
"hidden_contains": "AirPods Pro case, USB-C cable, phone manual"
}'Response:
{
"success": true,
"message": "Lost item reported successfully",
"item": {
"id": "uuid-here",
"user_id": "uuid-here",
"campus_id": "campus_a",
"item_name": "iPhone 13 Pro",
"category": "Electronics",
"last_seen_location": "Library Floor 2",
"status": "Lost",
"created_at": "2026-06-04T11:00:00.000Z"
},
"matches_found": 1,
"matches": [
{
"claim_id": "claim-uuid",
"found_item_id": "found-uuid",
"match_score": 67.5,
"founder_name": "Jane Smith"
}
]
}curl -X POST https://reclaimx.onrender.com/api/items/found \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE" \
-d '{
"campus_id": "campus_a",
"item_name": "iPhone 13 Pro",
"description": "Found near library, midnight green color",
"category": "Electronics",
"found_location": "Library Floor 2"
}'Response:
{
"success": true,
"message": "Found item reported successfully",
"item": {
"id": "uuid-here",
"user_id": "uuid-here",
"campus_id": "campus_a",
"item_name": "iPhone 13 Pro",
"category": "Electronics",
"found_location": "Library Floor 2",
"status": "Found",
"created_at": "2026-06-04T11:00:00.000Z"
},
"matches_found": 1,
"matches": [
{
"claim_id": "claim-uuid",
"lost_item_id": "lost-uuid",
"match_score": 67.5,
"loster_name": "John Doe"
}
]
}curl -X GET "https://reclaimx.onrender.com/api/items?campus_id=campus_a&category=Electronics"Response:
{
"success": true,
"items": [
{
"id": "uuid-1",
"item_name": "iPhone 13 Pro",
"category": "Electronics",
"last_seen_location": "Library Floor 2",
"status": "Lost",
"created_at": "2026-06-04T10:00:00.000Z",
"has_image": true
},
{
"id": "uuid-2",
"item_name": "iPhone 13 Pro",
"category": "Electronics",
"found_location": "Library Floor 2",
"status": "Found",
"created_at": "2026-06-04T11:00:00.000Z",
"has_image": false
}
],
"total": 2
}curl -X POST https://reclaimx.onrender.com/api/matches/verify \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE" \
-d '{
"claim_id": "claim-uuid-here",
"answer_1": "Black leather lining",
"answer_2": "Crack on back near camera, Apple sticker",
"answer_3": "AirPods Pro case and USB-C cable"
}'Response (Verified):
{
"success": true,
"message": "Ownership verified successfully",
"claim": {
"id": "claim-uuid",
"verification_score": 78.5,
"status": "Verified"
},
"trust_score_updated": {
"previous": 10,
"current": 20
}
}Response (Not Verified):
{
"success": false,
"message": "Verification failed β answers do not match",
"claim": {
"id": "claim-uuid",
"verification_score": 45.2,
"status": "Pending",
"failed_attempts": 1,
"remaining_attempts": 2
}
}curl -X POST https://reclaimx.onrender.com/api/matches/confirm-handover/claim-uuid-here \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE"Response:
{
"success": true,
"message": "Handover confirmed β both parties rewarded",
"claim": {
"id": "claim-uuid",
"status": "Resolved",
"loster_confirmed": true,
"founder_confirmed": true
},
"trust_score_updates": {
"loster": {
"previous": 10,
"current": 20
},
"founder": {
"previous": 15,
"current": 25
}
}
}curl -X POST https://reclaimx.onrender.com/api/matches/dismiss/claim-uuid-here \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"reason": "Not my item"
}'Response:
{
"success": true,
"message": "Match dismissed successfully",
"claim": {
"id": "claim-uuid",
"status": "Rejected"
}
}curl -X GET https://reclaimx.onrender.com/api/matches \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE"Response:
{
"success": true,
"claims": [
{
"id": "claim-uuid",
"lost_item_id": "lost-uuid",
"found_item_id": "found-uuid",
"match_score": 67.5,
"verification_score": 78.5,
"status": "Pending",
"item_name": "iPhone 13 Pro",
"category": "Electronics",
"created_at": "2026-06-04T11:00:00.000Z"
}
],
"total": 1
}curl -X PUT https://reclaimx.onrender.com/api/auth/profile \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_FIREBASE_ID_TOKEN_HERE" \
-d '{
"name": "John Doe Updated"
}'Response:
{
"success": true,
"message": "Profile updated successfully",
"user": {
"id": "uuid-here",
"name": "John Doe Updated",
"email": "john@example.com"
}
}curl -X GET https://reclaimx.onrender.com/api/healthResponse:
{
"status": "ok",
"timestamp": "2026-06-04T11:30:00.000Z",
"uptime": 86400,
"database": "connected",
"firebase": "connected",
"cloudinary": "connected"
}curl -X GET https://reclaimx.onrender.com/api/config/firebaseResponse:
{
"success": true,
"firebaseConfig": {
"apiKey": "AIza...",
"authDomain": "reclaimx.firebaseapp.com",
"projectId": "reclaimx",
"storageBucket": "reclaimx.appspot.com",
"messagingSenderId": "123456789",
"appId": "1:123456789:web:abc123"
}
}- Node.js β₯ 18
- npm or yarn
- Firebase project (Email/Password + Google + GitHub auth enabled)
- Supabase project
- Cloudinary account
git clone https://github.com/SniperRavan/RECLAIMX.git
cd RECLAIMXcd backend
npm install
cp .env.example .envEdit backend/.env and fill in these values:
# Server
PORT=5000
NODE_ENV=development
# Firebase Admin SDK
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=your-service-account-email@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Supabase
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# Cloudinary
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
# CORS (optional)
CORS_ORIGIN=http://localhost:3000
β οΈ Never commit.envorserviceAccountKey.jsonβ they're in.gitignore.
- Go to Firebase Console β Project Settings β Service Accounts
- Click Generate New Private Key
- Save as
backend/config/serviceAccountKey.json
- Open your Supabase project's SQL Editor
- Paste the full Database Schema SQL from above
- Click Run
Terminal 1 β Backend (port 5000):
cd backend
npm run devTerminal 2 β Frontend (port 3000):
cd frontend
npx serve . -l 3000Open http://localhost:3000 in your browser.
- Go to Vercel
- Import your repo
- Settings:
- Framework Preset: Other
- Root Directory:
frontend - Build Command: (leave empty)
- Output Directory:
.
- No environment variables needed for frontend
- Deploy
- Go to Render
- New Web Service
- Settings:
- Root Directory:
backend - Start Command:
node server.js - Environment:
PORT=5000 NODE_ENV=production FIREBASE_PROJECT_ID=your-project-id FIREBASE_CLIENT_EMAIL=your-service-account-email@your-project.iam.gserviceaccount.com FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" SUPABASE_URL=https://your-project.supabase.co SUPABASE_SERVICE_ROLE_KEY=your-service-role-key CLOUDINARY_CLOUD_NAME=your-cloud-name CLOUDINARY_API_KEY=your-api-key CLOUDINARY_API_SECRET=your-api-secret CORS_ORIGIN=https://reclaimx-chi.vercel.app
- Root Directory:
- Deploy
| Measure | Description |
|---|---|
| Secrets Management | All secrets in backend/.env β never in frontend HTML |
| Firebase Config | Served from backend endpoint β safe public config, not admin keys |
| Sensitive Data Filter | Blocks Aadhaar, PAN, card numbers in descriptions |
| Security Headers | Helmet.js sets strict headers on all responses |
| Rate Limiting | 100 requests / 15 min per IP (trust proxy enabled for Render) |
| Token Verification | Firebase ID token verified server-side on every protected route |
| Database Access | Supabase service role key is backend-only only |
| File Ignored | .env, serviceAccountKey.json in .gitignore |
- Rotate Firebase private key every 90 days
- Rotate Supabase service role key if compromised
- Use Render/Vercel secret management (not plain
.envin prod) - Enable secret scanning in GitHub repo settings
- Backend: Jest + Supertest for API endpoint tests
- Frontend: Vitest + Testing Library for component tests
- E2E: Playwright for critical user flows (login β report β match β verify)
- Install dev dependencies:
cd backend npm install --save-dev jest supertest - Create
backend/tests/api.test.js - Add test:
const request = require('supertest'); const app = require('../server'); describe('GET /api/health', () => { it('should return 200 OK', async () => { const response = await request(app).get('/api/health'); expect(response.status).toBe(200); expect(response.body.status).toBe('ok'); }); });
- Run:
npm test
Create .github/workflows/ci.yml:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: cd backend && npm install
- run: cd backend && npm test
- run: cd backend && npm run lint| Priority | Feature | Status | Target |
|---|---|---|---|
| π΄ High | Image similarity via vector embeddings (MobileNet + pgvector) | β Todo | v2.0 |
| π΄ High | Full Supabase RLS policies | β Todo | v1.1 |
| π‘ Medium | Email notifications on match creation (Resend integration) | β Todo | v1.2 |
| π‘ Medium | Verification modal UI in matches.html |
β Todo | v1.1 |
| π‘ Medium | Admin dashboard for campus coordinators | β Todo | v2.0 |
| π’ Low | Mobile app (React Native / Flutter) | β Todo | v3.0 |
| π’ Low | Accessibility improvements (WCAG 2.1 AA) | β Todo | v1.2 |
| π’ Low | Multi-language support (English + Hindi) | β Todo | v2.0 |
| Role | Name | GitHub |
|---|---|---|
| Lead Developer | Sniper Ravan | @SniperRavan |
| Team Member | Member 2 | Add GitHub |
| Team Member | Member 3 | Add GitHub |
- Institution: Private Institute
- Project Type: Final Year Project
- Supervisor: [Add Supervisor Name]
We welcome contributions! This section explains how to get started, our workflow, and expectations.
-
Fork the repository
- Click Fork at the top-right of the repo page
- You'll get
https://github.com/YOUR_USERNAME/RECLAIMX.git
-
Clone your fork
git clone https://github.com/YOUR_USERNAME/RECLAIMX.git cd RECLAIMX -
Add upstream remote
git remote add upstream https://github.com/SniperRavan/RECLAIMX.git
-
Create a feature branch
git checkout -b feature/your-feature-name
Branch naming convention:
feature/add-dark-mode-togglefix/resolve-login-bugdocs/update-api-referencetest/add-backend-tests
-
Make your changes
- Follow existing code style
- Add comments for complex logic
- Update documentation if needed
-
Test your changes
cd backend npm run lint # TODO: npm test (once tests are added)
-
Commit your changes
git add . git commit -m "feat: add dark mode toggle button"
Commit message convention (Conventional Commits):
feat:β New featurefix:β Bug fixdocs:β Documentation changesstyle:β Code style (formatting, semicolons)refactor:β Code refactoring (no feature change)test:β Adding testschore:β Maintenance (deps, build tools)
-
Sync with upstream (before pushing)
git fetch upstream git rebase upstream/main
-
Push to your fork
git push origin feature/your-feature-name
-
Open a Pull Request
- Go to your fork on GitHub
- Click Compare & pull request
- Select base repository:
SniperRavan/RECLAIMX - Select base branch:
main - Fill in the PR template below
Copy this into your PR description:
## Description
<!-- Briefly describe what this PR does -->
## Related Issue
<!-- Link to issue number if applicable -->
Closes #123
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing Done
<!-- Describe how you tested this -->
- [ ] Local testing completed
- [ ] Screenshots attached (if UI change)
- [ ] New tests added (if applicable)
## Checklist
- [ ] My code follows the project's style guidelines
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix/feature works
- [ ] All new and existing tests passed- Frontend: Vanilla JS, ES Modules, no frameworks
- Backend: Express.js, async/await, error handling
- Naming:
- Variables:
camelCase - Constants:
UPPER_SNAKE_CASE - Files:
kebab-case.html,kebab-case.js
- Variables:
- Comments: JSDoc for functions, inline comments for complex logic
- Indentation: 2 spaces (HTML, CSS, JS)
- Quotes: Single quotes
'for JS, double quotes"for JSON
- Be respectful and inclusive
- Provide constructive feedback
- Accept constructive criticism
- Focus on what's best for the community
- Open an issue for bugs or questions
- Tag issues with appropriate labels (
bug,enhancement,question) - Join discussions in GitHub Discussions tab
- Maintainer reviews your PR within 3β5 business days
- Feedback may be given β address comments and push updates
- Once approved, PR is merged into
main - Your contribution is credited in
CONTRIBUTORS.md
MIT License β see LICENSE for full text.
Brief summary: You're free to use, modify, and distribute this project for any purpose, including commercial use, as long as you include the original copyright notice and license text.
- Firebase for authentication
- Supabase for database
- Cloudinary for image storage
- Vercel & Render for hosting
- MIT License for open-source freedom
Built with β€οΈ by Sniper Ravan and team
GitHub Β·
Live Demo Β·
Contribute








