Files
git-contribution-graph/CLAUDE.md
T

74 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development
```bash
# Install dependencies (generates composer.lock if missing — commit it)
composer install
# Run dev server
APP_ENV=dev php -S localhost:8080 -t public
# Test the graph endpoint
curl "http://localhost:8080/graph.svg?theme=dark" -o graph.svg
curl "http://localhost:8080/health"
```
## Docker
```bash
# Build and run
docker compose up -d --build
# Force cache clear (clears the 1h filesystem cache)
docker compose exec graph rm -rf var/cache/*
# View logs
docker compose logs -f graph
```
There is no `composer.lock` in the repo. If you add or change dependencies, run `composer install` locally and commit the resulting lock file — without it, Docker builds resolve versions fresh each time and may produce inconsistent results.
The Dockerfile runs `composer install --no-scripts` (skipping Symfony post-install scripts) then `composer dump-autoload --optimize --no-dev` in the final stage. If `bin/console` fails with a missing class error inside the container, the most likely cause is the absent lock file causing an incomplete dependency resolution.
## Architecture
Single-controller Symfony app with no database. The request flow:
```
GET /graph.svg?theme=dark|light
└─ GraphController
├─ host check (ALLOWED_HOSTS env, optional)
├─ cache lookup (filesystem, 1h TTL, key = "graph_{theme}")
│ └─ on miss:
│ ├─ GitHubProvider → GitHub GraphQL API (contributionCalendar query)
│ ├─ GitLabProvider → GitLab REST /users/:id/events (paginated, 100/page)
│ └─ GiteaProvider → Gitea REST /api/v1/users/:user/heatmap
│ each returns array<string, int> (Y-m-d => count)
│ failures are caught and logged; remaining providers still render
│ └─ merge by date (sum counts across providers)
│ └─ SvgRenderer::render()
└─ Response: image/svg+xml, Cache-Control: public max-age=3600
```
**Provider activation:** a provider only runs when its env vars are non-empty. GitHub and GitLab require `_USER` + `_TOKEN`; Gitea additionally requires `_URL`. GitLab resolves a numeric user ID from the username via a `/api/v4/users?username=` lookup before fetching events.
**SvgRenderer:** builds a 53-column × 7-row grid aligned so the last column always ends on the Saturday of the current week. Five intensity levels (0 contributions → level 0, 13 → 1, 46 → 2, 79 → 3, 10+ → 4) mapped to GitHub's exact colour tokens. No external assets — the SVG is fully self-contained.
**Cache:** filesystem adapter (`var/cache/`), mounted as a Docker volume to survive container restarts. Theme is part of the cache key so dark and light are cached independently.
## Environment variables
| Variable | Required | Notes |
|---|---|---|
| `APP_SECRET` | Yes | 32+ char random string |
| `GITHUB_USER` / `GITHUB_TOKEN` | For GitHub | Token scope: `read:user` |
| `GITLAB_USER` / `GITLAB_TOKEN` | For GitLab | Token scopes: `read_user`, `read_api` |
| `GITLAB_URL` | No | Defaults to `https://gitlab.com` |
| `GITEA_USER` / `GITEA_TOKEN` / `GITEA_URL` | For Gitea | Token scope: `read:user` |
| `ALLOWED_HOSTS` | No | Comma-separated hostnames; empty = allow all |
Copy `.env` to `.env.local` for local development — `.env.local` is gitignored.