Overview

FitMatch is a comprehensive platform for planning and monitoring sports training routines and diets. It features a fully decoupled architecture, utilizing a robust Node.js/Express backend and a reactive cross-platform mobile frontend. The system is designed with a strong emphasis on type safety, strict architectural boundaries, and data integrity.

Image

The Frontend: Dart & the Evolution of Flutter

Dart is a client-optimized, object-oriented language developed by Google. Its real power lies in its dual compilation strategy: it uses JIT (Just-In-Time) compilation during development to enable lightning-fast Hot Reloads, and AOT (Ahead-Of-Time) compilation for production to deliver high-performance native machine code.

The State of Flutter: Flutter has evolved massively from a simple mobile UI toolkit into a mature, multi-platform framework. Recently, the ecosystem has matured significantly with the introduction of the Impeller rendering engine (replacing Skia), which eliminates shader compilation jank. By adopting Flutter, FitMatch guarantees a pixel-perfect, highly responsive UI across different devices from a single codebase, leveraging Clean Architecture to keep the UI strictly decoupled from the business logic.

Don't doubt checking the frontend repository for more details about the architecture and the code or check the [thesis](fitmatch/thesis.pdf) for more details about the project and viewing snapshots of the frontend.

Frontend Architecture
Frontend Architecture

Backend Robustness & Layered Architecture

The backend is built with Express and TypeScript, engineered for high reliability through a strict Layered Architecture. By enforcing these boundaries, the system becomes highly testable and resilient:

Presentation Layer: Handles REST routes and strict payload validation (using Zod/DTOs) before data ever touches the core.

Application Layer: Orchestrates business logic, complex transactions, and external notifications.

Domain Layer: Contains pure entities (User, Workout, Diet) and the core business rules, completely agnostic of the database or HTTP framework.

Infrastructure Layer: Manages Prisma repositories, file storage, and third-party adapters.

Check the backend repository for more details about the architecture and the code or check the [thesis](fitmatch/thesis.pdf).

Image

Data Layer: The Case for Prisma ORM

While raw SQL offers maximum control, favoring an ORM like Prisma in a TypeScript ecosystem provides a massive boost to safety and developer velocity.

Prisma generates a highly customized TypeScript client based on the database schema. This guarantees end-to-end type safety: if a column name changes in the database, the backend code will break at compile-time, not in production. Furthermore, it abstractly handles complex relational mappings (1-N, N-N), standardizes database migrations, and inherently protects against SQL injection attacks, all while allowing raw SQL drop-ins for edge-case performance optimizations.

Database Schemas
Database Schemas

Security Posture

  • Memory-Hard Hashing: Passwords are mathematically secured using Argon2id (adaptive and memory-hard), making the database highly resistant to brute-force and GPU-based attacks.
  • Stateless Authentication: Implements short-lived JWTs (HS256) with refresh tokens. By embedding user roles directly into token claims, the backend remains stateless, drastically improving horizontal scalability.
  • Defensive Layers: Includes login attempt rate-limiting, token revocation mechanisms, and optional 2FA to harden the authentication flow.

Expanded Developer Highlights

  • End-to-End Type Safety: By using TypeScript on the backend and Dart on the frontend, the system minimizes runtime type errors and mismatched API contracts.
  • Symmetrical Clean Architecture: Both the backend and the Flutter mobile app utilize Clean Architecture. The mobile app can swap its data source (API vs. local SQLite cache for offline mode) without rewriting a single UI widget.
  • Relational Integrity: Complex database schemas (workouts containing multiple exercises, dynamic diets, and measurement tracking) are enforced at the PostgreSQL level using constraints, cascading deletes, and unique indexes.
  • Modular Scalability: The stateless nature of the JWT implementation combined with the decoupled service layers means the backend can be easily containerized and load-balanced under heavy traffic.