Live portfolio demo

Daily habits,
measurable progress.

A multi-tenant gamified learning platform with streaks, XP, a role-gated admin panel, and HMAC-signed outbound webhooks. Built on Next.js 16, Prisma 6, and PostgreSQL.

Click either button to auto-fill the login form. Credentials also visible below.

LearnLoop learner dashboard on mobile with streak, XP bar, and lesson list
LearnLoop admin analytics dashboard with DAU chart, funnel, top learners, retention

Admin analytics: DAU line, completion funnel, top-10 learners, weekly retention.

What's actually in here

Every box a senior full-stack role checks, wrapped in one coherent product so a reviewer can trace a learner action through the whole system in under a minute.

๐Ÿ”ฅ

Mobile-first gamification

Streaks, XP bars, and badges. Timezone-safe daily rollover with DST handling, fully unit-tested.

๐Ÿ›ก๏ธ

Admin panel with RBAC

Three roles, tenant-scoped queries, self-demote protection. Every admin mutation writes a typed audit row.

๐Ÿข

Multi-tenant data model

Every tenant table carries organizationId. Cross-tenant reads bounce to 403 through a three-layer guard.

๐Ÿ“Š

Analytics dashboard

Daily active users, completion funnel, top learners by XP, weekly retention cohorts. Recharts, server rendered.

๐Ÿ”—

HMAC-signed webhooks

SHA-256 over timestamp, deliveryId, body. Exponential backoff with jitter, capped at 8 attempts.

๐Ÿ“„

CSV + PDF exports

Progress report as CSV via papaparse, per-learner report card as streamed PDF via @react-pdf/renderer.

Complete a lesson, watch it ripple

Marking a lesson complete fires a single transactional orchestrator that updates progress, activity, XP, streak, and badges in one Prisma transaction, then enqueues a signed webhook to every subscribed endpoint.

  • โœ“Streakcomputed in the user's local timezone, respecting DST.
  • โœ“XP event appended to a ledger. Level curve is 50ยทnยท(n+1).
  • โœ“Badges checked via pure rule matcher over { xp | streak | lessons } thresholds.
  • โœ“Webhook delivery signed sha256(secret, "ts.deliveryId.body"), retried with jittered backoff.
Webhook endpoint detail showing signing secret and delivery log

Built with

Next.js 16React 19TypeScriptTailwind v4PostgreSQL 16Prisma 6Auth.js v5VitestPlaywrightRecharts