Backend Engineer
Building intentional tech for meaningful connections.
What if you could only match with one person at a time?
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.
NiyyahMatch flips the script with a simple rule: you can only have ONE active match at a time.
Here's how it works:
It forces intentionality. No hedging bets, no endless window shopping. Just focused, meaningful conversations.
The match lock in action: once you match, browsing is locked until you resolve the current connection
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:
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.
Built a production-ready Spring Boot backend with security and scalability in mind:
@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.
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.
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.
Full OpenAPI documentation with interactive testing - all endpoints organized by controller
Backend MVP: Complete
Up Next:
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.