Skip to content

Comments

refactor: always use short id in api calls#545

Merged
nicotsx merged 1 commit intomainfrom
refactor/short-ids-api-contract
Feb 19, 2026
Merged

refactor: always use short id in api calls#545
nicotsx merged 1 commit intomainfrom
refactor/short-ids-api-contract

Conversation

@nicotsx
Copy link
Owner

@nicotsx nicotsx commented Feb 18, 2026

Summary by CodeRabbit

Release Notes

  • Refactor
    • Updated API endpoint paths across volumes, repositories, backup schedules, and snapshots to use shorter string-based identifiers instead of numeric IDs, improving consistency throughout the application.
    • Aligned parameter handling for backup schedule operations and snapshot management to support the updated identifier format.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Walkthrough

Migrates API route parameters and resource identifiers from id, scheduleId, and volumeId to shortId across volumes, repositories, snapshots, and backup schedules. Updates generated API client types/SDK, server controllers and services, client route handlers, and UI components to use the new identifier scheme.

Changes

Cohort / File(s) Summary
Generated API Client
app/client/api-client/sdk.gen.ts, app/client/api-client/types.gen.ts
Updated URL templates and path parameters from {id}, {scheduleId}, {volumeId} to {shortId}, {volumeShortId} across volume, repository, snapshot, and backup schedule endpoints. Updated ReorderBackupSchedulesData payload from scheduleIds to scheduleShortIds.
Client File Browsers
app/client/components/file-browsers/volume-file-browser.tsx, app/client/components/file-browsers/snapshot-tree-browser.tsx
Changed path identifiers in query options from id to shortId in list file operations for volumes and snapshots.
Client Repository Components
app/client/modules/repositories/tabs/info.tsx, app/client/modules/repositories/tabs/snapshots.tsx, app/client/components/restore-form.tsx
Updated mutation and query calls to use repository.shortId instead of repository.id for delete, doctor, unlock, and snapshot operations.
Client Backup Schedule Components
app/client/modules/backups/components/backup-card.tsx, app/client/modules/backups/components/schedule-summary.tsx, app/client/modules/backups/components/schedule-mirrors-config.tsx, app/client/modules/backups/components/schedule-notifications-config.tsx, app/client/modules/backups/components/snapshot-file-browser.tsx
Added scheduleShortId prop to notification and mirror config components; updated all schedule API calls to use shortId instead of scheduleId and schedule.shortId instead of schedule.id.
Client Backup List Management
app/client/modules/backups/routes/backups.tsx, app/client/modules/backups/routes/backup-details.tsx, app/client/components/snapshots-table.tsx, app/client/components/sortable-card.tsx
Updated schedule identifier tracking from numeric id to string shortId in state and mutations; widened SortableBackupCardProps.uniqueId from number to string | number.
Client Repository Routes
app/client/modules/repositories/routes/edit-repository.tsx, app/client/modules/repositories/routes/repository-details.tsx, app/client/modules/repositories/routes/snapshot-details.tsx, app/routes/(dashboard)/repositories/$repositoryId/...tsx
Updated all route loaders to fetch repository and snapshot data using path: { shortId } instead of path: { id } in API query options.
Client Volume Routes
app/client/modules/volumes/routes/volume-details.tsx, app/client/modules/volumes/tabs/info.tsx, app/client/modules/volumes/components/healthchecks-card.tsx, app/routes/(dashboard)/volumes/$volumeId.tsx
Updated volume mutation and query paths to use shortId instead of id for delete, mount, unmount, health-check, and update operations.
Client Backup Routes
app/routes/(dashboard)/backups/$backupId/...tsx
Updated route loaders to fetch backup schedule data using path: { shortId } and updated prefetch snapshots to use repository/schedule shortId.
Client Error Handling
app/client/lib/errors.tsx
Updated unlock repository error handler to use path: { shortId } instead of path: { id }.
Server Repository Controller and Service
app/server/modules/repositories/repositories.controller.ts, app/server/modules/repositories/repositories.service.ts, app/server/modules/repositories/__tests__/repositories.controller.test.ts
Renamed all route parameters from :id to :shortId; updated service calls to accept and resolve shortId instead of id; tightened findRepository to only query by shortId.
Server Volume Controller and Service
app/server/modules/volumes/volume.controller.ts, app/server/modules/volumes/volume.service.ts
Updated route parameters and service method signatures from id/idOrShortId to shortId/identifier; all volume operations (delete, mount, unmount, health-check, list files) now use the new identifier parameter name.
Server Backup Controller, Service, and DTO
app/server/modules/backups/backups.controller.ts, app/server/modules/backups/backups.service.ts, app/server/modules/backups/backups.dto.ts
Updated route parameters from :scheduleId to :shortId and volumeId to volumeShortId; refactored service methods to accept string | number identifiers with fallback resolution logic; updated reorder payload from scheduleIds to scheduleShortIds.
Server Tests
app/server/__tests__/isolation.test.ts
Updated test endpoint paths and data values to use shortId variables instead of numeric id in repository, volume, and backup schedule operations.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: refactoring API calls throughout the codebase to consistently use short IDs instead of numeric IDs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot
Copy link

