Skip to main content
George Khananaev
Case Study

Moon Support Hub: an enterprise ticketing platform

Next.js 16 with Prisma on MongoDB, 740+ source files, 186 React components, 135+ API endpoints, 60 models, and 14 scheduled background jobs

6 min read
Moon HolidaysDec 2025 — PresentEngineering Lead (architecture and delivery oversight)

Overview

Moon Support Hub is a full-featured enterprise support system built alongside the Travel Panel core platform. Ticketing with lifecycle management, knowledge base with a draft-to-published workflow, SLA policies, agent workload balancing, eight role-based access levels, real-time notifications, eight pre-built reports, and a customer portal for self-service.

By the numbers:

Metric Count
Source files 740+
React components 186
API endpoints 135+
Database models 60
Seed files 30
Built-in roles 8
Report types 8
Background jobs 14

My role on this project was engineering lead. I did not write the bulk of the code. I drove the architecture, reviewed every pull request, and kept the product on track.

Architecture

Clients (Browser, Mobile)
Next.js Application [:3000]
  ├── Frontend: App Router Pages, React Components, 4 Themes (Light, Dark, Moon, Green)
  └── Backend: REST API (135+ endpoints), SSE Streams (3 channels), Background Jobs (14 tasks)
Authentication Layer
  ├── Firebase Auth (Google, GitHub, Microsoft, Apple OAuth)
  ├── Local Auth (JWT Sessions)
  └── Office System API (external user/role sync)
Data Layer
  ├── MongoDB 5.0 Replica Set (:27017)
  ├── Prisma ORM (60 models)
  └── MinIO S3 (API :9000, Console :9001)
Communication: Mailpit SMTP (:1025, UI :8025)

Prisma on MongoDB is the first surprising choice. Most teams reach for Mongoose when they commit to MongoDB. Prisma's MongoDB support lets us get type-safe queries, schema migration, and a single source of truth for all 60 models — trading flexibility for discipline in a codebase that has to be maintained by a team rather than a solo engineer.

What the system does

Ticket management

Full lifecycle: create, track, assign, resolve, close tickets with complete audit trail. Configurable workflow (Open → In Progress → Pending → Resolved → Closed). Multi-channel intake (Email, Phone, Web, Chat, API). Merge related tickets and split complex ones with selective comment copying. Timer-based time tracking with session entries. Dynamic SLA due dates based on business hours. Automated escalation. File attachments via MinIO with presigned URLs. Gantt timeline view via Frappe Gantt. Full-text search. Bulk operations.

Comments and collaboration

Threaded nested replies, @mentions with real-time notifications, rich-text markdown editor, per-comment file attachments, upvote/downvote tracking, system comments for status changes, and canned responses with keyboard shortcuts.

Knowledge base

Multiple KBs organized by product or domain with department access control. Complete version history with author tracking. Publishing workflow: Draft → In Review → Approved → Published → Archived. Visibility controls (Public, Internal, Role-based). Article ratings (1-5 stars) with admin responses. Related articles. KB attachments with thumbnail generation. Search analytics including zero-result detection and content-gap reports. Self-service deflection measurement. KB session tracking with time-on-page. SEO metadata per article. Automatic article expiration.

RBAC (Role-Based Access Control)

Eight built-in roles: Administrator, Department Manager, Category Manager, Type Manager, Support Agent, Customer, Viewer, Employee. Three layers of enforcement:

  1. Page Permissions — which roles can access which pages
  2. UI Element Permissions — four levels (none / view / interact / full)
  3. API Permissions — endpoint protection by permission code

Plus Office Role Mapping for auto-assigning roles from external HR systems.

14 scheduled background jobs

Job Schedule Purpose
master-scheduler 1 min Orchestrates all jobs
aggregate-daily-stats Hourly 30-day ticket statistics
aggregate-interval-stats Hourly 24-hour statistics
aggregate-performance-stats Hourly SLA compliance metrics
aggregate-team-stats Hourly Team workload snapshot
aggregate-analytics-stats Hourly Comprehensive analytics
check-escalations 5 min Apply escalation rules
auto-assign-tickets 2 min Distribute unassigned tickets
calculate-burning-rates Hourly Agent productivity metrics
aggregate-customer-trends Hourly Customer behavior patterns
aggregate-csat-stats Hourly Satisfaction metrics
aggregate-kb-analytics Hourly Knowledge base metrics
send-scheduled-reports Configurable Daily/weekly/monthly email delivery
cleanup-attachments Daily Remove orphaned files

Jobs are database-driven with dynamic scheduling (interval, cron, daily, weekly, monthly), timezone-aware, with execution tracking, failure logging, and manual triggering. When a job fails, it lands in a failure log with the error for an operator to triage.

Real-time SSE streams

Three SSE channels, not one big firehose:

  • GET /api/notifications/stream — user notifications (mentions, assignments, updates)
  • GET /api/tickets/stream — live ticket count updates for sidebar badges
  • GET /api/system-config/stream — system-wide config broadcasts so settings propagate without page reloads

Splitting streams by concern means clients subscribe only to what they care about, and a noisy config channel does not delay an urgent notification.

8 pre-built reports

Executive Dashboard, Agent Performance, Team Reports, Customer Trends, SLA Performance, Knowledge Base, Ticket Operations, CSAT. Each has pre-aggregated hourly statistics for fast dashboard loading and can be subscribed to for scheduled email delivery (daily / weekly / monthly / quarterly / yearly). HTML email reports include embedded Recharts-generated charts.

Content richness

Markdown support with Mermaid diagrams, KaTeX math notation, Monaco editor for code content, Mammoth for Word document import, and PDF to PNG conversion.

Customer portal

My Tickets view, multi-step ticket creation with KB article suggestions, knowledge search for self-service, and post-resolution CSAT surveys with emoji rating scale and optional text feedback.

My role as lead

Architecture. I chose the stack (Next.js 16, MongoDB 5.0 Replica Set, Prisma, Firebase Auth, MinIO, Mailpit, Docker orchestration), designed the data model across 60 Prisma schemas, set the boundaries between subsystems, and decided which parts to build custom versus reach for libraries.

Code review. Every pull request, every iteration. I maintained the coding standards and architectural coherence as the team added features. Most of my PR comments were about consistency: naming, data shapes, error handling, RBAC application, and tests. Any one of those is minor in isolation. Together they are the difference between a codebase you can evolve for years and one that becomes a liability in six months.

Roadmap planning. Prioritization, breaking features into shippable milestones, and keeping stakeholders aligned on what would land when.

Mentorship. Pairing with developers on the hard parts, especially around the permission layers, the background-job scheduler, the SSE stream design, and the publishing workflow state machine.

Lessons from leading instead of building

The most useful thing a lead can do is ensure the team does not paint itself into a corner. The second most useful thing is saying no. Engineers want to build every feature the customer asks for. A lead's job is to decide which ones actually move the product forward and which ones introduce complexity that will cost more than they pay back.

Tech stack (chosen and reviewed, not primarily authored)

Next.js 16, TypeScript, Prisma ORM, MongoDB 5.0 Replica Set, Firebase Authentication (Google, GitHub, Microsoft, Apple, Local), MinIO S3, Mailpit SMTP (dev) and production SMTP, SSE, Recharts, Docker Compose, Mermaid, KaTeX, Monaco editor, Mammoth (Word import), 4 themes (Light, Dark, Moon, Green).

For an open-source reference implementation of the FastAPI + Redis + JWT auth patterns we used on the backend side of similar projects, see Dark Theme Auth FastAPI Server.

License: MoonHolidaysThai Co., Ltd.

Working on something similar?

I take on a handful of engagements at a time: architecture reviews, platform rescues, AI integration, and fractional technical leadership. The clearer the brief, the faster the reply.

How I work
TravelOffer: a multi-brand travel booking platform
TravelOffer: a multi-brand travel booking platform illustrationFeaturedMoon Holidays
4 minJul 2025 — Present

TravelOffer: a multi-brand travel booking platform

Next.js 16.1 + MongoDB booking flow with trilingual RTL/LTR support, state-machine order flow, and Stripe payments

A production Next.js 16 booking platform serving multiple brands under one codebase. Trilingual (English, Arabic, Hebrew) with full RTL/LTR support, cookie-based brand switching, a six-layer architecture, 30+ currency symbols, SMS/WhatsApp/Email/Google OAuth login, and a state-machine order flow from confirm to payment to completed.

nextjstypescriptmongodbstripe
Travel Panel: the core travel management platform
Travel Panel: the core travel management platform illustrationFeaturedMoon Holidays
11 minDec 2022 — Present

Travel Panel: the core travel management platform

FastAPI backend, Next.js operator portal, and B2B partner portal powering Moon Holidays end to end

Travel Panel is the core system at Moon Holidays. A FastAPI backend, a Next.js operator portal, a B2B partner portal, and the orchestrator for every downstream product: TravelOffer for end customers, Live Deck for call-center TVs, Vercel Controller for deployment cache, StaySync for allotment availability, and a WebSocket messenger for internal communication. Running on AWS with ALB, MemoryDB, CloudFront, S3, and more.

fastapinextjspythontypescript
StaySync: B2B hotel allotment management
StaySync: B2B hotel allotment management illustrationMoon Holidays
5 minFeb 2026 — Present

StaySync: B2B hotel allotment management

NestJS 11 + Drizzle + PostgreSQL 17 platform with 12 modules, 532 tests (99.63% allotment coverage), and a Contracts → Resolver → PoolBudget pipeline

StaySync is the B2B hotel allotment platform: allotment calendars, hardblocks with amendment history, booking orders, advisory-locked availability checks, and real-time sync with the Moon Holidays supplier API. Built on NestJS 11 with Drizzle ORM, PostgreSQL 17, Firebase auth, 12 business modules, 17 test suites, 532 tests, and two Next.js frontends consuming the API.

nestjstypescriptpostgresqldrizzle