Skip to content

Latest commit

Β 

History

109 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

βš™οΈ ecotask-backend

The EcoTask API server β€” proof verification, task management, and Stellar oracle.

A Node.js/Express backend that bridges the real world and the blockchain β€” processing proof submissions, coordinating validators, and triggering on-chain rewards.

CI Node.js Express PostgreSQL TypeScript License: MIT PRs Welcome Conventional Commits Contributor Covenant Status


🌍 Overview

ecotask-backend is the off-chain infrastructure layer of EcoTask. It acts as the trusted bridge between user actions in the mobile app and the Stellar smart contracts that release rewards.

The backend is responsible for:

  • πŸ—‚οΈ Task management β€” Creating, listing, and expiring tasks
  • πŸ“Έ Proof intake β€” Receiving photo + GPS submissions from the mobile app
  • πŸ” Verification coordination β€” Routing proofs to community validators or automated checks
  • ⛓️ Stellar oracle β€” Submitting verified results to the reward-engine smart contract
  • πŸ“Š Analytics β€” Tracking impact metrics (trees planted, plastic collected, COβ‚‚ offset)
  • πŸ”” Notifications β€” Alerting users when their proof is verified and reward is sent

✨ Key Responsibilities

Module What It Does
πŸ—‚οΈ Task API CRUD for tasks; filter by location, type, reward, status
πŸ“€ Proof API Accept photo uploads, extract GPS metadata, pin to IPFS
πŸ” Verification Engine Queue-based system routing proofs to validators
⛓️ Stellar Oracle Signs and submits reward transactions to Soroban contracts
πŸ‘€ User API Profile, wallet linking, impact history
πŸ“Š Analytics API Aggregated platform & user impact statistics
πŸ” Auth JWT-based auth with Stellar wallet signature verification

πŸ—οΈ Tech Stack

Layer Technology Why
Runtime Node.js 20 Fast, async-first, huge ecosystem
Framework Express 4 Lightweight, flexible REST APIs
Database PostgreSQL 15 Reliable relational data for tasks & users
ORM Prisma Type-safe DB queries with easy migrations
Queue BullMQ + Redis Async proof verification job queue
File Storage IPFS (via Web3.Storage) Decentralised, permanent proof storage
Blockchain Stellar SDK (JS) Submit transactions to reward-engine contract
Auth JWT + Stellar keypair Wallet-based authentication
Validation Zod Runtime schema validation
Testing Jest + Supertest Unit & integration tests
Docs Swagger / OpenAPI Auto-generated API documentation

πŸ“ Folder Structure

