Skip to content

0marii/syncflow-order-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SyncFlow: Modular Order API

A clean, service-oriented order management system built with NestJS and TypeScript. Designed for maintainability, strict typing, and clear separation of concerns.


🎯 The Philosophy

SyncFlow is built on the principle of Modular Service-Oriented Architecture.

Complex business logic does not require complex infrastructure. By leveraging Dependency Injection and clearly defined module boundaries, SyncFlow proves that a well-structured SOA system is readable, testable, and highly maintainable β€” without the overhead of asynchronous messaging infrastructure.

Each service owns its domain. Each module has one responsibility. The result is a codebase that any engineer can open, understand, and extend on day one.


πŸ—οΈ Architecture

We follow the standard NestJS layered approach, ensuring each module is fully responsible for its own domain logic and nothing else.

src/
β”œβ”€β”€ orders/
β”‚   β”œβ”€β”€ orders.module.ts
β”‚   β”œβ”€β”€ orders.controller.ts
β”‚   β”œβ”€β”€ orders.service.ts
β”‚   β”œβ”€β”€ dto/
β”‚   β”‚   β”œβ”€β”€ create-order.dto.ts
β”‚   β”‚   └── update-order.dto.ts
β”‚   └── entities/
β”‚       └── order.entity.ts
β”œβ”€β”€ inventory/
β”‚   β”œβ”€β”€ inventory.module.ts
β”‚   β”œβ”€β”€ inventory.service.ts
β”‚   └── entities/
β”‚       └── product.entity.ts
β”œβ”€β”€ notifications/
β”‚   β”œβ”€β”€ notifications.module.ts
β”‚   β”œβ”€β”€ notifications.service.ts
β”‚   └── notification.interface.ts   # provider-agnostic contract + DI token
β”œβ”€β”€ health/
β”‚   β”œβ”€β”€ health.module.ts
β”‚   └── health.controller.ts        # liveness + DB readiness probe
β”œβ”€β”€ common/
β”‚   └── filters/
β”‚       └── http-exception.filter.ts # consistent error responses
β”œβ”€β”€ database/
β”‚   └── database.module.ts          # TypeORM + SQLite configuration
β”œβ”€β”€ app.module.ts
└── main.ts

Core Domain Modules

Order Module Acts as the orchestrator. It handles the full transaction flow β€” from receiving the request, through stock validation, to sending the final confirmation. It coordinates InventoryService and NotificationService via constructor injection, keeping the flow readable and synchronous.

Inventory Module Encapsulates all stock logic. It validates availability and manages reservation locks, ensuring data integrity without leaking business rules into the Order layer.

Notification Module A dedicated service for user communication. The Orders layer depends only on the INotificationService interface (bound through the NOTIFICATION_SERVICE injection token), so the underlying provider (Email β†’ SMS β†’ Push) can be swapped by binding a different implementation β€” without touching a single line of core business logic. Notification delivery is treated as a side effect: a failure is logged and isolated so it can never roll back a successfully placed order.


πŸ§ͺ What This Project Demonstrates

This system is built to show that you understand how to write backend software that scales with a team, not just with traffic.

Concept Implementation
SOLID Principles Single Responsibility enforced at every layer β€” one class, one concern
Dependency Injection Full use of the NestJS IoC container for loose coupling
Clean API Design DTOs with class-validator enforce strict, self-documenting request schemas
Modular Boundaries No module reaches into another module's internals
Testability Services are injected, not instantiated β€” easy to mock and test in isolation
TypeScript Strictness Full strict mode β€” no any, no implicit types

πŸš€ Getting Started

Prerequisites

  • Node.js v20+
  • npm v9+

Run Locally

1. Clone the repository

git clone https://github.com/0marii/syncflow-order-api.git
cd syncflow-order-api

2. Install dependencies

npm install

3. Configure environment variables

cp .env.example .env

All variables have sensible defaults, so this step is optional for local development.

4. Start the development server

npm run start:dev

The API will be available at http://localhost:3000, and interactive Swagger documentation at http://localhost:3000/docs.

Environment Variables

Variable Default Description
PORT 3000 HTTP port the API listens on
DATABASE_PATH syncflow.sqlite SQLite file path (use :memory: for ephemeral storage)
NODE_ENV development When production, disables TypeORM schema auto-sync

πŸ“‘ API Endpoints

