This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
MyElectricalData is a secure API gateway that enables French individuals to access their Linky electricity data through professional Enedis APIs. The system acts as an intermediary, handling OAuth2 consent, caching, and rate limiting.
Architecture: Monorepo with FastAPI backend (apps/api/) and React/Vite frontend (apps/web/)
IMPORTANT : Ce projet supporte DEUX modes. Le mode Client est le défaut. Voir .claude/rules/modes.md pour les règles détaillées.
| Mode | Description | Docker Compose | Ports | Défaut |
|---|---|---|---|---|
| Client | Installation locale, mono-user, API MyElectricalData, exports | docker-compose.yml |
8100/8181 | ✅ |
| Serveur | Gateway complet avec admin, multi-users, Enedis direct | docker-compose.server.yml |
8000/8081 |
Les deux modes peuvent tourner en parallèle. Documentation mode client : docs/local-client/
# Development
make dev # Start development with hot-reload watching
make up # Start all services
make down # Stop all services
make restart # Restart all services
# Backend
make backend-logs # Show backend logs
make backend-restart # Restart backend only
make watch # Start backend file watcher
make stop-watch # Stop backend file watcher
# Database
make db-shell # Access PostgreSQL shell
make db-backup # Backup database
make migrate # Apply all pending migrations
make migrate-downgrade # Rollback last migration
make migrate-history # Show migration history
make migrate-current # Show current migration revision
make migrate-revision # Generate a new migration (autogenerate)
make migrate-stamp # Stamp database with current revision
# Maintenance
make logs # Show all logs
make ps # Show running containers
make clean # Clean temporary files
make rebuild # Rebuild all containers
make help # Show all available commandsAccess Points (Client Mode - Default):
- Frontend: http://localhost:8100
- Backend API: http://localhost:8181
- API Docs: http://localhost:8181/docs
- pgAdmin: http://localhost:5051
Access Points (Server Mode):
- Frontend: http://localhost:8000
- Backend API: http://localhost:8081
- API Docs: http://localhost:8081/docs
- pgAdmin: http://localhost:5050
# Start client mode services (default)
docker compose up -d
# View logs
docker compose logs -f backend-client
docker compose logs -f frontend-client
# Stop services
docker compose down
# Start server mode services
docker compose -f docker-compose.server.yml up -dPackage Manager: uv (Astral's fast Python package manager)
Using Makefile (from apps/api/ directory):
make sync # Install/sync dependencies (alias: make install)
make run # Run development server
make test # Run all tests with coverage
make test-unit # Run unit tests only
make test-integration # Run integration tests only
make lint # Run ruff + mypy
make format # Format code with black + ruff --fix
make clean # Clean cache filesManual Commands (without Makefile):
# Install dependencies
uv sync
# Run locally (without Docker)
uv run uvicorn src.main:app --reload --host 0.0.0.0 --port 8000
# Run tests
uv run pytest
uv run pytest tests/test_specific.py # Single file
uv run pytest tests/test_file.py::test_function # Single test
# Linting
uv run ruff check src tests
uv run mypy src
# Formatting
uv run black src tests
uv run ruff check --fix src testsDatabase Migration (Alembic):
# Auto-detect: SQLite (default) or PostgreSQL based on DATABASE_URL
# SQLite: sqlite+aiosqlite:///./data/myelectricaldata.db
# PostgreSQL: postgresql+asyncpg://user:pass@postgres:5432/db
# Apply all pending migrations (client mode - default)
docker compose exec backend-client alembic upgrade head
# Rollback last migration
docker compose exec backend-client alembic downgrade -1
# Show migration history
docker compose exec backend-client alembic history
# Generate a new migration (after modifying models)
docker compose exec backend-client alembic revision --autogenerate -m "Description"
# For existing databases, stamp with current revision
docker compose exec backend-client alembic stamp head
# Server mode migrations
docker compose -f docker-compose.server.yml exec backend alembic upgrade head
# Local development (from apps/api/)
cd apps/api
uv run alembic upgrade head
uv run alembic revision --autogenerate -m "Description"# Install dependencies
npm install
# Development server (standalone, without Docker)
npm run dev # Runs on http://localhost:3000
# Build for production
npm run build
# Type checking
npm run build # Includes tsc check
# Linting
npm run lint
# Tests
npm test # Run all tests
npm run test:ui # Interactive UI
npm run test:coverage # Generate coverage report- User Signup → Creates account with
client_id/client_secret(OAuth2 Client Credentials) - Login → JWT token (30-day expiration) stored in localStorage
- Enedis Consent → User authorizes at account level (not per-PDL)
- PDL Detection → All user's PDLs automatically retrieved from Enedis after consent
- API Access → Use
client_id/client_secretfor API calls
User → Frontend (React) → Backend (FastAPI) → Adapter → Enedis API
↓
Cache (Valkey)
↓
Database (SQLite/PostgreSQL)
adapters/: Enedis API wrapper with rate limiting (5 req/sec)routers/: FastAPI endpoints (accounts, pdl, enedis, admin, energy_offers)models/: SQLAlchemy models (User, PDL, Token, Role, EnergyProvider, EnergyOffer)middleware/: Auth verification, admin checksservices/: Cache (Valkey with Fernet encryption), email, rate limiter, price scrapersschemas/: Pydantic request/response validationconfig/: Settings with auto-detection of database type
pages/: Route components (Dashboard, Consumption, Settings, etc.)components/: Reusable UI components (Layout, PDLCard, etc.)api/: Axios clients for backend endpointsstores/: Zustand state management (auth, theme)hooks/: Custom React hookstypes/: TypeScript interfaces
Granular daily caching: Each day is cached individually, not entire date ranges
- Cache key pattern:
consumption:daily:{pdl}:{date} - Encryption: User's
client_secretas key (GDPR compliance) - TTL: 24 hours
- Rate limiting: 50 req/day uncached, 1000 req/day cached per user
Key relationships:
- User → has many PDLs (cascade delete)
- User → has many Tokens (cascade delete)
- PDL → has
usage_point_id(14-digit Enedis identifier) - Token → stores Enedis OAuth tokens (per PDL or global)
- EnergyProvider → has many EnergyOffers (with
scraper_urlsJSON field) - EnergyOffer → belongs to EnergyProvider (with
is_activeflag)
Automatic price scraping system for energy providers:
- 4 providers supported: EDF, Enercoop, TotalEnergies, Priméo Énergie
- Dynamic URLs: Scraper URLs stored in database (
scraper_urlsJSON field), editable via admin interface - Provider logos: Via Clearbit Logo API (
https://logo.clearbit.com/{domain}) - Fallback mechanism: Manual pricing data if scraping fails
- Preview mode: DRY RUN to compare current vs new offers before applying
- Admin interface:
/admin/offerswith logo display, URL management, preview/refresh actions
Scraper types:
- PDF parsing (EDF, Enercoop, TotalEnergies, Priméo)
- Fallback data for all providers
- ~133 total offers across 4 providers
See docs/server-mode/features/energy-providers-scrapers.md for detailed documentation.
Regles critiques : .claude/rules/design.md (injecte automatiquement pour apps/web/**)
Documentation complete : docs/specs/design/
Pour toute modification UI : Utiliser l'agent frontend-specialist
Verification : /check_design ou docs/specs/design/checklist.md
Project uses specialized Claude Code agents defined in .claude/agents/:
frontend-specialist.md: React/TypeScript, must check@docs/designbefore UI workbackend-specialist.md: Python/FastAPI, must follow API design rulesenedis-specialist.md: Expert API Enedis Data Connect, must check@docs/external-apis/enedis-apibefore any Enedis integrationdevops-specialist.md: Kubernetes/Helm for deployment
When agents generate code:
- Frontend: Must pass
npm run lint(ESLint + TypeScript) - Backend: Must follow PEP 8, include type hints
Coverage Targets (from docs/features-spec/rules/testing.md):
- Backend business logic: ≥80%
- API endpoints: ≥75%
- Frontend components: ≥65%
- E2E critical flows: Mandatory (signup → consent → API keys)
Backend Tests:
- Mock Enedis API calls except for contract tests
- Validate request/response schemas match
docs/features-spec/rules/api-design.json - Test cache hit/miss, encryption, quota enforcement
- Test cascade delete (account → PDLs, tokens, cache)
Frontend Tests:
- User interactions (forms, consent flow, CRUD PDL)
- Loading/error states on all views
- Dark mode persistence and contrast
- Responsive snapshots at key breakpoints
Backend (.env.api):
DATABASE_URL=sqlite+aiosqlite:///./data/myelectricaldata.db # or postgresql+asyncpg://...
REDIS_URL=redis://redis:6379/0
ENEDIS_CLIENT_ID=your-client-id
ENEDIS_CLIENT_SECRET=your-secret
ENEDIS_ENVIRONMENT=sandbox # or production
SECRET_KEY=your-jwt-secret
ADMIN_EMAILS=admin@example.com # Comma-separatedFrontend (.env):
VITE_API_BASE_URL=/api # In Docker, or http://localhost:8081 for local- Define Pydantic schemas in
apps/api/src/schemas/ - Create/extend router in
apps/api/src/routers/ - Add business logic in services if needed
- Update OpenAPI schema reference if applicable
- Write integration tests
- Update frontend TypeScript types in
apps/web/src/types/api.ts - Create API client method in
apps/web/src/api/
- Create component in
apps/web/src/pages/ - Follow design checklist:
docs/specs/design/checklist.md - Add route in
apps/web/src/App.tsx - Add navigation link in
apps/web/src/components/Layout.tsxif needed - Ensure
pt-6on root container and H1 icon pattern - Implement dark mode variants
# Server mode only (demo accounts are for the gateway)
docker compose -f docker-compose.server.yml exec backend python scripts/create_demo_account.py
# Creates: demo@myelectricaldata.fr / DemoPassword123!
# With 2 PDLs and 365 days of mock consumption/production dataSee docs/server-mode/demo/ for detailed implementation guide.
- Uses Caddy reverse proxy (automatic HTTPS)
- Frontend served as static files from Nginx
- Backend runs with Uvicorn
- PostgreSQL recommended over SQLite
- Valkey required for caching
Deployment docs:
- Server mode:
docs/server-mode/installation/docker.md - Client mode:
docs/local-client/installation/docker.md
All docs now in docs/:
docs/local-client/: Client mode documentation (installation, integrations, exports)docs/server-mode/: Server mode documentation (installation, administration, architecture, features)docs/specs/pages/: Page-specific guides for Claude (UI implementation guidelines)docs/features-spec/: Common features specifications (cache, database)docs/specs/design/: UI design system with component guidelinesdocs/server-mode/demo/: Demo account implementationdocs/external-apis/: External APIs documentation (Enedis, RTE)
- User data isolation: Every endpoint verifies PDL ownership
- Cache encryption: Fernet with user's
client_secret - OAuth tokens: Automatic refresh before expiration
- Cascade delete: Account deletion purges all user data
- Rate limiting: Adapter-level (5 req/s) + user quotas
See apps/api/SECURITY.md for detailed security model.
docs/features-spec/rules/api-design.json: API response format standarddocs/features-spec/rules/testing.md: Testing requirementsdocs/specs/design/checklist.md: UI compliance checklist.claude/agents/*.md: Agent-specific instructions.claude/rules/modes.md: Règles pour les modes serveur/clientdocs/local-client/: Documentation complète du mode client