Skip to content

feat: add contributions outside work hours endpoint under v1-alpha - #2237

Merged
epipav merged 3 commits into
mainfrom
feat/IN-1335-contributions-outside-work-hours
Sep 21, 2026
Merged

epipav merged 3 commits into
mainfrom
feat/IN-1335-contributions-outside-work-hours

Conversation

@epipav

@epipav epipav commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

What

Adds GET /v1-alpha/projects/{slug}/development/contributions-outside-work-hours, the API port of the Nuxt contribution-outside widget handler.

Query: repos[], startDate, endDate (UTC calendar days), includeCollaborations (boolean, default false), includeCodeContributions (boolean, default true). No granularity.

Response:

{
  "summary": { "current": 50, "previous": 40, "percentageChange": 25, "changeValue": 10,
               "periodFrom": "2025-01-01T00:00:00Z", "periodTo": "2025-03-31T00:00:00Z" },
  "weekdayOutsideHoursPercentage": 40,
  "weekendOutsideHoursPercentage": 10,
  "data": [ { "weekday": 1, "hour": 20, "contributions": 30 } ]
}

summary is the share of contributions made outside work hours, in percent, for the current period vs the previous one (changeValue in percentage points). The two percentages split that share into weekdays 18:00 to 08:00 and weekends. data is the heatmap for the current period.

Two concurrent calls to activity_heatmap_by_weekday_and_2hours_blocks (current and previous period), slug sent as project, dates as YYYY-MM-DD 00:00:00, both flags forwarded.

