Skip to content

Latest commit

 

History

121 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GPMS — Ganesh Puja Management System

Live Demo Next.js TypeScript Tailwind CSS Google Sheets

A physical receipt book has no audit trail, no backup, and no QR code. GPMS replaces all three — built for one committee, hardened like it serves a thousand.


Table of Contents


Overview

GPMS is a mobile-first web app that digitizes the financial operations — donations and expenses — of a Ganesh Puja Committee. It was purpose-built for a small, trusted team of 10–15 volunteers and admins managing roughly 500–1,000 records per season, not for internet-scale traffic. That constraint is a feature: every decision below optimizes for reliability and auditability over raw throughput.

In the field, a volunteer collects a donation, taps submit, and instantly shares a QR-coded PDF receipt over WhatsApp — no paper, no illegible handwriting, no "I'll enter it later and forget." Every receipt is publicly verifiable, so no one can fake one after the fact.

Live app: gpms-ksn.vercel.app


Features

🧾 Donation Workflow Captures donor name, phone, amount, payment mode (Cash/UPI), UPI reference, purpose, and remarks. Generates a DON- internal ID and a public RCT- receipt ID, then renders an A5 PDF receipt client-side (jspdf) with an embedded QR code (qrcode) — one tap to share on WhatsApp.
🧮 Expense Workflow Captures category, description, amount, vendor, and a bill upload (image/PDF, max 5MB). The bill is pushed to a restricted Google Drive folder and linked back to the ledger row under a unique EXP- ID.
🔐 Role-Based Access SuperAdmin/Admin — full control, including cancellations, user management, and audit logs. Volunteer — can record donations and expenses in the field, can't cancel or manage users. Viewer — read-only.
Public Verification Scanning a receipt's QR code opens /verify/[receiptId], proving the receipt is genuine while masking sensitive fields like the donor's phone number.

Tech Stack

Layer Technology
Frontend Next.js 14+ (App Router), React, Tailwind CSS, Lucide React
Auth NextAuth.js (Auth.js) v5 — Google OAuth, allow-listed Gmail addresses only
API layer Next.js API Routes, acting as a secured proxy
Backend Google Apps Script (GAS) Web App
Database Google Sheets — chosen deliberately for radical transparency; any committee elder can open it and audit every row without touching the app
File storage Google Drive (vendor bill uploads)
Hosting Vercel (frontend) · Google Cloud / Apps Script (backend)
PDF & QR jspdf, qrcode

Architecture

flowchart LR
    U["Volunteer / Admin<br/>Mobile Browser"] -->|Google OAuth| AUTH["NextAuth.js<br/>Allow-listed Gmail Gate"]
    AUTH --> FE["Next.js 14 Frontend<br/>(Vercel)"]
    FE -->|"proxy · 15s AbortController"| API["Next.js API Routes"]
    API -->|HTTPS| GAS["Google Apps Script<br/>Web App"]
    GAS -->|"LockService · atomic write"| SHEETS[("Google Sheets<br/>Donations · Expenses · Users · AuditLogs")]
    GAS -->|bill upload| DRIVE[("Google Drive<br/>Restricted Folder")]
    FE -->|"QR scan"| VERIFY["/verify/[receiptId]<br/>Public Portal"]
    VERIFY -.->|read-only, masked| SHEETS
Loading

The frontend never talks to Google Sheets directly — every write goes through the Apps Script layer, which is the only thing holding the lock and the only thing allowed to touch the spreadsheet.


Production-Grade Engineering

A 500-record community tool doesn't need this level of hardening — it has it anyway, because a committee's trust in the ledger is the entire point of building it digital in the first place.

Real-world problem Engineering solution
Bad mobile signal in a crowd → volunteer double-taps "Submit" Client generates a crypto.randomUUID() transaction ID that survives network timeouts; the backend rejects any row with a duplicate ID
Two volunteers submit at the same instant → race condition on sequential IDs LockService.getScriptLock() wraps ID generation and row insertion in one atomic, 15-second-timeout transaction
Bill uploads to Drive, then the Sheets write fails The (slow) Drive upload happens outside the lock for speed; on a failed or duplicate insert, the orphaned Drive file is automatically trashed — no storage leaks
Google's servers stall mid-request Every proxied API call is wrapped in a 15-second AbortController so the UI degrades gracefully instead of hanging
Malformed or absurd amounts corrupt the ledger Server-side validation hard-caps every amount between ₹1 and ₹9,999,999

Database Schema

Google Sheets serves as the database, with the backend relying on exact 0-indexed column positions.

Donations Sheet

Donation ID · Receipt ID · Donor Name · Phone · Amount · Payment Mode · UPI Ref · Collector ID · Collector Name · Purpose · Remarks · Status (Active/Cancelled) · Created At · Updated At · Transaction ID

Expenses Sheet

Expense ID · Category · Description · Vendor · Amount · Paid By ID · Paid By Name · Bill Link · Status (Active/Cancelled) · Created At · Updated At · Transaction ID

Supporting sheets

Users · Settings (holds Drive folder IDs) · Categories · AuditLogs · Metadata (ID sequence counters) · Sessions


Environment Variables

Vercel (frontend)
Variable Purpose
NEXT_PUBLIC_API_URL Deployed Apps Script Web App URL
AUTH_GOOGLE_ID Google OAuth client ID
AUTH_GOOGLE_SECRET Google OAuth client secret
AUTH_SECRET NextAuth.js encryption key
AUTH_URL Production Vercel domain
Apps Script (backend)

Deployed to execute as "Me" (the admin account) with access set to "Anyone." The Google Sheet ID is held in Config.gs, not in an env file.


Getting Started

# 1. Clone
git clone https://github.com/TechGenDM/<repo-name>.git
cd <repo-name>

# 2. Install
npm install

# 3. Configure — add the Vercel variables above to a .env.local
cp .env.example .env.local

# 4. Run locally
npm run dev

For the backend, deploy Config.gs and the rest of the Apps Script project from the Google Sheet's Extensions → Apps Script menu, execute as Me, set access to Anyone, then copy the resulting Web App URL into NEXT_PUBLIC_API_URL.


Public Verification Portal

GPMS verification seal

Every printed or shared receipt carries a QR code. Scanning it opens a public, read-only page at /verify/[receiptId] that confirms the receipt is genuine — while quietly masking sensitive fields like the donor's phone number. No login required, nothing to fake: the seal on the receipt matches the seal in the ledger, or it doesn't exist.



Roadmap

Ideas under consideration for future seasons — not commitments:

  • SMS/WhatsApp receipt delivery without opening the app
  • Season-over-season donor history lookup
  • CSV export for the committee's annual report
  • Offline-first submission queue for zero-signal collection points

Author

Devasish Mishra · "I was built to build."

GitHub LinkedIn

CS & AI student, Scaler School of Technology + BITS Pilani.


This project is built for one community's trust — not for the internet's traffic.

Ganpati Bappa Morya 🙏

About

Ganesh Puja Management System

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages