You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: add issues resolution endpoint under v1-alpha - #2236
Adds the first Development metric route to the alpha API:
GET /v1-alpha/projects/{slug}/development/issues-resolution?granularity=monthly&startDate=2025-06-20&endDate=2025-09-18&repos=<url>&repos=<url>
It returns the issues closed in the requested period against the previous period of the same length, the average time to resolve an issue in seconds, and one bucket per granularity step with the issues opened (totalIssues) and closed (closedIssues) in it.
It ports frontend/server/data/tinybird/development/issues-resolution.ts call for call: one project_buckets lookup, then four activities_count calls (current summary, previous summary, opened series, closed series) and one issues_average_resolve_velocity call, all in flight together, with the same filter params the widget sends and dates as YYYY-MM-DD 00:00:00.
Renames against the Nuxt handler
avgVelocityInDays is now avgResolveTimeSeconds; the value was always seconds.
Bucket keys dateFrom / dateTo are now startDate / endDate.
Decisions
granularity is required. Without it the pipe returns a single summary row with no bucket dates, so the series would be malformed; the UI always sends it.
The route resolves the project's bucketId once through client.getBucketIdForProject and passes it on the five pipe calls (six Tinybird round trips instead of ten). A project without a bucket returns 200 with zero counts and data: [], per the epic's definition of done for metric endpoints.
Every Tinybird failure (any status, network error, non-JSON body) becomes 503 upstream_unavailable, logged with the pipe name. Tinybird's own status never reaches the caller.
percentageChange is signed (the widget used Math.abs), via the shared toPeriodSummary.
Output dates are YYYY-MM-DDT00:00:00Z everywhere in the response; bucket bounds take the same shape as periodFrom / periodTo.
avgResolveTimeSeconds is nullable: the velocity pipe returns no row, or a null average, when nothing was closed in scope.
The summary schema reuses PeriodSummary field by field and gives the three count fields endpoint-specific descriptions, since every response field carries a unit-bearing description (that is the docs reference entry). Shared files stay untouched so the four sibling Development PRs merge cleanly; the small helpers in this route (Tinybird day formatter, UTC midnight formatter, 503 wrapper, bucket merge) are candidates for the consolidation chore that follows.
Tests
api/tests/development-issues-resolution.test.ts: 33 tests with fetch stubbed at the HTTP boundary and routed by pipe path and params. They cover the response shape, every Tinybird call's params, concurrency of the five calls, omitted dates, merge edge cases, the unknown slug, validation (missing or unknown granularity, timestamp dates, inverted range), 503 mapping for pipe and lookup failures, Cache-Control, and the OpenAPI entry (tag Development, required granularity enum, a description on every response field, absent from /v1).
From api/: pnpm test (14 files, 195 tests), pnpm tsc-check, pnpm lint and pnpm format:check pass.
Includes the routing-test parser fix from the base branch (62b136b).
Based on main, which includes #2231 (IN-1345) as ef31c9e. Jira: IN-1331
getPreviousDates preserves a calendar-month/day duration, not an equal number of days: Jan 31–Mar 1 (30 days inclusive) compares against Dec 29–Jan 30 (33 days). Describing these periods as the same length misstates this field’s public contract.
This issue also appears on line 151 of the same file.
The reason will be displayed to describe this comment to others. Learn more.
Confirmed avgResolveTimeSeconds passes straight through from averageIssueResolveVelocitySeconds with no conversion, and the test on line 196 pins the exact seconds value from the mock to prove it. The five pipe calls run through Promise.all sharing one resolved bucketId, an unknown slug returns zero data after just the bucket lookup, and every Tinybird failure maps to 503 without leaking upstream detail. Solid test coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the first Development metric route to the alpha API:
GET /v1-alpha/projects/{slug}/development/issues-resolution?granularity=monthly&startDate=2025-06-20&endDate=2025-09-18&repos=<url>&repos=<url>It returns the issues closed in the requested period against the previous period of the same length, the average time to resolve an issue in seconds, and one bucket per granularity step with the issues opened (
totalIssues) and closed (closedIssues) in it.{ "summary": { "current": 100, "previous": 50, "percentageChange": 100, "changeValue": 50, "periodFrom": "2025-06-20T00:00:00Z", "periodTo": "2025-09-18T00:00:00Z", "avgResolveTimeSeconds": 7451999 }, "data": [ { "startDate": "2025-06-01T00:00:00Z", "endDate": "2025-06-30T00:00:00Z", "totalIssues": 12, "closedIssues": 8 } ] }It ports
frontend/server/data/tinybird/development/issues-resolution.tscall for call: oneproject_bucketslookup, then fouractivities_countcalls (current summary, previous summary, opened series, closed series) and oneissues_average_resolve_velocitycall, all in flight together, with the same filter params the widget sends and dates asYYYY-MM-DD 00:00:00.Renames against the Nuxt handler
avgVelocityInDaysis nowavgResolveTimeSeconds; the value was always seconds.dateFrom/dateToare nowstartDate/endDate.Decisions
granularityis required. Without it the pipe returns a single summary row with no bucket dates, so the series would be malformed; the UI always sends it.bucketIdonce throughclient.getBucketIdForProjectand passes it on the five pipe calls (six Tinybird round trips instead of ten). A project without a bucket returns 200 with zero counts anddata: [], per the epic's definition of done for metric endpoints.upstream_unavailable, logged with the pipe name. Tinybird's own status never reaches the caller.percentageChangeis signed (the widget usedMath.abs), via the sharedtoPeriodSummary.YYYY-MM-DDT00:00:00Zeverywhere in the response; bucket bounds take the same shape asperiodFrom/periodTo.avgResolveTimeSecondsis nullable: the velocity pipe returns no row, or a null average, when nothing was closed in scope.PeriodSummaryfield by field and gives the three count fields endpoint-specific descriptions, since every response field carries a unit-bearing description (that is the docs reference entry). Shared files stay untouched so the four sibling Development PRs merge cleanly; the small helpers in this route (Tinybird day formatter, UTC midnight formatter, 503 wrapper, bucket merge) are candidates for the consolidation chore that follows.Tests
api/tests/development-issues-resolution.test.ts: 33 tests withfetchstubbed at the HTTP boundary and routed by pipe path and params. They cover the response shape, every Tinybird call's params, concurrency of the five calls, omitted dates, merge edge cases, the unknown slug, validation (missing or unknown granularity, timestamp dates, inverted range), 503 mapping for pipe and lookup failures,Cache-Control, and the OpenAPI entry (tagDevelopment, requiredgranularityenum, a description on every response field, absent from/v1).From
api/:pnpm test(14 files, 195 tests),pnpm tsc-check,pnpm lintandpnpm format:checkpass.Includes the routing-test parser fix from the base branch (62b136b).
Based on main, which includes #2231 (IN-1345) as ef31c9e. Jira: IN-1331
main