Telente CBT
A multi-tenant exam platform — 47 relational models, timed exams, question banks, instant results — with a service-key-isolated Python AI service for question generation.
- 47
- Prisma models
- 4
- Question types
- 2
- Services (TS + Python)
- 0
- Direct client → AI calls
- Role
- Lead engineer
- Year
- 2026
- Status
- Private
- Type
- Computer-based testing platform
01Overview
Telente CBT is a computer-based testing platform for schools, colleges and universities: secure exams, instant results, analytics, engagement mechanics, and AI-assisted question generation.
It is a TypeScript/Fastify/Prisma/PostgreSQL backend owning authentication, users, courses, exams, billing and the database, plus a Python/FastAPI service owning the AI features. Forty-seven Prisma models cover the exam, school and billing domains.
The part I care most about is the boundary between those two. Clients never reach the Python service. Every AI request goes client → TypeScript backend → Python service → provider, with the internal hop protected by a service key.
02The problem
Exam software has an unusually harsh failure profile. Two hundred students start a timed exam at the same second, a dropped connection cannot cost a candidate their answers, and a result that appears twice is worse than one that appears late.
Layered on top: schools are tenants with their own classes, teachers and subject assignments, so every query is a permissions question before it is a data question.
And AI question generation — genuinely useful for teachers — is a slow, failure-prone, expensive call sitting in the middle of an otherwise fast CRUD application. It could not be allowed to share a request path with the exam engine.
03Architecture
- 01
TypeScript backend as the only public surface
Fastify with Prisma over PostgreSQL 16 and Redis 7, behind an Nginx reverse proxy. It owns auth, users, courses, exams, billing and every write to the database. Internally it is layered — routes, controllers, services, repositories, providers, events, jobs — with DTOs and templates kept separate.
- 02
Python AI service, internal only
FastAPI handling question generation, question validation, AI chat, topic explanation and the practice question bank, calling Groq by default. Reachable only from the TypeScript backend, authenticated with a service key, never exposed to clients.
- 03
Exam engine
Timed exams with per-candidate question shuffling and immediate results, across MCQ, true/false, fill-in-the-blank and essay types, plus self-paced practice sessions with instant feedback.
- 04
Multi-tenant school model
Schools, classes and teacher–subject assignments as first-class entities, with role-based access control layered over every route.
- 05
Engagement layer
Achievements, leaderboards and streaks — the retention mechanics that separate a platform students use from one they are made to use.
- 06
Operations
Docker Compose for the full stack, a Makefile for the common paths, SMTP for transactional email, and payment-provider integration for institutional billing.
04Key decisions
Two runtimes, one public API
Keeping Python entirely internal means the AI surface can be rewritten, rate-limited, cached or removed without a single client change, and no untrusted request ever reaches the model layer directly.
Prisma over raw SQL
Forty-seven models is past the size where a human reliably remembers the schema. Generated types across the whole exam and school domain caught more bugs than the query-planner control I gave up.
Redis for exam session state
Exam timing and progress live in Redis, not Postgres. It keeps hot per-second writes off the primary and out of the transactional path the results depend on.
05Stack
- TypeScript
- Fastify
- Prisma
- PostgreSQL 16
- Redis 7
- Python
- FastAPI
- Groq
- Docker
- Nginx