Skip to content

[UI-01] React app scaffold and routing - #175

Open
loneil wants to merge 1 commit into
mainfrom
feature/ui-o1-react-app-scaffold
Open

[UI-01] React app scaffold and routing #175
loneil wants to merge 1 commit into
mainfrom
feature/ui-o1-react-app-scaffold

Conversation

@loneil

@loneil loneil commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

For #82

Adds the frontend application as apps/ui, a standalone npm package inside the monorepo with its own package.json, lockfile, and toolchain. It is not part of the root NestJS build, root ESLint config, or root Jest run.

App Details

Stack

  • React 19
  • Vite 8 with React Compiler enabled
  • TypeScript 6
    • TypeScript is 6.0 (matching the backend), not 7: typescript-eslint still stops at <6.1
  • React Router 8 (data mode)
  • Tailwind CSS 4
  • shadcn/ui (radix base)
  • TanStack Query
  • axios
  • zod
  • Vitest + Testing Library + MSW.

Routing

layout routes per the issue: public /login; auth-guarded shell (sidebar/header) wrapping /dashboard, /tenants, /tenants/:tenantId/* (tabbed layout: overview, users, connections, credentials, audit-logs, logs, settings), and /settings; plus 404 and a route error boundary. Pages are code-split via route-level lazy(). Placeholder pages reference their tracking issues in the repo (see #84#89 on parent epic).

API Client - Axios

  • Adds the bearer token to every request. On a 401 it refreshes the token once and retry (Matters because app-issued access tokens only live 5 minutes.)
  • Smooths over spec-vs-implementation gaps: errors and list responses are normalized to one shape, whether the backend returns the OpenAPI envelope or today's plainer Nest output. (The envelopes are tracked backend work - AG-06 #80. So the UI stays indifferent to when that lands.)
  • Endpoint paths live only in lib/api/resources/, when the flat routes move to the spec's nested /tenants/{id}/… form, only those files change.
  • TypeScript types come from the OpenAPI spec (npm run types:spec), not hand-written interfaces. generated, don't touch

The tenants pages use it against the real API (GET /api/v1/tenants, GET /api/v1/tenants/:id).

Auth

An AuthClient with two implementations currently flagged by VITE_AUTH_MODE
This is while Auth is work-in progress.

  • mock (default): fake session in sessionStorage; login/logout/refresh and the route guard genuinely work. Used until interactive OIDC exists.
  • oidc: real oidc-client-ts UserManager (Authorization Code + PKCE against this origin's /oidc). Dormant until AU-02 lands and an SPA client can be registered, completed by [UI-02] Login and auth integration #83 in this epic.

Same-origin by design — the Vite dev server proxies /api, /oidc, /health to the API (VITE_PROXY_TARGET, default localhost:3000), mirroring the production Caddy reverse proxy planned in #160. Every URL in the SPA is relative: no VITE_API_URL, no CORS on the API ever, one build artifact for all environments.

CI, tests, etc

Tests — 13 Vitest tests: unauthenticated redirect + mock login returning to the originally requested page, 401 single-flight refresh/retry, both error-shape normalizations, mock-auth session lifecycle, and the tenants table rendering from a bare-array response via MSW.

CI — new ui job in ci-checks.yml (Node 24, npm cache scoped to apps/ui/package-lock.json): npm ci, lint, format check, tests, build. Backend jobs untouched.

Docsapps/ui/README.md (structure + conventions), a Frontend section in docs/DEVELOPER.md, and docs/ui-bc-design-system-planning.md capturing how the interim theme maps onto BC Design System adoption (feeds #180).

Local Run
See docs above

@coveralls

coveralls commented Aug 17, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 32278629164

Coverage remained the same at 87.883%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3333
Covered Lines: 3091
Line Coverage: 92.74%
Relevant Branches: 2089
Covered Branches: 1674
Branch Coverage: 80.13%
Branches in Coverage %: Yes
Coverage Strength: 9.37 hits per line

💛 - Coveralls

@loneil
loneil force-pushed the feature/ui-o1-react-app-scaffold branch from c1dc175 to ef12bdd Compare August 19, 2026 04:27
@loneil
loneil requested a lite review from Copilot August 19, 2026 05:01
@loneil
loneil marked this pull request as ready for review August 19, 2026 05:02
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

🚀 PR Environment

URL https://pr-175-digital-trust-common-service-dev.apps.silver.devops.gov.bc.ca
Health https://pr-175-digital-trust-common-service-dev.apps.silver.devops.gov.bc.ca/health/live
Image ghcr.io/bcgov/digital-trust-common-service:pr-175
Commit 3b51ee8

Updated on every push. Torn down automatically when this PR closes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new standalone React/Vite-based admin UI application under apps/ui within the monorepo, including routing, auth scaffolding (mock + OIDC placeholder), an axios API client layer, and a dedicated UI CI job—while explicitly keeping the UI out of the root NestJS/Jest/ESLint toolchain.

Changes:

  • Introduces apps/ui as an isolated npm package (Vite + React Router + Tailwind + shadcn/ui) with its own lint/test/build pipeline.
  • Implements initial route tree (public /login, authenticated shell, tenants routes) plus placeholder pages and layouts.
  • Adds a normalized axios API client (Bearer + 401 refresh single-flight) with MSW/Vitest tests, and updates CI to run UI checks separately.

Reviewed changes

Copilot reviewed 59 out of 62 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
package.json Excludes UI from root Jest
eslint.config.mjs Excludes UI from root ESLint
docs/ui-bc-design-system-planning.md Adds BCDS alignment notes
docs/DEVELOPER.md Documents UI dev workflow
apps/ui/vite.config.ts Vite config + proxy + vitest
apps/ui/tsconfig.node.json TS config for Vite config
apps/ui/tsconfig.json TS project references
apps/ui/tsconfig.app.json TS config for app sources
apps/ui/src/test/setup.ts Vitest + MSW test setup
apps/ui/src/test/msw/server.ts MSW server bootstrap
apps/ui/src/test/msw/handlers.ts MSW tenants API handlers
apps/ui/src/routes/routes.tsx Route tree + lazy splitting
apps/ui/src/routes/routes.test.tsx Routing/auth guard tests
apps/ui/src/routes/require-auth.tsx Auth-guard layout route
apps/ui/src/pages/TenantsPage.tsx Tenants list page UI
apps/ui/src/pages/TenantsPage.test.tsx Tenants page MSW test
apps/ui/src/pages/TenantOverviewPage.tsx Tenant overview placeholder
apps/ui/src/pages/SettingsPage.tsx Settings placeholder page
apps/ui/src/pages/RouteErrorPage.tsx Router error boundary page
apps/ui/src/pages/PlaceholderPage.tsx Shared “coming soon” page
apps/ui/src/pages/NotFoundPage.tsx 404 page
apps/ui/src/pages/LoginPage.tsx Login page (mock/oidc)
apps/ui/src/pages/DashboardPage.tsx Dashboard placeholder cards
apps/ui/src/main.tsx App entry + router mount
apps/ui/src/lib/utils.ts Tailwind cn() helper
apps/ui/src/lib/env.ts Env parsing (auth mode)
apps/ui/src/lib/auth/types.ts AuthClient/AuthUser contracts
apps/ui/src/lib/auth/oidc-auth.ts OIDC auth client scaffold
apps/ui/src/lib/auth/mock-auth.ts Mock auth implementation
apps/ui/src/lib/auth/mock-auth.test.ts Mock auth tests
apps/ui/src/lib/auth/context.ts React auth context hook
apps/ui/src/lib/auth/auth-context.tsx AuthProvider wiring + seam
apps/ui/src/lib/api/types.gen.ts Generated OpenAPI types
apps/ui/src/lib/api/resources/tenants.ts Tenants resource functions
apps/ui/src/lib/api/queries/tenants.ts TanStack Query hooks
apps/ui/src/lib/api/pagination.ts List envelope normalization
apps/ui/src/lib/api/errors.ts Error shape normalization
apps/ui/src/lib/api/constants.ts API base path constant
apps/ui/src/lib/api/client.ts Axios client + refresh logic
apps/ui/src/lib/api/client.test.ts Client interceptor tests
apps/ui/src/layouts/TenantLayout.tsx Tenant tabbed layout
apps/ui/src/layouts/RootLayout.tsx App providers layout
apps/ui/src/layouts/AppShell.tsx Sidebar/header shell layout
apps/ui/src/index.css Tailwind + shadcn theme tokens
apps/ui/src/components/ui/table.tsx shadcn table primitive
apps/ui/src/components/ui/skeleton.tsx shadcn skeleton primitive
apps/ui/src/components/ui/separator.tsx shadcn separator primitive
apps/ui/src/components/ui/label.tsx shadcn label primitive
apps/ui/src/components/ui/input.tsx shadcn input primitive
apps/ui/src/components/ui/dropdown-menu.tsx shadcn dropdown primitive
apps/ui/src/components/ui/card.tsx shadcn card primitive
apps/ui/src/components/ui/button.tsx shadcn button primitive
apps/ui/src/components/ui/badge.tsx shadcn badge primitive
apps/ui/src/components/ui/avatar.tsx shadcn avatar primitive
apps/ui/README.md UI package docs/conventions
apps/ui/package.json UI deps/scripts/toolchain
apps/ui/index.html Vite HTML entry
apps/ui/eslint.config.mjs UI ESLint flat config
apps/ui/components.json shadcn CLI config
apps/ui/.env.example UI env example (proxy/auth)
.github/workflows/ci-checks.yml Adds dedicated ui CI job

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/ui/src/lib/auth/oidc-auth.ts
Comment thread apps/ui/src/layouts/AppShell.tsx Outdated
Comment thread apps/ui/src/routes/routes.tsx
@loneil
loneil force-pushed the feature/ui-o1-react-app-scaffold branch from 54e9a2f to ae63216 Compare August 19, 2026 05:30
@loneil
loneil requested a balanced review from Copilot August 19, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 62 out of 65 changed files in this pull request and generated no new comments.

Suppressed comments (4)

apps/ui/src/routes/require-auth.tsx:15

  • The guard claims to preserve the intended URL, but this drops fragment identifiers, so a protected deep link such as /tenants/123#details returns to /tenants/123 after sign-in. Preserve location.hash as well.
    docs/ui-bc-design-system-planning.md:6
  • This is already scheduled as issue #180, which is linked from this PR and blocked by #82, so describing it as a candidate issue is outdated. Point readers to the existing tracker.
    apps/ui/README.md:69
  • The root Jest config now explicitly ignores apps/ui (package.json:93-97), so it will not pick up *.spec.ts files here. Keep the naming convention, but avoid documenting a reason contradicted by this PR's configuration.
- Test files are `*.test.ts(x)` (never `*.spec.ts` — the root Jest config would
  pick those up).

apps/ui/src/lib/api/client.ts:54

  • When a refresh succeeds but the retried request is still unauthorized, every concurrent retried request reaches this branch and calls onAuthFailure. In OIDC mode that can launch multiple competing sign-out redirects, despite the single-flight guarantee documented below. Route both refresh failure and post-retry 401s through one shared auth-failure operation (reset when auth state changes).
  if (!config || config._retried) {
    authHandlers.onAuthFailure();

@jamshale jamshale left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you knew what you were doing 👍 I didn't go over every component in detail... I know we are waiting to have the logout merged, but it would be nice to have the app land on the login instead of hello world even if login is disabled.

That, and some screenshots of what some of the pages look like without needing to pull the branch and set everything up would be nice.

Looks well done though so I'll approve.

@PatStLouis

Copy link
Copy Markdown
Contributor

Follow-ups from review, filed so they aren't lost on merge:

Signed-off-by: Lucas ONeil <lucasoneil@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants