Files
chore/CLAUDE.md
Ryan Kegel a6944ad59c
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m41s
feat: Implement drag-and-drop reordering for routine items and add corresponding E2E tests
Co-authored-by: Copilot <copilot@github.com>
2026-05-19 19:30:44 -04:00

5.6 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

Family chore/reward manager. Flask + TinyDB backend (backend/), Vue 3 + TypeScript frontend (frontend/). Real-time updates flow over Server-Sent Events.

Commands

Backend (run from backend/)

  • Activate venv first: source .venv/bin/activate (mac/linux) — Python runs from backend/.venv/.
  • Dev server: python -m flask run --host=0.0.0.0 --port=5000 (entry: backend/main.py).
  • Required env vars at startup: SECRET_KEY, REFRESH_TOKEN_EXPIRY_DAYS, DIGEST_TOKEN_SECRET, VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY — Flask raises RuntimeError on boot if any are missing.
  • Optional: DB_ENV / DATA_ENV (prod | test | e2e) — picks data/ vs test_data/ directory (see backend/config/paths.py).
  • Tests: pytest tests/tests/conftest.py forces DB_ENV=test and sets dummy secrets. Single test: pytest tests/test_routine_api.py::test_name.
  • Create an admin user (cannot be done via signup): python scripts/create_admin.py.

Frontend (run from frontend/)

  • Dev: npm run dev (Vite, https://localhost:5173).
  • Build: npm run build. Type-check: npm run type-check. Lint: npm run lint.
  • Unit/component tests: npm run test:unit (Vitest). Single test: npx vitest run path/to/file.spec.ts.
  • E2E: npx playwright test from frontend/. Config at playwright.config.ts auto-starts both npm run dev and the Flask backend with DB_ENV=e2e DATA_ENV=e2e, so test data lands in backend/test_data/ and never touches production. The globalSetup seeds the DB and logs in; tests receive a pre-authenticated session via storageState — do not navigate to /auth/login. Import E2E_EMAIL / E2E_PASSWORD from e2e/e2e-constants.ts rather than hardcoding.
  • E2E suite is split into Playwright "projects" in playwright.config.ts (chromium-routines, chromium-task-assignment, …) — each bucket targets a directory under e2e/mode_parent/ and some use isolated users to avoid cross-bucket interference. Run a single bucket: npx playwright test --project=chromium-routines.

Architecture

API surface and nginx proxy

  • Each entity has its own Flask blueprint in backend/api/ (child_api.py, chore_api.py, routine_api.py, …). Registered in backend/main.py.
  • The frontend nginx (and Vite dev proxy) strips /api before forwarding. Backend routes must NOT include /api — backend defines @app.route('/user'), frontend calls /api/user.
  • The auth_api blueprint is the only one mounted under a prefix (/auth).
  • API errors return { error, code }; codes live in backend/api/error_codes.py. Frontend extracts them via parseErrorResponse(res) in frontend/src/common/api.ts.

Models — keep 1:1 parity

  • Python @dataclasses live in backend/models/. TypeScript interfaces live in frontend/src/common/models.ts. Any model change requires updating both.
  • Persistence is TinyDB (JSON files under data/db/ or test_data/db/). All DB access goes through the thread-safe LockedTable wrapper in backend/db/db.py. Always operate on model instances using from_dict() / to_dict() — never raw dicts.

SSE event bus (mandatory for every mutation)

  • Every backend mutation (add/edit/delete/trigger) must call send_event_for_current_user (from api/utils.py). Event types live in backend/events/types/ and frontend/src/common/backendEvents.ts (mirrored).
  • Frontend state is event-driven: register listeners in onMounted, clean up in onUnmounted. See components/BackendEventsListener.vue and src/common/backendEvents.ts.
  • The SSE endpoint is /events; per-user queues live in backend/events/sse.py.

Background schedulers

Started in backend/main.py at boot:

  • start_deletion_scheduler — runs hourly, deletes accounts that were marked-for-deletion at least ACCOUNT_DELETION_THRESHOLD_HOURS ago (default 720, min 24, max 720). Cleans pending rewards, children, tasks, rewards, images, then the user. Logs to logs/account_deletion.log.
  • start_digest_scheduler — email digests.
  • start_state_expiry_scheduler — expires stale state.
  • start_chore_expiry_notification_scheduler — chore expiry notifications.

Auth & security

  • JWT in HttpOnly + Secure + SameSite=Strict cookies. Verification tokens expire in 4 hours; password-reset tokens in 10 minutes.
  • Admin role is never assignable via signup — use backend/scripts/create_admin.py. Admin endpoints under /admin/* enforce role check.

Frontend conventions

  • Vue SFC file order: <template><script><style scoped>. TypeScript only inside <script>. All styles must be scoped.
  • Use only :root CSS variables from colors.css for colors/spacing/tokens (e.g. --btn-primary, --list-item-bg-good). No hardcoded hex/px values for themed properties.
  • Layout shells: ParentLayout for admin/management views, ChildLayout for child dashboard/focus views.
  • Images: models carry image_id; frontend resolves to image_url for rendering.

Specs

Feature specs live in .github/specs/. If a spec has a checklist, all items must be marked done before the feature is considered complete.

Gotchas

  • Backend Python imports assume backend/ is on sys.path (added by conftest.py for tests, by flask run cwd in dev). Run pytest from backend/.
  • Don't replace code with comments; mirror changes across backend + frontend so model/event parity holds.
  • E2E tests share a single seeded user by default — buckets that mutate shared state (default tasks, delete-account, create-child) deliberately use isolated users; preserve that pattern when adding new buckets.