dosubot bot commented Feb 18, 2026

Related Documentation

Checked 10 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/server/modules/repositories/__tests__/repositories.controller.test.ts (1)

189-229: ⚠️ Potential issue | 🟡 Minor

PATCH tests correctly use repository.shortId; add a positive integration test for GET /api/v1/repositories/:shortId.

The test suite has no positive GET test that creates a real repository record and retrieves it by shortId. Currently only a 404 test exists for non-existent repositories. Adding a GET test that creates and retrieves a record would ensure this common read path is exercised.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/server/modules/repositories/__tests__/repositories.controller.test.ts`
around lines 189 - 229, Add a positive integration test in
repositories.controller.test.ts that uses createTestSession() and
createRepositoryRecord(organizationId) to create a real repository, then call
app.request(`/api/v1/repositories/${repository.shortId}`) with method "GET" and
auth headers (getAuthHeaders(token)), assert res.status is 200, parse await
res.json() and assert expected fields (e.g., shortId, organizationId, config or
name) match the created repository values; place this alongside the existing GET
404 test so the common read path for the GET handler is exercised.
🧹 Nitpick comments (5)
app/client/modules/backups/components/schedule-summary.tsx (1)

64-69: summary.repositoryLabel is computed but never consumed.

summary.repositoryLabel (computed at line 67 using schedule.repositoryId) is not referenced anywhere in the JSX — the "Repository" card at line 175 uses schedule.repository.name directly. Additionally, schedule.repositoryId is a legacy non-short ID field that may no longer exist on BackupSchedule after this migration, silently yielding "No repository selected". The entire repositoryLabel entry in the summary object can be dropped.

🧹 Proposed cleanup
 		return {
 			vol: schedule.volume.name,
 			scheduleLabel,
-			repositoryLabel: schedule.repositoryId || "No repository selected",
 			retentionLabel: retentionParts.length > 0 ? retentionParts.join(" • ") : "No retention policy",
 		};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/client/modules/backups/components/schedule-summary.tsx` around lines 64 -
69, Remove the unused repositoryLabel property from the summary object: in the
ScheduleSummary component where you build the summary (the object that currently
contains vol, scheduleLabel, repositoryLabel, retentionLabel), delete the
repositoryLabel entry that uses schedule.repositoryId and any related fallback
text; ensure no other code expects summary.repositoryLabel and keep using
schedule.repository.name in the JSX (e.g., the "Repository" card) as before so
behavior is unchanged.
app/server/modules/repositories/repositories.service.ts (1)

185-222: Parameter names still say id / "Repository ID" but now accept shortIds — rename for clarity.

Every public service function (getRepository, deleteRepository, listSnapshots, listSnapshotFiles, restoreSnapshot, getSnapshotDetails, checkHealth, startDoctor, cancelDoctor, deleteSnapshot, deleteSnapshots, tagSnapshots, refreshSnapshots, updateRepository, unlockRepository, execResticCommand) uses id as the parameter name and the JSDoc at line 215 still reads @param id Repository ID. Since findRepository now performs a shortId-only lookup, all of these id parameters are semantically shortIds. Leaving them named id will mislead future contributors into passing UUIDs.

