Phase 6 — Advanced Analytics & Platform Hardening
Goal: Reporting, custom branding, API access tier, and operational hardening.
6.1 Backend — Analytics Endpoints
All gated by org.featureSnapshot.advancedAnalytics.
GET /v1/analytics/pipeline-funnel?jobId=:id — stage drop-off rates
GET /v1/analytics/time-to-hire?jobId=:id — avg days per stage
GET /v1/analytics/question-effectiveness — screening question pass/fail correlation
GET /v1/analytics/interviewer-activity — interviews conducted per recruiterGate: if (!org.featureSnapshot.advancedAnalytics) return res.status(403).json({...})
6.2 Backend — Custom Branding
Organization.brandingConfig (added to Organization model):
typescript
brandingConfig?: {
primaryColor: string;
logoUrl: string;
emailFooterText: string;
candidatePortalDomain?: string; // custom domain support
};Candidate-facing emails and session pages (screening, DSA, AI sessions) read brandingConfig from the org. Custom colors applied via CSS variables — no per-org frontend builds.
Gate: org.featureSnapshot.customBranding
6.3 Backend — Rate Limiting & Operational Hardening
- Rate limiting:
express-rate-limiton token-gated public endpoints (screening, DSA) — 60 req/min per IP - Request ID tracing:
x-request-idmiddleware on all requests for log correlation - AI evaluation queue: Move inline-async AI eval calls to BullMQ + Redis job queue for reliability (survives server restart)
- Health check:
GET /healthreturning{ status: 'ok', db: 'connected', queue: { depth: n } }
BullMQ Migration for AI Evaluation
typescript
// screeningEvaluationService.ts: instead of inline async call
await evaluationQueue.add('evaluate-screening', { interviewId: interview._id });
// evaluationWorker.ts: BullMQ worker processes jobs
evaluationQueue.process('evaluate-screening', async (job) => {
const { interviewId } = job.data;
await runScreeningEvaluation(interviewId);
});6.4 Frontend — Analytics Dashboard
Route: /analytics
src/pages/recruiter/Analytics.tsx:
- Pipeline funnel chart (per-stage conversion rates)
- Time-to-hire breakdown
- Gated by
featureSnapshot.advancedAnalytics— show upgrade prompt iffalse
6.5 Frontend — Candidate Portal Branding
Load Organization.brandingConfig at session start for public session pages. Apply via CSS variables:
css
:root {
--brand-primary: v-bind(brandingConfig.primaryColor);
}No per-org frontend builds required.
Phase 6 — Acceptance Criteria
- [ ] Analytics endpoints return 403 for orgs on plans without
advancedAnalytics: true - [ ] Candidate-facing session pages show org logo + brand color when set
- [ ] Screening session endpoint rate-limited to 60 req/min per IP
- [ ] AI evaluation queued via BullMQ — survives server restart without lost jobs
- [ ] Health check returns 200 with DB + queue status
- [ ]
x-request-idheader present on all API responses for log tracing