ecotask-backend/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ routes/                   # Express route definitions
β”‚   β”‚   β”œβ”€β”€ tasks.ts                  # GET/POST /tasks
β”‚   β”‚   β”œβ”€β”€ proofs.ts                 # POST /proofs
β”‚   β”‚   β”œβ”€β”€ users.ts                  # GET/PUT /users
β”‚   β”‚   β”œβ”€β”€ auth.ts                   # POST /auth/login, /auth/verify
β”‚   β”‚   β”œβ”€β”€ notifications.ts          # GET /notifications
β”‚   β”‚   └── analytics.ts              # GET /analytics
β”‚   β”‚
β”‚   β”œβ”€β”€ controllers/              # Route handler logic
β”‚   β”‚   β”œβ”€β”€ taskController.ts
β”‚   β”‚   β”œβ”€β”€ proofController.ts
β”‚   β”‚   β”œβ”€β”€ userController.ts
β”‚   β”‚   β”œβ”€β”€ authController.ts
β”‚   β”‚   └── analyticsController.ts
β”‚   β”‚
β”‚   β”œβ”€β”€ services/                 # Core business logic
β”‚   β”‚   β”œβ”€β”€ verificationService.ts    # Proof review & scoring
β”‚   β”‚   β”œβ”€β”€ stellarService.ts         # Stellar SDK + oracle calls
β”‚   β”‚   β”œβ”€β”€ ipfsService.ts            # Upload proofs to IPFS
β”‚   β”‚   β”œβ”€β”€ notificationService.ts    # Push notification dispatch
β”‚   β”‚   └── geoService.ts             # Location validation & distance
β”‚   β”‚
β”‚   β”œβ”€β”€ middleware/               # Express middleware
β”‚   β”‚   β”œβ”€β”€ auth.ts                   # JWT verification
β”‚   β”‚   β”œβ”€β”€ rateLimit.ts              # Request throttling
β”‚   β”‚   β”œβ”€β”€ upload.ts                 # Multer file upload config
β”‚   β”‚   └── errorHandler.ts           # Global error handling
β”‚   β”‚
β”‚   β”œβ”€β”€ models/                   # Prisma schema types & helpers
β”‚   β”‚   β”œβ”€β”€ task.ts
β”‚   β”‚   β”œβ”€β”€ proof.ts
β”‚   β”‚   └── user.ts
β”‚   β”‚
β”‚   β”œβ”€β”€ workers/                  # BullMQ background jobs
β”‚   β”‚   β”œβ”€β”€ verificationWorker.ts     # Process proof verification queue
β”‚   β”‚   └── rewardWorker.ts           # Trigger Stellar reward payouts
β”‚   β”‚
β”‚   β”œβ”€β”€ utils/                    # Shared helpers
β”‚   β”‚   β”œβ”€β”€ logger.ts                 # Structured logging
β”‚   β”‚   β”œβ”€β”€ stellarUtils.ts           # Key formatting & signing helpers
β”‚   β”‚   └── ipfsUtils.ts              # CID formatting & gateway URLs
β”‚   β”‚
β”‚   └── app.ts                    # Express app setup
β”‚
β”œβ”€β”€ prisma/
β”‚   β”œβ”€β”€ schema.prisma             # Database schema
β”‚   └── migrations/               # DB migration history
β”‚
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ routes/                   # Route integration tests
β”‚   └── services/                 # Service unit tests
β”‚
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ default.ts                # Default config values
β”‚   └── production.ts             # Production overrides
β”‚
β”œβ”€β”€ .env.example
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
└── package.json

πŸš€ Getting Started

Prerequisites

  • Node.js >= 20
  • PostgreSQL 15
  • Redis (for BullMQ job queue)
  • A Stellar testnet account (funded via Friendbot)

Installation

# 1. Clone the repo
git clone https://github.com/ecotask-network/ecotask-backend.git
cd ecotask-backend

# 2. Install dependencies
npm install

# 3. Set up environment variables
cp .env.example .env
# Fill in your database URL, Stellar keys, IPFS token, etc.

# 4. Run database migrations
npx prisma migrate dev

# 5. Seed the database with sample tasks
npm run db:seed

# 6. Start the development server
npm run dev

Or with Docker (infrastructure only)

docker-compose.yml runs just the supporting services β€” PostgreSQL and Redis. The API itself runs on your host:

# 1. Start Postgres and Redis in the background
docker-compose up -d

# 2. Install, configure, migrate and run the API
npm install
cp .env.example .env     # fill in DATABASE_URL, JWT_SECRET, Stellar keys, etc.
npx prisma migrate dev
npm run dev
# API available at http://localhost:3000

Environment Variables

# Server
PORT=3000
NODE_ENV=development
CORS_ORIGIN=*
LOG_LEVEL=info

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/ecotask

# Redis
REDIS_URL=redis://localhost:6379

# Queue retention
PROOF_VERIFICATION_QUEUE_COMPLETED_RETENTION_COUNT=1000
PROOF_VERIFICATION_QUEUE_FAILED_RETENTION_SECONDS=604800
REWARD_PAYOUT_QUEUE_COMPLETED_RETENTION_COUNT=1000
REWARD_PAYOUT_QUEUE_FAILED_RETENTION_SECONDS=604800
NOTIFICATION_DISPATCH_QUEUE_COMPLETED_RETENTION_COUNT=1000
NOTIFICATION_DISPATCH_QUEUE_FAILED_RETENTION_SECONDS=604800