Consider a follow-up rename to shortId (or at minimum update the JSDoc) to keep the contract explicit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/server/modules/repositories/repositories.service.ts` around lines 185 -
222, The public service functions getRepository, deleteRepository,
listSnapshots, listSnapshotFiles, restoreSnapshot, getSnapshotDetails,
checkHealth, startDoctor, cancelDoctor, deleteSnapshot, deleteSnapshots,
tagSnapshots, refreshSnapshots, updateRepository, unlockRepository, and
execResticCommand currently accept a parameter named id but rely on
findRepository which expects a shortId; rename the parameter from id to shortId
(and update all internal references and callers) or at minimum update the JSDoc
`@param` lines to indicate this is a shortId to avoid confusion; ensure function
signatures, any exported types, and tests/call sites are updated consistently so
the contract is explicit.
app/client/modules/backups/routes/backup-details.tsx (1)

127-130: Minor: listSnapshotsQueryOptions duplicates the options built on line 80.

The query options object on lines 127–130 mirrors the inline options in listSnapshotsOptions(...) on line 80. Consider extracting this once and reusing it in both places to avoid drift.

Proposed deduplication
+	const listSnapshotsQueryOptions = {
+		path: { shortId: schedule.repository.shortId },
+		query: { backupId: schedule.shortId },
+	};
+
 	const {
 		data: snapshots,
 		isLoading,
 		failureReason,
 	} = useQuery({
-		...listSnapshotsOptions({ path: { shortId: schedule.repository.shortId }, query: { backupId: schedule.shortId } }),
+		...listSnapshotsOptions(listSnapshotsQueryOptions),
 	});

Also applies to: 79-81

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/client/modules/backups/routes/backup-details.tsx` around lines 127 - 130,
The object literal for snapshot query options is duplicated; extract it to a
single constant (e.g., const snapshotQueryOptions) and use that constant in both
places where listSnapshotsOptions(...) and listSnapshotsQueryOptions are
currently constructed so both calls reference the same object; reference the
existing symbols schedule.repository.shortId and schedule.shortId when building
snapshotQueryOptions and replace the inline literals in
listSnapshotsOptions(...) and the listSnapshotsQueryOptions variable with this
shared constant.
app/client/modules/backups/components/schedule-mirrors-config.tsx (1)

27-33: Consider deriving scheduleId from the query response instead of requiring both props.

The component accepts both scheduleId: number and scheduleShortId: string — the numeric ID is only needed for SSE event matching (lines 110, 121). Since the schedule's numeric id is available on the mirrors response or could be fetched alongside, you could potentially drop the scheduleId prop and derive it internally, keeping the public surface shortId-only. Low priority since both values are readily available at the call site.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/client/modules/backups/components/schedule-mirrors-config.tsx` around
lines 27 - 33, The component's Props currently require both scheduleId (number)
and scheduleShortId (string) even though the numeric id exists in the mirrors
response; update the component to stop requiring scheduleId in the Props and
instead derive it from the GetScheduleMirrorsResponse (or fetch alongside)
inside the ScheduleMirrorsConfig component, then use that derived id for SSE
event matching where scheduleId was used; specifically remove scheduleId from
the Props type, read the numeric id from the initialData
(GetScheduleMirrorsResponse) or the mirrors payload, and replace usages tied to
SSE matching so external callers only provide scheduleShortId.
app/server/modules/backups/backups.service.ts (1)

333-362: Dead code: the typeof identifier === "number" branch is unreachable.

The DTO defines scheduleShortIds: "string[]" (line 379 in backups.dto.ts), and the controller passes body.scheduleShortIds (always string[]). The numeric branch (lines 348–354) will never execute. The (string | number)[] parameter type is misleading.

Consider narrowing the parameter to string[] to match the actual contract, or drop the numeric-ID resolution path entirely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/server/modules/backups/backups.service.ts` around lines 333 - 362, The
reorderSchedules function accepts (string | number)[] but the controller/DTO
always passes body.scheduleShortIds (string[]), so the numeric branch in
reorderSchedules is dead; update reorderSchedules signature to accept string[]
(rename parameter to scheduleShortIds if helpful), remove the typeof identifier
=== "number" branch and associated validIds/map checks, and simplify the mapping
to resolve each shortId via scheduleIdByShortId (throw NotFoundError when a
shortId is missing); also adjust any callers to pass string[] and update related
types in backups.dto.ts if needed to keep signatures consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/server/modules/backups/backups.service.ts`:
- Around line 194-207: The lookup in getScheduleForVolume uses
Number(volumeIdentifier) which can wrongly treat numeric-looking shortIds as
numeric IDs; change the query to only coerce to Number when the identifier is
actually numeric (e.g. typeof volumeIdentifier === 'number' or a strict
numeric-string test like /^\d+$/) and otherwise only compare against shortId, so
update the volumesTable.findFirst OR clause to conditionally include the { id:
Number(...) } branch only when the identifier is truly numeric and otherwise
only include { shortId: String(volumeIdentifier) } to avoid accidental matches.
- Around line 123-129: Introduce a type-aware resolver function (e.g.,
resolveSchedule) that accepts (identifier: string | number, organizationId:
string), builds the query WHERE based on typeof identifier (id for numbers,
shortId for strings), performs db.query.backupSchedulesTable.findFirst and
throws NotFoundError when missing; then replace the existing OR-based lookups in
updateSchedule, deleteSchedule, getScheduleForVolume, getMirrors, updateMirrors,
and getMirrorCompatibility to call resolveSchedule instead of using
Number(scheduleIdentifier) or the OR pattern to avoid numeric-string coercion
collisions.

