15 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
Restart After Local Changes
If the app is running manually in a terminal:
- Stop it with
Ctrl+C. - Make changes or pull changes from Git.
- Restart the app.
Local restart command:
.venv/bin/python run.py
If dependencies changed:
.venv/bin/pip install -r requirements.txt
If database tables changed:
.venv/bin/python scripts/init_db.py
Typical local update flow:
git pull
.venv/bin/pip install -r requirements.txt
.venv/bin/python scripts/init_db.py
.venv/bin/python run.py
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.
What To Commit To Git
Safe and expected to commit:
app/
scripts/
tests/
app.py
run.py
requirements.txt
.gitignore
project-context.md
Also commit deletions/moves when files are refactored.
Current old paths that were replaced:
init_db.py
templates/
static/
These old paths should remain deleted once the new app/ package layout is committed.
What Not To Commit
Keep these local only:
.venv/
instance/
instance/questions.db
questions.db
.env
__pycache__/
.vscode/
.idea/
Reasons:
.venv/is machine-specific.- SQLite databases contain local runtime data.
.envmay contain secrets.- cache/editor files are not project source.
Even with a self-hosted private Git server, avoid committing secrets.
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
Local Raspberry Pi testing is currently done manually on the home network.
The future goal is to run the app as a managed service with systemd, then later put it behind Gunicorn/Nginx for production.
Raspberry Pi Local Network Test Setup
Install system dependencies:
sudo apt update
sudo apt install -y git python3 python3-venv
Clone the repo:
git clone <your-self-hosted-git-url> wyr
cd wyr
Create and install into a virtual environment:
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Set local secrets and initialize the database:
export WYR_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')"
export WYR_ADMIN_USERNAME="youradmin"
export WYR_ADMIN_PASSWORD="yourstrongpassword"
.venv/bin/python scripts/init_db.py
Run on the home LAN:
WYR_SECRET_KEY="$WYR_SECRET_KEY" .venv/bin/flask --app run run --host 0.0.0.0 --port 5000
Open from another device on the same network:
http://<raspberry-pi-ip>:5000
Admin:
http://<raspberry-pi-ip>:5000/admin/login
Do not port-forward this app to the public internet yet.
Restart On The Pi During Manual Testing
If running manually in a terminal:
- Press
Ctrl+C. - Pull changes.
- Install any dependency updates.
- Run database setup if needed.
- Start the app again.
Command sequence:
git pull
.venv/bin/pip install -r requirements.txt
.venv/bin/python scripts/init_db.py
WYR_SECRET_KEY="$WYR_SECRET_KEY" .venv/bin/flask --app run run --host 0.0.0.0 --port 5000
If the Pi reboots, manually cd back into the project and run the Flask command again.
This will become easier after adding systemd.
Future Systemd Service
Future goal:
sudo systemctl start wyr
sudo systemctl stop wyr
sudo systemctl restart wyr
sudo systemctl status wyr
Benefits:
- app can start automatically after Pi reboot
- easier restart command
- logs can be viewed with
journalctl - app can run in the background without an open terminal
Example future log command:
journalctl -u wyr -f
This is not implemented yet.
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
.venv/bin/pip install -r requirements.txt
.venv/bin/python scripts/init_db.py
Then manually restart the Flask command.
Later, after the systemd service exists, the Pi restart step will become:
sudo systemctl restart wyr
Immediate Roadmap
Current Status
Local refactor and Admin Dashboard V1 are implemented.
Next Step
Add cooler layout and styling:
- improve the public voting page design
- improve the results page design
- improve admin dashboard styling
- make buttons, forms, and navigation feel more polished
- add better spacing, typography, and responsive layout
After Styling
Polish the admin flow and public behavior:
- improve layout
- add clearer success messages
- add better vote duplicate handling
- improve the empty state when no question is scheduled for today
- add CSRF protection before public internet exposure
After Local Pi Testing
Implement:
systemdservice for easier Pi management- automatic start on reboot
- clearer production environment variables
- basic log inspection workflow with
journalctl
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