# Contributing to openGym Thanks for taking a look. openGym is deliberately small and light on dependencies, and the aim is to keep it that way: easy to read, easy to self-host. ## Project layout ``` frontend/ React + Vite app (src/views, src/components, src/store, src/lib). Builds to static files. android/ and ios/ are the Capacitor shells for the standalone app (docs/MOBILE.md). api/ Backend: server.js on plain node:http, two dependencies (@simplewebauthn/server, web-push). coach/ is the optional AI coach; openapi.yaml documents every route. web/ Multi-stage Dockerfile (builds the frontend, serves it with nginx) and the nginx template. mcp/ Optional read-only MCP server for LLM clients (Claude Desktop, Cursor, ...). Not in the Docker build; it only runs when a client spawns it. See mcp/README.md. website/ The static project site at opengym.duarte-santos.ch. kubernetes/ Example manifests (docs/SELF_HOSTING_KUBERNETES.md). docs/ User and operator guides (index: docs/README.md); docs/dev/ has feature design notes. media/ Exercise images and GIFs, gitignored and fetched at runtime. ``` ## Running for development ```bash cp .env.example .env docker compose up -d --build # api + web + media on :8080 cd frontend && npm install && npm run dev # hot reload, proxies /api to :3000 cd frontend && npm test # training logic, locales, components cd api && npm test cd mcp && npm test ``` ## Guidelines - **Keep it dependency-light.** The frontend uses React, React Router and Zustand; `api/` has two dependencies. A new dependency on either side is a hard sell. - **Match the style.** Small components, clear names, comments only where the *why* isn't obvious. State lives in the Zustand store (`src/store`), pure helpers in `src/lib`. There is no linter or formatter config, so follow the surrounding code. - **Don't commit** `media/` or `data/`; both are gitignored. - **Click through what you touched**, including the workout flow, in a browser before opening a pull request. - **Training logic gets a unit test.** Anything that decides what you lift next, or reads a logged session back, belongs in a pure helper in `src/lib` with a test beside it. These rules are easy to get subtly wrong and nearly impossible to check by clicking; the progression engine has had real bugs that only a test caught. - **New UI strings go into every locale** in `frontend/src/locales/`. English is the source language and has no file. `node scripts/check-locales.mjs` (run in CI) flags a key that is missing, blank or has lost a `{n}` placeholder. Portuguese (Brazil) inherits from Portuguese (Portugal) and has its own guard test. ## Using AI tools openGym itself is developed with Claude Code (see [How openGym is built](README.md#how-opengym-is-built)), and [`CLAUDE.md`](CLAUDE.md) holds the project context for it. You're welcome to use whatever tools you like for a pull request. The bar is the same either way: you understand the change, it's tested, and you can answer questions about it in review. ## What CI does with your pull request