11 KiB
Would You Rather Website - Project Context
Project Goal
Build a lightweight "Would You Rather" website hosted on a Raspberry Pi 5.
Users visit the website, answer a daily question, and immediately see aggregated results after voting.
Example:
Would you rather be blind or deaf?
- Blind
- Deaf
After voting:
- Blind: 62%
- Deaf: 38%
Total votes: 523
Current Development Strategy
Development is being done on a laptop first.
Reasons:
- Easier coding workflow
- Faster testing
- Git integration from day one
- Easier version control
- Safer than developing directly on the Raspberry Pi
Deployment strategy:
Laptop
↓
Git
↓
GitHub
↓
Raspberry Pi
↓
git pull
↓
Production
Technology Stack
Backend
- Python
- Flask
- Flask application factory pattern
- Flask blueprints for public and admin routes
Database
- SQLite
- Local development database path:
instance/questions.db
Frontend
- HTML
- CSS
- Jinja2 templates
Authentication
- Flask sessions
- Werkzeug password hashing for admin passwords
Version Control
- Git
- GitHub
Future Production
- Gunicorn
- Systemd
- Nginx
- HTTPS with Let's Encrypt
Current Local Project Structure
The project has been refactored out of a single-file Flask app.
Current structure:
would-you-rather/
│
├── .venv/
├── .gitignore
├── app.py
├── run.py
├── requirements.txt
├── project-context.md
│
├── app/
│ ├── __init__.py
│ ├── admin.py
│ ├── database.py
│ ├── routes.py
│ │
│ ├── templates/
│ │ ├── public/
│ │ │ ├── index.html
│ │ │ └── results.html
│ │ │
│ │ └── admin/
│ │ ├── dashboard.html
│ │ ├── delete_confirm.html
│ │ ├── login.html
│ │ └── question_form.html
│ │
│ └── static/
│ └── style.css
│
├── scripts/
│ └── init_db.py
│
├── tests/
│ └── test_app.py
│
└── instance/
└── questions.db
Notes:
app.pyremains as a compatibility entrypoint.run.pyis the preferred local development entrypoint.instance/is ignored by Git.- Root-level
questions.dbis ignored and is no longer the active app database.
Current Application Architecture
App Factory
File:
app/__init__.py
Purpose:
- Creates the Flask app with
create_app(). - Configures
SECRET_KEY. - Configures SQLite database path.
- Ensures the
instance/directory exists. - Registers public and admin blueprints.
- Registers database teardown behavior.
Important config:
SECRET_KEY = os.environ.get("WYR_SECRET_KEY", "dev-only-change-me")
DATABASE = instance/questions.db
Production must set a real WYR_SECRET_KEY.
Database Helpers
File:
app/database.py
Purpose:
- Opens SQLite connections with
get_db(). - Uses
sqlite3.Rowso routes/templates can access fields by name. - Closes request-scoped connections with
close_db(). - Creates all tables with
init_db().
Public Routes
File:
app/routes.py
Routes:
/
/vote
/results
Behavior:
/displays the question scheduled for today's date./voteaccepts POSTedqidandvote./voteonly accepts votes for today's scheduled question./resultsdisplays today's vote counts, percentages, and total votes.- Empty states are shown if no question exists for today.
- Duplicate voting is still blocked by hashing the request IP address.
Current duplicate prevention is temporary.
Future plan:
- Use cookies or session identifiers instead of IP hashing.
Current Database Design
Questions Table
CREATE TABLE questions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL,
option_a TEXT NOT NULL,
option_b TEXT NOT NULL,
date TEXT NOT NULL UNIQUE
);
Purpose:
Stores scheduled daily questions.
Votes Table
CREATE TABLE votes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question_id INTEGER,
vote TEXT NOT NULL,
voter_hash TEXT NOT NULL
);
Purpose:
Stores user votes.
Stored values:
question_id- selected vote, currently
AorB voter_hash
Admins Table
CREATE TABLE admins (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL
);
Purpose:
Stores admin login accounts.
Passwords must never be stored in plain text.
Current implementation uses:
from werkzeug.security import generate_password_hash, check_password_hash
Admin Dashboard V1
Admin functionality has been implemented.
File:
app/admin.py
Routes:
/admin/login
/admin/logout
/admin/account
/admin/dashboard
/admin/question/new
/admin/question/edit/<id>
/admin/question/delete/<id>
Implemented behavior:
- Admin login with username/password.
- Password verification with Werkzeug password hashing.
- Successful login stores
session["admin"] = True. - Protected admin pages use
@admin_required. - Unauthenticated users are redirected to
/admin/login. - Admins can change their username and password from
/admin/account. - Changing credentials requires the current password.
- Dashboard lists all questions ordered by date descending.
- Admins can create questions.
- Admins can edit questions.
- Admins can delete questions.
- Delete also removes votes for that question.
- Duplicate question dates are blocked.
- Required fields are validated.
Dashboard V1 is intentionally simple.
No JavaScript calendar is implemented yet.
Local Development Setup
Install Dependencies
Use the virtual environment:
source .venv/bin/activate
pip install -r requirements.txt
Or run commands directly through .venv/bin/python.
Initialize the Database
Run:
.venv/bin/python scripts/init_db.py
This creates:
instance/questions.db
It also seeds:
- one sample question
- one local admin account
Default local admin login:
username: admin
password: admin
To override the seeded admin account:
WYR_ADMIN_USERNAME=myname WYR_ADMIN_PASSWORD=mypassword .venv/bin/python scripts/init_db.py
If the admin user already exists, the script will not overwrite that password.
Run the Site Locally
Preferred command:
.venv/bin/python run.py
Then open:
http://127.0.0.1:5000
Admin login:
http://127.0.0.1:5000/admin/login
Default local login:
admin / admin
Run Tests
Run:
.venv/bin/python -m unittest discover -s tests
Current automated tests cover:
- public empty state
- voting flow
- duplicate vote prevention
- admin login success
- admin login failure
- admin credential changes
- protected dashboard redirect
- duplicate date validation when creating questions
Manual Testing Checklist
Public Site
- Start the app:
.venv/bin/python run.py
- Open:
http://127.0.0.1:5000
-
Confirm the sample question appears if it is scheduled for today's date.
-
Click one answer.
-
Confirm the site redirects to
/results. -
Confirm results show percentages and total votes.
-
Vote again from the same browser/IP.
-
Confirm the duplicate vote does not increase the vote count.
Admin Site
- Open:
http://127.0.0.1:5000/admin/login
- Log in with:
admin / admin
-
Confirm the dashboard appears.
-
Click
Change Credentials. -
Confirm changing credentials requires the current password.
-
Save new credentials, log out, and confirm the new login works.
-
Click
Create Question. -
Add today's date or a future date, question, option A, and option B.
-
Save and confirm the new question appears in the dashboard.
-
Edit the question and confirm changes persist.
-
Try creating another question with the same date.
-
Confirm this error appears:
Date already has a question.
-
Delete a question and confirm it disappears from the dashboard.
-
Log out.
-
Visit
/admin/dashboardwhile logged out and confirm it redirects to/admin/login.
Development Notes
Current Compatibility Entrypoints
Preferred local command:
.venv/bin/python run.py
Compatibility command:
.venv/bin/python app.py
Both create the app through:
from app import create_app
Git Ignore Rules
The following local-only files/directories are ignored:
.venv/
__pycache__/
*.pyc
questions.db
instance/
.env
.vscode/
.idea/
The active SQLite database is intentionally not committed.
Future Admin Features
Dashboard Version 2
Use a proper calendar interface.
Possible library:
- FullCalendar
Desired behavior:
June 2026
13 Question
14 Question
15 Empty
16 Question
Clicking a date:
- opens edit view if the date has a question
- opens create view if the date is empty
Search
Search questions by:
- date
- question text
Statistics View
Admin dashboard should eventually show:
Question
Blind: 142
Deaf: 98
Total: 240
Useful for engagement analytics.
Future Public Features
Better Duplicate Vote Prevention
Replace IP hashing with:
- cookies
- sessions
- or lightweight anonymous visitor IDs
Archive
Browse historical questions.
Comments
Discussion under questions.
Country Statistics
Example:
Denmark
Blind: 65%
Deaf: 35%
United States
Blind: 52%
Deaf: 48%
AI Generated Images
One image per question.
Example:
Would you rather live underwater or in space?
with generated artwork.
User Accounts
Optional.
Users can:
- save history
- track participation
Future AI Features
Not a priority yet.
Planned later.
Possible route:
Generate next 30 questions
Workflow:
- AI generates questions.
- Questions fill empty dates.
- Admin reviews.
- Admin approves.
Potential providers:
- OpenAI
- OpenRouter
- Mistral
Future Raspberry Pi Deployment
Not currently being worked on.
Planned deployment stack:
Internet
↓
Cloudflare
↓
Nginx
↓
Gunicorn
↓
Flask
↓
SQLite
Deployment Workflow
On laptop:
git add .
git commit -m "feature"
git push
On Pi:
git pull
sudo systemctl restart wyr
Immediate Roadmap
Current Status
Local refactor and Admin Dashboard V1 are implemented.
Next Step
Polish the admin flow and public UI:
- improve layout
- add clearer success messages
- add better vote duplicate handling
- improve the empty state when no question is scheduled for today
After Admin Polish
Implement:
- calendar view
- question scheduling by date
- admin statistics
After Calendar
Implement:
- AI-assisted question generation
Long-Term Goal
A polished daily "Would You Rather" website that:
- runs on a Raspberry Pi 5
- uses a custom domain
- supports HTTPS
- allows browser-based question management
- supports AI-assisted content generation
- scales beyond the initial MVP