Skip to main content

Frontend Architecture

The frontend is a Next.js 16 application using the App Router, Apollo Client for GraphQL, custom TW* components with Tailwind CSS v4, and Zustand for client-side state.

Route Groups

The app/ directory uses Next.js route groups to segment by access level:

Route GroupPathPurpose
(visitor)/about, /jobs, /pricing, etc.Public pages, no auth
(shared)/userprofile, /cvbuilderAuthenticated, role-agnostic
company/company/*Employer-only (requires selectedCompanyId)
jobseeker/jobseeker/*Job seeker pages
auth/auth/signin, /auth/signupAuthentication flows
onboarding/onboarding/*First-time user setup
admin/admin/*Super admin dashboard

Provider Hierarchy

Providers are nested in app/providers.tsx. Order matters -- each layer depends on those above it:

info

WebSocketProvider is initialized with autoConnect={false}. Components that need WebSocket must call connect() explicitly.

State Management

LayerToolScope
Server cacheApollo Client (cache-and-network)GraphQL query results
Auth stateReact Context (UserAuthProvider)JWT, user profile, role
Page settingsZustand (usePageStore)View mode, pagination, field visibility
Modal stateReact Context (ModalContext)Global modal open/close
ThemeReact Context (ColorThemeProvider)CSS variable injection

Zustand Store (lib/pageStore.ts)

Persists page-specific preferences in localStorage under key aiqlick-page-store. State is keyed by userId:pathname so each user gets independent settings per page.

Stored settings include: view mode (grid/list/table), pagination offsets, field visibility toggles, and sort preferences.

Path Aliases

Configured in tsconfig.json. Key mappings:

AliasMaps toAliasMaps to
@/*./ (root)@graphql/*./graphql/operations/*
@components/*./components/*@apollo/*./graphql/apollo/*
@hooks/*./lib/hooks/*@utils/*./lib/utils/*
@ux/*./components/ux/*@reusable/*./components/reusable/*
@contexts/*./contexts/*@config/*./lib/config/*

Build Pipeline

ModeBundlerCommand
DevelopmentTurbopacknpm run dev (port 4000)
ProductionWebpacknpm run build

Layout Pattern

The app uses a flex-based overflow model to prevent double-scrollbar issues:

Environment Variables

VariablePurpose
NEXT_PUBLIC_API_URLBackend GraphQL endpoint (also AI gateway HTTP + voice WS path)
NEXT_PUBLIC_GRAPHQL_WS_URLBackend GraphQL subscriptions (also subscribeAi for AI streaming)
NEXT_PUBLIC_IMAGE_BASE_URLS3/CloudFront storage URL
NEXT_PUBLIC_APP_URLApp base URL (metadata, redirects)

Apollo Client Configuration

Defined in graphql/apollo/apolloClient.ts. The client uses a six-link chain:

authLink --> logLink (dev only) --> errorLink --> split(uploadLink | retryLink --> httpLink)
LinkPurpose
authLinkReads the JWT from localStorage and attaches it as Authorization: Bearer <token>
logLinkLogs GraphQL operation names and durations in development mode
errorLinkCatches 401 / UNAUTHENTICATED errors and redirects to /auth/signin with token cleanup
uploadLinkCustom multipart/form-data link for file uploads; bypasses retry to avoid timeout on large files
retryLinkRetries failed requests with exponential backoff
httpLinkStandard HTTP transport to the backend GraphQL endpoint
SettingValue
Timeout90 seconds (APOLLO_TIMEOUT)
Default fetch policycache-and-network
Auth error redirect/auth/signin

Authentication Flow

  1. User submits credentials via the signIn mutation.
  2. JWT token is stored in localStorage.
  3. authLink attaches the token to every subsequent GraphQL request.
  4. A 5-hour inactivity timer triggers automatic logout.
  5. On 401 or UNAUTHENTICATED error, errorLink clears the token and redirects to sign-in.

GraphQL Operations

Operations are organized into 34+ feature directories under graphql/operations/:

graphql/operations/
admin/ ai/ aiAgent/ badge/
billingConfig/ buzzfeed/ candidate/ collaboratingPartners/
companies/ contacts/ credit/ cv/
dashboard/ interview/ job/ jobSeekerInvitations/
meetingInsights/ messaging/ notification/ payment/
pipeline/ promo-code/ role/ schema/
sharelist/ skills/ talentPool/ talents/
types/ user/ ...

Each directory contains queries, mutations, and subscriptions specific to that feature. Reusable fragments are centralized in graphql/operations/schema/ by entity (USER_FIELDS, COMPANY_FIELDS, JOB_FIELDS, TALENT_FIELDS, CANDIDATE_FIELDS, CV_FIELDS, etc.).

AI Operations via the NestJS Gateway

The frontend has no direct connection to background-tasks. Every AI operation (CV extraction, job parsing, agent chat, voice, document processing, etc.) routes through the NestJS gateway over the same Apollo client + WebSocket connection used by the rest of the backend. Three GraphQL roots cover everything:

RootUsed for
subscribeAi(input: AiInput!)All streaming AI operations (10 ops registered server-side)
queryAi(input: AiHttpInput!)All AI HTTP queries (agent CRUD, conversation list, tool definitions, …)
mutateAi(input: AiHttpInput!)All AI HTTP mutations

Helpers in lib/ai/aiGateway.ts (subscribeAiOp, aiGatewayRequest) absorb the envelope-unwrap boilerplate so each AI hook stays small. See NestJS AI Gateway for the full architecture, the operation registries, and how to add a new AI operation.

Deployment

Deployed via AWS Amplify with auto-build on push:

BranchStageDomain
devDevelopmentdev.aiqlick.com
mainProductionwww.aiqlick.com

Secrets are fetched from AWS Secrets Manager during the Amplify preBuild phase via scripts/fetch-amplify-secrets.sh.