Skip to content
TALA
Esc
navigateopen⌘Jpreview
On this page

What's wired

55 of 74 backend routes have a frontend caller. The 19 that do not, which of them actually matter, and the contract gaps found alongside them.

Read from source on 2026-09-09 at backend@a164684 and frontend@ed55491, both on staging. backend@a164684 is still the tip; the frontend has since advanced to f2c1ead, which merges main into staging — recount before treating these numbers as current.

The one finding that matters: from the UI, every work item in the app is create-only. Nine of the 19 uncalled routes are the edit-and-delete half of projects, tasks, and comments. The backend has them; no frontend code path calls them.

Routes declared 74
Routes with a frontend caller 55
Routes with none 19

The 19

Work-item CRUD — 9 routes
GET    /api/projects/:id
PATCH  /api/projects/:id
DELETE /api/projects/:id
GET    /api/tasks/:id
PATCH  /api/tasks/:id
PATCH  /api/tasks/:id/position
DELETE /api/tasks/:id
PATCH  /api/tasks/:taskId/comments/:commentId
DELETE /api/tasks/:taskId/comments/:commentId

This is the real gap. From the UI, every work item in the app is create-only:

  • Tasks can be created and assigned, but never moved between columns, edited, or deleted.
  • Projects can be created and reordered, but not renamed or removed.
  • Comments can be posted, but not edited or removed.

All nine routes exist on the backend and carry guards. This is missing UI, not missing API.

Audit timeline — 4 routes
GET /api/timeline/user
GET /api/timeline                        ADMIN
GET /api/timeline/resource/:type/:id     ADMIN
GET /api/timeline/summary                ADMIN

The audit timeline is fully built — indexed on (action, createdAt) and (user, createdAt), with a retention cron — and entirely unsurfaced. The SPA’s /timeline route renders tasks instead.

Organization read and rename — 2 routes
GET   /api/organizations/:id
PATCH /api/organizations/:id

Org detail is read out of the list response instead. The consequence is that renaming an organization is unreachable from the UI, even for an OWNER.

Superseded and infrastructure — 4 routes
GET /health              probes only, outside the /api prefix
GET /api/seeder          superseded by the SeedPlans migration
GET /api/assets/logs     per-user variant of a route that is wired
GET /api/assets/:id      asset detail; the SPA reads assets out of the
                         collection listing instead

Expected. None of these need a frontend caller today — though GET /api/assets/:id is the natural backing for an asset detail view, and its absence is why the SPA has no way to open a single asset by ID.

Wired but unreachable

Two things pass the “has a caller” test and still do not work end to end.

getAssetVersions is never called

api/tala.ts exports it; nothing imports it. restoreAssetVersion is called from LibraryPage. So version restore ships without version listing — the UI restores a version number the user has no way to see.

Collection favourites never reach the server

useCollections.toggleFavorite writes to localStorage and returns. PATCH /api/collections/:id/favorite exists, and api/tala.ts exports favoriteCollection(). Neither is called.

Asset favourites do hit the server, so the two behave differently on a second device.

Contract inconsistencies

Where Issue
PATCH /api/assets/:id Requires collectionId in the body even though assets no longer require a collection. The SPA always sends one to work around it.
Paginated responses Carry no total or pageCount. Page numbers, a result count, and a last-page control cannot be built against the current envelope.
POST /api/upload/complete No idempotency key; a retry can duplicate an asset.

Page coverage

Page LOC State
LibraryPage 475 live
WorkspacePage 454 live
HomePage 283 live
ResetPasswordPage 246 live
LoginPage 233 live
SignUpPage 230 live
TimelinePage 211 live
VerifyEmailPage 129 live
LoadingPage 118 live
TeamsPage 73 live
ForgotPasswordPage 66 live
BillingPage 49 plans only, no billing
InvitationPage 40 live
WorkspaceDetailPage 18 thin wrapper
ProfilePage 10 stub
SettingsPage 3 placeholder copy

The counts above were read from source rather than from an existing document, because the existing documents disagree with the code in about ten places — see Documentation drift for the full list of corrections.

Was this page helpful?