lablup / lablup/backend.ai-webui
Settle how the loader behaves before backend-ai-connected, and where it reads project/user from
- Dominant language
- TypeScript
- Stars
- 133
- Forks
- 81
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 355
Description
## Question
A router loader runs outside React, so it cannot read React context or (safely) jotai. Two concrete consequences need deciding before the prototype.
**1. The cold-boot gate.** `RelayEnvironment.ts` awaits `globalThis.backendaiclient` via the `backend-ai-connected` event before any request leaves. On a cold entry to `/session` the loader runs while the client may not exist yet. Decide:
- Does the loader fire `loadQuery` anyway and let the network layer's existing wait absorb it, or does it detect "not connected" and return nothing, letting the page fall back to its in-render path?
- If it returns nothing, what does the page do — keep a `useLazyLoadQuery` fallback, or `useQueryLoader` with a null initial ref plus an effect? Two code paths for the same data is a maintenance cost; say whether that cost is accepted and why.
- Is cold boot even worth optimising here, or is the honest answer "in-app navigation only, cold boot unchanged"?
**2. Where the loader reads project and user.** `scopeId` is `project:${currentProject.id`} and the filter carries the current user uuid. Decide where the loader gets them and what happens on a project switch — a wrong `scopeId` does not fail loudly, it silently shows another project's sessions.
**Deliverable**: a decision per bullet, with the failure mode each choice accepts.
Map: FR-3636.
----
## Amendment (2026-08-23, after FR-3639 resolved)
**Part 2 is largely solved — verify and adopt rather than re-derive.**
The worry was that `scopeId` needs a project **UUID** while the URL carries only `:projectName`, and that the name→id resolution runs through `useAccessibleProjects` → `useLazyLoadQuery` → an effect in `ProjectScopeLayout` — all after a synchronous loader. That would have made the loader preload the _previous_ project's sessions on a project switch.
It does not. `react/src/helper/loginSessionAuth.ts:131-137` builds a synchronous name→UUID map at login:
```
const groupMap: Record = {};
groups.forEach((element: any) => { groupMap[element.name] = element.id; });
(globalThis as any).backendaiclient.groupIds = groupMap;
```
It maps **every** group returned by `group.list(...)` — the `userGroupIds.includes(...)` filter just above applies to `backendaiclient.groups` (the sorted _name_ array), not to `groupIds`. And `current_group_id()` is itself `groupIds[current_group]` (`:146-150`). So the loader reads `globalThis.backendaiclient.groupIds[params.projectName]` and gets the right UUID for an arbitrary URL project, with no jotai read and no divergence window.
What is left on part 2:
- **Confirm the MODEL_STORE gap.** `useAccessibleProjects.tsx:34-38` says the login-time list "only contains GENERAL-type projects". That is about `backendaiclient.groups`; whether `group.list(true, false, …)` puts MODEL_STORE groups into `groupIds` was not verified. Check it.
- **Decide the miss behaviour.** `if (!projectId) return null` is safe (the page owns that fetch) but silent. Loud vs silent is a product call.
- **Decide the freshness question.** `groupIds` is built once at login. A project created or renamed mid-session is not in it. The same guard covers it; say so explicitly.
**Part 1 (the cold-boot gate) is unchanged, with two constraints added from FR-3639:**
- The loader must **never return** `undefined` and never throw — `loaderData[id]` stays undefined, `isMissingData` is permanently true, `shouldRevalidate` is never consulted again, and every nuqs param set re-fetches. Silent, and invisible locally. Return `null`.
- But `null` **pins**: it is not `undefined`, so `isMissingData` is false, `shouldRevalidate` returns false, and the route stays at `null` until the user leaves and re-enters. `shouldRevalidate`'s argument object carries no `loaderData`, so the guard cannot see this. The page must own the recovery outright — the loader will not get a second chance on that route instance. Decide the page-side path with that as a hard fact, not a fallback.
JIRA Issue: FR-3641
Contributor guide
No contributing guide indexed for this repository
Research direction
Read RelayEnvironment.ts and the loader path first, then inspect loginSessionAuth.ts:131-150, useAccessibleProjects.tsx:34-38, and ProjectScopeLayout. Verify whether group.list includes MODEL_STORE groups in groupIds and document decisions for the cold-boot gate, project miss and freshness behavior, and page recovery, including each accepted failure mode.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100