Data Flow
This page describes how data moves between AIQLick's services, covering API communication, database access patterns, real-time streaming connections, and the billing pipeline.
Frontend to Backend
The frontend communicates with the backend exclusively through GraphQL over HTTP and WebSocket.
- Protocol: GraphQL queries and mutations over HTTPS (
POST /graphql); subscriptions over WebSocket using thegraphql-wsprotocol. - Authentication: JWT token sent in the
Authorization: Bearer {token}header. Tokens are stored inlocalStorageon the client. - File uploads: Multipart/form-data via a custom upload link that bypasses retry logic to avoid re-uploading on timeout.
- Timeout: 90 seconds per operation (
APOLLO_TIMEOUT). - Caching: Default fetch policy is
cache-and-network. - Error handling: Authentication failures (401,
UNAUTHENTICATED) trigger an automatic redirect to/auth/signin.
Frontend to Background Tasks
The frontend connects directly to background-tasks for AI operations, bypassing the backend entirely. This is configured through separate environment variables:
NEXT_PUBLIC_API_URL-- backend HTTP endpoint, also used for AI gateway HTTP (queryAi/mutateAi) and voice WS.NEXT_PUBLIC_GRAPHQL_WS_URL-- backend WS endpoint, also used for AI streaming (subscribeAi).- Auth: The same JWT token is passed via the
Authorizationheader on HTTP and viaconnectionParamson the WebSocket connection. AI traffic flows through the NestJS AI gateway, which mints a separate internal-service JWT for the upstream call to background-tasks; the frontend never sees that token.
Streaming Subscriptions
AI operations stream typed progress events back to the frontend in real time:
| Subscription | Purpose |
|---|---|
cvExtraction | CV parsing with structured data extraction |
faceExtraction | Face detection from CV documents |
jobParsing | Job description analysis |
candidateJobMatching / userJobMatching | Live matching score calculation |
agentChat | Streaming AI agent responses (emits ChatProcessing, ChatContextLoaded, ChatChunk, ChatToolCall, ChatToolResult, ChatComplete, ChatError) |
meetingInsight | AI-generated meeting analysis |
textRewrite | AI text rewriting |
Backend and Background Tasks (Shared Database)
The backend and background-tasks share the same PostgreSQL database instance per environment. This is the primary integration point between the two services.
- Schema ownership: The Prisma schema in
aiqlick-backend/prisma/schema.prismais the single source of truth (135 models). All migrations and schema changes originate here. - Backend access: Uses Prisma 6 ORM with full type safety and relation loading.
- Background-tasks access: Uses raw AsyncPG queries against the same tables. There is no ORM layer; SQL is written directly.
- Coordination: Both services read and write to shared tables. For example, the backend creates
Meetingrecords while background-tasks writesTranscriptionrows andMeetingInsightanalysis for the same meeting. - Event signaling: Redis pub/sub is used for real-time coordination when database polling is insufficient.
There are no direct API calls between the backend and background-tasks. All data sharing happens through the database and Redis.
Jigasi to Background Tasks
The custom Jigasi fork streams audio from Jitsi meetings to background-tasks for real-time transcription.
- Transport: WebSocket connection to
wss://ai.aiqlick.com/transcription/ws. - Audio format: Binary PCM frames (16kHz, 16-bit, mono).
- Processing: Background-tasks forwards the audio to AWS Transcribe for speech-to-text conversion and writes
Transcriptionrecords to the database. - Result delivery: Transcription segments are stored in PostgreSQL and available to the frontend through GraphQL queries.
Jitsi Events to Background Tasks
Prosody (the XMPP server in the Jitsi stack) sends webhook notifications to background-tasks when meeting lifecycle events occur.
- Endpoints:
POST /api/events/room/createdandPOST /api/events/room/destroyed - Events: Room creation, participant join/leave, room destruction.
- Trigger: When a meeting ends, background-tasks automatically generates a
MeetingInsightfrom the accumulated transcription data using AWS Bedrock.
Billing Data Flow
Credit-based billing spans both the backend and background-tasks:
- The backend handles Stripe webhook events (subscription changes, pack purchases, refunds) and adjusts credit balances accordingly. Plan limits are enforced by the
@CheckPlanLimitguard. - Background-tasks checks credit availability before each AI operation (
BillingGate.pre_check()) and deducts credits after completion (BillingGate.check_and_consume()). Every operation is logged toAIOperationLogwith token counts and credit cost. - Credit routing depends on the user's current mode:
EMPLOYERwith aselectedCompanyIdcharges the company balance;JOB_SEEKERmode charges the personal user balance. - Credit transfers: Pack purchases land in the user's personal balance. Billing owners transfer credits to company balances via the
transferCreditsmutation. - Enterprise (POSTPAID): For enterprise companies, the
BillingGatebypasses credit checks and logs usage toAIOperationLogwithout deduction. A monthly cron generates Stripe invoices from aggregated usage. Overdue invoices block platform access until paid.