Method Endpoint Description
POST /orders Create a new order
GET /orders Retrieve all orders
GET /orders/:id Retrieve a single order by ID
PATCH /orders/:id Update an order
DELETE /orders/:id Delete an order
GET /health Liveness and database readiness probe
GET /docs Interactive Swagger / OpenAPI documentation

Example Request β€” Create Order

POST /orders
Content-Type: application/json

{
  "productId": "prod_abc123",
  "quantity": 2,
  "userId": "user_xyz789"
}

Example Response

{
  "id": "ord_001",
  "productId": "prod_abc123",
  "quantity": 2,
  "userId": "user_xyz789",
  "status": "CONFIRMED",
  "createdAt": "2026-01-15T10:30:00.000Z"
}

🧩 How a Request Flows Through the System

Client
  β”‚
  β–Ό
OrdersController        ← validates request shape via DTO
  β”‚
  β–Ό
OrdersService           ← orchestrates the business logic
  β”œβ”€β”€β–Ά InventoryService.checkAndReserve()      ← validates & locks stock
  └──▢ NotificationService.sendConfirmation()  ← notifies the user
  β”‚
  β–Ό
Response returned to Client

Everything is synchronous, predictable, and easy to trace in a debugger or a code review.


πŸ”’ Data Integrity & Concurrency

Stock is a shared resource, so the system is designed to stay correct under concurrent load:

  • Atomic reservations β€” InventoryService.checkAndReserve() reserves stock with a single conditional UPDATE ... WHERE stock >= :quantity. The check and the decrement happen as one indivisible operation, so two simultaneous orders can never both pass and oversell the same units.
  • Transactional orchestration β€” creating, updating, and deleting an order runs inside a database transaction. If updating an order requires re-reserving stock and that fails, the transaction rolls back, leaving inventory and orders perfectly consistent.
  • Isolated side effects β€” notifications run outside the order transaction. A delivery failure is logged but never rolls back a successfully placed order.

βœ… Validation

All incoming requests are validated using class-validator and class-transformer before they reach the service layer.

// create-order.dto.ts
import { IsString, IsInt, Min, IsNotEmpty } from 'class-validator';

export class CreateOrderDto {
  @IsString()
  @IsNotEmpty()
  productId: string;

  @IsInt()
  @Min(1)
  quantity: number;

  @IsString()
  @IsNotEmpty()
  userId: string;
}

Invalid requests are rejected automatically with a descriptive 400 Bad Request response β€” no manual validation logic required.


πŸ§ͺ Testing

Services are designed with injection in mind, making them straightforward to mock and test in complete isolation.

# Run all unit and integration tests
npm run test

# Generate a coverage report
npm run test:cov

Coverage target: β‰₯ 80%

Testing Philosophy

Because every dependency is injected, testing OrdersService does not require a real InventoryService. You provide a mock, and you test one concern at a time β€” exactly as SOLID principles intend.

const mockInventoryService = {
  checkAndReserve: jest.fn().mockResolvedValue(true),
};

const module = await Test.createTestingModule({
  providers: [
    OrdersService,
    { provide: InventoryService, useValue: mockInventoryService },
  ],
}).compile();

πŸ—ΊοΈ Execution Roadmap

  • Phase 1: Foundation β€” NestJS project setup, module scaffolding, Order entity definition
  • Phase 2: Domain Logic β€” InventoryService with atomic stock validation and reservation logic
  • Phase 3: Integration β€” Wire OrdersService to InventoryService and NotificationService via DI
  • Phase 4: Validation β€” Full request validation using class-validator on all DTOs
  • Phase 5: Reliability β€” Comprehensive unit tests, integration tests, and coverage report
  • Phase 6: Persistence & Polish β€” TypeORM + SQLite, Swagger docs, health checks, global error handling

πŸ› οΈ Tech Stack

Technology Purpose
NestJS Framework β€” modules, controllers, services, DI container
TypeScript Strict typing across the entire codebase
TypeORM Persistence layer and transactional data access
SQLite (better-sqlite3) Zero-config embedded database
class-validator Declarative DTO validation
class-transformer Request payload transformation
@nestjs/config Environment-based configuration
@nestjs/swagger OpenAPI documentation at /docs
@nestjs/terminus Health checks at /health
Jest Unit and integration testing
ESLint + Prettier Code quality and consistent formatting

πŸ“ License

Distributed under the MIT License. See LICENSE for details.


Β© 2026 Mohammad Al Omari

About

NestJS order API with modular SOA design, atomic inventory reservations, transactional order flows, and strict DTO validation. Built to demonstrate SOLID principles, DI, and maintainable backend architecture.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors