Skip to content

GraphQL PoC [DO NOT MERGE]#8232

Draft
kruulik wants to merge 11 commits into
mainfrom
graphql-poc-apollo
Draft

GraphQL PoC [DO NOT MERGE]#8232
kruulik wants to merge 11 commits into
mainfrom
graphql-poc-apollo

Conversation

@kruulik
Copy link
Copy Markdown
Contributor

@kruulik kruulik commented May 19, 2026

Summary

Draft / PoC.

Wires the home dashboard at / to GraphQL via Apollo Client, consuming the Strawberry endpoint from this fidesplus PR.

  • One combined DashboardOverview query for the six static cards, with @defer on agentBriefing so the dashboard paints on the first multipart chunk and the LLM-backed briefing banner arrives in a second chunk.
  • priorityActions and activityFeed keep their own per-card queries — their interactive variables (dimension filter, infinite-scroll pagination) would force the combined query to refetch on every change.
  • Drop-in adapter hooks: every existing card changed by exactly one import line. dashboard.slice.ts is kept (mutations stay on RTK).

Run it

Against the real backend (fidesplus on the paired branch must be running):

cd clients/admin-ui && npm run dev

Mocks only, no backend required:

cd clients/admin-ui && npm run dev:mock-graphql

Open http://localhost:3000/ — dashboard is GraphQL-backed under the alphaDashboard feature flag.

Regen typed documents after SDL changes

cd clients/admin-ui && npm run graphql:generate

Run this after nox -s graphql_emit_schema on the paired backend branch.

Paired backend

ethyca/fidesplus#3618.

🤖 Generated with Claude Code

kruulik and others added 7 commits May 15, 2026 01:29
Adds a /dashboard-graphql variant that fetches all dashboard data via a
single GraphQL query through @apollo/client. The existing dashboard at
/ is untouched.

- codegen.ts with client-preset, reading schema.graphql
- scripts/sync-graphql-sdl.mjs syncs SDL into a TS constant for the mock
  layer so the loader config is bundler-agnostic
- MSW handler intercepts POST /graphql with @graphql-tools/mock when
  NEXT_PUBLIC_MOCK_GRAPHQL=true; toggle is independent of NEXT_PUBLIC_MOCK_API
- ApolloProvider sits next to the Redux Provider in _app.tsx; auth link
  reads the redux token and applies addCommonHeaders, matching RTK Query
- Paired with fidesplus graphql-poc-be@104cba76c

Local PoC branch — do not push.
The Strawberry endpoint is mounted at /graphql, outside the /api/v1
prefix the existing rewrites cover, so against the real backend the
client's POST /graphql would 404 on the Next dev server. Add a rewrite
mirroring the existing /health one. Mock mode is unaffected — MSW
intercepts /graphql before the rewrite.

Local PoC branch — do not push.
ProtectedRoute redirects to / when useNav finds no active match for the
path. Add the variant route to NAV_CONFIG as hidden (reachable by URL,
not shown in the sidebar) so the PoC page is accessible.

Local PoC branch — do not push.
NEXT_PUBLIC_FIDESCTL_API is /api/v1 in local dev (not empty as the
client assumed), so the prior URI resolved to /api/v1/graphql and 404'd
against the backend, which mounts GraphQL at the app root /graphql. Use
the relative /graphql path so the Next rewrite proxies it to the backend
and MSW still intercepts it in mock mode.

Local PoC branch — do not push.
The dashboard at / now fetches through Apollo. Per-card queries (not one
combined query) to preserve independent auth failure and progressive
per-card loading, matching REST behaviour and the LLM-backed agent
briefing's latency.

- src/features/dashboard-graphql/queries.graphql: 8 per-card operations
- src/features/dashboard-graphql/hooks.ts: drop-in replacements with the
  exact RTK hook names/signatures/return shapes, mapping camelCase gql
  responses onto the existing snake_case ~/features/dashboard/types so
  each card changes only its import path
