MemberJunction / MemberJunction/MJ

Client TenantContext lost when metadata loaded from cache

Open
#2,163 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TSQL
Stars
29
Forks
6
Avg merge
2d 1h
Merged PRs (30d)
323

Description

## Problem

When a client (e.g., MJ Explorer) loads metadata from the local cache (IndexedDB/localStorage), `UserInfo.TenantContext` is `undefined` — even though the server middleware correctly sets it on every request.

This happens because:

1. `ProviderBase.Config()` calls `CheckToSeeIfRefreshNeeded()` which compares entity metadata timestamps
2. If metadata is fresh, `GetAllMetadata()` is skipped entirely — which means `GetCurrentUser()` never runs
3. `GetCurrentUser()` is where `GraphQLDataProvider` sends the `CurrentUserAndRoles` query, which batches `CurrentUserTenantContext`
4. Without that query, `TenantContext` is never fetched from the server

The `TenantContext` property on `UserInfo` is a non-enumerable getter/setter (intentionally hidden from `Object.keys()` for GraphQL query building). It **does** get serialized into the cache when present, but the cached value becomes stale when server-side middleware configuration changes (e.g., enabling BCSaaS tenant middleware for the first time).

## Root Cause

`CheckToSeeIfRefreshNeeded()` only compares entity/field metadata timestamps. It has no visibility into whether the `CurrentUser` object has changed due to:
- New server middleware being added (e.g., BCSaaS tenant context)
- Changes to the user's organization memberships
- Changes to the middleware's behavior

## Current Workaround

Clearing browser site data (local storage / IndexedDB) forces a full metadata refresh including `GetCurrentUser()`, which picks up the `TenantContext`.

## Potential Solutions

1. **Server-side config version stamp** — Include a hash of the active middleware/plugin set in the metadata status response (`GetDatasetStatusByName`), so any server config change triggers a cache miss
2. **Always refresh CurrentUser per session** — Call `GetCurrentUser()` once per browser session regardless of metadata cache state (lightweight — only the `CurrentUserAndRoles` query, not the full metadata dataset)
3. **Shorter TTL for CurrentUser** — Treat `CurrentUser` as having a shorter cache lifetime than entity metadata

Option 2 seems like the best balance of simplicity and correctness — `CurrentUser` is inherently session-specific data that shouldn't be cached across sessions.

## Relevant Code

- `ProviderBase.Config()`: `packages/MJCore/src/generic/providerBase.ts` ~line 1951
- `GraphQLDataProvider.GetCurrentUser()`: `packages/GraphQLDataProvider/src/graphQLDataProvider.ts` ~line 370
- `CurrentUserContextResolver`: `packages/MJServer/src/resolvers/CurrentUserContextResolver.ts`

## Reproduction Steps

1. Start an MJ server with tenant middleware enabled (e.g., BCSaaS)
2. Log into MJ Explorer — `TenantContext` is populated correctly
3. Refresh the page — metadata is loaded from cache, `TenantContext` is still present (cached value)
4. Now change the server config (e.g., enable a new middleware that modifies `TenantContext`)
5. Refresh the page — `TenantContext` shows the **old** cached value, not the new server value
6. Clear site data and refresh — `TenantContext` is now correct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.