Summary
src/seed_db.py starts by running db.drop_all(), which wipes every table — including all registered users, their saved progress, game progress, and admin flags — every time it is executed. Running the documented seeding script on an existing database destroys all user data. The seeding logic is also duplicated a third time in src/app.py:42-72 (auto-seed on startup), and seed_db.py inserts without calling the project validation that the data loader depends on.
Evidence
src/seed_db.py:6-11:
def seed_database():
with app.app_context():
# Create all tables
db.drop_all()
db.create_all()
db.drop_all() is unconditional. The README/CONTRIBUTING flow points developers to run this seed script; on any database that has accumulated users/progress, that command silently destroys it.
- The same insert loop exists in
src/app.py:42-72 (auto-seed when Project.query.count() == 0), so the logic is triplicated and can drift.
- Unlike the
app.py path, seed_db.py performs no validation of projects.json (validate_projects in utils/data_loader.py is used by the tests but not here); malformed entries are inserted as-is and a failure mid-loop leaves a partially committed database (no transaction rollback).
Impact
- Accidental data loss: anyone following the documented seed workflow loses all user data.
- Code drift between the three seeding implementations (
seed_db.py, app.py startup, tests).
Suggested Fix
- Replace
db.drop_all() with an idempotent upsert: db.create_all() only, then update-or-insert each project by id (matching the app.py auto-seed behavior).
- Guard the destructive path behind an explicit opt-in flag (e.g.,
--reset) with a confirmation prompt.
- Reuse a single shared seeding helper instead of three copies.
Summary
src/seed_db.pystarts by runningdb.drop_all(), which wipes every table — including all registered users, their saved progress, game progress, and admin flags — every time it is executed. Running the documented seeding script on an existing database destroys all user data. The seeding logic is also duplicated a third time insrc/app.py:42-72(auto-seed on startup), andseed_db.pyinserts without calling the project validation that the data loader depends on.Evidence
src/seed_db.py:6-11:db.drop_all()is unconditional. The README/CONTRIBUTING flow points developers to run this seed script; on any database that has accumulated users/progress, that command silently destroys it.src/app.py:42-72(auto-seed whenProject.query.count() == 0), so the logic is triplicated and can drift.app.pypath,seed_db.pyperforms no validation ofprojects.json(validate_projectsinutils/data_loader.pyis used by the tests but not here); malformed entries are inserted as-is and a failure mid-loop leaves a partially committed database (no transaction rollback).Impact
seed_db.py,app.pystartup, tests).Suggested Fix
db.drop_all()with an idempotent upsert:db.create_all()only, then update-or-insert each project by id (matching the app.py auto-seed behavior).--reset) with a confirmation prompt.