diff options
| author | Christian Cleberg <[email protected]> | 2026-08-02 15:29:32 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-08-02 15:29:32 -0500 |
| commit | e7ec619ff25af162e464c1118571edb28b536a48 (patch) | |
| tree | 4e7820e951ed9c7ef1fc2fffbe36db43d7cca831 /API.md | |
| parent | 5d258a14f09f16b40f9007755b07ce123b524dd8 (diff) | |
| download | hutch-stats-main.tar.gz hutch-stats-main.tar.bz2 hutch-stats-main.zip | |
Diffstat (limited to 'API.md')
| -rw-r--r-- | API.md | 560 |
1 files changed, 0 insertions, 560 deletions
@@ -1,560 +0,0 @@ -# API Reference - -`srht-contrib` exposes a small HTTP JSON API for health checks, contribution calendar reads, manual polling, and optional tracked repository management. - -Base URL examples: - -- Local development: `http://127.0.0.1:8000` -- Deployed example: `https://hutch-stats.example.com` - -Content type: - -- Request bodies: `application/json` -- Response bodies: `application/json` - -Authentication: - -- Public endpoints: - - `GET /health` - - `GET /api/contributions/{actor}` - - `GET /api/contributions/{actor}/stats` -- Protected endpoints require `X-API-Key`: - - `POST /api/contributions/poll` - - all `/api/repositories*` - -Example protected header: - -```http -X-API-Key: your-api-key -``` - -## Common Conventions - -Actors: - -- Actors are SourceHut canonical names such as `~your-user`. -- Actor aliases may resolve to the canonical actor through configured alias mappings. - -Dates: - -- Query date format is `YYYY-MM-DD`. -- `year` and `from`/`to` are mutually exclusive on contribution endpoints. - -Contribution ranges: - -- Contribution read endpoints return zero-filled days, so clients do not need to patch missing dates. -- Public contribution reads also register the actor for background indexing. A first lookup may therefore return an empty graph while the scheduler catches up. -- Clients may add `prioritize_self=true` on contribution read endpoints to explicitly request temporary indexing priority for the signed-in user's own graph. -- Incremental indexing and one-year backfill are separate. An actor can be recently indexed before the retained one-year window is fully filled in. -- The service only retains and backfills the most recent 365 days of activity. - -Background polling: - -- When `ENABLE_SCHEDULER=true`, the service runs one poll immediately at startup and then continues polling on `POLL_INTERVAL_SECONDS`. -- The scheduler always seeds `DEFAULT_ACTOR` as a known actor. -- Public contribution reads register additional actors for later background polling. -- The scheduler only processes due actors, up to `DISCOVERY_BATCH_SIZE` per pass. -- Scheduled first indexing skips bounded one-year backfill work, then drains backfill in later scheduled passes so newly requested actors become indexed sooner. -- Manual polling remains available through `POST /api/contributions/poll`. - -Repository names: - -- Repository create/update accepts either: - - shorthand `repo-name` - - canonical `~owner/repo-name` -- Stored repository names are normalized to canonical `~owner/repo-name` form. -- Git polling auto-discovers repositories owned by the actor through SourceHut. -- Tracked repositories are optional force-includes for git polling; they are not required for normal owned-repository discovery. - -## Health - -### `GET /health` - -Returns a basic service health response. - -Auth: - -- Public - -Response `200 OK`: - -```json -{ - "status": "ok" -} -``` - -## Contributions - -### `GET /api/contributions/{actor}` - -Returns a contribution calendar for an actor over a year or explicit date range. - -Auth: - -- Public - -Path parameters: - -- `actor` string: SourceHut actor, for example `~your-user` - -Query parameters: - -- `year` integer, optional -- `from` string `YYYY-MM-DD`, optional -- `to` string `YYYY-MM-DD`, optional -- `prioritize_self` boolean, optional - -Rules: - -- Provide either `year` -- Or provide both `from` and `to` -- Do not combine `year` with `from`/`to` - -Behavior notes: - -- This endpoint resolves aliases to a canonical actor before querying data. -- This endpoint also registers the actor for background indexing and updates the actor's `last_requested_at` timestamp. -- When `prioritize_self=true`, registration also applies a temporary scheduler boost so that due polls for that actor run ahead of the normal due queue. -- The response is always immediate; it does not wait for SourceHut polling to finish. -- One-year backfill runs in bounded background batches and may take multiple scheduler passes to complete. - -Example by year: - -```bash -curl "http://127.0.0.1:8000/api/contributions/~your-user?year=2026" -``` - -Example by range: - -```bash -curl "http://127.0.0.1:8000/api/contributions/~your-user?from=2026-03-01&to=2026-04-15" -``` - -Response `200 OK`: - -```json -{ - "actor": "~your-user", - "from": "2026-03-01", - "to": "2026-04-15", - "is_indexed": false, - "last_polled_at": null, - "indexing_state": "pending", - "is_recent_window_backfilled": false, - "recent_backfill_state": "in_progress", - "recent_backfill_completed_at": null, - "days": [ - { "date": "2026-03-01", "count": 0, "score": 0.0 }, - { "date": "2026-03-02", "count": 3, "score": 2.5 } - ] -} -``` - -Response fields: - -- `actor` string: canonical actor after alias resolution -- `from` string: inclusive start date -- `to` string: inclusive end date -- `is_indexed` boolean: whether the service has already completed at least one successful recent/incremental poll for this actor -- `last_polled_at` string or `null`: most recent successful poll time, if any -- `indexing_state` string: one of `pending`, `indexed`, or `error` -- `is_recent_window_backfilled` boolean: whether the service has finished filling the retained one-year history window -- `recent_backfill_state` string: one of `pending`, `in_progress`, `completed`, or `error` -- `recent_backfill_completed_at` string or `null`: when one-year backfill completed, if it has -- `days` array: - - `date` string `YYYY-MM-DD` - - `count` integer contribution count for the day - - `score` float weighted score for the day - -Indexing state semantics: - -- `pending`: the actor is known but has not completed a successful poll yet -- `indexed`: at least one successful poll has completed for the actor -- `error`: the most recent poll attempt for the actor failed - -Recent backfill semantics: - -- the service only retains and backfills the most recent 365 days of activity -- `pending`: the actor has not started one-year backfill yet -- `in_progress`: one-year backfill is actively progressing in bounded background batches -- `completed`: the retained one-year window is fully backfilled -- `error`: the most recent backfill attempt failed - -Retention notes: - -- activity older than 365 days is not retained -- scheduled polling periodically prunes contribution rows older than the retained window - -Possible errors: - -- `400 Bad Request` for invalid or conflicting date input - -Example `400`: - -```json -{ - "detail": "Provide `year` or both `from` and `to`." -} -``` - -### `GET /api/contributions/{actor}/stats` - -Returns aggregated stats for the same date selection rules as the calendar endpoint. - -Auth: - -- Public - -Path parameters: - -- `actor` string - -Query parameters: - -- `year` integer, optional -- `from` string `YYYY-MM-DD`, optional -- `to` string `YYYY-MM-DD`, optional -- `prioritize_self` boolean, optional - -Behavior notes: - -- This endpoint has the same actor-registration and alias-resolution behavior as the calendar endpoint. -- When `prioritize_self=true`, registration also applies the same temporary scheduler boost as the calendar endpoint. -- This endpoint returns immediately and does not block on SourceHut polling. -- This endpoint also reflects whether the retained one-year history window has been fully backfilled yet. - -Example: - -```bash -curl "http://127.0.0.1:8000/api/contributions/~your-user/stats?from=2026-03-01&to=2026-04-15" -``` - -Response `200 OK`: - -```json -{ - "actor": "~your-user", - "from": "2026-03-01", - "to": "2026-04-15", - "is_indexed": true, - "last_polled_at": "2026-04-11T18:05:00Z", - "indexing_state": "indexed", - "is_recent_window_backfilled": true, - "recent_backfill_state": "completed", - "recent_backfill_completed_at": "2026-04-11T18:02:00Z", - "total_events": 126, - "total_score": 116.75, - "active_days": 14, - "longest_streak": 5, - "current_streak": 0 -} -``` - -Response fields: - -- `actor` string -- `from` string -- `to` string -- `is_indexed` boolean -- `last_polled_at` string or `null` -- `indexing_state` string -- `is_recent_window_backfilled` boolean -- `recent_backfill_state` string -- `recent_backfill_completed_at` string or `null` -- `total_events` integer -- `total_score` float -- `active_days` integer -- `longest_streak` integer -- `current_streak` integer - -Possible errors: - -- `400 Bad Request` for invalid or conflicting date input - -### `POST /api/contributions/poll` - -Triggers a manual SourceHut poll for the given actor and stores any newly discovered events. - -Auth: - -- Requires `X-API-Key` - -Query parameters: - -- `actor` string: SourceHut actor to poll - -Example: - -```bash -curl -X POST \ - -H "X-API-Key: your-api-key" \ - "http://127.0.0.1:8000/api/contributions/poll?actor=~your-user" -``` - -Response `200 OK`: - -```json -{ - "actor": "~your-user", - "inserted_events": 57, - "services": ["todo", "git"] -} -``` - -Response fields: - -- `actor` string: canonical actor after alias resolution -- `inserted_events` integer: number of newly inserted normalized events -- `services` array of strings: currently `["todo", "git"]` - -Behavior notes: - -- Manual polling also updates the actor's indexing metadata. -- Manual polling also advances one-year backfill by bounded batches for each supported service. -- Git polling auto-discovers the actor's owned repositories and unions in any configured tracked repositories. - -Possible errors: - -- `401 Unauthorized` if the API key is missing or invalid -- `502 Bad Gateway` if polling SourceHut fails - -Example `401`: - -```json -{ - "detail": "Invalid API key." -} -``` - -Example `502`: - -```json -{ - "detail": "SourceHut polling failed: HTTP error from SourceHut: 502" -} -``` - -## Tracked Repositories - -All repository endpoints are protected and require `X-API-Key`. - -Tracked repositories are optional force-includes for git polling. Each repository is associated with an actor and stored in canonical `~owner/repo` form. - -### `GET /api/repositories` - -Lists tracked git repositories. - -Auth: - -- Requires `X-API-Key` - -Query parameters: - -- `actor` string, optional: filter to a canonical actor or alias - -Example: - -```bash -curl \ - -H "X-API-Key: your-api-key" \ - "http://127.0.0.1:8000/api/repositories?actor=~your-user" -``` - -Response `200 OK`: - -```json -[ - { - "id": 1, - "service": "git", - "actor": "~your-user", - "repo_name": "~your-user/your-repo" - } -] -``` - -### `GET /api/repositories/{repository_id}` - -Fetches one tracked repository by numeric ID. - -Auth: - -- Requires `X-API-Key` - -Path parameters: - -- `repository_id` integer - -Example: - -```bash -curl \ - -H "X-API-Key: your-api-key" \ - "http://127.0.0.1:8000/api/repositories/1" -``` - -Response `200 OK`: - -```json -{ - "id": 1, - "service": "git", - "actor": "~your-user", - "repo_name": "~your-user/your-repo" -} -``` - -Possible errors: - -- `404 Not Found` if the repository ID does not exist - -### `POST /api/repositories` - -Creates a tracked repository entry. - -Auth: - -- Requires `X-API-Key` - -Request body: - -```json -{ - "actor": "~your-user", - "repo_name": "your-repo" -} -``` - -Example: - -```bash -curl -X POST \ - -H "X-API-Key: your-api-key" \ - -H "Content-Type: application/json" \ - -d '{"actor":"~your-user","repo_name":"your-repo"}' \ - "http://127.0.0.1:8000/api/repositories" -``` - -Response `201 Created`: - -```json -{ - "id": 1, - "service": "git", - "actor": "~your-user", - "repo_name": "~your-user/your-repo" -} -``` - -Possible errors: - -- `401 Unauthorized` if the API key is missing or invalid -- `409 Conflict` if the normalized repository already exists for that actor -- `422 Unprocessable Content` if `actor` or `repo_name` is blank or malformed - -### `PATCH /api/repositories/{repository_id}` - -Updates an existing tracked repository. - -Auth: - -- Requires `X-API-Key` - -Path parameters: - -- `repository_id` integer - -Request body: - -```json -{ - "actor": "~your-user", - "repo_name": "~your-user/your-other-repo" -} -``` - -Body rules: - -- At least one of `actor` or `repo_name` must be present - -Example: - -```bash -curl -X PATCH \ - -H "X-API-Key: your-api-key" \ - -H "Content-Type: application/json" \ - -d '{"repo_name":"~your-user/your-other-repo"}' \ - "http://127.0.0.1:8000/api/repositories/1" -``` - -Response `200 OK`: - -```json -{ - "id": 1, - "service": "git", - "actor": "~your-user", - "repo_name": "~your-user/your-other-repo" -} -``` - -Possible errors: - -- `404 Not Found` -- `409 Conflict` -- `422 Unprocessable Content` - -### `DELETE /api/repositories/{repository_id}` - -Deletes a tracked repository. - -Auth: - -- Requires `X-API-Key` - -Path parameters: - -- `repository_id` integer - -Example: - -```bash -curl -X DELETE \ - -H "X-API-Key: your-api-key" \ - "http://127.0.0.1:8000/api/repositories/1" -``` - -Response `204 No Content` - -Possible errors: - -- `404 Not Found` - -## Error Summary - -Common status codes: - -- `200 OK` successful read or manual poll -- `201 Created` successful repository creation -- `204 No Content` successful repository deletion -- `400 Bad Request` invalid date parameters -- `401 Unauthorized` missing or invalid API key -- `404 Not Found` missing repository record -- `409 Conflict` duplicate repository after normalization -- `422 Unprocessable Content` invalid repository payload -- `502 Bad Gateway` upstream SourceHut failure during poll - -## OpenAPI - -FastAPI also serves an OpenAPI document at: - -```text -/openapi.json -``` - -If interactive docs are enabled by your deployment, the standard FastAPI docs may also be available at: - -```text -/docs -``` |
