Harden JSON storage (atomic writes + crash-safe loads) + suggestions lightbulb

- storage.py: atomic save_json (temp+fsync+os.replace) and load_json that
  survives missing/corrupt files (moves corrupt aside). Closes #11/#12.
- route all data modules + app.py helpers through storage (closes #31 core);
  fixes mutable DEFAULT_FUNDS/DEFAULT_CARS return (#23).
- gunicorn --workers 1 --threads 4 to remove the write race (#13); strip
  Dockerfile template scaffolding (#40).
- base.html: 💡 suggestions link in the shared nav (shows on every page).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 16:34:06 -05:00
parent 494f5e3b5b
commit be74ca1eb7
10 changed files with 95 additions and 86 deletions

View File

@@ -24,16 +24,6 @@ RUN chmod +x /entrypoint.sh
EXPOSE 8000
ENTRYPOINT ["/entrypoint.sh"]
# ---- ADJUST THIS LINE to the app's real entry point ----
# Flask (app object named `app` in app.py):
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "app:app"]
#
# FastAPI (app object named `app` in main.py) — swap the CMD for:
# RUN pip install "uvicorn[standard]"
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
#
# Django (project package `mysite`):
# CMD ["gunicorn", "--bind", "0.0.0.0:8000", "mysite.wsgi:application"]
#
# Streamlit:
# CMD ["streamlit", "run", "app.py", "--server.port=8000", "--server.address=0.0.0.0"]
# Single worker + threads: the app stores state in JSON/SQLite files on the
# volume, so multiple processes would race. Threads handle light concurrency.
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "1", "--threads", "4", "app:app"]