Changes vs the Nuxt handler

  • Route renamed from contribution-outside.
  • Heatmap cell day (0 = Monday) becomes weekday with ISO numbering (1 = Monday to 7 = Sunday). The - 1 in Nuxt existed for the ECharts axis index; the API passes the pipe value through.
  • percentageChange is signed and null when the previous share is 0 and the current is not (shared toPeriodSummary).
  • periodFrom/periodTo are always present as ISO-8601 UTC; the current call uses the same defaulted range (2010-01-01 to today) so the summary covers exactly the reported period.
  • Unknown slug returns 200 with zero shares and an empty heatmap (the client's TinybirdProjectNotFoundError is caught by class; every other Tinybird failure is 503 upstream_unavailable).

Decisions

  • Timezone, stated as a fact in the route description: the hour buckets are in each contributor's local time. The pipe reads contributions_with_local_time_ds, built daily by contributions_with_local_time.pipe in linuxfoundation/crowd.dev as toDayOfWeek(addHours(timestamp, offset)) / intDiv(toHour(...), 2) * 2, with offset looked up from the contributor's profile country or location. Contributors without a mappable location are excluded from the dataset. The startDate/endDate filter is on the original UTC timestamp.
  • The pipe declares neither includeCollaborations nor includeCodeContributions; Nuxt forwards both and Tinybird ignores unknown params. Exposed as the ticket asks and forwarded; flagged for the Tinybird side.
  • summary uses a local OutsideWorkHoursSummary schema (spread of PeriodSummary.properties) so current, previous and changeValue carry percent descriptions; schemas/common.ts stays untouched in this PR.

Tests

api/tests/development-contributions-outside-work-hours.test.ts: 44 cases with fetch stubbed at the HTTP boundary and routed by pipe and startDate. Covers the response shape and exact keys, both pipe calls and their params, concurrency (a gated stub times out a sequential implementation), the flag defaults and coercion, every work-hours boundary block, signed and null percentageChange, empty and zero-count results, unknown slug, date validation and defaults, the 503 mapping for pipe, bucket lookup, network and non-JSON failures, Cache-Control, and the OpenAPI listing (tag, description, field descriptions, params, absence from /v1).

pnpm test, pnpm tsc-check, pnpm lint, pnpm format:check in api/: green (14 files, 206 tests). Includes the routing-test parser fix from the base branch (62b136b).

Helpers to consolidate later

toTinybirdDateTime/tinybirdRange, the fetchHeatmap 503-and-unknown-slug wrapper, share (zero-guarded percent), and the PeriodSummary description override; siblings define the same shapes.

Based on main, which includes #2241 (IN-1348, directory-based route registration) as dd37a7a. Jira: IN-1335

Copilot AI balanced review requested due to automatic review settings September 21, 2026 11:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Tinybird’s strict date filters currently omit the end day and exact start boundary, contradicting the calendar-day API contract.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Adds a v1-alpha endpoint for contributions outside work hours, backed by Tinybird.

Changes:

  • Adds response schemas, period comparison, and heatmap mapping.
  • Registers the endpoint under /v1-alpha.
  • Adds comprehensive integration and OpenAPI tests.
File Description
api/​src/​versions/​v1-alpha/​development/​contributions-outside-work-hours.ts Implements the endpoint and schemas.
api/​src/​versions/​v1-alpha/​index.ts Registers the route.
api/​tests/​development-contributions-outside-work-hours.test.ts Tests behavior, failures, and API documentation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread api/src/versions/v1-alpha/development/contributions-outside-work-hours.ts Outdated
Copilot AI review requested due to automatic review settings September 21, 2026 11:25
@epipav

epipav commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

the strict > startDate / < endDate compare lives in the tinybird pipe and this route sends the same YYYY-MM-DD 00:00:00 values nuxt and the sibling endpoints send -- out of scope here, tracked with the shared date helpers. wording fixed in 41fd2e9 👍

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Date boundaries exclude requested data, and the advertised contribution filters currently have no effect.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (1)

Copilot AI review requested due to automatic review settings September 21, 2026 11:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Calendar-day bounds exclude requested activity, and the documented contribution filters currently have no effect.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Correct empty-state documentation for complete heatmap grids

api/​src/​versions/​v1-alpha/​development/​contributions-outside-work-hours.ts:89

The empty-state description does not match the upstream pipe, which always returns the complete 7×12 grid for a known project and fills missing cells with zero. Clarify that only an unknown project returns an empty array; otherwise clients may implement an empty state that never appears.

This issue also appears in the following locations of the same file:

  • line 94
  • line 146

@epipav epipav self-assigned this Sep 21, 2026

@gaspergrom gaspergrom left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traced the weekday pass-through against the Nuxt handler and the pipe's filter logic. The raw pipe value is already ISO numbered, 1 for Monday through 7 for Sunday, so dropping the Nuxt -1 step is correct, not a reindex bug. The percentage null guard, the weekday/weekend split, and the concurrent calls all hold up, and the tests assert concrete weekday numbers instead of just checking for a key.

Base automatically changed from feat/IN-1345-project-endpoint to main September 21, 2026 12:26
@epipav
epipav force-pushed the feat/IN-1335-contributions-outside-work-hours branch 2 times, most recently from 4388611 to b8d48ea Compare September 21, 2026 12:41
Copilot AI review requested due to automatic review settings September 21, 2026 12:41

@themarolt themarolt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm - one question on the bucket lookups, nothing blocking

Comment thread api/src/versions/v1-alpha/development/contributions-outside-work-hours.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Tinybird’s exclusive timestamp comparisons currently omit the end date despite the API advertising inclusive calendar-day ranges.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 1 Low severity

Open (2)

Comment thread api/src/versions/v1-alpha/development/contributions-outside-work-hours.ts Outdated
@epipav
epipav changed the base branch from main to refactor/IN-1348-autoload-routes September 21, 2026 12:56
Copilot AI review requested due to automatic review settings September 21, 2026 12:56
@epipav
epipav force-pushed the feat/IN-1335-contributions-outside-work-hours branch from b8d48ea to 18b96b9 Compare September 21, 2026 12:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The upstream pipe’s exclusive date comparisons omit the documented end date from results.

Review effort: Balanced
Findings: 1 High severity · 1 Low severity

Open (2)

Base automatically changed from refactor/IN-1348-autoload-routes to main September 21, 2026 14:16
…-1335

Signed-off-by: anilb <epipav@gmail.com>
…1335

Signed-off-by: anilb <epipav@gmail.com>
Copilot AI review requested due to automatic review settings September 21, 2026 14:18
@epipav
epipav force-pushed the feat/IN-1335-contributions-outside-work-hours branch 2 times, most recently from 18b96b9 to d9f423a Compare September 21, 2026 14:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The concurrent calls duplicate uncached bucket lookups, and the default-date test can fail across UTC midnight.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity · 1 Low severity

Open (4)

Comment thread api/src/versions/v1-alpha/development/contributions-outside-work-hours.ts Outdated
Comment thread api/tests/development-contributions-outside-work-hours.test.ts
Signed-off-by: anilb <epipav@gmail.com>
Copilot AI review requested due to automatic review settings September 21, 2026 14:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation matches the described contract and includes thorough integration coverage with no unresolved blocking issues.

Review effort: Balanced
Findings: None

Resolved since last review (4)

@epipav
epipav merged commit bcf7698 into main Sep 21, 2026
11 checks passed
@epipav
epipav deleted the feat/IN-1335-contributions-outside-work-hours branch September 21, 2026 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants