Frontend: runtime ConfigContext, provider-aware AuthContext, OpenAI/AOAI model components

The browser bundle is now tenant-portable. Auth provider, Entra IDs, and feature flags come from `GET /config` at startup rather than being baked into the build - so one image can serve Supabase, local, and Entra deployments without a rebuild per customer.

multi-tenantinfrastructure

Maintained by Allen Morgan · verified on MikeWatch

contexts/ConfigContext.tsx fetches /config on mount and exposes useConfig(). It also exports getCachedAuthProvider(), a module-level function that reads the last fetched value from localStorage - this lets helpers outside React components answer "what auth mode am I in" without needing a context ref. The localStorage fallback prevents a blank-flash on hot reload during development.

AuthContext.tsx branches on the resolved provider. Supabase mode works as before. Local mode reads a JWT from localStorage. Entra mode reads from a hash fragment after the OIDC callback. Sign-out routes through GET /api/auth/logout in all three cases rather than constructing the Microsoft logout URL in the browser. The Supabase client construction is now lazy - a getSupabaseClient() factory that throws with a clear message in non-supabase deployments, instead of the previous pattern of constructing against placeholder env vars and failing silently later.

lib/auth-token.ts centralizes bearer token retrieval. Every component that used to call supabase.auth.getSession() now calls getBrowserAccessToken(), and responses go through bounceIfUnauthorized() which redirects to the login page on 401.

The second commit converts dynamic-segment routes ([id], [chatId], [reviewId]) to SSR shells that delegate to client components reading useParams() at runtime. This is a requirement of Next.js output: "export" - server-baked params resolve to the placeholder _ in a static export, so the parameter has to be read client-side. The Account → Models page adds OpenAI key field, an Azure OpenAI settings section (endpoint, API key, API version), and a deployment dropdown that queries /api/llm/azure-openai/deployments. AOAI model entries use the pattern aoai:<deploymentName> as the ID, matching the backend's model routing.

So what The lazy Supabase client and the `auth-token.ts` abstraction are decent patterns regardless of whether you need the provider story - they clean up a scattered pattern of `supabase.auth.getSession()` calls across components. The SSR-shell conversion and ConfigContext are only relevant if you want `output: "export"` or runtime-configurable auth. The AOAI components pair with the backend LLM additions and are only useful if you're pulling those too.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from Altien/mikeOssAzure, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
948ff2c4 feat(frontend): runtime ConfigContext + provider-aware AuthContext Allen Morgan 2026-05-08 ↗ GitHub
commit body
Frontend half of the auth-boundary work.  The browser bundle is now
tenant-portable: the same image ships everywhere and reads its
deployment-mode configuration from /config at startup.

  * contexts/ConfigContext.tsx  - fetches /config on mount, exposes
                                  useConfig() and getCachedAuthProvider()
                                  so module-level helpers can answer
                                  "what mode are we in" without holding
                                  a React context.  Persists to
                                  localStorage so a hot reload doesn't
                                  blank-flash the supabase login page on
                                  an entra deployment.

  * contexts/AuthContext.tsx    - now branches on the resolved provider
                                  (supabase / local / entra) and routes
                                  sign-out through the new GET
                                  /api/auth/logout server endpoint
                                  rather than constructing the Microsoft
                                  logout URL in the browser.

  * lib/supabase.ts             - lazy getSupabaseClient() factory.
                                  Throws a clear error in non-supabase
                                  deployments rather than constructing
                                  a client against placeholder env
                                  vars.  Same treatment for
                                  supabase-server.ts and lib/auth.ts -
                                  helpers gracefully return null /
                                  skip when env vars are absent
                                  instead of asserting on placeholders.

  * lib/auth-token.ts           - central browser token retrieval that
                                  picks the right source (supabase
                                  session / local-mode hash / entra
                                  hash) based on cached provider.
                                  bounceIfUnauthorized() shared by every
                                  data-fetch hook.

  * components/providers.tsx    - wraps app shell with ConfigProvider
                                  outside AuthProvider so auth bootstrap
                                  can read from runtime config.

  * Consumers migrated off the old `supabase` named export to the
    lazy factory: contexts/UserProfileContext, app/lib/mikeApi,
    app/components/{assistant,shared}/*, app/hooks/*,
    app/login + signup pages.  All routes auth their requests through
    auth-token's getBrowserAccessToken() so provider mode is invisible
    to the call sites.
0c5fc8da feat(frontend): SSR shells, account/models, AOAI-aware components Allen Morgan 2026-05-08 ↗ GitHub
commit body
Pages and components that interact with the new auth + LLM boundaries.

  * Page components for the dynamic-segment routes are now SSR shells
    that delegate to client components reading the URL at runtime.
    Required by Next.js `output: "export"` - server-baked params
    resolve to the placeholder "_" regardless of the URL, so the
    runtime-shape lookup has to happen client-side.  Affects:
      - assistant/chat/[id]
      - projects/[id]
      - projects/[id]/assistant/chat/[chatId]
      - projects/[id]/tabular-reviews/[reviewId]
      - tabular-reviews/[id]
      - workflows/[id]
    Each gains a sibling *Client.tsx that holds the interactive logic.

  * Account → Models page                - surfaces OpenAI + Azure
                                           OpenAI alongside Anthropic /
                                           Google.  AOAI deployment
                                           dropdown queries
                                           /api/llm/azure-openai/deployments
                                           against the user's stored
                                           AOAI endpoint.

  * Account page                         - provider-aware header (entra
                                           hides supabase-only controls).

  * Assistant chat input + model toggle  - ApiKeyAvailability now
                                           includes openaiApiKey and
                                           azureOpenai availability so
                                           the model dropdown lights up
                                           the right options.

  * Tabular review components             - same boundary updates for
                                           the tabular chat panel.

  * /diagnostics/route/[id]              - dev-only client page that
                                           introspects how the static-
                                           export shell maps to the
                                           current URL; used while
                                           debugging the SSR shell
                                           pattern.

  * app/lib/modelAvailability.ts         - adds openaiApiKey +
                                           azureOpenai branches.

  * app/page.tsx                         - provider-aware redirect
                                           between supabase and entra
                                           login flows.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-200.md from inside the repo you want the changes in.

⬇ Download capture-thread-200.md