مرحبا (Hello), I'm Mo

Backend Engineer

Building intentional tech for meaningful connections.

Scroll to explore

Featured Project

NiyyahMatch

What if you could only match with one person at a time?

The Problem

Modern dating apps give you endless options - swipe left, swipe right, keep scrolling. For Muslim singles looking for marriage, this creates a paradox: more choices = less commitment = fewer meaningful connections.

People treat potential partners like a buffet. Always wondering if someone "better" is just one more swipe away.

The Solution: Match Lock

NiyyahMatch flips the script with a simple rule: you can only have ONE active match at a time.

Here's how it works:

  • You get 12 daily swipes (resets at midnight UTC)
  • When you match with someone, your profile is "locked"
  • You can't browse new profiles while matched
  • You message, get to know each other, and decide: move forward or move on
  • Only after resolving the current match can you explore new connections

It forces intentionality. No hedging bets, no endless window shopping. Just focused, meaningful conversations.

App Flow

NiyyahMatch welcome and account creation flow showing onboarding steps NiyyahMatch match lock feature - showing daily discovery, match screen, and locked browsing state

The match lock in action: once you match, browsing is locked until you resolve the current connection

Why I Built This (Honestly)

I didn't start NiyyahMatch thinking "I'm going to build the next big dating app." I started it because I wanted to learn Spring Boot beyond the basic CRUD tutorials, and I figured if I'm going to spend weeks on a project, it might as well solve a real problem.

Turns out, building something people might actually use forces you to learn fast:

  • Security was a wake-up call. Can't just store passwords in plain text when you're dealing with real user data. Learned about BCrypt, JWT tokens, NIST compliance standards - stuff that actually matters in production.
  • Database design got real. Relationships between users, matches, messages, swipes - I had to think through edge cases I'd never encountered in tutorials. What happens when both users swipe right at the same time? How do you prevent duplicate matches?
  • API architecture clicked. Building a proper layered structure (Controller → Service → Repository) felt overly complex at first, but once you have 20+ endpoints, it makes total sense. Separation of concerns isn't just theory.
  • Validation is harder than it looks. Custom validators, DTO patterns, exception handling - you don't appreciate this stuff until you try to build an API that doesn't crash when users send garbage data.

The "match lock" idea came from watching friends swipe through hundreds of profiles and never actually message anyone. Made it part of the project spec, and suddenly I had a unique feature to build around. Happy accident.

Tech Stack & Architecture

Built a production-ready Spring Boot backend with security and scalability in mind:

Backend
  • Java 17 + Spring Boot 4.0.1
  • PostgreSQL 15 with JPA/Hibernate
  • Maven for dependency management
Security
  • JWT token-based authentication
  • BCrypt password hashing (NIST SP 800-63B compliant)
  • DTO pattern to prevent password exposure
API Design
  • RESTful endpoints with Swagger docs
  • Global exception handling
  • Custom validators (e.g., @MinAge)
Architecture
  • Clean layered structure
  • Controller → Service → Repository → Entity
  • Bean validation (JSR 380)

Code Highlights

Custom Validator for Age Verification
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MinAgeValidator.class)
public @interface MinAge {
    String message() default "Must be at least 18 years old";
    int value() default 18;
    // ... constraint boilerplate
}

// Validator implementation ensures users meet minimum age requirement
public class MinAgeValidator implements ConstraintValidator<MinAge, LocalDate> {
    private int minAge;

    @Override
    public boolean isValid(LocalDate birthDate, ConstraintValidatorContext context) {
        if (birthDate == null) return false;
        return Period.between(birthDate, LocalDate.now()).getYears() >= minAge;
    }
}

Why this matters: Age verification is critical for a marriage app. Custom validators keep validation logic clean and reusable across the codebase.

DTO Pattern for Security
public class UserResponseDTO {
    private Long id;
    private String email;
    private String firstName;
    // ... other safe fields
    // NOTE: Password is NEVER exposed in DTOs

    public static UserResponseDTO fromEntity(User user) {
        return UserResponseDTO.builder()
            .id(user.getId())
            .email(user.getEmail())
            .firstName(user.getFirstName())
            .build();
    }
}

The DTO pattern ensures sensitive data (like hashed passwords) never leaves the database layer. Every API response uses DTOs instead of raw entities.

Match Lock Business Logic
public boolean canUserSwipe(Long userId) {
    // Check if user has an active match
    Optional<Match> activeMatch = matchRepository
        .findActiveMatchForUser(userId);

    if (activeMatch.isPresent()) {
        // User is "locked" - cannot browse new profiles
        return false;
    }

    // Check daily swipe limit
    int swipesToday = swipeRepository
        .countSwipesForUserToday(userId);

    return swipesToday < MAX_DAILY_SWIPES; // 12 swipes per day
}

This is the core of the "match lock" feature. Simple boolean check, but it fundamentally changes user behavior - no multitasking matches.

Interactive API Documentation

Swagger UI showing NiyyahMatch API endpoints - user-controller, match-controller, message-controller, and auth-controller

Full OpenAPI documentation with interactive testing - all endpoints organized by controller

Current Status & Roadmap

Backend MVP: Complete

Up Next:

  • Integration testing suite
  • React frontend development
  • Private beta launch with Muslim student communities

About Me

Mo - Backend Engineer

I'm a backend engineer who gets excited about solving real problems with clean code. NiyyahMatch started because I saw people in my community struggling with the same dating app fatigue everyone else faces, but with the added pressure of finding someone who shares their faith and values.

When I'm not coding, you'll find me at the mosque, reading, working on calisthenics, running, playing soccer, or drinking chai with friends.

Looking for backend or fullstack opportunities where I can work with people who care about building things that matter.

Let's Connect

Always happy to talk about projects, opportunities, or just grab chai and chat.