lablup / lablup/backend.ai-webui

Settle how the loader behaves before backend-ai-connected, and where it reads project/user from

Open
#8,987 0 comments 0 reactions 0 assignees View on GitHub
wayfinder:grilling
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.