Net-Zero Thailand is an MVP platform that lets users log everyday low-carbon activities — taking the bus, recycling, and planting trees — and rewards them with voucher points, backed by a real API, state machines, PostgreSQL transactions, an idempotent ledger, RBAC, and full-stack calculation logic.
Note: All data, identities, and provider integrations in this repository are mock/synthetic — for demo purposes only. See Disclaimer below for the full scope.
- Activity logging — Submit bus, recycling, and tree-planting activities with photo/GPS evidence via a responsive PWA
- Review workflow — Reviewer role checks submitted evidence through a real state machine before approval
- CO2e calculation — Versioned, source-referenced factor catalog with a fail-closed resolver (no factor/approval → no CO2e or points)
- Voucher ledger — Idempotent, transactional point accounting redeemable at demo merchants
- Role-based access — JWT auth with
user,reviewer,merchant, andadminroles - Dashboards — Consumer and operations views for tracking activity, points, and review status
- Node.js 24, TypeScript, pnpm
- Responsive React/Vite PWA
- Modular monolith NestJS/Fastify
- PostgreSQL 17/PostGIS and Graphile Worker
- S3-compatible object storage; MinIO for local development
apps/
api/ # NestJS/Fastify backend — auth, claims, evidence, rewards, community
web/ # React/Vite PWA — consumer and operations UI
worker/ # Graphile Worker background jobs
packages/
domain/ # Core calculation logic (bus, carbon, claims, rewards)
contracts/ # Shared API contracts/types
seed/ # Demo fixtures and approved factor data
migrations/ # Database migrations
cp .env.example .env
pnpm install
docker compose up -d postgres minio
docker compose run --rm minio-init
pnpm demo:reset
pnpm devWeb app: http://localhost:5173
API operational status: http://localhost:3000/health/ready (not a production-readiness gate)
pnpm demo:reset deterministically resets data and creates review fixtures for bus, recycling, and tree under the mock_demo scope without requiring real people, devices, or external providers.
Demo data commands are rejected unless MOCK_DEMO_ENABLED=true. Both resource scopes are mock_demo, the database/object storage/web URLs are loopback addresses, and the database contains a matching persistent mock_demo marker. demo:reset creates the marker only for a newly created database when all business tables are empty. db:seed-demo cannot create the marker itself.
The demo accounts use JWTs and real RBAC roles: user, reviewer, merchant, and admin.
Single-use demo QR tokens:
DEMO-BIN-BKK-01:TOKEN-0001
DEMO-BIN-BKK-01:TOKEN-0002
DEMO-BIN-BKK-01:TOKEN-0003
The CO2e displayed is an estimated CO2e value derived from TGO factors/methods with versioning. The factors are only source-referenced candidate data, and mock approval is limited to the mock_demo scope for demo purposes only. This is not certification, endorsement, or support from TGO, carbon credits, or offsets. It does not claim fraud prevention or proof that a real activity occurred.
Identity data, evidence, timestamps, locations, and provider responses are all mock/synthetic/demo-only. There is no real connection to TGO, transport systems, AI, OIDC, stores, payments, or partner systems, and there is no deployment or claim of production readiness.
The factor catalog and resolver operate in fail-closed mode: if scope, labeling, provenance, or approval is incomplete, the system must not create CO2e or score values. Bus results are a heuristic of the MVP; recycling evidence refers to proof of material delivery, not proof that recycling succeeded; tree results are expected one-year sequestration estimates, not proof that the tree will survive.