# Background jobs
EXPIRY_SWEEP_INTERVAL_MS=900000

# Stellar
STELLAR_NETWORK=testnet
STELLAR_ORACLE_SECRET_KEY=YOUR_ORACLE_SECRET_KEY
REWARD_ENGINE_CONTRACT_ID=YOUR_CONTRACT_ID

# IPFS
WEB3_STORAGE_TOKEN=YOUR_WEB3_STORAGE_TOKEN

# Auth
JWT_SECRET=your_jwt_secret_here
JWT_EXPIRES_IN=7d

# Rate limits (per-user)
PROOF_RATE_LIMIT_WINDOW_MS=3600000
PROOF_RATE_LIMIT_MAX=20
CLAIM_RATE_LIMIT_WINDOW_MS=3600000
CLAIM_RATE_LIMIT_MAX=50

# Notifications
NOTIFICATION_WEBHOOK_TIMEOUT_MS=5000
NOTIFICATION_EMAIL_FROM=EcoTask <[email protected]>

# Community validation
VALIDATOR_ASSIGNMENT_COUNT=3
VALIDATOR_QUORUM_REQUIRED=2

Completed jobs are capped independently for each BullMQ queue. Failed jobs remain available for investigation for the configured number of seconds and are then removed as newer failed jobs finish.

To apply the same policy to jobs accumulated before retention was enabled:

npm run build
npm run queues:cleanup

To run the isolated Redis load check and confirm queue keys and memory remain bounded:

npm run build
npm run queues:verify-retention

Production startup rejects missing JWT secrets and all development or documentation placeholders stored in this repository. This denial list does not measure secret strength; generate a fresh random secret for every deployment.


πŸ“‘ API Overview

The endpoint reference below is the authoritative API documentation for the current version. The API is versionless for now; once stable, breaking changes will be gated behind /v1 and /v2 prefixes.

Tasks

GET    /api/tasks              # List tasks (filter by type, location, status, reward)
GET    /api/tasks/:id          # Get single task details
POST   /api/tasks              # Create a task (admin/sponsor only)
PUT    /api/tasks/:id          # Update task (admin only)
DELETE /api/tasks/:id          # Delete/expire a task
POST   /api/tasks/:id/claim    # Claim a task (24h claim window)
DELETE /api/tasks/:id/claim    # Release a claim
GET    /api/tasks/:id/claims   # List active claims for a task

Tasks accept an optional maxCompletions capacity; once that many proofs are approved the task is auto-marked COMPLETED. Overdue ACTIVE tasks are flipped to EXPIRED by a background sweeper (EXPIRY_SWEEP_INTERVAL_MS).

Claims are enforced. Submitting a proof requires a valid, unexpired claim on the task: POST /api/proofs returns 403 when the submitter holds no active claim, and a claim whose expiresAt has passed is rejected at submit time even before the background sweeper marks it expired. Each proof is stored with the claimId of the claim it was submitted under. (Proofs created before this rule was introduced are grandfathered: their claimId is NULL and they remain valid.)

Proofs

POST   /api/proofs             # Submit proof (photo + GPS + task_id)
GET    /api/proofs/:id         # Get proof status
GET    /api/proofs/user/:id    # Get all proofs by a user
GET    /api/proofs/review      # List pending proofs; ?reviewReason=no_validators filters escalations (admin)
POST   /api/proofs/:id/review  # Approve/reject an inconclusive proof (admin)

Proofs that the auto-verifier cannot decide are left for an admin to review via POST /api/proofs/:id/review, which resolves the verdict, notifies the user, and enqueues the reward payout when approved. If no community validator can be assigned, the verification worker immediately moves the proof back to the existing PENDING admin-reviewable state and records a manual-review marker. Admins can list only those proofs with GET /api/proofs/review?reviewReason=no_validators.

