Logo Lanfrica

Edvin-Kjall/EasyPay-Rwanda-Cloudflare

Domain:

digital infrastructure

Record type:

software
Creator:
Edv
Host:
EasyPay Rwanda — Cloudflare edition. Accept MTN MoMo payments via QR codes. React + Clerk auth + Cloudflare Workers + D1. Not officially endorsed by or affiliated with MTN. # EasyPay Rwanda (Cloudflare edition) Accept MTN MoMo payments in Rwanda via QR codes and USSD push, with shop dashboards, customer logs, and SMS campaign management. This is a full port of the original Firebase-based app to the Cloudflare developer platform: | Concern | Before (Firebase) | Now (Cloudflare) | | --------- | ---------------------------- | ------------------------------------------------- | | Auth | Firebase Auth (Google) | **Clerk** (`@clerk/clerk-react` + `@clerk/backend`) | | Database | Cloud Firestore | **Cloudflare D1** (SQLite) | | Backend | Firestore security rules | **Cloudflare Worker** API (Hono), token-verified | | Hosting | Static hosting | **Worker Static Assets** (SPA) via `@cloudflare/vite-plugin` | ## Architecture - **`src/`** — React 19 + TypeScript + Tailwind CSS 4 SPA (Vite). Routes: `/` (sign-in / routing), `/admin`, `/shop/:shopId/dashboard`, `/pay/:shopId` (public payment page). - **`worker/index.ts`** — Hono API running in the same Worker: - Public: `GET /api/shops/:id`, `POST /api/shops/:id/transactions` (records the payment and returns the USSD string), and the click tracker `GET /t/:campaignId/:phone` (302 redirect + one click per phone). - Authenticated (Clerk session token in `Authorization: Bearer …`): `GET /api/me`, `GET /api/shops/:id/dashboard`, `PATCH /api/shops/:id`. - Admin only: `GET /api/admin/overview`, `POST/DELETE /api/admin/shops…`, `DELETE /api/admin/customers/:phone`, `GET/POST /api/admin/campaigns`. - **`migrations/0001_init.sql`** — D1 schema: `shops`, `transactions`, `customers`, `admins`, `campaigns`, `clicks`. - Admin access = the signed-in user's primary email is in the `ADMIN_EMAILS` var (comma-separated) or in the `admins` D1 table. No emails are hardcoded in the frontend. Requests to `/api/*` and `/t/*` hit the Worker first (`assets.run_worker_first`); everything else is served as …