In `@app/server/modules/repositories/repositories.service.ts`:
- Around line 32-38: findRepository was tightened to lookup only by shortId, but
restoreSnapshot passes the full DB UUID (repository.id) into getSnapshotDetails
which calls findRepository and therefore fails to find the repo; update
restoreSnapshot to pass the repository shortId (e.g., repository.shortId) into
getSnapshotDetails (instead of repository.id) so
getSnapshotDetails/findRepository continue to match on shortId, and verify
getSnapshotDetails, restoreSnapshot and any other callers expect and propagate
the shortId parameter consistently.

---

Outside diff comments:
In `@app/server/modules/repositories/__tests__/repositories.controller.test.ts`:
- Around line 189-229: Add a positive integration test in
repositories.controller.test.ts that uses createTestSession() and
createRepositoryRecord(organizationId) to create a real repository, then call
app.request(`/api/v1/repositories/${repository.shortId}`) with method "GET" and
auth headers (getAuthHeaders(token)), assert res.status is 200, parse await
res.json() and assert expected fields (e.g., shortId, organizationId, config or
name) match the created repository values; place this alongside the existing GET
404 test so the common read path for the GET handler is exercised.

---

Nitpick comments:
In `@app/client/modules/backups/components/schedule-mirrors-config.tsx`:
- Around line 27-33: The component's Props currently require both scheduleId
(number) and scheduleShortId (string) even though the numeric id exists in the
mirrors response; update the component to stop requiring scheduleId in the Props
and instead derive it from the GetScheduleMirrorsResponse (or fetch alongside)
inside the ScheduleMirrorsConfig component, then use that derived id for SSE
event matching where scheduleId was used; specifically remove scheduleId from
the Props type, read the numeric id from the initialData
(GetScheduleMirrorsResponse) or the mirrors payload, and replace usages tied to
SSE matching so external callers only provide scheduleShortId.

In `@app/client/modules/backups/components/schedule-summary.tsx`:
- Around line 64-69: Remove the unused repositoryLabel property from the summary
object: in the ScheduleSummary component where you build the summary (the object
that currently contains vol, scheduleLabel, repositoryLabel, retentionLabel),
delete the repositoryLabel entry that uses schedule.repositoryId and any related
fallback text; ensure no other code expects summary.repositoryLabel and keep
using schedule.repository.name in the JSX (e.g., the "Repository" card) as
before so behavior is unchanged.

In `@app/client/modules/backups/routes/backup-details.tsx`:
- Around line 127-130: The object literal for snapshot query options is
duplicated; extract it to a single constant (e.g., const snapshotQueryOptions)
and use that constant in both places where listSnapshotsOptions(...) and
listSnapshotsQueryOptions are currently constructed so both calls reference the
same object; reference the existing symbols schedule.repository.shortId and
schedule.shortId when building snapshotQueryOptions and replace the inline
literals in listSnapshotsOptions(...) and the listSnapshotsQueryOptions variable
with this shared constant.

In `@app/server/modules/backups/backups.service.ts`:
- Around line 333-362: The reorderSchedules function accepts (string | number)[]
but the controller/DTO always passes body.scheduleShortIds (string[]), so the
numeric branch in reorderSchedules is dead; update reorderSchedules signature to
accept string[] (rename parameter to scheduleShortIds if helpful), remove the
typeof identifier === "number" branch and associated validIds/map checks, and
simplify the mapping to resolve each shortId via scheduleIdByShortId (throw
NotFoundError when a shortId is missing); also adjust any callers to pass
string[] and update related types in backups.dto.ts if needed to keep signatures
consistent.

In `@app/server/modules/repositories/repositories.service.ts`:
- Around line 185-222: The public service functions getRepository,
deleteRepository, listSnapshots, listSnapshotFiles, restoreSnapshot,
getSnapshotDetails, checkHealth, startDoctor, cancelDoctor, deleteSnapshot,
deleteSnapshots, tagSnapshots, refreshSnapshots, updateRepository,
unlockRepository, and execResticCommand currently accept a parameter named id
but rely on findRepository which expects a shortId; rename the parameter from id
to shortId (and update all internal references and callers) or at minimum update
the JSDoc `@param` lines to indicate this is a shortId to avoid confusion; ensure
function signatures, any exported types, and tests/call sites are updated
consistently so the contract is explicit.

@nicotsx nicotsx force-pushed the refactor/short-ids-api-contract branch from be5d2ed to 7cb274f Compare February 19, 2026 18:06
Copy link
Owner Author

nicotsx commented Feb 19, 2026

@nicotsx nicotsx merged commit 8681ebc into main Feb 19, 2026
5 checks passed
@nicotsx nicotsx deleted the refactor/short-ids-api-contract branch February 19, 2026 19:08
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.

1 participant