Skip to content

feat: add shared api schemas and period helpers - #2230

Merged
epipav merged 2 commits into
mainfrom
feat/IN-1330-development-shared-schemas
Sep 21, 2026
Merged

epipav merged 2 commits into
mainfrom
feat/IN-1330-development-shared-schemas

Conversation

@epipav

@epipav epipav commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the building blocks that every Development endpoint will import, so the fourteen endpoints share one set of request params and one summary shape. This PR adds no routes.

api/src/schemas/common.ts (TypeBox):

  • ProjectSlugParams: any non-empty slug, so an unknown project reaches the handler and returns empty data
  • DateRangeQuery: repos as repeated keys (a single value becomes a one-item array), and startDate and endDate as YYYY-MM-DD UTC calendar days
  • Granularity: daily | weekly | monthly | quarterly | yearly, emitted as a plain OpenAPI enum
  • PeriodSummary: current, previous, percentageChange, changeValue, periodFrom, periodTo

api/src/lib/period.ts:

  • getPreviousDates: a port of the helper in frontend/server/data/util.ts that uses native UTC dates in place of Luxon, and returns the same previous periods, month-end clamping included
  • calculatePercentageChange and toPeriodSummary
  • InvalidDateRangeError: a start date after the end date returns 400 invalid_request, where Nuxt returned a 500

Decisions worth a look

  • percentageChange is signed, so a drop reads -50. Nuxt returned Math.abs(...). It is null when previous is 0 and current isn't, where Nuxt left the key out.
  • The previous period keeps Nuxt's boundary and ends the day before startDate, so the API's numbers match the widgets.
  • percentageChange is declared with nullable: true because the spec is OpenAPI 3.0.3, which has no type: 'null'.

Testing

  • api/tests/period.test.ts: Luxon parity on 10 fixture ranges (UI presets, month-end clamp, leap day), defaults, two non-UTC host time zones, inverted ranges, and the percentage math
  • api/tests/common-schemas.test.ts: the schemas wired into a throwaway Fastify route, covering validation, query coercion, null serialization and the generated OpenAPI
  • A one-off script compared getPreviousDates with the real Luxon implementation on 523,666 date ranges and found no mismatches.

References

  • JIRA: IN-1330, a sub-task of IN-1141 (Endpoints phase 1: Development)
  • Blocks IN-1331 to IN-1344

Signed-off-by: anilb <epipav@gmail.com>
Copilot AI balanced review requested due to automatic review settings September 18, 2026 16:06

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.

🟡 Changes recommended

Valid date inputs can produce corrupted ranges, and shared enum and error-envelope conventions are not followed.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds reusable TypeBox schemas and UTC period helpers for upcoming Development API endpoints.

Changes:

  • Defines shared request and summary schemas.
  • Implements previous-period and percentage calculations.
  • Adds schema integration and date-math tests.
File summaries
File Description
api/src/schemas/common.ts Adds common API schemas.
api/src/lib/period.ts Adds period calculations and summaries.
api/tests/common-schemas.test.ts Tests validation, coercion, and OpenAPI output.
api/tests/period.test.ts Tests date ranges and summary calculations.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 4
  • Review effort level: Balanced

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

Comment thread api/src/lib/period.ts
Comment thread api/src/lib/period.ts
Comment thread api/src/lib/period.ts
Comment thread api/src/schemas/common.ts Outdated
Signed-off-by: anilb <epipav@gmail.com>
Copilot AI review requested due to automatic review settings September 18, 2026 16:30

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.

🟡 Changes recommended

The date schema conflicts with the documented API contract, and the empty-slug test expects the wrong HTTP status.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

api/src/schemas/common.ts:18

  • The public API plan commits all date inputs to UTC ISO-8601 timestamps (api/docs/arch/PUBLIC_API_PLAN.md:386), but this shared schema rejects that form and accepts only calendar dates. Either accept and normalize the documented timestamp contract, or update the architecture decision and dependent helpers/tests if the contract has intentionally changed.
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread api/tests/common-schemas.test.ts
@epipav

epipav commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

re copilot's date note on common.ts:18: keeping startDate/endDate as YYYY-MM-DD, which is ISO-8601 too. the pipes only see days, so a timestamp's time of day would be silently dropped.

@epipav epipav self-assigned this Sep 18, 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 Luxon-to-native date port by hand against the month-end clamp cases, and the numbers match. Schemas and tests cover the signed percentage and null cases well.

@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 - the luxon port checks out, including the clamp-then-subtract-days order. one question on the repos bound

Comment thread api/src/schemas/common.ts
@epipav
epipav merged commit dda6106 into main Sep 21, 2026
11 checks passed
@epipav
epipav deleted the feat/IN-1330-development-shared-schemas branch September 21, 2026 08:40
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