Photo analysis

Every uploaded photo is hashed (SHA-256) and its EXIF metadata is extracted on submission. The auto-verifier uses this data for real checks instead of the old placeholder photo_quality scoring:

  • photo_quality β€” at least one photo meets the minimum resolution (480Γ—480)
  • photo_recency β€” at least one photo carries an EXIF capture timestamp within the last 7 days (blocks stale/stock images)
  • photo_not_duplicate β€” no photo may reuse a hash already submitted on another proof; reuse is treated as fraud and immediately rejects the proof

These checks complement the existing GPS-radius and task-expiry checks.

Rate limiting & abuse controls

Beyond the global express-rate-limit throttles, sensitive endpoints apply per-user (or per-IP for anonymous callers) limits backed by Redis:

Endpoint Default limit Env vars
POST /api/proofs 20 / hour PROOF_RATE_LIMIT_WINDOW_MS, PROOF_RATE_LIMIT_MAX
POST/DELETE /:id/claim 50 / hour CLAIM_RATE_LIMIT_WINDOW_MS, CLAIM_RATE_LIMIT_MAX

The limiter reports RateLimit-* headers and Retry-After on 429s, and fails open if Redis is unreachable so infrastructure hiccups never block legitimate traffic.

Users

POST   /api/auth/login         # Authenticate with Stellar wallet signature
GET    /api/users/:id          # Get user profile & stats
PUT    /api/users/:id          # Update profile
GET    /api/users/:id/impact   # Get impact history (trees, plastic, COβ‚‚)

Notifications

GET    /api/notifications             # Paginated inbox for the logged-in user
GET    /api/notifications/unread-count
POST   /api/notifications/preferences # Set email + webhook delivery channels
POST   /api/notifications/:id/read    # Mark one notification as read
POST   /api/notifications/read-all    # Mark all as read

Beyond the in-app inbox, notifications are pushed to outbound channels. Set email and/or webhookUrl via POST /api/notifications/preferences and a background worker dispatches each new notification to the configured channels:

  • Webhook β€” a JSON payload is POSTed to the user's webhookUrl (NOTIFICATION_WEBHOOK_TIMEOUT_MS guards the request)
  • Email β€” dispatched through a mock transport that logs the message; swap in an SMTP provider to go live

Each notification tracks which channel it went through (channel), whether it was delivered (deliveredAt) and any delivery failure (deliveryError).

Analytics

GET    /api/analytics/platform   # Global platform impact stats
GET    /api/analytics/trends     # Daily approved proofs & rewards series
GET    /api/leaderboard          # Top contributors (proofs + total reward)

Audit (admin)

GET    /api/audit                # Query audit logs (user, resource, paginated)

Community validation

Proofs that the auto-checks can't resolve are routed to community validators instead of always landing in the admin queue. Every submission is coordinated by validatorService:

Auto-check inconclusive
       β”‚
       β–Ό
assignValidators(): picks `VALIDATOR_ASSIGNMENT_COUNT` least-loaded
validators (lowest reviewCount), excluding the proof's submitter
       β”‚
       β–Ό
Validators cast verdicts via POST /api/validator/reviews/:proofId
       β”‚
       β–Ό
resolveQuorum(): first verdict to reach `VALIDATOR_QUORUM_REQUIRED`
votes finalizes the proof β€” then notifies, completes the task and pays
       β”‚
       β–Ό
Split votes with no quorum β†’ escalated to admin review

Validator reputation is rewarded: agreeing with the final quorum verdict earns +1 validatorReputation, dissenting costs -1. Admin endpoints manage the roster:

GET    /api/validators                     # List validators by reputation (admin)
POST   /api/validators/:userId/activate    # Promote a user to validator (admin)
POST   /api/validators/:userId/deactivate  # Demote back to user (admin)
GET    /api/validator/reviews              # My assigned, undecided reviews (validator)
POST   /api/validator/reviews/:proofId     # Cast verdict: approved | rejected