- 9 one-line import swaps in src/home/*
- ApolloProvider moved into _app.tsx (inside Redux Provider) so the home
  dashboard subtree has it
- deleted pages/dashboard-graphql.tsx + DashboardGraphqlView + the
  hidden nav entry; removed the monolithic dashboard.graphql
- dashboard.slice.ts kept (update mutation stays on RTK)

Local PoC branch — do not push.
The drop-in hooks rebuilt the mapped object every render, giving `data`
a new reference each time. useInfiniteActivityFeed keys a setState
effect on `data`, so it re-fired every render -> "Maximum update depth
exceeded". Memoize each mapping on the raw query data (Apollo keeps a
stable data ref until the result changes) so consumers see a stable
identity.

Local PoC branch — do not push.
Folds the six static dashboard cards (posture, trends, system coverage,
privacy requests, astralis, agent briefing) into one combined query and
defers agentBriefing — the slow LLM-backed field — so the dashboard
paints on the first multipart chunk and the briefing banner arrives in
a second chunk.

priorityActions and activityFeed keep their own per-card queries; their
interactive variables (dimension filter, infinite-scroll pagination)
would otherwise force the whole combined query to refetch on every
filter change or "load more".

Apollo's HTTP link auto-negotiates multipart/mixed — no client config
change. Apollo deduplicates concurrent useQuery(DashboardOverviewDocument)
calls with identical variables into a single network request, so the six
static drop-in hooks all share one POST.

Requires the BE bump to strawberry-graphql 0.315.5 with
enable_experimental_incremental_execution=True (paired commit on
fidesplus graphql-poc-be).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment May 20, 2026 6:19pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored May 20, 2026 6:19pm

Request Review

@kruulik kruulik changed the title Dashboard GraphQL PoC — Apollo Client with @defer GraphQL PoC [DO NOT MERGE] May 19, 2026
@kruulik kruulik added the do not merge Please don't merge yet, bad things will happen if you do label May 19, 2026
# Conflicts:
#	clients/admin-ui/package.json
#	clients/admin-ui/src/pages/_app.tsx
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
See the Details below.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 9606e56.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

  • clients/admin-ui/package.json
  • clients/package-lock.json

kruulik and others added 2 commits May 19, 2026 00:27
Decisions live in the separate decisions doc; this file mostly duplicated
that and held conversation-style context that isn't useful to readers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Run prettier --write on graphql codegen output and schema files to
satisfy the admin-ui format:ci check. No behavior changes; only
quote style and line-wrap adjustments to auto-generated files
(schema.graphql, src/__generated__/graphql/*, schema-string.ts).
Copy link
Copy Markdown
Contributor

@galvana galvana left a comment

Choose a reason for hiding this comment

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

I've opened #8250 on top of this branch with production-readiness improvements. The paired backend PR is ethyca/fidesplus#3628. Key inline comments below.

awaitingResponse
risksIdentified
}
... @defer(label: "agentBriefing") {
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.

Try replacing @defer with a separate query. @defer requires graphql-core>=3.3.0a9 (alpha) on the backend. A separate DashboardAgentBriefing query achieves the same UX -- dashboard paints from DashboardOverview, and the slow LLM briefing arrives independently. The network cost is one additional small request vs. multipart streaming -- negligible for this use case.

Applied in #8250.

import { DashboardGraphqlProvider } from "~/features/dashboard-graphql/DashboardGraphqlProvider";

import store, { persistor } from "../app/store";
import theme from "../theme";
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.

Try scoping ApolloProvider inside ProtectedRoute. Currently wraps the entire app tree including login/forgot-password pages. This creates an Apollo client for every visitor before auth. Moving it inside ProtectedRoute means no unnecessary client instantiation on unauthenticated pages, and the auth token is guaranteed available when the client is created.

Applied in #8250.

ApolloClient,
createHttpLink,
InMemoryCache,
type NormalizedCacheObject,
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.

Try moving the endpoint under /api/v1. /graphql at the app root needs a custom Next rewrite and sits outside existing CORS/proxy/middleware rules. /api/v1/plus/graphql is covered by the existing /api/v1/:first/:second* rewrite, and inherits all backend infrastructure.

Applied in #8250.

@@ -0,0 +1,319 @@
/**
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.

Research note: is Apollo the right client for this? For read-only views with no mutations, Apollo's normalized cache provides little value -- there are no writes to propagate across views. The complexity tax of cache.modify, cache.evict, and partial cache hits may not be worth it.

RTK Query with a thin GraphQL fetcher (or TanStack Query) would be simpler for this use case and wouldn't require a second caching paradigm alongside RTK.

Source: TanStack Query vs SWR vs Apollo 2026, RTK Query Comparison

Not blocking -- just worth discussing before this ships.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Please don't merge yet, bad things will happen if you do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants