Imported from ajpeders/gym-app (
AGENTS.md). Install upstream withnpx skills add ajpeders/gym-app. Copyright stays with the author.
Repository Guide
Boundaries
- This is two independent projects with no root task runner:
api/is Python 3.13/FastAPI;frontend/is Expo SDK 54/React Native/TypeScript. Run commands from the relevant directory. - Use the settled domain names: a
Splitis a weekly plan, aWorkoutis a plan-day template, and aSessionis a logged bout. Scheduling (weekdays, where 0=Sun, plusfloating) belongs toWorkout. - Backend entrypoint is
api/app/main.py; every REST router is mounted under/api, then the companion coach is mounted at/api/companion. - Frontend routes live in
frontend/src/app; API calls and manually mirrored contract types live infrontend/src/api/client.tsandfrontend/src/api/types.ts. Keep those types/calls aligned with backend schemas and routes when changing the API.
Verification
- API setup:
uv venv .venv && uv pip install -r requirements.txt. Plainpipmay fail buildingpydantic-corewithout a toolchain. - API focused test:
.venv/bin/python -m pytest tests/test_sessions.py -q(replace the file or append::test_name). Full check:python3 -m compileall -q app && .venv/bin/python -m pytest -q. - Frontend install:
npm ci. CI check:npm run typecheck; runnpm run export:webwhen changing web/build behavior. There is no frontend test suite, and thelintscript has no ESLint packages/config installed. - CI is
.forgejo/workflows/ci.yml, not GitHub Actions configuration. It runs API compile then pytest, and frontendnpm cithen TypeScript.
Backend Traps
- Settings and the SQLAlchemy engine are created at import time, and
get_settings()is cached. Tests must setGYM_DATA_DIR,GYM_SEED_ON_START=false, and related environment variables before importingapp;tests/conftest.pyalready does this and uses an isolated SQLite file without network seeding. - There is no Alembic.
create_all()handles new tables only; for a new column, updatemodels.pyand add its(table, column, SQL type)tuple to_ADDED_COLUMNSinapi/app/db.py. - Preserve owner-scoped queries on authenticated resources. Missing and foreign-owned records intentionally both return 404.
companionis pinned from Forgejo inapi/requirements.txt. CI rewrites that public HTTPS URL to the runner's internal Forgejo address; do not replace it with a PyPI dependency.
Frontend And Deploy Traps
- Use the SDK 54 versioned Expo docs (
https://docs.expo.dev/versions/v54.0.0/), matchingpackage.jsonand the lockfile. React Compiler is enabled inapp.json. EXPO_PUBLIC_API_URLmust be a bare origin such ashttp://localhost:8000;client.tsappends/api. The static web build bakes this value in at image build time.- Only set logging is offline-first.
frontend/src/lib/offline.tspersists queued sets before network writes; starting/finishing sessions and other mutations still require the API. - Production publishes no API host port. Traefik sends
/apitogym-apiat higher priority and/to the staticgym-web; both are behindlocal-only@file.