From 8206e975d08a09e80f97bc1ee6a394148db10499 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Thu, 24 Sep 2026 00:11:47 +1000 Subject: [PATCH] docs: add session log for Flask multi-user rewrite --- .../2025-12-10-flask-multiuser-rewrite.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .claude-context/sessions/2025-12-10-flask-multiuser-rewrite.md diff --git a/.claude-context/sessions/2025-12-10-flask-multiuser-rewrite.md b/.claude-context/sessions/2025-12-10-flask-multiuser-rewrite.md new file mode 100644 index 0000000..2c44d38 --- /dev/null +++ b/.claude-context/sessions/2025-12-10-flask-multiuser-rewrite.md @@ -0,0 +1,44 @@ +# Flask Multi-User Rewrite of Raccoon Timekeeper + +**Date:** 2025-12-10 +**Project:** Raccoon-TimeKeeper +**Status:** resolved +**Tags:** flask, sqlalchemy, flask-login, auth, docker, gunicorn, timezone, migration + +## Context +Raccoon Timekeeper started life as a Google Apps Script / Google Sheets time tracker. Jess wanted it self-hosted as a Python app with proper security: an admin created on first run (resettable from the CLI), admins able to add users, and strict per-user isolation so each person only sees their own timesheets. After the rewrite, testing surfaced two bugs: data not persisting across container restarts, and entries landing in the wrong week of the weekly summary. + +## Key Decisions +- **Flask + SQLAlchemy + Flask-Login** rather than staying on Apps Script — self-hosting, real user accounts and role-based access weren't practical on Sheets. +- **First-run setup page** that redirects to admin creation when no admin exists — avoids shipping default credentials. +- **CLI recovery (`flask reset-admin`)** instead of a web "forgot password" flow — no mail server dependency, and recovery requires shell access, which is the right trust boundary. +- **User isolation enforced server-side** — every API query filters on `current_user.id`; UI hiding alone was rejected as insufficient. +- **Admin self-protection** — admins cannot deactivate, demote or delete their own account, preventing a lockout with zero admins. +- **Kept the original grayscale raccoon theme** — functional rewrite only, not a redesign. +- **Local-date handling in JS** instead of `toISOString()` — the UTC conversion shifted dates across the day boundary (AU timezone) and pushed entries into the neighbouring week. + +## Technical Details +- Stack: Flask, Flask-SQLAlchemy, Flask-Login, Werkzeug password hashing; SQLite by default via `DATABASE_URL` (default `sqlite:///timekeeper.db`); `SECRET_KEY` from env. +- Deployed with Docker (`Dockerfile`, `docker-compose.yml`) running under gunicorn. +- CLI commands: `flask init-db`, `flask reset-admin`, `flask create-user [--admin]`, `flask list-users`. +- Flexible time input accepted: `1:30`, `1.5`, `90m`, `1h 30m`. +- **Persistence bug root cause:** `init_db()` only ran inside `if __name__ == '__main__':`, which gunicorn never executes. Fix: run DB initialisation at app import time regardless of how the app is launched. +- **Week-shift bug root cause:** `Date.prototype.toISOString()` returns UTC. Fix: format dates from local `getFullYear()/getMonth()/getDate()` throughout the front-end JS. + +## Code Changes +- `app.py` — full rewrite: models, auth, admin routes, user-scoped API, CLI commands, import-time DB init. +- `requirements.txt` — added Flask-Login / SQLAlchemy dependencies. +- `templates/` — added `setup`, `login`, admin user management, task/settings management and change-password templates; `index.html` date handling fixed. +- `static/` — CSS and JavaScript utilities. +- `README.md` — security model, install and CLI documentation. +- `.env.example`, `Dockerfile`, `docker-compose.yml` — container deployment. + +## Open Questions / Next Steps +- Confirm the Docker volume mapping keeps the SQLite file outside the container layer (the import-time init fixed table creation, but data persistence also depends on the volume). +- No password-reset path for regular users other than an admin resetting it — acceptable for now. +- Repo has been idle since Dec 2025; confirm whether it's still in use before investing further. + +## Artifacts +- Final fix commit: `e50d48e` — Fix timezone issue in date handling - use local dates instead of UTC +- README security docs: `3a3e8e4` +- Repo: https://gitea.hideawaygaming.com.au/jessikitty/Raccoon-TimeKeeper