πŸ” Verification Flow

User submits proof
       β”‚
       β–Ό
Proof saved to DB (status: pending)
       β”‚
       β–Ό
Photo + GPS pinned to IPFS
       β”‚
       β–Ό
Job added to BullMQ verification queue
       β”‚
       β–Ό
verificationWorker picks up job
       β”‚
       β”œβ”€β”€ Auto-checks (GPS in task zone? Photo contains relevant content?)
       β”‚
       └── Community validator review (if auto-check inconclusive)
              β”‚
              β–Ό
        Proof approved / rejected
              β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
       β–Ό             β–Ό
   Rejected       Approved
   (notify)          β”‚
                     β–Ό
            rewardWorker triggers
            Stellar oracle call
                     β”‚
                     β–Ό
            ECO tokens / USDC sent
            to user's Stellar wallet
                     β”‚
                     β–Ό
            User notified βœ…

Inconclusive proofs are routed to community validators for quorum review (see Community validation); only split votes with no quorum fall through to the admin review queue (GET /api/proofs/review, resolved via POST /api/proofs/:id/review), which re-enters the flow at "Proof approved / rejected".


πŸ§ͺ Testing

# Run all tests
npm test

# Run with coverage report
npm run test:coverage

# Run integration tests only
npm run test:integration

πŸ—ΊοΈ Roadmap

Where the project is today and where it's headed. Priorities may shift based on contributor and community feedback β€” see the discussions and issues for the lively plan.

Shipped (v0.1)

  • Stellar wallet-based auth (challenge β†’ signature β†’ JWT)
  • Task CRUD, geo-bounded listing, claims, capacity limits (maxCompletions), and automatic expiry
  • Proof intake: photo upload, EXIF GPS extraction, IPFS pinning
  • Verification pipeline: auto-checks (GPS radius, photos, task expiry) with confidence scoring, plus admin review for inconclusive proofs
  • Reward payouts via the Stellar SDK (mock mode for local dev)
  • DB-backed notification inbox with read/unread tracking
  • Notification delivery: webhook + email channels with delivery tracking
  • Per-user Redis-backed rate limits on proof submissions and task claims
  • Photo analysis: SHA-256 hashing, resolution/recency checks, duplicate detection
  • Community validator program: quorum voting, reputation, and fair assignment
  • Platform analytics, daily trends, and a rewards-enriched leaderboard
  • Audit logging of mutating admin/API actions

In progress

  • Integrating the reward-engine Soroban contract (the oracle secret and contract ID are configured, but payouts currently use a direct payment op)
  • Swap the mock email transport for a real SMTP provider

Planned

  • API versioning, pagination hypermedia, and generated OpenAPI docs
  • Impact reporting standardization (trees, plastic, COβ‚‚) with exportable verifiable claims

🀝 Contributing

Backend developers, DevOps engineers, and database architects especially welcome! See CONTRIBUTING.md to get started.


πŸ’¬ Contact & Community

Questions, ideas, or feedback? Reach the team and fellow contributors here:

Channel What it's for
GitHub Discussions General questions, feature ideas, project chat
GitHub Issues Bug reports and trackable feature requests
EcoTask docs hub Project-wide documentation and announcements

Please follow our Code of Conduct in all interactions. Security issues should be reported privately β€” see SECURITY.md.


πŸ“„ License

MIT β€” see LICENSE for details.


Ecosystem

This is part of the EcoTask Network:

Repo Description
EcoTask-app Mobile dApp
EcoTask-backend Node.js API & verification engine
EcoTask-contracts Stellar Soroban smart contracts
EcoTask-docs Documentation hub

Part of the EcoTask Network β€” Because the environment deserves an economy.

About

ecotask-backend is the off-chain infrastructure layer of EcoTask. It acts as the trusted bridge between user actions in the mobile app and the Stellar smart contracts that release rewards.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages