AR
IMMAR — landing page hero

IMMAR

IMMAR (إيمار) is a multi-teacher e-learning platform built for an education business in Iraq: teachers publish courses inside isolated workspaces, students unlock a course with a single-use subscription code in a Flutter app and watch watermarked video on a limited set of registered devices, and platform staff run onboarding, moderation and teacher settlements from one web console, Arabic-first and RTL. One ASP.NET Core (.NET 8) backend over PostgreSQL serves both apps. On a two-engineer team, Ahmed leads that backend, wrote the founding engineering design pack and built the React dashboard's API layer, routing and platform console; his teammate leads the Flutter app and the landing page. An ongoing client engagement, in development since July 2026.

Deliverables

ASP.NET Core (.NET 8) modular monolith API

PostgreSQL / EF Core, 74 tables

Hangfire job platform (17 jobs)

Cloudflare Stream, S3, FCM & SMS adapters

Dashboard API layer & platform console (React 19)

Year

2026

Project Role

Backend Lead

Live Website

System architecture

How it is built

Client apps

Student app

Students — Android & iOS

Flutter · Dart

Teacher workspace

Teachers & their teams

React 19 · Vite 8 · TypeScript

Platform console

Owner, admins, accountant, support

Same SPA, role-routed

Landing page

Public marketing site

React 19 · Vite · static

Background jobs

  • 17 catalogued Hangfire jobs (12 platform, 5 per-tenant fan-out)
  • Push outbox drain · scheduled announcements
  • Transcode status sync · abandoned-attempt sweep
  • Nightly analytics rollups per workspace and platform

IMMAR API — modular monolith

ASP.NET Core 8 · C# · EF Core 8 · FluentValidation · JWT

Route surfaces

/auth/app/teacher/admin/public/webhooks

Layers

  1. 01Api — controllers per surface, permission gates, rate limits, uniform { data, meta } envelope
  2. 02Application — 88 services, validators, 86 stable error codes (ar/en), job catalogue
  3. 03Domain — 74 entities, workspace-scoped contracts, string-constant vocabularies
  4. 04Infrastructure — EF Core + Npgsql, global tenancy filter, provider adapters, Hangfire

Provider adapters

  • Cloudflare Stream — upload, transcode webhook, signed HLS playback
  • S3-compatible object storage — presigned uploads and reads
  • Firebase Cloud Messaging (HTTP v1) — push
  • Iraqi SMS gateway — OTP delivery
  • PDFsharp — per-student PDF watermarking

Data

PostgreSQL 15

74 tables, 24 EF Core migrations, one composed tenancy + soft-delete filter

Object storage

Course library, attachments, submissions, avatars

Hangfire store

Job runs ledger and dead-letter handling on PostgreSQL

Tenancy
One workspace per teacher; fail-closed EF global filter; cross-workspace reads answer 404
Identity
Phone-only registration with OTP; JWT access + rotating refresh tokens with reuse detection
Authorization
60 permission keys, 8 system roles, custom workspace roles; 286 permission-gated actions
API
63 controllers · 364 HTTP endpoints · 6 route surfaces
Data model
74 domain entities mapped 1:1 to 74 PostgreSQL tables
Protected media
Encrypted HLS via locally signed short-lived tokens bound to user, device, lesson and IP; watermarked PDFs
Money
Single-use codes redeemed in one transaction; commission frozen on each sale; settlements draft → approved → paid
Quality
1,951 unit test cases passing (1,520 methods) + 91 PostgreSQL-backed integration tests
Delivery
GitHub Actions CI, multi-stage Docker image, staging on a PaaS; two-engineer team since July 2026

One request, end to end: a student activates a subscription code

  1. 01The Flutter app posts the code with an Idempotency-Key header over a mobile network that may retry.
  2. 02The activation rate-limit policy and the bearer + device check run before any controller code.
  3. 03The application service opens one explicit transaction and locks the code row.
  4. 04The code flips to used, the enrollment is created, and a partial unique index refuses a concurrent duplicate.
  5. 05The sale is written with the commission rate resolved now and frozen onto it — later rate changes never rewrite history.
  6. 06The course counter is bumped and the transaction commits; a retried request replays the stored response instead of failing.
  7. 07After commit, lead-conversion attribution and the notification outbox are queued for background jobs.
  8. 08The app receives the enrollment and can open the first lesson with a fresh playback token.

Apps overview

The apps

Teacher workspace

Teachers and their assistants: build courses, sell access, run exams, follow students and get settled.

React 19 · Vite 8 · TypeScript · TanStack Query · React Hook Form + Zod · i18next (ar/en, RTL-first) · Vitest

  • Home with the actions that need attention, then the course workspace with route-per-tab
  • Curriculum builder with drag-and-drop sections and lessons, media library with direct-to-storage uploads
  • Assessment builder (sections, question bank, randomization), grading queue and gradebook
  • Students, leads, subscription-code batches with printable cards, team roles and activity log

Platform console

The platform owner, admins, the accountant and support staff, in the same SPA behind platform-scope permissions.

Same React 19 SPA, role-routed navigation, 3,343 i18n keys at exact Arabic/English parity, 57 routed screens

  • Command centre with KPIs and the teacher-onboarding and course-moderation queues
  • Users, teachers and platform roles with a permission matrix
  • Sales transactions, teacher settlements and receipts
  • Reference data, announcements, FAQs, legal pages, settings, audit log

Student app

Students on Android and iOS: activate a code, watch protected lessons, sit exams, hand in assignments.

Flutter · Dart · GoRouter · HLS player · FCM push · 711 localisation keys per locale · 475 tests

  • Phone + OTP onboarding, device chooser, home feed ordered by what is due
  • Code activation with an explicit unknown-outcome state for bad networks
  • Video lessons behind short-lived tokens with a moving per-student watermark
  • Timed exams with per-answer autosave, six question types and a review-then-submit step

What it does

Modules

01

Identity & devices

  • Phone-only accounts with OTP registration, login and password reset
  • Refresh-token rotation with reuse detection; replay revokes the whole family
  • Registered devices per student with self-service slot freeing
  • Six named rate-limit policies plus per-destination OTP throttling
02

Workspaces, roles & team

  • Isolated workspace per teacher on one database
  • 60 permission keys in teacher and platform scopes, 8 system roles
  • Custom workspace roles, team members and an activity log
  • Workspace-qualified permission claims inside the token
03

Learning

  • Subject → course → section → lesson with nine lesson types
  • Course library, attachments with acknowledgements, free previews
  • Simulation embeds behind a host allow-list
  • Publish, takedown and moderation lifecycle
04

Protected media

  • Cloudflare Stream upload tickets and transcode sync
  • Locally signed HLS playback tokens bound to user, device, lesson and IP
  • Quality ladder parsed from the HLS master playlist
  • Per-student watermark on video and on every PDF page
05

Codes & sales

  • Crypto-random single-use codes on an ambiguity-free alphabet, batches with printable QR cards
  • Race-safe redemption in one transaction, idempotent under retries
  • Renewal codes that extend an existing enrollment
  • Commission resolved and frozen onto each sale
06

Exams & assignments

  • Question bank, sections, selection rules and randomization
  • Server-clock attempts on a frozen paper, per-answer autosave
  • Objective auto-grading, grading queue, remediation, gradebook weights
  • Assignments with file submissions and grader feedback
07

Finance

  • Append-only sales ledger with receipts and voids
  • Teacher settlements: draft → approved → paid with signed adjustments
  • Sequenced receipt numbers from the database
  • Teacher revenue views and platform transaction reports
08

Communication

  • 23 notification event types with preferences and quiet hours
  • Push outbox drained to FCM by a background job
  • Announcements with audience targeting and scheduled broadcast
  • Lesson Q&A threads and a leads queue from the public site
09

Platform administration

  • Teacher onboarding and commission, course moderation queue
  • Reference data: subjects, stages, branches, all 18 governorates
  • Settings, feature flags, audit log, FAQs and legal pages
  • Nightly analytics rollups and dashboards

Engineering stories

The problems worth telling

The problem

Every teacher runs an isolated workspace with its own courses, team, subscription codes and revenue, on one shared codebase and one database, so a forgotten filter has to fail closed rather than surface another teacher's data.

The content has to stop leaking: video served as encrypted HLS behind short-lived, per-viewer playback tokens with an on-screen watermark, PDFs stamped with the student's details, and every account capped to a small number of registered devices.

Access is sold as printed single-use codes redeemed from a phone over unreliable mobile networks, so a code must never unlock a course twice or be lost to a retried request, and every paid redemption has to record a sale with the commission frozen at that moment.

Identity is phone-number-only with OTP, the product is Arabic-first and RTL with English second, and the same rules for exams, codes and permissions have to hold across a Flutter app and a web dashboard talking to one API.

Role & responsibilities

Backend lead on a two-engineer team: the initial architecture and most of the code, 60 of the 63 API controllers, 364 HTTP endpoints across 6 audience surfaces, 74 domain entities mapped 1:1 to 74 PostgreSQL tables, 20 of the 24 EF Core migrations, and review of 57 of its 61 pull requests.

Identity, access and tenancy: phone-only registration with OTP, JWT with workspace-scoped permission claims and refresh-token rotation with reuse detection, the per-student device limit, 6 named rate-limit policies, a permission-first RBAC of 60 keys and 8 system roles on 286 controller actions, and a fail-closed EF Core global filter on every workspace-scoped entity.

The money and exam flows: subscription-code batches and race-safe redemption in one transaction with the commission frozen onto each sale, the settlement lifecycle (draft, approved, paid) with append-only adjustments and receipts, server-clock exam attempts with autosave, auto-grading and an expiry sweep (exam sections and grading concurrency co-built with his teammate), and 23 notification event types drained to FCM by background jobs.

Provider adapters, jobs and tests: the Cloudflare Stream, S3, FCM HTTP v1 and SMS adapters with a dev double behind each port (PDF watermarking by his teammate), the 17-job Hangfire platform with a job-runs ledger and dead-letter handling, the PostgreSQL-backed integration-test harness, most of the 1,520 xUnit test methods, CI and the Dockerfile.

Beyond the backend: the founding design pack the team built from (SRS, architecture, conventions, runbook); the React 19 dashboard's scaffold, typed API layer (37 service objects, 270 methods), permission-first routing and platform console, with the visual system, data tables and assessment builder by his teammate; and push notifications, announcements and video-player fixes in the Flutter app his teammate leads.

Tenancy that cannot be forgotten

Every workspace-scoped entity gets one composed EF Core global filter (soft-delete and workspace) built at model time, a per-request scope that fails closed to an empty workspace when nothing resolves, and a background-job mode that throws instead of silently returning zero rows when a job never declared its scope; the SaveChanges interceptor stamps and validates the workspace on every write. Teacher permissions travel in the token as workspace-qualified claims, so a right held in one workspace never resolves in another, and a cross-workspace read answers 404, not 403. A missed filter shows up as an empty page or an exception in the 91 PostgreSQL-backed integration tests, never as another teacher's data.

A subscription code is a money event

Redeeming a code has to flip the code, create the enrollment, record the sale with the commission rate frozen onto it and bump the course counter as one unit, from a phone that may retry. It runs in one explicit transaction with a row lock on the renewal path, a partial unique index on active (student, course) refuses concurrent duplicates, and his teammate added a dedicated rate-limit policy on the activation endpoint plus an Idempotency-Key store so a timed-out retry gets the original response back instead of an ambiguous already-enrolled error. Later rate changes never rewrite history, because the rate lives on the sale, not on the teacher.

Video that costs one signature per play

Protected lessons stream from Cloudflare Stream as encrypted HLS, but asking the provider's API for a signed URL on every play would be slow and rate-limited. The backend mints the short-lived playback token locally in the provider's exact format, bound to the student, device, lesson, asset and IP and audited on every issue, and returns the per-student watermark text alongside the manifest for the app to render. Quality selection, which the provider does not expose, comes from parsing the HLS master playlist once at transcode time and re-signing each rendition at play time, and the transcode webhook is read as raw bytes and HMAC-verified before any model binding.

Outcome

One backend serving both apps: 63 controllers and 364 endpoints over 74 tables, 60 permission keys and 8 system roles on 286 gated actions, 17 catalogued Hangfire jobs, 5 production provider adapters and 86 stable error codes with Arabic and English catalog entries, backed by 1,951 passing unit test cases and 91 PostgreSQL-backed integration tests. Around it, a React 19 dashboard with 57 routed screens, 3,343 i18n keys at exact Arabic/English parity and 679 Vitest tests, a Flutter student app for Android and iOS with 43 screens and 711 localisation keys per locale, and a public landing page. An ongoing client engagement built by two engineers, in development since July 2026.

What I learned

Tenant isolation has to be a property of the data layer, not a habit of the developer: a filter that can be forgotten will be, so make the missing filter fail closed and let integration tests prove it.

On a product sold through codes, the transaction boundary is the product: redemption, enrollment, the sale and its frozen commission have to commit together, and a retry from a bad network needs an idempotent answer, not an error.

Two engineers move in parallel across four repos only if the contract is written down: the design pack, the shared error and permission vocabularies and a pull-request gate on every repo did more for velocity than any framework choice.

Selected Work

Work

that shipped

to production.

Sendy landing page — run every order from first click to final delivery

Sendy

Multi-tenant delivery and e-commerce operations platform: one ASP.NET Core API, five React frontends, real-time tracking and AI-powered store tooling.

Web Platform • Logistics & E-Commerce • 2026

IMMAR — landing page hero

IMMAR

Multi-teacher e-learning platform for Iraq: one ASP.NET Core API, a React dashboard and a Flutter student app, with protected video, exams and settlements.

E-Learning Platform • Education • 2026

Nawa project card

Nawa

Multi-tenant AI call-center and service operations platform: real-time voice and chat over WebRTC and Twilio, policy-driven tool orchestration, billable usage.

AI Operations Platform • Voice & Chat • 2025

Madhmoon project card

Madhmoon

Fintech innovation project for digital inclusion in Iraq, designed, validated and pitched by a multidisciplinary team. First place at the Fintech Hackathon.

Fintech Concept • Fintech Hackathon • 1st Place

NANO project card

NANO

AI-powered OCR web app that extracts and digitizes text from images in real time. First place at the First ITS Hackathon.

AI OCR Web App • First ITS Hackathon • 1st Place

Core Banking project card

Core Banking

Core banking system concept covering transactional flows and consistency requirements. Second place at the Second ITS Hackathon.

Fintech Concept • Second ITS Hackathon • 2nd Place

Form Builder project card

Form Builder

A form builder built for usability and rapid, collaborative delivery under hackathon time pressure. Second place at Entrepreneurship Week.

Web App • Entrepreneurship Week • 2nd Place

Experience

Where I learned it.

Ahmed Imad Tarq at the Fintech Hackathon final ceremony

Want the full story?

The CV has the details: roles, stack, hackathons and education.

Download My CVPDF, One Page

Or just email, no pressure

ahmed.emadtarq@gmail.com