# Device-Verified Voting — Frontend + Google Form Ballot

> The independent, frontend-only rating booth. Device fingerprint → authorization gate → hidden Google Form submit. Honest limits documented.

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
[![Static](https://img.shields.io/badge/frontend-only-static-brightgreen.svg)](./index.html)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
[![Form](https://img.shields.io/badge/ballot-google_forms-blue.svg)](./form.html)

**The independent standard for lightweight polls.** Transparent fingerprinting · Prefilled device ID · Zero backend required.

---

🌐 **Live Demo** `./index.html` · 📚 **Setup** [`README-SETUP.md`](./README-SETUP.md) · 💰 **Cost** `$0 (Forms + Pages)` · 🔒 **Limits** [table below](#-limits-read-before-trusting-this)

---

## 📈 Star History

> ⭐ **If this saves you one rigged poll, star this repo.**

---

## The Manifesto

The polling status quo is broken: straw polls with no device check, Google Forms with editable IDs, vendors selling "tamper-proof" that isn't.

This sits outside that — no server to trust, no black box. Fingerprint in `index.html` is auditable, prefill via `entry.<ID>` is visible in source, limits printed in-UI. If you need true tamper-proof, we tell you to leave (Typeform webhooks / custom backend).

No incentive to oversell security. Free, MIT, frontend-only.

## See It Run (10-Second Demo)

```bash
python3 -m http.server 8080
# open http://localhost:8080
# 1. Badge: Checking → Device authorized (simulated)
# 2. Pick ★★★★★ → Submit rating → background POST to Forms, Google UI never shown
```

Config at top of `index.html`: `FORM_ID`, `RATING_ENTRY_ID`, `VERIFY_ENDPOINT` (null = simulate).

---

## 🧮 How Votes Are Scored (Stars 1–5)

| Field | Entry ID | Type |
|-------|----------|------|
| Rating | `1591633300` | Scale 1–5 |
| Feedback | `326955045` | Text |
| Suggestions | `1696159737` | Text |
| Name | `485428648` | Text |
| Device ID | _(add field, set `DEVICE_ENTRY_ID`)_ | Short answer, prefilled |

Submit: hidden `formResponse` POST to `docs.google.com`, target `gform` iframe. Rating value must match form scale options.

### Why No Paid Placements / No Fake Guarantees

> You cannot buy trust here. `verifyDevice()` is simulated unless you set `VERIFY_ENDPOINT`. We document what Google *can't* do (validate at submit, stop devtools edits).

## ⚔️ How We Compare

| Feature | This | Raw Google Form | Typeform+webhook | Custom backend |
|---------|------|-----------------|------------------|----------------|
| Device gate before ballot | ✅ | ❌ | ✅ | ✅ |
| No backend needed | ✅ | ✅ | ❌ | ❌ |
| Validate at submit | ❌ (says so) | ❌ | ✅ | ✅ |
| Stop devtools edits | ❌ | ❌ | partial | ✅ |
| $0 + MIT | ✅ | ✅ | ❌ | ❌ |

## 🔒 Limits (read before trusting this)

| Goal | Status |
|------|--------|
| Embed Form in app | ✅ |
| Device signature | ✅ |
| Verify before showing form | ✅ (simulated locally) |
| Auto-include signature | ✅ via prefilled URL |
| Verify at submission | ❌ Google never tells your server |
| Stop devtools ID edits | ❌ |
| Stop refresh/incognito dupes | ❌ |

For true tamper-proof: Typeform/Jotform + webhooks (server verifies hidden field), or Firebase/custom API validating vote + signature atomically.

## ❓ FAQ — Pre-emptive Troll Disarmament

**Q: Frontend-only "verification" is theater.**

> A: Yes — labeled *simulated* in UI + README. Real gate needs `VERIFY_ENDPOINT` allowlist + voted-DB. Even then Forms can't validate at submit — we say use webhooks if that matters.

**Q: Why not just share the Google Form link?**

> A: Do, if you don't need a gate. This adds: branded booth, fingerprint prefill, authorized-only reveal — $0.

## 🤝 Contributing

Read [CONTRIBUTING.md](./CONTRIBUTING.md). Backend adapters (`verify-device` examples), anti-dupe notes welcome.

## 📄 License

[MIT](./LICENSE). No affiliation with Google.
