Dialogue LMS is a custom learning platform for Dialogue Dil Okulları that runs the school's commercial funnel and its classroom delivery in the same system — including a synchronised digital coursebook that every student in a live lesson sees turn, zoom and get annotated in real time.
Client context
Dialogue Dil Okulları is an English and German language school in Fatih, İstanbul, teaching for 27 years. Its operation had grown into parallel systems that did not talk to each other: enquiries in one place, the timetable in another, attendance on paper, instalment plans in a spreadsheet, and the coursebook as a physical object that only works when everyone is in the same room.
The platform was built by Fenext as a customer deployment of its FenLMS core, and runs today at lms.dialogue.com.tr.
The operational challenge
Two problems, and they turned out to be the same problem.
The commercial side leaked. A prospect who filled in a form and never got a call back was indistinguishable from one who had been called twice. Nobody could see, on one screen, how many enquiries had become paying students, which callbacks had blown past a reasonable response time, or which instalments were 30 days overdue rather than 3.
The delivery side was unevidenced. Once a lesson moved online, the school lost what a physical classroom gives you for free: who turned up, who left early, what was covered, and — most acutely for a language school — the shared page of the coursebook that a teacher points at. Screen-sharing a PDF is not that. It is blurry, the teacher's marks do not survive the lesson, and the student gets no page of their own.
The link between the two is that a school cannot bill confidently for delivery it cannot evidence.
Product strategy
Two decisions shaped everything else. Build one system with role-specific surfaces rather than a classroom tool plus a CRM plus a billing add-on: five roles — student, teacher, manager, admin, super admin — share one PostgreSQL schema, one authentication boundary and one design system, each seeing a different door into the same facts. And treat the coursebook as a first-class data type, not an uploaded file — which is what made real-time page synchronisation, per-page audio and persistent annotation possible at all.
The core solution
A public front door that produces qualified leads. The marketing site carries a free CEFR placement exam, scored server-side, over a 236-question bank across three exams (adult English: 6 sections, 116 questions; junior English and German: 4 sections, 60 each). A visitor who finishes it has told the school their level, their target language and when they can be called — a lead with a level attached, not an email address.
A sales funnel that shows its own leaks. The manager's funnel counts every stage — enquiry received, called, placement taken, awaiting payment, enrolled — and shows the drop-off between each pair. Beside it sits a callback queue ordered oldest-first, with an explicit badge on anything past 48 hours and an owner on each row.
Collections with ageing, not just a total. Payments are recorded through iyzico's hosted checkout (with the callback token re-verified against iyzico before anything is marked PAID) or manually at the school with an instalment plan. Overdue instalments are bucketed 1–9 / 10–29 / 30+ days, so a manager triages instead of scrolling.
A live classroom with the book inside it. Lessons run on LiveKit, in a custom tabbed stage — Book, Screen, Camera — rather than an off-the-shelf video grid, because the book needed to be a peer of the video, not a screen-share hidden behind it.
Attendance that fills itself in. Signature-verified LiveKit webhooks record every join and leave. The system proposes an attendance state per student against a 50%-of-duration threshold, pre-filling "left 22 minutes early" before the teacher has typed anything. The teacher confirms with one click, then signs off a class-book entry that moves DRAFT → SUBMITTED → REVIEWED and locks against later edits.
The part that is genuinely hard: the synchronised book
The coursebook is a 162-page volume, imported by a pipeline that renders each PDF page to three WebP variants under content-addressed storage keys, choosing the render DPI per page. The source turned out to be a hybrid — the first three units native vector text, everything after them flat 144-ppi scans — so a single global DPI would either have blurred half the book or fabricated resolution for the other half. Unit codes (1A, 1B, …) are attached per page, and the audio programme is bound by extracting each page's printed CD1 12 references and matching them to files, so opening page 8 surfaces exactly the four tracks printed on page 8.
In a live lesson, the teacher's page turns, zoom, pan, laser pointer and ink are published over the LiveKit data channel. Two rules make it trustworthy rather than merely fast:
- Shared ink is never peer-to-peer. A stroke is written to the database first and then broadcast by the server, so "this ink is real" and "this ink is on your screen" cannot disagree, and a student who joins late gets the same state as everyone else.
- A student honours viewport and pointer packets only from the presenter's identity. Ephemeral signals are sent lossy and cheaply from the client, so the trust check is done at the receiver against the room's presenter, not assumed from the transport.
Recording was the last piece: the lesson is captured through a custom room-composite egress template that renders the book alongside the camera strip, so the replay shows the page the class was actually on.
My role
Sole architect and engineer across the stack: data model and 35 migrations, authentication and role boundaries, the LiveKit integration and its webhook pipeline, the book render/annotation/synchronisation system, the operations and finance surfaces, the design system, the CI gates and the deployment.
Technical approach worth a buyer's attention
Next.js 15 (App Router, server actions), React 19, TypeScript, Drizzle ORM over PostgreSQL (100 tables), NextAuth, Tailwind, LiveKit, S3/MinIO, Redis/BullMQ, iyzico — deployed as a single Docker image behind Traefik on one VPS via GitHub Actions, with a concurrency group so two deploys cannot race each other. The schema is multi-tenant-ready; the deployment runs single-tenant.
The part I would point at in a technical conversation is the CI gates, which are project-specific and catch failures that neither type-checking nor tests can see:
| Gate | Catches |
|---|---|
| Turkish localisation (5 scanners) | Missing diacritics, wrong I/İ casing, broken suffix agreement, text that overflows its control |
| WCAG contrast | Resolves the real Tailwind config and measures the ratio an element actually paints, per theme, on a ratchet baseline that fails on regression and on unclaimed progress |
Dead dark: classes and dead routes |
A dark-mode class naming a colour the palette does not define (Tailwind emits nothing, no error, the dark theme silently never happens), and menu entries pointing at routes that no longer resolve or that cross a role boundary |
Outcomes and evidence
The platform is deployed and live at lms.dialogue.com.tr, with the marketing site and placement exam open to anyone. The capability is demonstrable end to end: placement exam to scored lead, lead to callback queue to payment, payment to scheduled lesson, lesson to webhook-derived attendance to a signed class-book entry, and a 162-page coursebook that synchronises across a live room.
I am deliberately not quoting adoption or revenue figures. The school had not switched the delivery modules on at the time of writing, so any percentage improvement would be invented. The honest claim is capability delivered, not usage measured.
Need a similar product or workflow? If you run an institution where the sales pipeline, the timetable and the classroom are three different systems that disagree with each other, that is the problem this platform was built to remove.






