All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m41s
Co-authored-by: Copilot <copilot@github.com>
5.6 KiB
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 frombackend/.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 raisesRuntimeErroron boot if any are missing. - Optional:
DB_ENV/DATA_ENV(prod|test|e2e) — picksdata/vstest_data/directory (seebackend/config/paths.py). - Tests:
pytest tests/—tests/conftest.pyforcesDB_ENV=testand 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 testfromfrontend/. Config atplaywright.config.tsauto-starts bothnpm run devand the Flask backend withDB_ENV=e2e DATA_ENV=e2e, so test data lands inbackend/test_data/and never touches production. TheglobalSetupseeds the DB and logs in; tests receive a pre-authenticated session viastorageState— do not navigate to/auth/login. ImportE2E_EMAIL/E2E_PASSWORDfrome2e/e2e-constants.tsrather than hardcoding. - E2E suite is split into Playwright "projects" in
playwright.config.ts(chromium-routines,chromium-task-assignment, …) — each bucket targets a directory undere2e/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 inbackend/main.py. - The frontend nginx (and Vite dev proxy) strips
/apibefore forwarding. Backend routes must NOT include/api— backend defines@app.route('/user'), frontend calls/api/user. - The
auth_apiblueprint is the only one mounted under a prefix (/auth). - API errors return
{ error, code }; codes live inbackend/api/error_codes.py. Frontend extracts them viaparseErrorResponse(res)infrontend/src/common/api.ts.
Models — keep 1:1 parity
- Python
@dataclasses live inbackend/models/. TypeScript interfaces live infrontend/src/common/models.ts. Any model change requires updating both. - Persistence is TinyDB (JSON files under
data/db/ortest_data/db/). All DB access goes through the thread-safeLockedTablewrapper inbackend/db/db.py. Always operate on model instances usingfrom_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(fromapi/utils.py). Event types live inbackend/events/types/andfrontend/src/common/backendEvents.ts(mirrored). - Frontend state is event-driven: register listeners in
onMounted, clean up inonUnmounted. Seecomponents/BackendEventsListener.vueandsrc/common/backendEvents.ts. - The SSE endpoint is
/events; per-user queues live inbackend/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 leastACCOUNT_DELETION_THRESHOLD_HOURSago (default 720, min 24, max 720). Cleans pending rewards, children, tasks, rewards, images, then the user. Logs tologs/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 bescoped. - Use only
:rootCSS variables fromcolors.cssfor colors/spacing/tokens (e.g.--btn-primary,--list-item-bg-good). No hardcoded hex/px values for themed properties. - Layout shells:
ParentLayoutfor admin/management views,ChildLayoutfor child dashboard/focus views. - Images: models carry
image_id; frontend resolves toimage_urlfor 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 onsys.path(added byconftest.pyfor tests, byflask runcwd in dev). Run pytest frombackend/. - 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.