Architecture
System Overview
Multi-tenant AI interview platform architecture with event-driven microservices.
The AI Interview System is an event-driven, multi-tenant platform. At its core is a NestJS API gateway that orchestrates three subsystems: the Agno Python agents for AI reasoning, the Vert.x WebSocket edge for real-time interview audio, and the HITL workflow engine for human oversight.
Architecture Layers
| Layer | Technology | Responsibility |
|---|---|---|
| API Gateway | NestJS 10 + TypeScript | REST/A2A endpoints, JWT/API-key auth, multi-tenant routing |
| Agno Agents | Python + Agno framework | Skill validation, plan generation, real-time interview, assessment |
| WebSocket Edge | Vert.x (JVM) | Real-time audio streaming between candidate and agent |
| Database | PostgreSQL 16 + pgvector | Interview data, workflow states, skill embeddings (RLS) |
| Event Bus | Apache Kafka | Async event streaming between all services |
| Cache | Redis 7 | Session data, rate limiting, distributed locks |
Multi-tenancy
Every database query is filtered by tenantId. Row-Level Security policies at the PostgreSQL level enforce isolation even if application code has a bug.
typescript
// Every controller extracts tenantId from the JWT
@Get()
async findAll(@TenantId() tenantId: string) {
return this.interviewService.findAll(tenantId);
}
// Every service filters by tenantId
async findAll(tenantId: string) {
return this.prisma.interview.findMany({
where: { tenantId }, // Required — never omit!
});
}Never query the database without a
tenantId filter. All services enforce this via the @TenantId() decorator and RLS policies.Kafka Event Topics
| Topic | Published By | Consumed By | Trigger |
|---|---|---|---|
| interview.info_needed | API Gateway | Notification Service | Data validation fails |
| skill.validation.requested | API Gateway | Agno Planner Agent | Data complete / info completed |
| plan.generated | Agno Agent | Workflow Engine | Plan generation complete |
| approval.approved | API Gateway | Candidate Access | Recruiter approves plan |
| approval.rejected | API Gateway | Agno Agent | Recruiter rejects plan |
| interview.completed | Vert.x Edge | Agno Assessor Agent | Interview session ends |
| assessment.completed | Agno Agent | Workflow Engine | AI assessment ready |
Service Ports
| Service | Port | Protocol |
|---|---|---|
| API Gateway (NestJS) | 3009 | HTTP/REST + Kafka |
| Agno Agents (Python) | 8000 | HTTP + Kafka |
| WebSocket Edge (Vert.x) | 8080 | WebSocket |
| PostgreSQL | 5432 | TCP |
| Kafka | 9092 | TCP |
| Redis | 6379 | TCP |
Interview Data Flow
1. Plan Generation
text
External System
│
▼
POST /api/v1/a2a/interview (API Gateway)
│
├── Validate data completeness
│
├── Save to PostgreSQL (state: RECEIVED → VALIDATING_SKILLS)
│
└── Publish: skill.validation.requested (Kafka)
│
▼
Agno Planner Agent (Python)
│
├── Validate skills via pgvector similarity search
├── Generate interview plan using Claude/GPT
└── Publish: plan.generated (Kafka)
│
▼
API Gateway consumes → state: PENDING
│
└── Send webhook: interview.plan_generated2. Live Interview
text
Candidate Browser
│
├── GET /candidate-access/:token/info
├── POST /candidate-access/:token/request-otp
├── POST /candidate-access/:token/verify-otp → session token
└── POST /candidate-access/:token/start → sessionId
│
▼
WebSocket: ws://localhost:8080 (Vert.x Edge)
│
├── Audio chunks: candidate voice (16kHz PCM)
├── Kafka: video.candidate.stream (30s WebM chunks)
│
└── Agno Interview Agent:
├── Transcribe candidate speech
├── Generate agent responses
└── Synthesize TTS audio → candidate browserPermissions
| Permission | Roles | Description |
|---|---|---|
| interview:create | ADMIN, RECRUITER | Create new interviews via A2A or internal API |
| interview:read | ADMIN, RECRUITER, VIEWER | Read interview details and status |
| interview:update | ADMIN, RECRUITER | Update interview data (HITL completion) |
| interview:approve | ADMIN, RECRUITER | Approve/reject plans and assessments |
| interview:delete | ADMIN | Delete interview records |
Was this page helpful?