5.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
F1tness Parser is a FastAPI-based web application that parses fitness training data from two note formats:
- Obsidian Notes: Markdown tables with
# DD.MM.YYYY (trainer-session)headers - Apple Notes: Bold markdown tables with
**DD.MM.YYYY (trainer-session)**headers
The project is split into two applications in one repository:
backend/- FastAPI JSON API (parsers, models, services, PostgreSQL)frontend/- static site on plain HTML + CSS + JS (ES modules, no build step), served by nginx, which also proxies/api/to the backend
Development Commands
The project is developed and run only in Docker: there is no local Python setup. Everything below runs inside the fastapi-app container (backend code lives in backend/, inside the container it is /app) (.env must have POSTGRES_DATABASE_HOST=postgres, see .env.example).
Docker Development
# Start backend (:8000) + frontend (:8080) + PostgreSQL (applies migrations on start, hot reload for backend/app/)
# Open http://localhost:8080
docker compose up --build
# Apply migrations manually (Alembic; the app itself does NOT migrate on startup)
docker compose exec fastapi-app alembic upgrade head
# Create a migration after changing tables in app/core/database/tables.py
# (-u keeps the generated file owned by you instead of root)
docker compose exec -u "$(id -u):$(id -g)" fastapi-app alembic revision --autogenerate -m "describe change"
# Import all Obsidian + Apple notes into the database
docker compose exec fastapi-app python -m app.cli import [--replace]
# Stop (keeps the data) / stop and drop the database volume
docker compose down
docker compose down -v
Rebuild (--build) is needed only after changing requirements*.txt, Dockerfile or pyproject.toml.
Testing
Tests that need a database use a separate <POSTGRES_DATABASE_DB>_test database (TEST_DATABASE_URL, created automatically). Without it they are skipped.
# Run all tests
docker compose exec fastapi-app pytest
# Run specific test file
docker compose exec fastapi-app pytest tests/test_core/test_obsidian_parser.py
# Without a running stack (starts postgres, runs once, removes the container)
docker compose run --rm fastapi-app pytest
Type Checking
docker compose exec fastapi-app mypy app/
Architecture
Core Components
Parser Architecture: The system uses a base parser class (backend/app/core/parsers/base.py) with format-specific implementations:
ObsidianNotesParser- handles Obsidian markdown formatAppleNotesParser- handles Apple notes format- Each parser includes exercise name mapping for normalization
Data Models: Located in backend/app/core/dto/training.py:
Training- represents a workout sessionExercise- individual exercise with multiple approachesApproach- single set with weight and reps
API Structure (backend, JSON only):
/api/v1/trainings/(GET list, GET/PUT/DELETE{id}/; PUT replaces the whole training),/api/v1/exercises/,/api/v1/exercises/progress/?name=,/api/v1/users/(POST, GET list with?role=, GET/PATCH/DELETE{id}/; role istrainerortrainee, passwords are hashed with scrypt, no login yet),/api/v1/parser/parse/,/api/v1/health/
Frontend (frontend/):
index.html,exercises.html,parse.html,users.html- pages;js/common.js(API + DOM helpers),js/table.js(DataTables 3 wrapper), one module per page,js/modal.js(Bootstrap modal shell),js/edit-dialog.js+js/edit-form.js(training edit modal),js/user-dialog.js(user create/edit modal)vendor/- Bootstrap (CSS + JS bundle), Chart.js and DataTables 3 (jQuery-free): the only third-party codenginx.conf- serves static files and proxies/api/tofastapi-app:8000(same origin, no CORS)
Database
Trainings belong to a trainee (trainings.trainee_id, required) and optionally have a trainer (trainings.trainer_id, NULL = solo); both are users (role trainee / trainer). A user with trainings can't be deleted. python -m app.cli import takes the trainer from the note header and matches it with a trainer user by "First Last".
The backend uses PostgreSQL through async SQLAlchemy (asyncpg). tables are described with SQLAlchemy Core (no ORM) in backend/app/core/database/tables.py, TrainingRepository (backend/app/core/database/repository.py) is the data access layer, and a session is injected into endpoints with Depends(get_session). Schema migrations are handled by Alembic (alembic.ini, migrations/); the URL is taken from app/config.py.
Configuration is managed through backend/app/config.py using Pydantic settings with .env file support.
Key Files
backend/app/main.py- FastAPI application setup with lifespan managementbackend/app/config.py- Application configuration and database settingsbackend/run.py- Standalone uvicorn runner (unused: Docker starts uvicorn fromcompose.yaml)backend/migrations/- Alembic environment and versionscompose.yaml- Docker Compose setup: backend, frontend, PostgreSQL
Environment Setup
Copy .env.example to .env (repo root) and configure:
- PostgreSQL connection settings
- Debug mode
- PYTHONPATH (for Docker)
The application will run database migrations automatically on startup through the FastAPI lifespan event.