|
| 1 | +# NSNVC Citizen Contribution Tracker |
| 2 | + |
| 3 | +A lightweight web app for the **New Serchhip North Village Council (NSNVC)**, Mizoram, India, to track monthly citizen contributions (derived from MGNREGA wages) for each household — and let citizens look up their own balance. |
| 4 | + |
| 5 | +**Live site:** https://enga018.github.io/nsnvc-contribution/ |
| 6 | + |
| 7 | +It is a single HTML file. No build step, no server of its own — just static hosting plus Firebase for data and admin login. |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## What it does |
| 12 | + |
| 13 | +### For citizens (public, no login) |
| 14 | +- Look up a contribution balance by typing the **job card number** (the part after the slash is enough). |
| 15 | +- See a clean statement: name, status (Cleared / Due / Partly paid), the amount still to pay, and a collapsible payment history (oldest first). |
| 16 | +- Browse the list of households who still owe. |
| 17 | +- **Pay Now (UPI):** opens the citizen's UPI app (GPay / PhonePe / Paytm) with the council's UPI ID and amount pre-filled. The council confirms the payment manually once it arrives. |
| 18 | + |
| 19 | +### For the council (admin, email/password login) |
| 20 | +- Dashboard with a single **"Still to collect"** figure (total outstanding + number of pending households). |
| 21 | +- Filter households by **Pending / Paid / Deferred / All**, and by **period** ("Pending: January", etc.). |
| 22 | +- Open any household to add a contribution, record a payment, **mark fully paid**, **forgive** part or all of a balance, or **defer** a charge (for someone still awaiting their wages). |
| 23 | +- **Edit or delete** any history entry; balances recompute from the ledger automatically. |
| 24 | +- **Import from Excel:** |
| 25 | + - First-time historical register (one-time, with a guard against duplicating existing data). |
| 26 | + - Monthly update file — detects the layout and asks you to confirm which column is the job card, name and amount, so fixed header names aren't required. |
| 27 | + - Bank payment file — records payments and flags rows it can't match. |
| 28 | + - A duplicate-period guard warns before re-importing a period already added. |
| 29 | +- **Export** the owing list (with payment detail) as CSV. |
| 30 | +- **Backup & restore:** download a full JSON backup of every household and its history, or restore from one. |
| 31 | +- **Recalculate all balances** — rebuilds every total from its history if anything ever looks off. |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Tech stack |
| 36 | + |
| 37 | +- **Vanilla JavaScript**, single `index.html` (no frameworks, no bundler) |
| 38 | +- **Firebase Firestore** — database |
| 39 | +- **Firebase Authentication** — admin login (email/password) |
| 40 | +- **SheetJS (xlsx)** — Excel parsing, loaded on demand from a CDN |
| 41 | +- **GitHub Pages** — free static hosting |
| 42 | + |
| 43 | +The app runs in a local **test mode** with sample data if no Firebase config is present, so you can try the UI without a backend. |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Setup |
| 48 | + |
| 49 | +### 1. Firebase |
| 50 | +1. Create a Firebase project and enable **Firestore** and **Authentication → Email/Password**. |
| 51 | +2. Add an admin user under Authentication. |
| 52 | +3. Copy your web app config into the `firebaseConfig` object near the top of `index.html`: |
| 53 | + |
| 54 | + ```js |
| 55 | + const firebaseConfig = { |
| 56 | + apiKey: "…", |
| 57 | + authDomain: "YOUR_PROJECT.firebaseapp.com", |
| 58 | + projectId: "YOUR_PROJECT", |
| 59 | + storageBucket: "YOUR_PROJECT.firebasestorage.app", |
| 60 | + messagingSenderId: "…", |
| 61 | + appId: "…" |
| 62 | + }; |
| 63 | + ``` |
| 64 | + |
| 65 | + > The web `apiKey` is **not** a secret — it is meant to ship in client code. Access is controlled by Firestore security rules, not by hiding the key. |
| 66 | +
|
| 67 | +### 2. Firestore security rules |
| 68 | +Public read (so citizens can look up balances), admin-only write: |
| 69 | + |
| 70 | +``` |
| 71 | +rules_version = '2'; |
| 72 | +service cloud.firestore { |
| 73 | + match /databases/{database}/documents { |
| 74 | +
|
| 75 | + match /citizens/{cid} { |
| 76 | + allow read: if true; |
| 77 | + allow write: if request.auth != null && request.auth.token.email == "YOUR_ADMIN_EMAIL"; |
| 78 | + match /{sub=**} { |
| 79 | + allow read: if true; |
| 80 | + allow write: if request.auth != null && request.auth.token.email == "YOUR_ADMIN_EMAIL"; |
| 81 | + } |
| 82 | + } |
| 83 | +
|
| 84 | + match /meta/{doc} { |
| 85 | + allow read: if true; |
| 86 | + allow write: if request.auth != null && request.auth.token.email == "YOUR_ADMIN_EMAIL"; |
| 87 | + } |
| 88 | +
|
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +Replace `YOUR_ADMIN_EMAIL` with your admin login email. The `meta` rule lets the duplicate-import guard remember which periods have been imported. |
| 94 | + |
| 95 | +### 3. Deploy |
| 96 | +Commit `index.html` to the repo and enable **GitHub Pages** (Settings → Pages → deploy from branch). The app is served from the repo's `index.html`. |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Data model (brief) |
| 101 | + |
| 102 | +Each household is a document in the `citizens` collection, keyed by its full job card (with `/` encoded). It stores name, job card, totals (`totalCharged`, `totalPaid`, `balance`, `deferredTotal`) and a `ledger` subcollection of entries: |
| 103 | + |
| 104 | +- `charge` — a period's contribution (can be `deferred`) |
| 105 | +- `payment` — money received (cash / bank / UPI) |
| 106 | +- `forgive` — a waived amount |
| 107 | + |
| 108 | +Balances are derived from the ledger: effective balance = (charges excluding deferred) − payments. Payments are not tied to specific periods; the period filter applies them oldest-first (FIFO). |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## Backups |
| 113 | + |
| 114 | +The data lives only in Firestore, so **take a backup regularly**: Admin → Backup / Restore → Download backup. Keep the JSON file somewhere safe. Restore reads that file back. There is no automatic off-site backup. |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## Notes |
| 119 | + |
| 120 | +- Designed for low-end phones and patchy connectivity — minimal, fast, single file. |
| 121 | +- Built and maintained for NSNVC, Mizoram. |
0 commit comments