From d9a164ef605ba3c13e7bf9d9b1df1a1ac2ef11a6 Mon Sep 17 00:00:00 2001
From: Muhammad Surani <ms02309@surrey.ac.uk>
Date: Wed, 27 Mar 2024 22:52:40 +0000
Subject: [PATCH] Implementation of the Flight Booking Service

---
 BookingService/.gitignore                     | 263 ++++++++++++
 .../FlightBooking.Service.Tests.csproj        |  37 ++
 .../FlightBooking.Service.Tests/UnitTest1.cs  |  10 +
 BookingService/FlightBooking.Service.sln      |  31 ++
 .../Controllers/BookingsController.cs         |  88 ++++
 .../Controllers/SeatsController.cs            |  42 ++
 .../Controllers/StripeController.cs           |  69 ++++
 .../Data/Configs/ConfigSettings.cs            |  15 +
 .../Data/Configs/ConfigSettingsModule.cs      |  10 +
 .../FlightBooking.Service/Data/Constants.cs   |  38 ++
 .../Data/DTO/BookingDTO.cs                    |  56 +++
 .../Data/DTO/BookingOrderDTO.cs               |  25 ++
 .../Data/DTO/FlightFareDTO.cs                 |  16 +
 .../Data/DTO/FlightInformationDTO.cs          |  19 +
 .../Data/DTO/ReservedSeatDTO.cs               |  17 +
 .../Data/DTO/StripeDataDTO.cs                 |  32 ++
 .../Data/DatabaseSeeding.cs                   | 158 +++++++
 .../FlightBooking.Service/Data/Enums.cs       |  40 ++
 .../Data/FlightBookingContext.cs              |  70 ++++
 .../BookingConfiguration.cs                   |  27 ++
 .../BookingOrderConfiguration.cs              |  13 +
 .../FlightFareConfiguration.cs                |  17 +
 .../FlightInformationConfiguration.cs         |  13 +
 .../PaymentConfiguration.cs                   |  17 +
 .../ReservedSeatConfiguration.cs              |  17 +
 .../Data/Models/Booking.cs                    |  36 ++
 .../Data/Models/BookingOrder.cs               |  26 ++
 .../Data/Models/FlightFare.cs                 |  28 ++
 .../Data/Models/FlightInformation.cs          |  25 ++
 .../Data/Models/PassengerInformation.cs       |  20 +
 .../Data/Models/Payment.cs                    |  30 ++
 .../Data/Models/ReservedSeat.cs               |  22 +
 .../Data/Repository/GenericRepository.cs      | 257 ++++++++++++
 .../Data/Repository/IGenericRepository.cs     |  36 ++
 .../Data/Repository/RepositoryModule.cs       |  17 +
 .../FlightBooking.Service.csproj              |  45 ++
 .../FlightBooking.Service.http                |   6 +
 .../Middleware/ErrorHandlingMiddleware.cs     |   6 +
 .../Middleware/MiddlewareExtensions.cs        |  10 +
 .../FlightBooking.Service/Program.cs          |  63 +++
 .../Properties/launchSettings.json            |  41 ++
 .../Services/BookingOrderService.cs           | 391 ++++++++++++++++++
 .../Services/BookingService.cs                | 101 +++++
 .../Services/FlightBookingProfile.cs          |  29 ++
 .../Services/FlightFareService.cs             |  44 ++
 .../Services/FlightService.cs                 |  47 +++
 .../Interfaces/IBookingOrderService.cs        |  21 +
 .../Services/Interfaces/IBookingService.cs    |  35 ++
 .../Services/Interfaces/IFlightFareService.cs |  21 +
 .../Services/Interfaces/IFlightService.cs     |  22 +
 .../Interfaces/IReservedSeatService.cs        |  29 ++
 .../Services/Interfaces/IStripeService.cs     |  22 +
 .../Services/PaymentService.cs                |   6 +
 .../Services/ReservedSeatService.cs           | 127 ++++++
 .../Services/ResponseFormatter.cs             | 176 ++++++++
 .../Services/ServicesModule.cs                |  17 +
 .../Services/StripeService.cs                 | 147 +++++++
 .../FlightBooking.Service/Startup.cs          | 162 ++++++++
 .../appsettings.Development.json              |  21 +
 .../FlightBooking.Service/appsettings.json    |  22 +
 .../FlightBooking.Service/nlog.config         |  40 ++
 .../FlightBooking.Service/readme.md           | 385 +++++++++++++++++
 62 files changed, 3673 insertions(+)
 create mode 100644 BookingService/.gitignore
 create mode 100644 BookingService/FlightBooking.Service.Tests/FlightBooking.Service.Tests.csproj
 create mode 100644 BookingService/FlightBooking.Service.Tests/UnitTest1.cs
 create mode 100644 BookingService/FlightBooking.Service.sln
 create mode 100644 BookingService/FlightBooking.Service/Controllers/BookingsController.cs
 create mode 100644 BookingService/FlightBooking.Service/Controllers/SeatsController.cs
 create mode 100644 BookingService/FlightBooking.Service/Controllers/StripeController.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Configs/ConfigSettings.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Configs/ConfigSettingsModule.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Constants.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/BookingDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/BookingOrderDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/FlightFareDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/FlightInformationDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/ReservedSeatDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DTO/StripeDataDTO.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/DatabaseSeeding.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Enums.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/FlightBookingContext.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingOrderConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightFareConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightInformationConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/PaymentConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/ModelConfigurations/ReservedSeatConfiguration.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/Booking.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/BookingOrder.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/FlightFare.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/FlightInformation.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/PassengerInformation.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/Payment.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Models/ReservedSeat.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Repository/GenericRepository.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Repository/IGenericRepository.cs
 create mode 100644 BookingService/FlightBooking.Service/Data/Repository/RepositoryModule.cs
 create mode 100644 BookingService/FlightBooking.Service/FlightBooking.Service.csproj
 create mode 100644 BookingService/FlightBooking.Service/FlightBooking.Service.http
 create mode 100644 BookingService/FlightBooking.Service/Middleware/ErrorHandlingMiddleware.cs
 create mode 100644 BookingService/FlightBooking.Service/Middleware/MiddlewareExtensions.cs
 create mode 100644 BookingService/FlightBooking.Service/Program.cs
 create mode 100644 BookingService/FlightBooking.Service/Properties/launchSettings.json
 create mode 100644 BookingService/FlightBooking.Service/Services/BookingOrderService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/BookingService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/FlightBookingProfile.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/FlightFareService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/FlightService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IBookingOrderService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IBookingService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IFlightFareService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IFlightService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IReservedSeatService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/Interfaces/IStripeService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/PaymentService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/ReservedSeatService.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/ResponseFormatter.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/ServicesModule.cs
 create mode 100644 BookingService/FlightBooking.Service/Services/StripeService.cs
 create mode 100644 BookingService/FlightBooking.Service/Startup.cs
 create mode 100644 BookingService/FlightBooking.Service/appsettings.Development.json
 create mode 100644 BookingService/FlightBooking.Service/appsettings.json
 create mode 100644 BookingService/FlightBooking.Service/nlog.config
 create mode 100644 BookingService/FlightBooking.Service/readme.md

diff --git a/BookingService/.gitignore b/BookingService/.gitignore
new file mode 100644
index 0000000..1242aad
--- /dev/null
+++ b/BookingService/.gitignore
@@ -0,0 +1,263 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+#*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+/WellaHealthApiCore/Generated
+/WellahealthCore.AzureFunctions
diff --git a/BookingService/FlightBooking.Service.Tests/FlightBooking.Service.Tests.csproj b/BookingService/FlightBooking.Service.Tests/FlightBooking.Service.Tests.csproj
new file mode 100644
index 0000000..78b328a
--- /dev/null
+++ b/BookingService/FlightBooking.Service.Tests/FlightBooking.Service.Tests.csproj
@@ -0,0 +1,37 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
+  </PropertyGroup>
+	<PropertyGroup>
+		<EnableNETAnalyzers>true</EnableNETAnalyzers>
+	</PropertyGroup>
+  <ItemGroup>
+	  <PackageReference Include="coverlet.collector" Version="6.0.1">
+		  <PrivateAssets>all</PrivateAssets>
+		  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+	  </PackageReference>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
+    <PackageReference Include="xunit" Version="2.5.3" />
+	  <PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
+		  <PrivateAssets>all</PrivateAssets>
+		  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+	  </PackageReference>
+	<PackageReference Include="MockQueryable.Moq" Version="7.0.0" />
+	<PackageReference Include="Moq" Version="4.18.4" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\FlightBooking.Service\FlightBooking.Service.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="Xunit" />
+  </ItemGroup>
+
+</Project>
diff --git a/BookingService/FlightBooking.Service.Tests/UnitTest1.cs b/BookingService/FlightBooking.Service.Tests/UnitTest1.cs
new file mode 100644
index 0000000..127caef
--- /dev/null
+++ b/BookingService/FlightBooking.Service.Tests/UnitTest1.cs
@@ -0,0 +1,10 @@
+namespace FlightBooking.Service.Tests
+{
+    public class UnitTest1
+    {
+        [Fact]
+        public void Test1()
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service.sln b/BookingService/FlightBooking.Service.sln
new file mode 100644
index 0000000..2a079f3
--- /dev/null
+++ b/BookingService/FlightBooking.Service.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34622.214
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlightBooking.Service", "FlightBooking.Service\FlightBooking.Service.csproj", "{0043031F-8453-4554-90A8-DA1921F95235}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlightBooking.Service.Tests", "FlightBooking.Service.Tests\FlightBooking.Service.Tests.csproj", "{C7FCD62C-5D7D-44BB-8A38-821BEBE2BBC9}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0043031F-8453-4554-90A8-DA1921F95235}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0043031F-8453-4554-90A8-DA1921F95235}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0043031F-8453-4554-90A8-DA1921F95235}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0043031F-8453-4554-90A8-DA1921F95235}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C7FCD62C-5D7D-44BB-8A38-821BEBE2BBC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C7FCD62C-5D7D-44BB-8A38-821BEBE2BBC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C7FCD62C-5D7D-44BB-8A38-821BEBE2BBC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C7FCD62C-5D7D-44BB-8A38-821BEBE2BBC9}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1CCB1631-8F04-4C14-AC4D-9CFC54B609B7}
+	EndGlobalSection
+EndGlobal
diff --git a/BookingService/FlightBooking.Service/Controllers/BookingsController.cs b/BookingService/FlightBooking.Service/Controllers/BookingsController.cs
new file mode 100644
index 0000000..d9d2de4
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Controllers/BookingsController.cs
@@ -0,0 +1,88 @@
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Services;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.AspNetCore.Mvc;
+using System.Net.Mime;
+
+namespace FlightBooking.Service.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class BookingsController : ControllerBase
+    {
+        private readonly IBookingService _bookingService;
+        private readonly IBookingOrderService _bookingOrderService;
+
+        public BookingsController(IBookingService bookingService, IBookingOrderService bookingOrderService)
+        {
+            _bookingService = bookingService;
+            _bookingOrderService = bookingOrderService;
+        }
+
+        [HttpGet("bookingNumber/{bookingNumber}")]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BookingDTO))]
+        [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public async Task<IActionResult> GetBookingsByBookingNumber([FromRoute] string bookingNumber)
+        {
+            ServiceResponse<BookingDTO?> result = await _bookingService.GetBookingByBookingNumberAsync(bookingNumber);
+
+            return result.FormatResponse();
+        }
+
+        [HttpGet("email/{email}")]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<BookingDTO>))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public IActionResult GetBookingsByEmail([FromRoute] string email)
+        {
+            ServiceResponse<IEnumerable<BookingDTO>?> result = _bookingService.GetBookingsByEmail(email);
+
+            return result.FormatResponse();
+        }
+
+        [HttpGet("orderNumber/{orderNumber}")]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<BookingDTO>))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public IActionResult GetBookingsByOrderNumber([FromRoute] string orderNumber)
+        {
+            ServiceResponse<IEnumerable<BookingDTO>?> result = _bookingService.GetBookingsByOrderNumber(orderNumber);
+
+            return result.FormatResponse();
+        }
+
+        [HttpGet("id/{bookingId}")]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BookingDTO))]
+        [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))]
+        public async Task<IActionResult> GetBookingById([FromRoute] int bookingId)
+        {
+            ServiceResponse<BookingDTO?> result = await _bookingService.GetBookingByBookingId(bookingId);
+
+            return result.FormatResponse();
+        }
+
+        [HttpPost]
+        [Consumes(MediaTypeNames.Application.Json)]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BookingResponseDTO))]
+        [ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status500InternalServerError, Type = typeof(ProblemDetails))]
+        public async Task<IActionResult> PostBooking([FromBody] BookingOrderDTO bookingOrderDTO)
+        {
+            ServiceResponse<BookingResponseDTO?> result = await _bookingOrderService.CreateBookingOrderAsync(bookingOrderDTO);
+
+            return result.FormatResponse();
+        }
+
+        [HttpGet("payment/{orderNumber}")]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BookingResponseDTO))]
+        [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public async Task<IActionResult> GetBookingPayment([FromRoute] string orderNumber)
+        {
+            ServiceResponse<BookingResponseDTO?> result = await _bookingOrderService.GetCheckoutUrlAsync(orderNumber);
+
+            return result.FormatResponse();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Controllers/SeatsController.cs b/BookingService/FlightBooking.Service/Controllers/SeatsController.cs
new file mode 100644
index 0000000..a6ca8bb
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Controllers/SeatsController.cs
@@ -0,0 +1,42 @@
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Services;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.AspNetCore.Mvc;
+using System.Net.Mime;
+
+namespace FlightBooking.Service.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class SeatsController : ControllerBase
+    {
+        private readonly IReservedSeatService _service;
+
+        public SeatsController(IReservedSeatService service)
+        {
+            _service = service;
+        }
+
+        [HttpGet]
+        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<ReservedSeatDTO>))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public IActionResult GetAvailableSeats([FromQuery] string flightNumber)
+        {
+            ServiceResponse<IEnumerable<ReservedSeatDTO>> result = _service.GetAvailableSeatsByFlightNumber(flightNumber);
+
+            return result.FormatResponse();
+        }
+
+        [HttpPost]
+        [Consumes(MediaTypeNames.Application.Json)]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProblemDetails))]
+        [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+        public async Task<IActionResult> ReserveSeat([FromBody] ReservedSeatRequestDTO requestDTO)
+        {
+            ServiceResponse<string> result = await _service.ReserveSeatAsync(requestDTO);
+
+            return result.FormatResponse();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Controllers/StripeController.cs b/BookingService/FlightBooking.Service/Controllers/StripeController.cs
new file mode 100644
index 0000000..0f9bf55
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Controllers/StripeController.cs
@@ -0,0 +1,69 @@
+using FlightBooking.Service.Data.Configs;
+using FlightBooking.Service.Services;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using Stripe;
+using System.Text;
+
+namespace FlightBooking.Service.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class StripeController : ControllerBase
+    {
+        private readonly StripeConfig _stripeConfig;
+        private readonly IStripeService _stripeService;
+        private readonly ILogger<StripeController> _logger;
+
+        public StripeController(IOptionsMonitor<StripeConfig> options, IStripeService stripeService, ILogger<StripeController> logger)
+        {
+            _stripeConfig = options.CurrentValue;
+            _stripeService = stripeService;
+            _logger = logger;
+        }
+
+        //webhook for stripe to verify payment
+        [HttpPost]
+        public async Task<IActionResult> NotificationWebhookAsync()
+        {
+            //var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
+
+            string requestBody;
+            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
+            {
+                requestBody = await reader.ReadToEndAsync();
+            }
+
+            if (string.IsNullOrEmpty(requestBody))
+            {
+                //_logger.LogInformation("Event object is empty", eventObject);
+                return BadRequest();
+            }
+
+            string stripeSigningKey = _stripeConfig.SigningSecret;
+
+            Event stripeEvent;
+
+            try
+            {
+                stripeEvent = EventUtility.ConstructEvent(requestBody, Request.Headers["Stripe-Signature"], stripeSigningKey, throwOnApiVersionMismatch: false);
+            }
+            catch (StripeException exception)
+            {
+                _logger.LogError(exception.ToString());
+                return BadRequest();
+            }
+
+            //Since this is the only event we are handling.
+            if (stripeEvent.Type == Events.CheckoutSessionCompleted)
+            {
+                var response = await _stripeService.ProcessPayment(stripeEvent);
+
+                return response.FormatResponse();
+            }
+
+            return Ok();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Configs/ConfigSettings.cs b/BookingService/FlightBooking.Service/Data/Configs/ConfigSettings.cs
new file mode 100644
index 0000000..72ff348
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Configs/ConfigSettings.cs
@@ -0,0 +1,15 @@
+namespace FlightBooking.Service.Data.Configs
+{
+    public class ConfigSettings
+    {
+    }
+
+    public class StripeConfig
+    {
+        public const string ConfigName = nameof(StripeConfig);
+
+        public string SecretKey { get; set; } = null!;
+        public string PublicKey { get; set; } = null!;
+        public string SigningSecret { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Configs/ConfigSettingsModule.cs b/BookingService/FlightBooking.Service/Data/Configs/ConfigSettingsModule.cs
new file mode 100644
index 0000000..21c0d09
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Configs/ConfigSettingsModule.cs
@@ -0,0 +1,10 @@
+namespace FlightBooking.Service.Data.Configs
+{
+    public static class ConfigSettingsModule
+    {
+        public static void AddConfigSettings(this IServiceCollection services, IConfiguration configuration)
+        {
+            services.Configure<StripeConfig>(configuration.GetSection(StripeConfig.ConfigName));
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Constants.cs b/BookingService/FlightBooking.Service/Data/Constants.cs
new file mode 100644
index 0000000..ff8ff81
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Constants.cs
@@ -0,0 +1,38 @@
+namespace FlightBooking.Service.Data
+{
+    public class Constants
+    {
+    }
+
+    internal static class RepositoryConstants
+    {
+        public const string LoggingStarted = "Started logging";
+        public const string CreateNullError = "Attempt to insert empty entity. Type of Entity : {0}";
+        public const string DeleteNullError = "Could not find entity for deleting. type of Entity : {0}";
+        public const string BulkDeleteNullError = "Attempt to Delete empty list of entities. Type of Entity : {0}";
+        public const string BulkCreateNullError = "Attempt to insert empty list of entities. Type of Entity : {0}";
+        public const string EmptySaveInfo = "No changes was written to underlying database.";
+        public const string UpdateException = "Update Exception";
+        public const string UpdateConcurrencyException = "Update Concurrency Exception";
+        public const string SaveChangesException = "Generic Error in Generic Repo Update method";
+    }
+
+    internal static class ServiceErrorMessages
+    {
+        public const string Success = "The operation was successful";
+        public const string Failed = "An unhandled errror has occured while processing your request";
+        public const string UpdateError = "There was an error carrying out operation";
+        public const string MisMatch = "The entity Id does not match the supplied Id";
+        public const string EntityIsNull = "Supplied entity is null or supplied list of entities is empty. Check our docs";
+        public const string EntityNotFound = "The requested resource was not found. Verify that the supplied Id is correct";
+        public const string Incompleted = "Some actions may not have been successfully processed";
+        public const string EntityExist = "An entity of the same name or id exists";
+        public const string InvalidParam = "A supplied parameter or model is invalid. Check the docs";
+        public const string UnprocessableEntity = "The action cannot be processed";
+        public const string InternalServerError = "An internal server error and request could not processed";
+        public const string OperationFailed = "Operation failed";
+
+        public const string ParameterEmptyOrNull = "The parameter list is null or empty";
+        public const string RequestIdRequired = "Request Id is required";
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/BookingDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/BookingDTO.cs
new file mode 100644
index 0000000..8a93333
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/BookingDTO.cs
@@ -0,0 +1,56 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.DTO
+{
+    public class BookingDTO
+    {
+        public int Id { get; set; }
+        public string FirstName { get; set; } = null!;
+        public string LastName { get; set; } = null!;
+        public string PhoneNumber { get; set; } = null!;
+        public string Email { get; set; } = null!;
+        public string Address { get; set; } = null!;
+        public DateOnly DateOfBirth { get; set; }
+
+        [EnumDataType(typeof(Gender))]
+        public Gender Gender { get; set; }
+        public DateTime CreatedAt { get; set; }
+
+        public string BookingNumber { get; set; } = null!;
+        public int BookingOrderId { get; set; }
+
+        [EnumDataType(typeof(BookingStatus))]
+        public BookingStatus BookingStatus { get; set; } = BookingStatus.Pending;
+        public string? SeatNumber { get; set; }
+
+        public BookingFlightInformationDTO FlightInformation { get; set; } = null!;
+        public BookingFlightFareDTO FlightFare { get; set; } = null!;
+    }
+
+    public class BookingRequestDTO
+    {
+        [Required]
+        public string FirstName { get; set; } = null!;
+
+        [Required]
+        public string LastName { get; set; } = null!;
+
+        public string PhoneNumber { get; set; } = null!;
+        public string? Email { get; set; }
+
+        [Required]
+        public string Address { get; set; } = null!;
+
+        [Required]
+        public DateOnly DateOfBirth { get; set; }
+
+        [EnumDataType(typeof(Gender))]
+        public Gender Gender { get; set; } = Gender.PreferNotToSay;
+
+        [Required]
+        [Range(1, int.MaxValue)]
+        public int OutboundFareId { get; set; } //We are keeping Fare per booking to allow flexibility e.g Adult in Economy and Child in Business class
+
+        public int? ReturnFareId { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/BookingOrderDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/BookingOrderDTO.cs
new file mode 100644
index 0000000..80a6ee1
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/BookingOrderDTO.cs
@@ -0,0 +1,25 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.DTO
+{
+    public class BookingOrderDTO
+    {
+        [Required]
+        public string Email { get; set; } = null!;
+
+        [Required]
+        public string OutboundFlightNumber { get; set; } = null!;
+
+        public string? ReturnFlightNumber { get; set; }
+
+        [Required]
+        public List<BookingRequestDTO> Bookings { get; set; } = new List<BookingRequestDTO>();
+    }
+
+    public class BookingResponseDTO
+    {
+        public string OrderNumber { get; set; } = null!;
+        public string PaymentLink { get; set; } = null!;
+        public DateTime OrderExpiration { get; set; } = DateTime.UtcNow.AddHours(1);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/FlightFareDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/FlightFareDTO.cs
new file mode 100644
index 0000000..ae7db01
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/FlightFareDTO.cs
@@ -0,0 +1,16 @@
+namespace FlightBooking.Service.Data.DTO
+{
+    public class FlightFareDTO : BookingFlightFareDTO
+    {
+        public int Id { get; set; }
+        public decimal AvailableSeats { get; set; }
+    }
+
+    public class BookingFlightFareDTO
+    {
+        public string FareCode { get; set; } = null!;
+        public string FareName { get; set; } = null!;
+        public decimal Price { get; set; }
+        public string FlightNumber { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/FlightInformationDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/FlightInformationDTO.cs
new file mode 100644
index 0000000..eb8acda
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/FlightInformationDTO.cs
@@ -0,0 +1,19 @@
+namespace FlightBooking.Service.Data.DTO
+{
+    public class FlightInformationDTO : BookingFlightInformationDTO
+    {
+        public int Id { get; set; }
+        public int SeatCapacity { get; set; }
+        public int AvailableSeats { get; set; }
+    }
+
+    public class BookingFlightInformationDTO
+    {
+        public string FlightNumber { get; set; } = null!;
+        public string Origin { get; set; } = null!;
+        public string Destination { get; set; } = null!;
+        public DateTime DepartureDate { get; set; }
+        public DateTime ArrivalDate { get; set; }
+        public string Airline { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/ReservedSeatDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/ReservedSeatDTO.cs
new file mode 100644
index 0000000..862b363
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/ReservedSeatDTO.cs
@@ -0,0 +1,17 @@
+namespace FlightBooking.Service.Data.DTO
+{
+    public class ReservedSeatDTO
+    {
+        public string SeatNumber { get; set; } = null!; // e.g 1A, 33B
+
+        public string FlightNumber { get; set; } = null!;
+
+        public bool IsReserved { get; set; }
+    }
+
+    public class ReservedSeatRequestDTO
+    {
+        public string SeatNumber { get; set; } = null!; // e.g 1A, 33B
+        public string BookingNumber { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DTO/StripeDataDTO.cs b/BookingService/FlightBooking.Service/Data/DTO/StripeDataDTO.cs
new file mode 100644
index 0000000..b6ca868
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DTO/StripeDataDTO.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.DTO
+{
+    public class StripeDataDTO
+    {
+        [Required]
+        public string SuccessUrl { get; set; } = null!;
+
+        [Required]
+        public string CancelUrl { get; set; } = null!;
+
+        [Required]
+        public string ProductName { get; set; } = null!;
+
+        [Required]
+        public string ProductDescription { get; set; } = null!;
+
+        [Required]
+        [Range(0.5, double.MaxValue)] //minimum of 50 cents
+        public decimal Amount { get; set; }
+
+        [Required]
+        public string CustomerEmail { get; set; } = null!;
+
+        [Required]
+        public string CurrencyCode { get; set; } = "USD";
+
+        [Required]
+        public string OrderNumber { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/DatabaseSeeding.cs b/BookingService/FlightBooking.Service/Data/DatabaseSeeding.cs
new file mode 100644
index 0000000..bd27596
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/DatabaseSeeding.cs
@@ -0,0 +1,158 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Data
+{
+    public static class DatabaseSeeding
+    {
+        public static void Initialize(IServiceProvider serviceProvider)
+        {
+            using (var context = new FlightBookingContext(serviceProvider.GetRequiredService<DbContextOptions<FlightBookingContext>>()))
+            {
+                if (context.FlightInformation.Any())
+                {
+                    return;
+                }
+
+                string flightA = Guid.NewGuid().ToString("N")[..4].ToUpper();
+                string flightB = Guid.NewGuid().ToString("N")[..4].ToUpper();
+                List<FlightFare> flightFaresA = new List<FlightFare>
+                {
+                    new FlightFare
+                    {
+                        FareName = "Economy class",
+                        FareCode = "Eco-1",
+                        Price = 4000,
+                        SeatCapacity = 30,
+                        SeatReserved = 0,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                    },
+                    new FlightFare
+                    {
+                        FareName = "Business class",
+                        FareCode = "Biz-1",
+                        Price = 4000,
+                        SeatCapacity = 30,
+                        SeatReserved = 0,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                    },
+                };
+
+                List<FlightFare> flightFaresB = new List<FlightFare>
+                {
+                    new FlightFare
+                    {
+                        FareName = "Economy class",
+                        FareCode = "Eco-11",
+                        Price = 5000,
+                        SeatCapacity = 20,
+                        SeatReserved = 0,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                    },
+                    new FlightFare
+                    {
+                        FareName = "Business class",
+                        FareCode = "Biz-11",
+                        Price = 4000,
+                        SeatCapacity = 10,
+                        SeatReserved = 0,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                    },
+                };
+
+                //Create available seats
+                var reservedSeatsA = GenerateSeats(flightA, 60);
+                var reservedSeatsB = GenerateSeats(flightB, 60);
+
+                List<FlightInformation> flights = new List<FlightInformation>
+                {
+                    new FlightInformation
+                    {
+                        SeatCapacity = 60,
+                        DepartureDate = DateTime.UtcNow.AddMonths(3),
+                        ArrivalDate = DateTime.UtcNow.AddMonths(3).AddHours(4),
+                        Airline = "Emirates",
+                        SeatReserved = 0,
+                        Destination = "London",
+                        Origin = "Lagos",
+                        FlightNumber = flightA,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                        FlightFares = flightFaresA,
+                        ReservedSeats = reservedSeatsA,
+                    },
+                    new FlightInformation
+                    {
+                        SeatCapacity = 40,
+                        DepartureDate = DateTime.UtcNow.AddMonths(3).AddDays(7),
+                        ArrivalDate = DateTime.UtcNow.AddMonths(3).AddDays(7).AddHours(4),
+                        Airline = "Emirates",
+                        SeatReserved = 0,
+                        Destination = "Lagos",
+                        Origin = "London",
+                        FlightNumber = flightB,
+                        CreatedAt = DateTime.UtcNow,
+                        UpdatedAt = DateTime.UtcNow,
+                        FlightFares = flightFaresB,
+                        ReservedSeats = reservedSeatsB
+                    }
+                };
+
+                context.FlightInformation.AddRange(flights);
+
+                context.SaveChanges();
+
+                context.Database.EnsureCreated();
+            }
+        }
+
+        private static List<ReservedSeat> GenerateSeats(string flightNumber, int flightCapacity)
+        {
+            //assume seats are in group of 4 Alphabets e.g 1A, 1B, 1C, 1D
+
+            Dictionary<int, string> SeatMaps = new Dictionary<int, string>
+            {
+                {1, "A" },
+                {2, "B" },
+                {3, "C" },
+                {4, "D" }
+            };
+
+            int seatId = 1;
+            int seatCount = 1;
+
+            List<string> seatNumbers = new List<string>();
+
+            for (int i = 1; i < flightCapacity + 1; i++)
+            {
+                if (seatCount > 4)
+                {
+                    seatId++;
+                    seatCount = 1;
+                }
+
+                seatNumbers.Add(seatId + SeatMaps[seatCount]);
+                seatCount++;
+            }
+
+            List<ReservedSeat> reservedSeats = new List<ReservedSeat>();
+
+            foreach (var seatNumber in seatNumbers)
+            {
+                reservedSeats.Add(new ReservedSeat
+                {
+                    BookingNumber = null,
+                    FlightNumber = flightNumber,
+                    IsReserved = false,
+                    SeatNumber = seatNumber
+                });
+            }
+
+            return reservedSeats;
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Enums.cs b/BookingService/FlightBooking.Service/Data/Enums.cs
new file mode 100644
index 0000000..15a8a62
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Enums.cs
@@ -0,0 +1,40 @@
+namespace FlightBooking.Service.Data
+{
+    public enum Gender
+    {
+        Female = 1,
+        Male,
+        Transgender,
+        Fluid,
+        PreferNotToSay
+    }
+
+    public enum InternalCode
+    {
+        UpdateError = -1,
+        Failed,
+        Success,
+        EntityIsNull,
+        EntityNotFound,
+        Mismatch,
+        InvalidParam,
+        Incompleted,
+        ListEmpty,
+        EntityExist,
+        Unprocessable,
+        Unauthorized,
+    }
+
+    public enum SortOrder
+    {
+        ASC = 1,
+        DESC = 2
+    }
+
+    public enum BookingStatus
+    {
+        Pending = 1,
+        Confirmed,
+        Paid
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/FlightBookingContext.cs b/BookingService/FlightBooking.Service/Data/FlightBookingContext.cs
new file mode 100644
index 0000000..ecdf63e
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/FlightBookingContext.cs
@@ -0,0 +1,70 @@
+using FlightBooking.Service.Data.ModelConfigurations;
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Data
+{
+    public class FlightBookingContext : DbContext
+    {
+        public FlightBookingContext(DbContextOptions<FlightBookingContext> options) : base(options)
+        {
+        }
+
+        public DbSet<Booking> Bookings { get; set; }
+        public DbSet<BookingOrder> BookingOrders { get; set; }
+        public DbSet<ReservedSeat> ReservedSeats { get; set; }
+        public DbSet<Payment> Payments { get; set; }
+        public DbSet<FlightFare> FlightFares { get; set; }
+        public DbSet<FlightInformation> FlightInformation { get; set; }
+
+        protected override void OnModelCreating(ModelBuilder modelBuilder)
+        {
+            base.OnModelCreating(modelBuilder);
+
+            //configure each model
+
+            modelBuilder.ApplyConfiguration(new FlightInformationConfiguration());
+            modelBuilder.ApplyConfiguration(new FlightFareConfiguration());
+            modelBuilder.ApplyConfiguration(new BookingConfiguration());
+            modelBuilder.ApplyConfiguration(new BookingOrderConfiguration());
+            modelBuilder.ApplyConfiguration(new PaymentConfiguration());
+            modelBuilder.ApplyConfiguration(new ReservedSeatConfiguration());
+
+            ////Ensure all dates are saved as UTC and read as UTC:
+            ////https://github.com/dotnet/efcore/issues/4711#issuecomment-481215673
+
+            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
+            {
+                foreach (var property in entityType.GetProperties())
+                {
+                    if (property.ClrType == typeof(DateTime))
+                    {
+                        modelBuilder.Entity(entityType.ClrType)
+                         .Property<DateTime>(property.Name)
+                         .HasConversion(
+                          v => v.ToUniversalTime(),
+                          v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
+                    }
+                    else if (property.ClrType == typeof(DateTime?))
+                    {
+                        modelBuilder.Entity(entityType.ClrType)
+                         .Property<DateTime?>(property.Name)
+                         .HasConversion(
+                          v => v.HasValue ? v.Value.ToUniversalTime() : v,
+                          v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);
+                    }
+                }
+            }
+        }
+
+        public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
+        {
+            return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
+        }
+
+        //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+        //{
+        //    base.OnConfiguring(optionsBuilder);
+        //}
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingConfiguration.cs
new file mode 100644
index 0000000..a07fc63
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingConfiguration.cs
@@ -0,0 +1,27 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class BookingConfiguration : IEntityTypeConfiguration<Booking>
+    {
+        public void Configure(EntityTypeBuilder<Booking> entity)
+        {
+            entity.HasOne(d => d.BookingOrder).WithMany(p => p.Bookings)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.BookingOrderId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+
+            entity.HasOne(d => d.FlightInformation).WithMany(p => p.Bookings)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.FlightId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+
+            entity.HasOne(d => d.FlightFare).WithMany(p => p.Bookings)
+               .HasPrincipalKey(p => p.Id)
+               .HasForeignKey(d => d.FlightFareId)
+               .OnDelete(DeleteBehavior.ClientSetNull);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingOrderConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingOrderConfiguration.cs
new file mode 100644
index 0000000..7ab6170
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/BookingOrderConfiguration.cs
@@ -0,0 +1,13 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class BookingOrderConfiguration : IEntityTypeConfiguration<BookingOrder>
+    {
+        public void Configure(EntityTypeBuilder<BookingOrder> entity)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightFareConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightFareConfiguration.cs
new file mode 100644
index 0000000..298a02f
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightFareConfiguration.cs
@@ -0,0 +1,17 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class FlightFareConfiguration : IEntityTypeConfiguration<FlightFare>
+    {
+        public void Configure(EntityTypeBuilder<FlightFare> entity)
+        {
+            entity.HasOne(d => d.FlightInformation).WithMany(p => p.FlightFares)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.FlightInformationId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightInformationConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightInformationConfiguration.cs
new file mode 100644
index 0000000..2af41e5
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/FlightInformationConfiguration.cs
@@ -0,0 +1,13 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class FlightInformationConfiguration : IEntityTypeConfiguration<FlightInformation>
+    {
+        public void Configure(EntityTypeBuilder<FlightInformation> entity)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/PaymentConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/PaymentConfiguration.cs
new file mode 100644
index 0000000..5b13234
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/PaymentConfiguration.cs
@@ -0,0 +1,17 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class PaymentConfiguration : IEntityTypeConfiguration<Payment>
+    {
+        public void Configure(EntityTypeBuilder<Payment> entity)
+        {
+            entity.HasOne(d => d.BookingOrder).WithMany(p => p.Payments)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.BookingOrderId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/ModelConfigurations/ReservedSeatConfiguration.cs b/BookingService/FlightBooking.Service/Data/ModelConfigurations/ReservedSeatConfiguration.cs
new file mode 100644
index 0000000..9ca62f1
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/ModelConfigurations/ReservedSeatConfiguration.cs
@@ -0,0 +1,17 @@
+using FlightBooking.Service.Data.Models;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace FlightBooking.Service.Data.ModelConfigurations
+{
+    public class ReservedSeatConfiguration : IEntityTypeConfiguration<ReservedSeat>
+    {
+        public void Configure(EntityTypeBuilder<ReservedSeat> entity)
+        {
+            entity.HasOne(d => d.FlightInformation).WithMany(p => p.ReservedSeats)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.FlightInformationId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/Booking.cs b/BookingService/FlightBooking.Service/Data/Models/Booking.cs
new file mode 100644
index 0000000..315ea18
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/Booking.cs
@@ -0,0 +1,36 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class Booking
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string FirstName { get; set; } = null!;
+        public string LastName { get; set; } = null!;
+        public string PhoneNumber { get; set; } = null!;
+        public string? Email { get; set; }
+        public string Address { get; set; } = null!;
+        public DateOnly? DateOfBirth { get; set; }
+        public Gender Gender { get; set; }
+
+        public string BookingNumber { get; set; } = null!;
+        public int BookingOrderId { get; set; }
+
+        public BookingStatus BookingStatus { get; set; } = BookingStatus.Pending;
+
+        public int FlightId { get; set; }
+        public int FlightFareId { get; set; }
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public virtual FlightInformation FlightInformation { get; set; } = null!;
+        public virtual FlightFare FlightFare { get; set; } = null!;
+        public virtual BookingOrder BookingOrder { get; set; } = null!;
+
+        //one to one to for seats. one booking at most one seat
+
+        public ReservedSeat? ReservedSeat { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/BookingOrder.cs b/BookingService/FlightBooking.Service/Data/Models/BookingOrder.cs
new file mode 100644
index 0000000..5dce348
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/BookingOrder.cs
@@ -0,0 +1,26 @@
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class BookingOrder
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string OrderNumber { get; set; } = null!;
+        public string Email { get; set; } = null!;
+
+        [Precision(19, 4)]
+        public decimal TotalAmount { get; set; }
+
+        public BookingStatus OrderStatus { get; set; } = BookingStatus.Pending;
+        public int NumberOfAdults { get; set; }
+        public int NumberOfChildren { get; set; }
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public ICollection<Booking> Bookings { get; set; } = new List<Booking>();
+        public ICollection<Payment> Payments { get; set; } = new List<Payment>();
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/FlightFare.cs b/BookingService/FlightBooking.Service/Data/Models/FlightFare.cs
new file mode 100644
index 0000000..9dfca35
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/FlightFare.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class FlightFare
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public int FlightInformationId { get; set; }
+        public string FareCode { get; set; } = null!;
+        public string FareName { get; set; } = null!;
+
+        [Precision(19, 4)]
+        public decimal Price { get; set; }
+
+        public int SeatCapacity { get; set; }
+        public int SeatReserved { get; set; }
+
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public ICollection<Booking> Bookings { get; set; } = new List<Booking>();
+
+        public virtual FlightInformation FlightInformation { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/FlightInformation.cs b/BookingService/FlightBooking.Service/Data/Models/FlightInformation.cs
new file mode 100644
index 0000000..ed01d2e
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/FlightInformation.cs
@@ -0,0 +1,25 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class FlightInformation
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string FlightNumber { get; set; } = null!;
+        public string Origin { get; set; } = null!;
+        public string Destination { get; set; } = null!;
+        public DateTime DepartureDate { get; set; }
+        public DateTime ArrivalDate { get; set; }
+        public string Airline { get; set; } = null!;
+        public int SeatCapacity { get; set; }
+        public int SeatReserved { get; set; }
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public ICollection<Booking> Bookings { get; set; } = new List<Booking>();
+        public ICollection<FlightFare> FlightFares { get; set; } = new List<FlightFare>();
+        public ICollection<ReservedSeat> ReservedSeats { get; set; } = new List<ReservedSeat>();
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/PassengerInformation.cs b/BookingService/FlightBooking.Service/Data/Models/PassengerInformation.cs
new file mode 100644
index 0000000..1bcb851
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/PassengerInformation.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class PassengerInformation
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string FirstName { get; set; } = null!;
+        public string LastName { get; set; } = null!;
+        public string? PhoneNumber { get; set; }
+        public string? Email { get; set; }
+        public string Address { get; set; } = null!;
+        public DateOnly DateOfBirth { get; set; }
+        public Gender Gender { get; set; }
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/Payment.cs b/BookingService/FlightBooking.Service/Data/Models/Payment.cs
new file mode 100644
index 0000000..4e9e2cb
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/Payment.cs
@@ -0,0 +1,30 @@
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class Payment
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string CustomerEmail { get; set; } = null!;
+
+        [Precision(19, 4)]
+        public decimal TransactionAmount { get; set; }
+
+        public string PaymentReference { get; set; } = null!;
+        public string OrderNumber { get; set; } = null!;
+        public string CurrencyCode { get; set; } = null!;
+        public string PaymentChannel { get; set; } = null!;
+        public string PaymentStatus { get; set; } = null!;
+        public int BookingOrderId { get; set; }
+        public DateTime TransactionDate { get; set; }
+        public string? MetaData { get; set; }
+
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public virtual BookingOrder BookingOrder { get; set; } = null!;
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Models/ReservedSeat.cs b/BookingService/FlightBooking.Service/Data/Models/ReservedSeat.cs
new file mode 100644
index 0000000..6f6fb69
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Models/ReservedSeat.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace FlightBooking.Service.Data.Models
+{
+    public class ReservedSeat
+    {
+        [Key]
+        public int Id { get; set; }
+
+        public string SeatNumber { get; set; } = null!; // e.g 1A, 33B
+        public string? BookingNumber { get; set; }
+        public int? BookingId { get; set; }  //FK to Booking
+        public string FlightNumber { get; set; } = null!;
+        public int FlightInformationId { get; set; }
+        public bool IsReserved { get; set; } = false;
+        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
+
+        public virtual FlightInformation FlightInformation { get; set; } = null!;
+        public virtual Booking? Booking { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Repository/GenericRepository.cs b/BookingService/FlightBooking.Service/Data/Repository/GenericRepository.cs
new file mode 100644
index 0000000..584354a
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Repository/GenericRepository.cs
@@ -0,0 +1,257 @@
+using Microsoft.EntityFrameworkCore;
+using System.Linq.Expressions;
+
+namespace FlightBooking.Service.Data.Repository
+{
+    public class GenericRepository<T> : IGenericRepository<T> where T : class, new()
+    {
+        //Responses: failed=0, success=1
+
+        //IEnumerable iterates over an in-memory collection while IQueryable does so on the DB
+        // call to .ToList to enable instant query against DB
+
+        protected FlightBookingContext _db;
+        protected ILogger _logger;
+
+        public GenericRepository(FlightBookingContext db, ILogger<GenericRepository<T>> logger)
+        {
+            _logger = logger;
+            _db = db;
+        }
+
+        public IQueryable<T> GetAll()
+        {
+            return _db.Set<T>();
+        }
+
+        public DbSet<T> GetDbSet()
+        {
+            return _db.Set<T>();
+        }
+
+        public IQueryable<T> Query()
+        {
+            return _db.Set<T>().AsQueryable();
+        }
+
+        #region Async Methods
+
+        public async Task<T?> GetByIdAsync(int id)
+        {
+            var entity = await _db.Set<T>().FindAsync(id);
+
+            return entity;
+        }
+
+        public async Task<T?> GetByGuidAsync(Guid id)
+        {
+            var entity = await _db.Set<T>().FindAsync(id);
+
+            return entity;
+        }
+
+        public async Task<int> CreateAsync(T entity, bool isSave = true)
+        {
+            if (entity == null)
+            {
+                _logger.LogError(RepositoryConstants.CreateNullError, typeof(T).Name);
+                return (int)InternalCode.EntityIsNull;
+            }
+
+            _db.Set<T>().Add(entity);
+
+            if (isSave)
+            {
+                return await SaveChangesToDbAsync();
+            }
+
+            return (int)InternalCode.Success;
+        }
+
+        public async Task<int> UpdateAsync(T entity, bool isSave = true)
+        {
+            //Check for this in each overriding implementation or services
+            //var prev = await GetById(id);
+
+            //if (prev == null)
+            //{
+            //    return 0;
+            //}
+
+            _db.Set<T>().Update(entity);
+
+            if (isSave)
+            {
+                return await SaveChangesToDbAsync();
+            }
+
+            return (int)InternalCode.Success;
+        }
+
+        public async Task<int> DeleteAsync(int id, bool isSave = true)
+        {
+            T? entity = await GetByIdAsync(id);
+
+            if (entity == null)
+            {
+                _logger.LogError(RepositoryConstants.DeleteNullError, typeof(T).Name);
+                return (int)InternalCode.EntityNotFound;
+            }
+
+            _db.Set<T>().Remove(entity);
+
+            if (isSave)
+            {
+                return await SaveChangesToDbAsync();
+            }
+
+            return (int)InternalCode.Success;
+        }
+
+        public async Task<int> BulkDeleteAsync(IEnumerable<int> entityId, bool isSave = true)
+        {
+            if (entityId == null || !entityId.Any())
+            {
+                _logger.LogError(RepositoryConstants.BulkDeleteNullError, typeof(T).Name);
+                return (int)InternalCode.EntityIsNull;
+            }
+
+            DbSet<T> table = _db.Set<T>();
+
+            foreach (int id in entityId)
+            {
+                T? entity = await GetByIdAsync(id);
+                if (entity != null)
+                {
+                    table.Remove(entity);
+                }
+            }
+
+            if (isSave)
+            {
+                return await SaveChangesToDbAsync();
+            }
+
+            return (int)InternalCode.Success;
+        }
+
+        public async Task<int> BulkCreateAsync(IEnumerable<T> entities, bool isSave = true)
+        {
+            if (entities == null || !entities.Any())
+            {
+                _logger.LogError(RepositoryConstants.BulkCreateNullError, typeof(T).Name);
+                return (int)InternalCode.EntityIsNull;
+            }
+
+            DbSet<T> table = _db.Set<T>();
+
+            table.AddRange(entities);
+
+            if (isSave)
+            {
+                return await SaveChangesToDbAsync();
+            }
+
+            return (int)InternalCode.Success;
+        }
+
+        //calling this once works since we are using just one DbContext
+        //TODO: returning 0 should not lead to 500 error. 0 means no entries were added which may be because all entries have been added already
+        //fix this after tests have been writing for projects
+        public async Task<int> SaveChangesToDbAsync()
+        {
+            _logger.LogInformation(RepositoryConstants.LoggingStarted);
+            int saveResult;
+
+            try
+            {
+                int tempResult = await _db.SaveChangesAsync(); //give numbers of entries updated in db. in some cases e.g Update, when no data changes, this method returns 0
+                if (tempResult == 0)
+                {
+                    _logger.LogInformation(RepositoryConstants.EmptySaveInfo);
+                }
+                saveResult = (int)InternalCode.Success; //means atleast one entry was made. 1 is InternalCode.Success.
+                                                        //saveResult = tempResult > 0 ? 1 : 0; //means atleast one entry was made. 1 is InternalCode.Success
+            }
+            catch (DbUpdateConcurrencyException ex)
+            {
+                _logger.LogError(ex, RepositoryConstants.UpdateConcurrencyException);
+                saveResult = (int)InternalCode.UpdateError;
+                throw;
+            }
+            catch (DbUpdateException ex)
+            {
+                _logger.LogError(ex, RepositoryConstants.UpdateException);
+                saveResult = (int)InternalCode.UpdateError;
+                throw;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, RepositoryConstants.SaveChangesException);
+                saveResult = (int)InternalCode.UpdateError;
+                throw;
+            }
+            return saveResult;
+        }
+
+        public async Task<bool> EntityExistsAsync(int id)
+        {
+            T? entityFound = await _db.Set<T>().FindAsync(id);
+            if (entityFound == null)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        #endregion Async Methods
+
+        public IQueryable<T> OrderByText(IQueryable<T> data, SortOrder order, Expression<Func<T, string>> expression)
+        {
+            IQueryable<T> orderedData;
+            if (order == SortOrder.ASC)
+            {
+                orderedData = data.OrderBy(expression);
+            }
+            else
+            {
+                orderedData = data.OrderByDescending(expression);
+            }
+
+            return orderedData;
+        }
+
+        public IQueryable<T> OrderByDate(IQueryable<T> data, SortOrder order, Expression<Func<T, DateTime>> expression)
+        {
+            IQueryable<T> orderedData;
+            if (order == SortOrder.ASC)
+            {
+                orderedData = data.OrderBy(expression);
+            }
+            else
+            {
+                orderedData = data.OrderByDescending(expression);
+            }
+
+            return orderedData;
+        }
+
+        public async Task<List<T>> TakeAndSkipAsync(IQueryable<T> data, int pageSize, int pageIndex)
+        {
+            //List<T> paginatedList = new List<T>();
+
+            //if (data == null || data.Count() <= 0)
+            //    return paginatedList;
+
+            //if (pageSize == 0 && pageIndex == 0)
+            //    return paginatedList;
+
+            int numRowSkipped = pageSize * (pageIndex - 1);
+
+            List<T> paginated = await data.Skip(numRowSkipped).Take(pageSize).ToListAsync();
+
+            return paginated;
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Repository/IGenericRepository.cs b/BookingService/FlightBooking.Service/Data/Repository/IGenericRepository.cs
new file mode 100644
index 0000000..74e90c8
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Repository/IGenericRepository.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore;
+using System.Linq.Expressions;
+
+namespace FlightBooking.Service.Data.Repository
+{
+    public interface IGenericRepository<T> where T : class
+    {
+        Task<int> BulkCreateAsync(IEnumerable<T> entities, bool isSave = true);
+
+        Task<int> BulkDeleteAsync(IEnumerable<int> ids, bool isSave = true);
+
+        Task<int> CreateAsync(T entity, bool isSave = true);
+
+        Task<int> DeleteAsync(int id, bool isSave = true);
+
+        Task<bool> EntityExistsAsync(int id);
+
+        Task<T?> GetByIdAsync(int id);
+
+        Task<T?> GetByGuidAsync(Guid id);
+
+        Task<int> UpdateAsync(T entity, bool isSave = true);
+
+        Task<int> SaveChangesToDbAsync();
+
+        DbSet<T> GetDbSet();
+
+        IQueryable<T> Query();
+
+        Task<List<T>> TakeAndSkipAsync(IQueryable<T> data, int pageSize, int pageIndex);
+
+        IQueryable<T> OrderByText(IQueryable<T> data, SortOrder order, Expression<Func<T, string>> expression);
+
+        IQueryable<T> OrderByDate(IQueryable<T> data, SortOrder order, Expression<Func<T, DateTime>> expression);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Data/Repository/RepositoryModule.cs b/BookingService/FlightBooking.Service/Data/Repository/RepositoryModule.cs
new file mode 100644
index 0000000..90b6c0e
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Data/Repository/RepositoryModule.cs
@@ -0,0 +1,17 @@
+using FlightBooking.Service.Data.Models;
+
+namespace FlightBooking.Service.Data.Repository
+{
+    public static class RepositoryModule
+    {
+        public static void AddRepository(this IServiceCollection services)
+        {
+            services.AddScoped<IGenericRepository<Booking>, GenericRepository<Booking>>();
+            services.AddScoped<IGenericRepository<FlightInformation>, GenericRepository<FlightInformation>>();
+            services.AddScoped<IGenericRepository<FlightFare>, GenericRepository<FlightFare>>();
+            services.AddScoped<IGenericRepository<Payment>, GenericRepository<Payment>>();
+            services.AddScoped<IGenericRepository<BookingOrder>, GenericRepository<BookingOrder>>();
+            services.AddScoped<IGenericRepository<ReservedSeat>, GenericRepository<ReservedSeat>>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/FlightBooking.Service.csproj b/BookingService/FlightBooking.Service/FlightBooking.Service.csproj
new file mode 100644
index 0000000..217d79c
--- /dev/null
+++ b/BookingService/FlightBooking.Service/FlightBooking.Service.csproj
@@ -0,0 +1,45 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+	<PropertyGroup>
+		<EnableNETAnalyzers>true</EnableNETAnalyzers>
+		<UserSecretsId>b1b4ccfd-9fcb-4702-b4e5-c4e88d0bc805</UserSecretsId>
+	</PropertyGroup>
+
+	<ItemGroup>
+		<PackageReference Include="AutoMapper" Version="13.0.1" />
+		<PackageReference Include="Azure.Identity" Version="1.10.4" />
+		<PackageReference Include="libphonenumber-csharp" Version="8.13.30" />
+		<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.2" />
+		<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.2" />
+		<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.5" />
+		<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
+			<PrivateAssets>all</PrivateAssets>
+			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+		</PackageReference>
+		<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
+			<PrivateAssets>all</PrivateAssets>
+			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+		</PackageReference>
+		<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.1" />
+		<PackageReference Include="MySqlConnector" Version="2.3.5" />
+		<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.8" />
+		<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.3.1" />
+
+		<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
+		<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.2" />
+		<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
+		<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.3.1" />
+		<PackageReference Include="NuGet.Common" Version="6.9.1" />
+		<PackageReference Include="NuGet.Protocol" Version="6.9.1" />
+		<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.1" />
+		<PackageReference Include="Stripe.net" Version="43.18.0" />
+		<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
+		<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.3.1" />
+	</ItemGroup>
+
+</Project>
diff --git a/BookingService/FlightBooking.Service/FlightBooking.Service.http b/BookingService/FlightBooking.Service/FlightBooking.Service.http
new file mode 100644
index 0000000..045f70b
--- /dev/null
+++ b/BookingService/FlightBooking.Service/FlightBooking.Service.http
@@ -0,0 +1,6 @@
+@FlightBooking.Service_HostAddress = http://localhost:5000
+
+GET {{FlightBooking.Service_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/BookingService/FlightBooking.Service/Middleware/ErrorHandlingMiddleware.cs b/BookingService/FlightBooking.Service/Middleware/ErrorHandlingMiddleware.cs
new file mode 100644
index 0000000..1510d26
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Middleware/ErrorHandlingMiddleware.cs
@@ -0,0 +1,6 @@
+namespace FlightBooking.Service.Middleware
+{
+    public class ErrorHandlingMiddleware
+    {
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Middleware/MiddlewareExtensions.cs b/BookingService/FlightBooking.Service/Middleware/MiddlewareExtensions.cs
new file mode 100644
index 0000000..6b50b93
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Middleware/MiddlewareExtensions.cs
@@ -0,0 +1,10 @@
+namespace FlightBooking.Service.Middleware
+{
+    public static class MiddlewareExtensions
+    {
+        public static IApplicationBuilder UseErrorHandlingMiddleware(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<ErrorHandlingMiddleware>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Program.cs b/BookingService/FlightBooking.Service/Program.cs
new file mode 100644
index 0000000..041f1b1
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Program.cs
@@ -0,0 +1,63 @@
+using FlightBooking.Service.Data;
+using NLog;
+using NLog.Web;
+
+namespace FlightBooking.Service
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
+
+            try
+            {
+                logger.Debug("init main");
+
+                var host = CreateHostBuilder(args).Build();
+
+                using (var scope = host.Services.CreateScope())
+                {
+                    var services = scope.ServiceProvider;
+
+                    try
+                    {
+                        DatabaseSeeding.Initialize(services);
+                    }
+                    catch (Exception ex)
+                    {
+                        logger.Error(ex, "An error occurred seeding the DB.");
+                    }
+                }
+
+                host.Run();
+            }
+            catch (Exception exception)
+            {
+                //NLog: catch setup errors
+                logger.Error(exception, "Stopped program because of exception");
+                throw;
+            }
+            finally
+            {
+                // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
+                LogManager.Shutdown();
+            }
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args)
+        {
+            return Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                })
+                .ConfigureLogging(logging =>
+                {
+                    logging.ClearProviders();
+                    logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
+                })
+                .UseNLog();  // NLog: Setup NLog for Dependency injection
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Properties/launchSettings.json b/BookingService/FlightBooking.Service/Properties/launchSettings.json
new file mode 100644
index 0000000..434256c
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:37680",
+      "sslPort": 44321
+    }
+  },
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "https": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "https://localhost:7287;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/BookingOrderService.cs b/BookingService/FlightBooking.Service/Services/BookingOrderService.cs
new file mode 100644
index 0000000..f1d70bd
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/BookingOrderService.cs
@@ -0,0 +1,391 @@
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class BookingOrderService : IBookingOrderService
+    {
+        private readonly IGenericRepository<BookingOrder> _orderRepo;
+        private readonly IGenericRepository<FlightInformation> _flightRepo;
+        private readonly IGenericRepository<FlightFare> _flightFareRepo;
+        private readonly IStripeService _stripeService;
+
+        private readonly ILogger<BookingOrderService> _logger;
+
+        private List<FlightFare> allFlightFares = new List<FlightFare>(); //declare once so we can use it throughout
+
+        public BookingOrderService(IGenericRepository<BookingOrder> orderRepo, IGenericRepository<FlightInformation> flightRepo,
+            IGenericRepository<FlightFare> flightFareRepo, IStripeService stripeService, ILogger<BookingOrderService> logger)
+        {
+            _orderRepo = orderRepo;
+            _flightRepo = flightRepo;
+            _flightFareRepo = flightFareRepo;
+            _stripeService = stripeService;
+            _logger = logger;
+        }
+
+        public async Task<ServiceResponse<BookingResponseDTO?>> CreateBookingOrderAsync(BookingOrderDTO order)
+        {
+            if (order == null)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.InvalidParam);
+            }
+
+            /*
+                Checks:
+                - outbound and return flights cannot be same
+                - Check if all the flights are available
+                - Check if the fares have available seats
+                - If Checks are not passed, return 422
+             */
+
+            bool hasReturnFlight = !string.IsNullOrWhiteSpace(order.ReturnFlightNumber);
+
+            //Outbound and Return flights cannot be the same
+            if (hasReturnFlight && order.ReturnFlightNumber == order.OutboundFlightNumber)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "Outbound and return flights cannot be the same");
+            }
+
+            int totalFlights = order.Bookings.Count;
+
+            FlightInformation outboundFlightInfo = new FlightInformation();
+            FlightInformation returnFlightInfo = new FlightInformation();
+
+            //Check if the outbound flight is valid and if seats are available
+            var outboundFlight = CheckAvailableFlight(order.OutboundFlightNumber, totalFlights);
+
+            //If flight not valid, return false
+            if (outboundFlight.FlightInformation == null)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "The selected flight is not valid");
+            }
+
+            //if it's booked to Max, return error
+            if (outboundFlight.IsBookedToMax)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "The number of flights exceed number of available seats");
+            }
+
+            outboundFlightInfo = outboundFlight.FlightInformation;
+
+            //Check if Return flight available and not booked to max
+
+            if (hasReturnFlight)
+            {
+                //If none of the Booking
+
+                var returnFlight = CheckAvailableFlight(order.ReturnFlightNumber!, totalFlights);
+
+                if (returnFlight.FlightInformation == null)
+                {
+                    return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "The selected flight is not valid");
+                }
+
+                if (returnFlight.IsBookedToMax)
+                {
+                    return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "The number of flights exceed number of available seats");
+                }
+
+                returnFlightInfo = returnFlight.FlightInformation;
+            }
+
+            //Check if the selected Fares for each flight is valid and seats are available
+            var (IsAllFareExists, IsAnyFareMaxedOut, FareCodes) = CheckIfAnyFareIsMaxedOut(order, hasReturnFlight);
+
+            if (!IsAllFareExists)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "Some selected fare do not exist. Please check that all fare exists");
+            }
+
+            if (IsAnyFareMaxedOut)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "The number of flights exceed number of available seats");
+            }
+
+            //if all checks passed, lets reduce number of available seats.
+            //If Checks are passed, set status as InProgress and reduce available seats to avoid overbooking the flight
+            //We hold a seat for N mins max(N is set in config). Use a background job to return UnbookedSeats back into the Pool
+
+            await UpdateAvailableSeats(order, FareCodes);
+
+            string orderReference = Guid.NewGuid().ToString("N")[..10].ToUpper();
+
+            //Create all the bookings
+            List<Booking> bookings = new List<Booking>();
+
+            decimal totalAmount = 0;
+            foreach (var booking in order.Bookings)
+            {
+                //TODO: Use AutoMapper
+                bookings.Add(new Booking
+                {
+                    FirstName = booking.FirstName,
+                    LastName = booking.LastName,
+                    PhoneNumber = booking.PhoneNumber,
+                    Email = booking.Email,
+                    DateOfBirth = booking.DateOfBirth,
+                    Address = booking.Address,
+                    Gender = booking.Gender,
+                    BookingNumber = Guid.NewGuid().ToString("N")[..10].ToUpper(),
+                    BookingStatus = BookingStatus.Confirmed,
+                    FlightId = outboundFlightInfo.Id,
+                    FlightFareId = booking.OutboundFareId,
+                    CreatedAt = DateTime.UtcNow
+                });
+
+                totalAmount += allFlightFares.FirstOrDefault(x => x.Id == booking.OutboundFareId)!.Price;
+
+                //If return flight, add a seperate booking
+                if (hasReturnFlight)
+                {
+                    bookings.Add(new Booking
+                    {
+                        FirstName = booking.FirstName,
+                        LastName = booking.LastName,
+                        PhoneNumber = booking.PhoneNumber,
+                        Email = booking.Email,
+                        DateOfBirth = booking.DateOfBirth,
+                        Address = booking.Address,
+                        Gender = booking.Gender,
+                        BookingNumber = Guid.NewGuid().ToString("N")[..10].ToUpper(),
+                        BookingStatus = BookingStatus.Confirmed,
+                        FlightId = returnFlightInfo.Id,
+                        FlightFareId = (int)booking.ReturnFareId!,
+                        CreatedAt = DateTime.UtcNow
+                    });
+
+                    totalAmount += allFlightFares.FirstOrDefault(x => x.Id == booking.ReturnFareId)!.Price;
+                }
+            }
+
+            //Sum all cost as part of Order
+
+            BookingOrder bookingOrder = new BookingOrder
+            {
+                Bookings = bookings,
+                Email = order.Email,
+                OrderStatus = BookingStatus.Confirmed,
+                TotalAmount = totalAmount,
+                OrderNumber = orderReference,
+                CreatedAt = DateTime.UtcNow,
+                NumberOfAdults = 1,
+                NumberOfChildren = 1,
+            };
+
+            int result = await _orderRepo.CreateAsync(bookingOrder);
+
+            if (result != 1)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, (InternalCode)result);
+            }
+
+            //Generate payment link with the cost if payment successful
+
+            /*
+             Return Order Number, Payment Link, Payment Expiry
+             */
+            StripeDataDTO stripeData = new StripeDataDTO
+            {
+                SuccessUrl = "https://localhost:44321/success",
+                CancelUrl = "https://localhost:44321/cancel",
+                ProductDescription = $"Booking for {orderReference}",
+                Amount = totalAmount,
+                CurrencyCode = "USD",
+                CustomerEmail = order.Email,
+                ProductName = "Flight Booking Service",
+                OrderNumber = orderReference,
+            };
+
+            var stripeResponse = _stripeService.GetStripeCheckoutUrl(stripeData);
+
+            BookingResponseDTO bookingResponse = new BookingResponseDTO
+            {
+                OrderNumber = orderReference,
+                PaymentLink = stripeResponse.Data
+            };
+
+            return new ServiceResponse<BookingResponseDTO?>(bookingResponse, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<BookingResponseDTO?>> GetCheckoutUrlAsync(string orderNumber)
+        {
+            if (string.IsNullOrWhiteSpace(orderNumber))
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.InvalidParam, "Order reference not supplied");
+            }
+
+            //gett the order details
+            var orderDetails = await _orderRepo.Query()
+                .FirstOrDefaultAsync(x => x.OrderNumber == orderNumber);
+
+            if (orderDetails == null)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.EntityNotFound, "The order with the supplied order number was not found");
+            }
+
+            if (orderDetails.OrderStatus == BookingStatus.Paid)
+            {
+                return new ServiceResponse<BookingResponseDTO?>(null, InternalCode.Unprocessable, "This order has already been paid for");
+            }
+
+            StripeDataDTO stripeData = new StripeDataDTO
+            {
+                SuccessUrl = "https://localhost:44321/success",
+                CancelUrl = "https://localhost:44321/cancel",
+                ProductDescription = $"Booking for Order : {orderDetails.OrderNumber}",
+                Amount = orderDetails.TotalAmount,
+                CurrencyCode = "USD",
+                CustomerEmail = orderDetails.Email,
+                ProductName = "Flight Booking Service",
+                OrderNumber = orderNumber
+            };
+
+            var stripeResponse = _stripeService.GetStripeCheckoutUrl(stripeData);
+
+            BookingResponseDTO bookingResponse = new BookingResponseDTO
+            {
+                OrderNumber = orderNumber,
+                PaymentLink = stripeResponse.Data
+            };
+
+            return new ServiceResponse<BookingResponseDTO?>(bookingResponse, InternalCode.Success);
+        }
+
+        private (FlightInformation? FlightInformation, bool IsBookedToMax) CheckAvailableFlight(string flightNumber, int totalFlights)
+        {
+            FlightInformation? flightInformation = _flightRepo.Query()
+                .FirstOrDefault(x => x.FlightNumber == flightNumber);
+
+            //If flight not valid, return false
+            if (flightInformation == null)
+            {
+                return (flightInformation, false);
+            }
+
+            int availableFlightCapacity = flightInformation.SeatCapacity - flightInformation.SeatReserved;
+
+            return (flightInformation, totalFlights > availableFlightCapacity);
+        }
+
+        private (bool IsAllFareExists, bool IsAnyFareMaxedOut, List<int> FareCodes) CheckIfAnyFareIsMaxedOut(BookingOrderDTO order, bool hasReturnFlight)
+        {
+            //get all flight fares for all the list ID. We can then use throughout the booking process
+            var validFlightFares = _flightFareRepo.Query()
+                .Include(x => x.FlightInformation)
+                .Where(x => x.FlightInformation.FlightNumber == order.OutboundFlightNumber);
+
+            //if return flight, then add the fares
+            if (hasReturnFlight)
+            {
+                validFlightFares = _flightFareRepo.Query()
+                .Include(x => x.FlightInformation)
+                .Where(x => x.FlightInformation.FlightNumber == order.OutboundFlightNumber
+                    || x.FlightInformation.FlightNumber == order.ReturnFlightNumber);
+            }
+
+            //we get all the flight fares and save to the variable so we can reuse
+            allFlightFares = validFlightFares.ToList();
+
+            List<int> fareIds = new List<int>();
+
+            //get all fare Id
+            var outboundFares = order.Bookings
+                .Select(x => x.OutboundFareId)
+                .ToList();
+
+            //Add to a list
+            fareIds.AddRange(outboundFares);
+
+            //we check if all fares are valid for that flight
+            var isAllFareValid = allFlightFares.Any(x => outboundFares.Contains(x.Id)
+                    && x.FlightInformation.FlightNumber == order.OutboundFlightNumber);
+
+            //if atleast one of the fare in the outbound flight is invalid, return false
+            if (!isAllFareValid)
+            {
+                return (false, true, new List<int>());
+            }
+
+            //check the codes for the return flights are also valid
+            if (hasReturnFlight)
+            {
+                var returnFares = order.Bookings
+                    .Select(x => (int)x.ReturnFareId!)
+                    .ToList();
+
+                fareIds.AddRange(returnFares);
+
+                isAllFareValid = allFlightFares.Any(x => returnFares.Contains(x.Id)
+                         && x.FlightInformation.FlightNumber == order.ReturnFlightNumber);
+
+                if (!isAllFareValid)
+                {
+                    return (false, true, new List<int>());
+                }
+            }
+
+            var flightFares = allFlightFares
+                .Select(y => new
+                {
+                    y.Id,
+                    y.FareCode,
+                    AvailableSeats = y.SeatCapacity - y.SeatReserved
+                }).ToList();
+
+            //group the fares by Id
+            var fareGroup = fareIds.GroupBy(x => x).ToList();
+
+            bool isAnyFareMaxedOut = true;
+
+            //for each fare, check if the seats are available
+            foreach (var group in fareGroup)
+            {
+                isAnyFareMaxedOut = flightFares.Any(x => x.Id == group.Key && group.Count() > x.AvailableSeats);
+
+                //if any fare is maxed out, terminate the loop
+                if (isAnyFareMaxedOut)
+                {
+                    break;
+                }
+            }
+
+            return (true, isAnyFareMaxedOut, fareIds);
+        }
+
+        private async Task UpdateAvailableSeats(BookingOrderDTO order, List<int> fareCodes)
+        {
+            int totalFlights = order.Bookings.Count;
+
+            int result = await _flightRepo.Query()
+                .Where(x => x.FlightNumber == order.OutboundFlightNumber)
+                .ExecuteUpdateAsync(x => x.SetProperty(y => y.SeatReserved, y => y.SeatReserved + totalFlights));
+
+            //If a return is booked, reduce the seats too
+            if (!string.IsNullOrWhiteSpace(order.ReturnFlightNumber))
+            {
+                result = await _flightRepo.Query()
+                    .Where(x => x.FlightNumber == order.ReturnFlightNumber)
+                    .ExecuteUpdateAsync(x => x.SetProperty(y => y.SeatReserved, y => y.SeatReserved + totalFlights));
+            }
+
+            //update fare capacity. includes all fares, initial and return
+            var grouped = fareCodes
+                .GroupBy(x => x).ToList();
+
+            foreach (var fare in grouped)
+            {
+                result = await _flightFareRepo.Query()
+                    .Where(x => x.Id == fare.Key)
+                    .ExecuteUpdateAsync(x => x.SetProperty(y => y.SeatReserved, y => y.SeatReserved + fare.Count()));
+            }
+
+            return;
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/BookingService.cs b/BookingService/FlightBooking.Service/Services/BookingService.cs
new file mode 100644
index 0000000..9dd41fe
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/BookingService.cs
@@ -0,0 +1,101 @@
+using AutoMapper;
+using AutoMapper.QueryableExtensions;
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class BookingService : IBookingService
+    {
+        private readonly IGenericRepository<Booking> _bookingRepo;
+        private readonly IMapper _mapper;
+
+        public BookingService(IGenericRepository<Booking> bookingRepo, IMapper mapper)
+        {
+            _bookingRepo = bookingRepo;
+            _mapper = mapper;
+        }
+
+        public async Task<ServiceResponse<BookingDTO?>> GetBookingByBookingNumberAsync(string bookingNumber)
+        {
+            if (string.IsNullOrWhiteSpace(bookingNumber))
+            {
+                return new ServiceResponse<BookingDTO?>(null, InternalCode.InvalidParam, "No booking number supplied");
+            }
+
+            var booking = await _bookingRepo.Query()
+                .Include(x => x.FlightFare)
+                .Include(x => x.FlightInformation)
+                .Include(x => x.ReservedSeat)
+                .FirstOrDefaultAsync(x => x.BookingNumber == bookingNumber);
+
+            if (booking == null)
+            {
+                return new ServiceResponse<BookingDTO?>(null, InternalCode.EntityNotFound, "No booking with that booking number exists");
+            }
+
+            var bookingDTO = _mapper.Map<Booking, BookingDTO>(booking);
+
+            return new ServiceResponse<BookingDTO?>(bookingDTO, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<BookingDTO?>> GetBookingByBookingId(int bookingId)
+        {
+            var booking = await _bookingRepo.Query()
+                .Include(x => x.FlightFare)
+                .Include(x => x.FlightInformation)
+                .Include(x => x.ReservedSeat)
+                .FirstOrDefaultAsync(x => x.Id == bookingId);
+
+            if (booking == null)
+            {
+                return new ServiceResponse<BookingDTO?>(null, InternalCode.EntityNotFound, "No booking with that booking ID exists");
+            }
+
+            var bookingDTO = _mapper.Map<Booking, BookingDTO>(booking);
+
+            return new ServiceResponse<BookingDTO?>(bookingDTO, InternalCode.Success);
+        }
+
+        public ServiceResponse<IEnumerable<BookingDTO>?> GetBookingsByEmail(string email)
+        {
+            if (string.IsNullOrWhiteSpace(email))
+            {
+                return new ServiceResponse<IEnumerable<BookingDTO>?>(null, InternalCode.InvalidParam, "No email supplied");
+            }
+
+            var bookings = _bookingRepo.Query()
+                .Include(x => x.FlightFare)
+                .Include(x => x.FlightInformation)
+                .Include(x => x.ReservedSeat)
+                .Where(x => x.Email == email)
+                .ProjectTo<BookingDTO>(_mapper.ConfigurationProvider)
+                .ToList();
+
+            return new ServiceResponse<IEnumerable<BookingDTO>?>(bookings, InternalCode.Success);
+        }
+
+        public ServiceResponse<IEnumerable<BookingDTO>?> GetBookingsByOrderNumber(string orderNumber)
+        {
+            if (string.IsNullOrWhiteSpace(orderNumber))
+            {
+                return new ServiceResponse<IEnumerable<BookingDTO>?>(null, InternalCode.InvalidParam, "No order number supplied");
+            }
+
+            var bookings = _bookingRepo.Query()
+                .Include(x => x.FlightFare)
+                .Include(x => x.FlightInformation)
+                .Include(x => x.ReservedSeat)
+                .Where(x => x.BookingOrder.OrderNumber == orderNumber)
+                .ProjectTo<BookingDTO>(_mapper.ConfigurationProvider)
+                .ToList();
+
+            return new ServiceResponse<IEnumerable<BookingDTO>?>(bookings, InternalCode.Success);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/FlightBookingProfile.cs b/BookingService/FlightBooking.Service/Services/FlightBookingProfile.cs
new file mode 100644
index 0000000..4a7d890
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/FlightBookingProfile.cs
@@ -0,0 +1,29 @@
+using AutoMapper;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+
+namespace FlightBooking.Service.Services
+{
+    public class FlightBookingProfile : Profile
+    {
+        public FlightBookingProfile()
+        {
+            CreateMap<FlightFare, FlightFareDTO>()
+                .ForMember(dest => dest.AvailableSeats, opt => opt.MapFrom(src => src.SeatCapacity - src.SeatReserved))
+                .ForMember(dest => dest.FlightNumber, opt => opt.MapFrom(src => src.FlightInformation.FlightNumber));
+
+            CreateMap<ReservedSeat, ReservedSeatDTO>();
+
+            CreateMap<FlightInformation, FlightInformationDTO>()
+                .ForMember(dest => dest.AvailableSeats, opt => opt.MapFrom(src => src.SeatCapacity - src.SeatReserved));
+
+            CreateMap<FlightInformation, BookingFlightInformationDTO>();
+
+            CreateMap<FlightFare, BookingFlightFareDTO>()
+               .ForMember(dest => dest.FlightNumber, opt => opt.MapFrom(src => src.FlightInformation.FlightNumber));
+
+            CreateMap<Booking, BookingDTO>()
+                .ForMember(dest => dest.SeatNumber, opt => opt.MapFrom(src => src.ReservedSeat != null ? src.ReservedSeat.SeatNumber : null));
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/FlightFareService.cs b/BookingService/FlightBooking.Service/Services/FlightFareService.cs
new file mode 100644
index 0000000..33bb18c
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/FlightFareService.cs
@@ -0,0 +1,44 @@
+using AutoMapper;
+using AutoMapper.QueryableExtensions;
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class FlightFareService : IFlightFareService
+    {
+        private readonly IGenericRepository<FlightFare> _fareRepository;
+        private readonly IMapper _mapper;
+
+        public FlightFareService(IMapper mapper, IGenericRepository<FlightFare> fareRepository)
+        {
+            _mapper = mapper;
+            _fareRepository = fareRepository;
+        }
+
+        public ServiceResponse<IEnumerable<FlightFareDTO>?> GetFaresByFlightNumber(string flightNumber)
+        {
+            var fares = _fareRepository.Query()
+                .Include(x => x.FlightInformation)
+                .Where(x => x.FlightInformation.FlightNumber == flightNumber)
+                .ProjectTo<FlightFareDTO>(_mapper.ConfigurationProvider)
+                .ToList();
+
+            return new ServiceResponse<IEnumerable<FlightFareDTO>?>(fares, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<string>> UpdateFlightFareCapacityAsync(int fareId)
+        {
+            int result = await _fareRepository.Query()
+                .Where(x => x.Id == fareId)
+                .ExecuteUpdateAsync(x => x.SetProperty(y => y.SeatReserved, y => y.SeatReserved + 1));
+
+            return new ServiceResponse<string>(string.Empty, (InternalCode)result);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/FlightService.cs b/BookingService/FlightBooking.Service/Services/FlightService.cs
new file mode 100644
index 0000000..f7f4e13
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/FlightService.cs
@@ -0,0 +1,47 @@
+using AutoMapper;
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class FlightService : IFlightService
+    {
+        private readonly IGenericRepository<FlightInformation> _flightRepo;
+        private readonly IMapper _mapper;
+
+        public FlightService(IGenericRepository<FlightInformation> flightRepo, IMapper mapper)
+        {
+            _mapper = mapper;
+            _flightRepo = flightRepo;
+        }
+
+        public async Task<ServiceResponse<FlightInformationDTO?>> GetFlightInformationAsync(string flightNumber)
+        {
+            FlightInformation? flight = await _flightRepo.Query()
+                .FirstOrDefaultAsync(x => x.FlightNumber == flightNumber);
+
+            if (flight == null)
+            {
+                return new ServiceResponse<FlightInformationDTO?>(null, InternalCode.EntityNotFound, "flight not found");
+            }
+
+            FlightInformationDTO flightDto = _mapper.Map<FlightInformation, FlightInformationDTO>(flight);
+
+            return new ServiceResponse<FlightInformationDTO?>(flightDto, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<string>> UpdateFlightCapacityAsync(string flightNumber, int bookedSeats)
+        {
+            int result = await _flightRepo.Query()
+                .Where(x => x.FlightNumber == flightNumber)
+                .ExecuteUpdateAsync(x => x.SetProperty(y => y.SeatReserved, y => y.SeatReserved + bookedSeats));
+
+            return new ServiceResponse<string>(string.Empty, (InternalCode)result);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IBookingOrderService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IBookingOrderService.cs
new file mode 100644
index 0000000..7e1b124
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IBookingOrderService.cs
@@ -0,0 +1,21 @@
+using FlightBooking.Service.Data.DTO;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IBookingOrderService
+    {
+        /// <summary>
+        /// Create a new order with a list of booking. Accepts one-way, two and multiple bookings per order
+        /// </summary>
+        /// <param name="order"></param>
+        /// <returns>Returns an object containing payment reference and order number</returns>
+        Task<ServiceResponse<BookingResponseDTO?>> CreateBookingOrderAsync(BookingOrderDTO order);
+
+        /// <summary>
+        /// Creates a Stripe payment link using the order number to search for the particular order
+        /// </summary>
+        /// <param name="orderNumber"></param>
+        /// <returns>Returns an object containing payment reference and order number</returns>
+        Task<ServiceResponse<BookingResponseDTO?>> GetCheckoutUrlAsync(string orderNumber);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IBookingService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IBookingService.cs
new file mode 100644
index 0000000..47c5aae
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IBookingService.cs
@@ -0,0 +1,35 @@
+using FlightBooking.Service.Data.DTO;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IBookingService
+    {
+        /// <summary>
+        /// Get booking information using booking ID
+        /// </summary>
+        /// <param name="bookingId"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<BookingDTO?>> GetBookingByBookingId(int bookingId);
+
+        /// <summary>
+        /// Get booking information using booking number
+        /// </summary>
+        /// <param name="bookingNumber"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<BookingDTO?>> GetBookingByBookingNumberAsync(string bookingNumber);
+
+        /// <summary>
+        /// Get all bookings for an email address
+        /// </summary>
+        /// <param name="email"></param>
+        /// <returns></returns>
+        ServiceResponse<IEnumerable<BookingDTO>?> GetBookingsByEmail(string email);
+
+        /// <summary>
+        /// Get all booking for an order
+        /// </summary>
+        /// <param name="orderNumber"></param>
+        /// <returns></returns>
+        ServiceResponse<IEnumerable<BookingDTO>?> GetBookingsByOrderNumber(string orderNumber);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IFlightFareService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IFlightFareService.cs
new file mode 100644
index 0000000..34e4545
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IFlightFareService.cs
@@ -0,0 +1,21 @@
+using FlightBooking.Service.Data.DTO;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IFlightFareService
+    {
+        /// <summary>
+        /// Get all the fares for a flight using flight number
+        /// </summary>
+        /// <param name="flightNumber"></param>
+        /// <returns></returns>
+        ServiceResponse<IEnumerable<FlightFareDTO>?> GetFaresByFlightNumber(string flightNumber);
+
+        /// <summary>
+        /// Update the flight capacity
+        /// </summary>
+        /// <param name="fareId"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<string>> UpdateFlightFareCapacityAsync(int fareId);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IFlightService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IFlightService.cs
new file mode 100644
index 0000000..290f5d2
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IFlightService.cs
@@ -0,0 +1,22 @@
+using FlightBooking.Service.Data.DTO;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IFlightService
+    {
+        /// <summary>
+        /// Gets the flight information for a flight
+        /// </summary>
+        /// <param name="flightNumber"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<FlightInformationDTO?>> GetFlightInformationAsync(string flightNumber);
+
+        /// <summary>
+        /// Updates the flight capacity
+        /// </summary>
+        /// <param name="flightNumber"></param>
+        /// <param name="bookedSeats"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<string>> UpdateFlightCapacityAsync(string flightNumber, int bookedSeats);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IReservedSeatService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IReservedSeatService.cs
new file mode 100644
index 0000000..c0f7055
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IReservedSeatService.cs
@@ -0,0 +1,29 @@
+using FlightBooking.Service.Data.DTO;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IReservedSeatService
+    {
+        /// <summary>
+        /// Gets all available seats for a flight
+        /// </summary>
+        /// <param name="flightNumber"></param>
+        /// <returns></returns>
+        ServiceResponse<IEnumerable<ReservedSeatDTO>> GetAvailableSeatsByFlightNumber(string flightNumber);
+
+        /// <summary>
+        /// Creates a seat reservation for a valid booking
+        /// </summary>
+        /// <param name="requestDTO"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<string>> ReserveSeatAsync(ReservedSeatRequestDTO requestDTO);
+
+        /// <summary>
+        /// Generates seat numbers for a flight based on flight capacity
+        /// </summary>
+        /// <param name="flightNumber"></param>
+        /// <param name="flightCapacity"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<string>> GenerateSeatNumbersAsync(string flightNumber, int flightCapacity);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/Interfaces/IStripeService.cs b/BookingService/FlightBooking.Service/Services/Interfaces/IStripeService.cs
new file mode 100644
index 0000000..abfb0f0
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/Interfaces/IStripeService.cs
@@ -0,0 +1,22 @@
+using FlightBooking.Service.Data.DTO;
+using Stripe;
+
+namespace FlightBooking.Service.Services.Interfaces
+{
+    public interface IStripeService
+    {
+        /// <summary>
+        /// Creates a Stripe payment link
+        /// </summary>
+        /// <param name="stripeDataDTO"></param>
+        /// <returns>Payment link</returns>
+        ServiceResponse<string> GetStripeCheckoutUrl(StripeDataDTO stripeDataDTO);
+
+        /// <summary>
+        /// Processes Stripe events when a checkout (payment) is completed
+        /// </summary>
+        /// <param name="stripeEvent"></param>
+        /// <returns></returns>
+        Task<ServiceResponse<string>> ProcessPayment(Event stripeEvent);
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/PaymentService.cs b/BookingService/FlightBooking.Service/Services/PaymentService.cs
new file mode 100644
index 0000000..b66d125
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/PaymentService.cs
@@ -0,0 +1,6 @@
+namespace FlightBooking.Service.Services
+{
+    public class PaymentService
+    {
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/ReservedSeatService.cs b/BookingService/FlightBooking.Service/Services/ReservedSeatService.cs
new file mode 100644
index 0000000..16126d1
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/ReservedSeatService.cs
@@ -0,0 +1,127 @@
+using AutoMapper;
+using AutoMapper.QueryableExtensions;
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class ReservedSeatService : IReservedSeatService
+    {
+        private readonly IGenericRepository<ReservedSeat> _seatRepo;
+        private readonly IGenericRepository<Booking> _bookingRepo;
+        private readonly IMapper _mapper;
+
+        public ReservedSeatService(IGenericRepository<ReservedSeat> seatRepository, IGenericRepository<Booking> bookingRepo,
+            IMapper mapper)
+        {
+            _seatRepo = seatRepository;
+            _bookingRepo = bookingRepo;
+            _mapper = mapper;
+        }
+
+        public async Task<ServiceResponse<string>> ReserveSeatAsync(ReservedSeatRequestDTO requestDTO)
+        {
+            if (requestDTO == null)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.InvalidParam);
+            }
+
+            //check if booking is valid
+            Booking? booking = await _bookingRepo.Query()
+               .Include(x => x.FlightInformation)
+               .FirstOrDefaultAsync(x => x.BookingNumber == requestDTO.BookingNumber);
+
+            if (booking == null)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.EntityNotFound, "Booking not found for the supplied booking number");
+            }
+
+            //check if seat is available
+            ReservedSeat? existingSeat = await _seatRepo.Query()
+                .Include(x => x.FlightInformation)
+                .FirstOrDefaultAsync(x => x.FlightNumber == booking.FlightInformation.FlightNumber
+                    && x.SeatNumber == requestDTO.SeatNumber);
+
+            if (existingSeat == null)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.Unprocessable, "The selected seat number does not exist");
+            }
+
+            if (existingSeat.IsReserved)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.Unprocessable, "The selected seat has already been reserved");
+            }
+
+            //reserve the seat
+            existingSeat.IsReserved = true;
+            existingSeat.BookingNumber = booking.BookingNumber;
+            existingSeat.BookingId = booking.Id;
+
+            int result = await _seatRepo.SaveChangesToDbAsync();
+
+            return new ServiceResponse<string>(string.Empty, (InternalCode)result);
+        }
+
+        public ServiceResponse<IEnumerable<ReservedSeatDTO>> GetAvailableSeatsByFlightNumber(string flightNumber)
+        {
+            List<ReservedSeatDTO> seats = _seatRepo.Query()
+                .Where(x => x.FlightNumber == flightNumber && !x.IsReserved)
+                .ProjectTo<ReservedSeatDTO>(_mapper.ConfigurationProvider)
+                .ToList();
+
+            return new ServiceResponse<IEnumerable<ReservedSeatDTO>>(seats, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<string>> GenerateSeatNumbersAsync(string flightNumber, int flightCapacity)
+        {
+            //assume seats are in group of 4 Alphabets e.g 1A, 1B, 1C, 1D
+
+            Dictionary<int, string> SeatMaps = new Dictionary<int, string>
+            {
+                {1, "A" },
+                {2, "B" },
+                {3, "C" },
+                {4, "D" }
+            };
+
+            int seatId = 1;
+            int seatCount = 1;
+
+            List<string> seatNumbers = new List<string>();
+
+            for (int i = 1; i < flightCapacity + 1; i++)
+            {
+                if (seatCount > 4)
+                {
+                    seatId++;
+                    seatCount = 1;
+                }
+
+                seatNumbers.Add(seatId + SeatMaps[seatCount]);
+                seatCount++;
+            }
+
+            List<ReservedSeat> reservedSeats = new List<ReservedSeat>();
+
+            foreach (var seatNumber in seatNumbers)
+            {
+                reservedSeats.Add(new ReservedSeat
+                {
+                    BookingNumber = null,
+                    FlightNumber = flightNumber,
+                    IsReserved = false,
+                    SeatNumber = seatNumber
+                });
+            }
+
+            int result = await _seatRepo.BulkCreateAsync(reservedSeats);
+
+            return new ServiceResponse<string>(string.Empty, (InternalCode)result);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/ResponseFormatter.cs b/BookingService/FlightBooking.Service/Services/ResponseFormatter.cs
new file mode 100644
index 0000000..504c418
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/ResponseFormatter.cs
@@ -0,0 +1,176 @@
+using FlightBooking.Service.Data;
+using Microsoft.AspNetCore.Mvc;
+
+namespace FlightBooking.Service.Services
+{
+    public static class FormatResponseExtension
+    {
+        public static ActionResult FormatResponse<T>(this ServiceResponse<T> serviceResponse)
+        {
+            ObjectResult response;
+            ProblemDetails problemDetails;
+
+            if (serviceResponse == null)
+            {
+                problemDetails = new ProblemDetails
+                {
+                    Status = 500,
+                    Title = ServiceErrorMessages.OperationFailed,
+                    Type = "https://tools.ietf.org/html/rfc7231#section-6.6"
+                };
+                return new ObjectResult(problemDetails)
+                {
+                    StatusCode = 500
+                };
+            }
+
+            switch (serviceResponse.ServiceCode)
+            {
+                case InternalCode.Failed:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 500,
+                        Title = ServiceErrorMessages.OperationFailed,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.6"
+                    };
+                    response = new ObjectResult(problemDetails)
+                    {
+                        StatusCode = 500
+                    };
+
+                    return response;
+
+                case InternalCode.Success:
+
+                    if (serviceResponse.Data != null)
+                    {
+                        Type dataType = serviceResponse.Data.GetType();
+
+                        if (dataType == typeof(string))
+                        {
+                            string? data = serviceResponse!.Data as string;
+                            if (string.IsNullOrEmpty(data))
+                            {
+                                return new OkResult();
+                            }
+                        }
+                    }
+
+                    return new OkObjectResult(serviceResponse.Data);
+
+                case InternalCode.UpdateError:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 500,
+                        Title = ServiceErrorMessages.InternalServerError,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.6"
+                    };
+                    response = new ObjectResult(problemDetails)
+                    {
+                        StatusCode = 500,
+                    };
+                    return response;
+
+                case InternalCode.Mismatch:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 400,
+                        Title = ServiceErrorMessages.MisMatch,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"
+                    };
+                    return new BadRequestObjectResult(problemDetails);
+
+                case InternalCode.EntityIsNull:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 400,
+                        Title = ServiceErrorMessages.EntityIsNull,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"
+                    };
+                    return new BadRequestObjectResult(problemDetails);
+
+                case InternalCode.InvalidParam:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 400,
+                        Title = ServiceErrorMessages.InvalidParam,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"
+                    };
+                    return new BadRequestObjectResult(problemDetails);
+
+                case InternalCode.EntityNotFound:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 404,
+                        Title = ServiceErrorMessages.EntityNotFound,
+                        Detail = string.IsNullOrEmpty(serviceResponse.Message) ? "The requested resource was not found" : serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.4"
+                    };
+                    return new NotFoundObjectResult(problemDetails);
+
+                case InternalCode.Incompleted:
+                    return new AcceptedResult("", serviceResponse.Data);
+
+                case InternalCode.ListEmpty:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 400,
+                        Title = ServiceErrorMessages.EntityIsNull,
+                        Detail = serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1"
+                    };
+                    return new BadRequestObjectResult(problemDetails);
+
+                case InternalCode.EntityExist:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 409,
+                        Title = ServiceErrorMessages.EntityExist,
+                        Detail = string.IsNullOrEmpty(serviceResponse.Message) ? $"An entity of the type exists" : serviceResponse.Message,
+                        Type = "https://tools.ietf.org/html/rfc7231#section-6.5.8"
+                    };
+                    return new ConflictObjectResult(problemDetails);
+
+                case InternalCode.Unprocessable:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 422,
+                        Title = ServiceErrorMessages.UnprocessableEntity,
+                        Detail = string.IsNullOrEmpty(serviceResponse.Message) ? "The request cannot be processed" : serviceResponse.Message
+                    };
+                    return new UnprocessableEntityObjectResult(problemDetails);
+
+                case InternalCode.Unauthorized:
+                    problemDetails = new ProblemDetails
+                    {
+                        Status = 401,
+                        Title = "Unathorized request",
+                        Detail = "The supplied credentials is invalid."
+                    };
+                    return new UnauthorizedObjectResult(problemDetails);
+
+                default:
+                    return new OkObjectResult(serviceResponse.Data);
+            }
+        }
+    }
+
+    public class ServiceResponse<T>
+    {
+        public InternalCode ServiceCode { get; set; } = InternalCode.Failed;
+        public T Data { get; set; }
+        public string Message { get; set; }
+
+        public ServiceResponse(T data, InternalCode serviceCode = InternalCode.Failed, string message = "")
+        {
+            Message = message;
+            ServiceCode = serviceCode;
+            Data = data;
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/ServicesModule.cs b/BookingService/FlightBooking.Service/Services/ServicesModule.cs
new file mode 100644
index 0000000..30710dc
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/ServicesModule.cs
@@ -0,0 +1,17 @@
+using FlightBooking.Service.Services.Interfaces;
+
+namespace FlightBooking.Service.Services
+{
+    public static class ServicesModule
+    {
+        public static void AddServices(this IServiceCollection services)
+        {
+            services.AddScoped<IBookingService, BookingService>();
+            services.AddScoped<IBookingOrderService, BookingOrderService>();
+            services.AddScoped<IReservedSeatService, ReservedSeatService>();
+            services.AddScoped<IFlightFareService, FlightFareService>();
+            services.AddScoped<IFlightService, FlightService>();
+            services.AddScoped<IStripeService, StripeService>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Services/StripeService.cs b/BookingService/FlightBooking.Service/Services/StripeService.cs
new file mode 100644
index 0000000..ab75571
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Services/StripeService.cs
@@ -0,0 +1,147 @@
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.Configs;
+using FlightBooking.Service.Data.DTO;
+using FlightBooking.Service.Data.Models;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Services.Interfaces;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using Stripe;
+using Stripe.Checkout;
+
+namespace FlightBooking.Service.Services
+{
+    ///<inheritdoc />
+    public class StripeService : IStripeService
+    {
+        private readonly StripeConfig _stripeConfig;
+        private readonly IGenericRepository<Payment> _paymentRepo;
+        private readonly IGenericRepository<BookingOrder> _orderRepo;
+
+        private readonly ILogger<StripeService> _logger;
+
+        public StripeService(IOptionsMonitor<StripeConfig> options, IGenericRepository<Payment> paymentRepo,
+            IGenericRepository<BookingOrder> orderRepo, ILogger<StripeService> logger)
+        {
+            _stripeConfig = options.CurrentValue;
+            _paymentRepo = paymentRepo;
+            _orderRepo = orderRepo;
+            _logger = logger;
+        }
+
+        public ServiceResponse<string> GetStripeCheckoutUrl(StripeDataDTO stripeDataDTO)
+        {
+            if (stripeDataDTO == null)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.InvalidParam, "Invalid Data");
+            }
+
+            string checkoutUrl = string.Empty;
+
+            try
+            {
+                StripeConfiguration.ApiKey = _stripeConfig.SecretKey;
+
+                var amountInCents = stripeDataDTO.Amount * 100;
+
+                var options = new SessionCreateOptions
+                {
+                    LineItems = new List<SessionLineItemOptions>
+                    {
+                      new SessionLineItemOptions
+                      {
+                        PriceData = new SessionLineItemPriceDataOptions
+                        {
+                            Currency = stripeDataDTO.CurrencyCode,
+                            UnitAmountDecimal = amountInCents, //in cents
+                            ProductData = new SessionLineItemPriceDataProductDataOptions
+                            {
+                                Name = stripeDataDTO.ProductName,
+                                Description = stripeDataDTO.ProductDescription
+                            },
+                        },
+                        Quantity = 1,
+                      },
+                    },
+                    Mode = "payment",
+                    SuccessUrl = stripeDataDTO.SuccessUrl,
+                    CancelUrl = stripeDataDTO.CancelUrl,
+                    ClientReferenceId = stripeDataDTO.OrderNumber,
+                    CustomerEmail = stripeDataDTO.CustomerEmail,
+                };
+                var service = new SessionService();
+                Session session = service.Create(options);
+                checkoutUrl = session.Url;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogCritical(ex.ToString());
+            }
+
+            return new ServiceResponse<string>(checkoutUrl, InternalCode.Success);
+        }
+
+        public async Task<ServiceResponse<string>> ProcessPayment(Event stripeEvent)
+        {
+            if (stripeEvent == null)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.InvalidParam);
+            }
+
+            var session = stripeEvent.Data.Object as Session;
+
+            //check if payment already saved, if yes, return
+            bool isPaymentSaved = _paymentRepo.Query()
+                .Any(x => x.OrderNumber == session!.ClientReferenceId);
+
+            if (isPaymentSaved)
+            {
+                return new ServiceResponse<string>(string.Empty, InternalCode.Success);
+            }
+
+            string orderNumber = session!.ClientReferenceId;
+
+            var bookingOrder = await _orderRepo.Query()
+                .Include(x => x.Bookings)
+                .FirstOrDefaultAsync(x => x.OrderNumber == orderNumber);
+
+            if (bookingOrder == null)
+            {
+                _logger.LogCritical("Payment made for a booking that doesn't exist");
+                return new ServiceResponse<string>(string.Empty, InternalCode.Success);
+            }
+
+            //save payment
+            Payment payment = new Payment
+            {
+                TransactionDate = session!.Created,
+                OrderNumber = orderNumber,
+                MetaData = JsonConvert.SerializeObject(session),
+                BookingOrderId = bookingOrder.Id,
+                CurrencyCode = session.Currency,
+                CustomerEmail = session.CustomerEmail,
+                PaymentReference = Guid.NewGuid().ToString("N").ToUpper(),
+                PaymentStatus = session.PaymentStatus,
+                CreatedAt = DateTime.UtcNow,
+                TransactionAmount = (decimal)session.AmountTotal!,
+                PaymentChannel = "Stripe",
+            };
+
+            await _paymentRepo.CreateAsync(payment);
+
+            //update flight and booking information
+
+            bookingOrder.OrderStatus = BookingStatus.Paid;
+
+            foreach (var booking in bookingOrder.Bookings)
+            {
+                booking.BookingStatus = BookingStatus.Paid;
+            }
+
+            await _orderRepo.SaveChangesToDbAsync();
+
+            return new ServiceResponse<string>(string.Empty, InternalCode.Success);
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/Startup.cs b/BookingService/FlightBooking.Service/Startup.cs
new file mode 100644
index 0000000..540cfff
--- /dev/null
+++ b/BookingService/FlightBooking.Service/Startup.cs
@@ -0,0 +1,162 @@
+using FlightBooking.Service.Data;
+using FlightBooking.Service.Data.Configs;
+using FlightBooking.Service.Data.Repository;
+using FlightBooking.Service.Middleware;
+using FlightBooking.Service.Services;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
+using Newtonsoft.Json.Converters;
+using System.Text;
+
+namespace FlightBooking.Service
+{
+    public class Startup
+    {
+        public static readonly LoggerFactory _myLoggerFactory =
+            new LoggerFactory(new[]
+            {
+                new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider()
+            });
+
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            //we keep using NewtonSoft so that serialization of reference loop can be ignored, especially because of EFCore
+            services.AddControllers()
+                .AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)
+                .AddNewtonsoftJson(x => x.SerializerSettings.Converters.Add(new StringEnumConverter()));
+
+            services.AddAutoMapper(typeof(Startup));
+
+            //Configuration for SQL Servr and MySql
+            string mysqlConnectionString = Configuration.GetConnectionString("FlightBookingServiceDb_Mysql")!;
+            var mySqlServerVersion = new MySqlServerVersion(new Version(8, 0, 36));
+
+            services.AddDbContext<FlightBookingContext>(options =>
+            {
+                //options.UseLoggerFactory(_myLoggerFactory).EnableSensitiveDataLogging(); //DEV: ENABLE TO SEE SQL Queries
+
+                //To Use Sql Server
+                //options.UseSqlServer(Configuration.GetConnectionString("FlightBookingServiceDb"));
+
+                //To Use MySql
+                options.UseMySql(mysqlConnectionString, mySqlServerVersion, opt => opt.EnableRetryOnFailure())
+                    .LogTo(Console.WriteLine, LogLevel.Warning)
+                    .EnableSensitiveDataLogging()
+                    .EnableDetailedErrors();
+            });
+
+            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
+            {
+                //For OpenId Connect tokens
+                options.Authority = Configuration["JWTConfig:Issuer"];
+                options.Audience = Configuration["JWTConfig:Issuer"];
+                options.SaveToken = true;
+
+                options.TokenValidationParameters = new TokenValidationParameters
+                {
+                    ValidateIssuer = true,
+                    ValidateAudience = false,
+                    ValidateLifetime = true,
+                    ValidateIssuerSigningKey = true,
+                    ValidIssuers = [Configuration["JWTConfig:Issuer"], Configuration["JWTConfig:Issuer"]],
+                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWTConfig:Key"]!)),
+                };
+            });
+
+            services.AddCors(option =>
+            {
+                option.AddDefaultPolicy(
+                    builder =>
+                    {
+                        builder
+                        .AllowAnyOrigin()
+                        .SetIsOriginAllowedToAllowWildcardSubdomains()
+                        .AllowAnyHeader()
+                        .AllowAnyMethod();
+                    });
+            });
+
+            services.AddSignalR();
+            services.AddHttpClient();
+            services.AddHttpContextAccessor();
+
+            //Add our custom services
+            services.AddRepository();
+            services.AddServices();
+
+            services.AddEndpointsApiExplorer();
+            services.AddSwaggerGen(options =>
+            {
+                options.SwaggerDoc("v1", new OpenApiInfo { Title = "Flight Booking API", Version = "v1" });
+            });
+
+            //Add our configs
+            services.AddConfigSettings(Configuration);
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+        {
+            //https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0
+            //The following Startup.Configure method adds middleware components for common app scenarios:
+
+            //1. Exception / error handling (HTTP Strict Transport Security Protocol in prod)
+            //2. HTTPS redirection
+            //3. Static File Middleware
+            //4. Cookie Policy Middleware
+            //5. Routing Middleware (UseRouting) to route requests.
+            //5. Cors
+            //5. Custom route
+            //6. Authentication Middleware
+            //7. Authorization Middleware
+            //8. Session Middleware
+            //9. Endpoint Routing Middleware (UseEndpoints
+
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+                //app.UseDatabaseErrorPage();
+            }
+            else
+            {
+                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+                app.UseHsts();
+                app.UseErrorHandlingMiddleware(); //custom error handler
+                                                  //app.UseExceptionHandler();
+            }
+
+            app.UseHttpsRedirection();
+
+            app.UseRouting();
+
+            app.UseCors();//this was moved here since the BasicAuthMiddleware below is also authentication and cors must come before authentication.
+
+            if (env.IsDevelopment() || env.IsStaging())
+            {
+                app.UseSwagger();
+                app.UseSwaggerUI(opt =>
+                {
+                    opt.SwaggerEndpoint("/swagger/v1/swagger.json", "Flight Booking API");
+                });
+            }
+
+            app.UseAuthentication();
+            app.UseAuthorization();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapControllers();
+            });
+        }
+    }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/appsettings.Development.json b/BookingService/FlightBooking.Service/appsettings.Development.json
new file mode 100644
index 0000000..14d2ada
--- /dev/null
+++ b/BookingService/FlightBooking.Service/appsettings.Development.json
@@ -0,0 +1,21 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "ConnectionStrings": {
+    "FlightBookingServiceDb": "Server=.;Database=FlightBooking_Db;User ID=sa;Password=beforwardj!;Trusted_Connection=False;Encrypt=False;Connection Timeout=180;",
+    "FlightBookingServiceDb_Mysql": "Server=localhost;Database=FlightBooking_Db;User=root;Password=P@ss1ord"
+  },
+  "JWTConfig": {
+    "Key": "28298659-1c10-4f2e-b045-42698ab4b02b",
+    "Issuer": "https://localhost:44321"
+  },
+  "StripeConfig": {
+    "PublicKey": "",
+    "SecretKey": "",
+    "SigningSecret": ""
+  }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/appsettings.json b/BookingService/FlightBooking.Service/appsettings.json
new file mode 100644
index 0000000..31a3e8d
--- /dev/null
+++ b/BookingService/FlightBooking.Service/appsettings.json
@@ -0,0 +1,22 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  "ConnectionStrings": {
+    "FlightBookingServiceDb": "Server=.;Database=FlightBooking_Db;User ID=sa;Password=beforwardj!;Trusted_Connection=False;Encrypt=False;Connection Timeout=180;",
+    "FlightBookingServiceDb_Mysql": "Server=localhost;Database=FlightBooking_Db;User=root;Password=P@ss1ord"
+  },
+  "JWTConfig": {
+    "Key": "28298659-1c10-4f2e-b045-42698ab4b02b",
+    "Issuer": "https://localhost:44321"
+  },
+  "StripeConfig": {
+    "PublicKey": "",
+    "SecretKey": "",
+    "SigningSecret": ""
+  }
+}
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/nlog.config b/BookingService/FlightBooking.Service/nlog.config
new file mode 100644
index 0000000..1967321
--- /dev/null
+++ b/BookingService/FlightBooking.Service/nlog.config
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      autoReload="true"
+      internalLogLevel="Info"
+      internalLogFile=".\log\internal-nlog.txt">
+
+	<!-- enable asp.net core layout renderers -->
+	<extensions>
+		<add assembly="NLog.Web.AspNetCore" />
+	</extensions>
+
+	<!-- the targets to write to -->
+	<targets>
+		<!-- write logs to file  -->
+		<target xsi:type="File" name="allfile" fileName=".\log\nlog-all-${shortdate}.log"
+				layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
+		<!-- another file log, only own logs. Uses some ASP.NET core renderers -->
+		<target xsi:type="File" name="ownFile-web" fileName=".\log\nlog-own-${shortdate}.log"
+				layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|${callsite}| body: ${aspnet-request-posted-body}" />
+
+		<!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
+		<target xsi:type="Console" name="lifetimeConsole" layout="${level:truncate=4:lowercase=true}: ${logger}[0]${newline}      ${message}${exception:format=tostring}" />
+	</targets>
+
+	<!-- rules to map from logger name to target -->
+	<rules>
+		<!--All logs, including from Microsoft-->
+		<logger name="*" minlevel="Trace" writeTo="allfile" />
+
+		<!--Output hosting lifetime messages to console target for faster startup detection -->
+		<logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="lifetimeConsole, ownFile-web" final="true" />
+
+		<!--Skip non-critical Microsoft logs and so log only own logs (BlackHole) -->
+		<logger name="Microsoft.*" maxlevel="Info" final="true" />
+		<logger name="System.Net.Http.*" maxlevel="Info" final="true" />
+
+		<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
+	</rules>
+</nlog>
\ No newline at end of file
diff --git a/BookingService/FlightBooking.Service/readme.md b/BookingService/FlightBooking.Service/readme.md
new file mode 100644
index 0000000..77617ad
--- /dev/null
+++ b/BookingService/FlightBooking.Service/readme.md
@@ -0,0 +1,385 @@
+Libraries Used:
+
+1. NLog. We used NLog for logging. By default all logs with level Informational are saved. This setting can be changed in the appsettings.json
+
+nlog.config contains the file that is used to configure our NLog.
+
+2. Automapper: This is a great utility tool that allows mapping one model or DTO (Data Transfer Object) to another. It helps to us avoid repetitve code. 
+   To use, we first add a line in the `ConfigureServices` method of our `Startup.cs`: 
+
+   `services.AddAutoMapper(typeof(Startup));`
+
+  The  we declare a class that contains our mappings:
+  ```
+  public class FlightBookingProfile : Profile
+    {
+        public FlightBookingProfile()
+        {
+            CreateMap<FlightFare, FlightFareDTO>()
+                .ForMember(dest => dest.AvailableSeats, opt => opt.MapFrom(src => src.SeatCapacity - src.SeatReserved))
+                .ForMember(dest => dest.FlightNumber, opt => opt.MapFrom(src => src.FlightInformation.FlightNumber));
+        }
+    }
+  ```
+
+
+3. We also installed NewtonSoftJson library for working with Json input and output.
+
+4. Swashbuckle was also installed so we can generate Swagger documentation from our controllers.
+
+5. Some libraries for using Jwt for authentication were also added.
+
+
+## Program Flow.
+
+Controller -> Services -> Repository -> EntityFramework -> Data
+
+
+### Controllers 
+
+They represent our endpoints based on the MVC pattern.
+Each controller has been decorated with attributes that makes it easy to read what input and output to expect.
+For example, our `ReservedSeatController`:
+
+```
+ [Route("api/[controller]")]
+ [ApiController]
+ public class SeatsController : ControllerBase
+ {
+     private readonly IReservedSeatService _service;
+
+     public SeatsController(IReservedSeatService service)
+     {
+         _service = service;
+     }
+
+     [HttpGet]
+     [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<ReservedSeatDTO>))]
+     [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+     public IActionResult GetAvailableSeats([FromQuery] string flightNumber)
+     {
+         ServiceResponse<IEnumerable<ReservedSeatDTO>> result = _service.GetAvailableSeatsByFlightNumber(flightNumber);
+
+         return result.FormatResponse();
+     }
+
+     [HttpPost]
+     [Consumes(MediaTypeNames.Application.Json)]
+     [ProducesResponseType(StatusCodes.Status200OK)]
+     [ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProblemDetails))]
+     [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
+     public async Task<IActionResult> ReserveSeat([FromBody] ReservedSeatRequestDTO requestDTO)
+     {
+         ServiceResponse<string> result = await _service.ReserveSeatAsync(requestDTO);
+
+         return result.FormatResponse();
+     }
+ }
+```
+
+In the above, we have to methods in the controller which corresponds to 2 endpoints.
+
+First, we inject our `IReservedSeatService` into the controller.
+
+The first endpoint is a GET endpoint:
+And the attributes show that it can return a 200, 400 and 422 response. The 400 and 422 responses are in types of ProblemDetails which is a specification for returning API responses.
+
+This part: `([FromQuery] string flightNumber)` indicates that a query string named ``flightNumber`` is passed to the endpoint generated by this method.
+
+The `_service` returns a type of `ServiceResponse` which is then formatted to return the appropriate response. More on this later
+
+
+The second endpoint is a POST endpoint:
+The attributes show it accepts a body (`[FromBody]`) of type application/json (`MediaTypeNames.Application.Json`) and response produced are 200, 422, 400.
+
+
+
+### Services
+They represent the logic for our app. We this pattern to make it easy to test the services.
+By abstracting the services to use Interfaces, we can easily write tests that can be flexible.
+
+We rely on the built-in Dependency Injection framework to resolve service dependencies.
+
+In each service, we inject Repository classes and other Services.
+
+The services also have to be registered and we do this by declaring a static class that will do the registration:
+
+```
+public static class ServicesModule
+{
+    public static void AddServices(this IServiceCollection services)
+    {
+        services.AddScoped<IBookingService, BookingService>();
+        services.AddScoped<IBookingOrderService, BookingOrderService>();
+        services.AddScoped<IReservedSeatService, ReservedSeatService>();
+        services.AddScoped<IFlightFareService, FlightFareService>();
+        services.AddScoped<IFlightService, FlightService>();
+        services.AddScoped<IStripeService, StripeService>();
+    }
+}
+```
+Here: We register each service as a Scoped dependency. Scoped means that the service will only be active for the duration of a request (i.e Http Request).
+
+Then we call the method in our Startup.cs:
+` services.AddServices();`
+
+Each service also returns a type `ServiceResponse<T>` where T is a class
+
+The `ServiceResponse<T>` is declared in the `ResponseFormatter.cs`
+
+```
+public class ServiceResponse<T>
+{
+    public InternalCode ServiceCode { get; set; } = InternalCode.Failed;
+    public T Data { get; set; }// = null;
+    public string Message { get; set; }
+
+    public ServiceResponse(T data, InternalCode serviceCode = InternalCode.Failed, string message = "")
+    {
+        Message = message;
+        ServiceCode = serviceCode;
+        Data = data;
+    }
+}
+```
+We declare the `ServiceResponse` to be a generic class. It's properties are:
+`InternalCode` that indicates the status. InternalCode is an enum	 
+`Data`: which is a type of `T`
+`Message`: optional message
+
+The `FormatResponse` is an extension method that accepts a `ServiceResponse<T>` and then checks the Internal Code and uses that to 
+return an appropriate response.
+
+This makes it easy for us to return a uniform type of response.
+2xx responses return a simple 2xx and an optional data
+4xx and 5xx responses return a type of `ProblemDetails`. 
+The helps to give more context to the nature of the response.
+
+
+### Repository
+
+We use a Repository pattern that wraps EntityFramework unit of work pattern. The class is declared as a Generic class so that we can pass any model to it.
+We then declare helper methods that in turn call EntityFramework methods:
+
+```
+ public class GenericRepository<T> : IGenericRepository<T> where T : class, new()
+ {
+     //Responses: failed=0, success=1
+
+     //IEnumerable iterates over an in-memory collection while IQueryable does so on the DB
+     // call to .ToList to enable instant query against DB
+
+     protected FlightBookingContext _db;
+     protected ILogger _logger;
+
+     //...omitted for brevity
+
+     public async Task<T?> GetByGuidAsync(Guid id)
+     {
+       var entity = await _db.Set<T>().FindAsync(id);
+       return entity;
+     }
+
+}
+```
+
+In the aboved, we pass a type of `DbContext` and a `Logger`. 
+In the `GetByGuidAsync()` method, we use the `_db` of that model to find the data.
+
+We must also inject the Repository of each model so we can use anywhere in our project:
+```
+public static class RepositoryModule
+{
+    public static void AddRepository(this IServiceCollection services)
+    {
+        services.AddScoped<IGenericRepository<Booking>, GenericRepository<Booking>>();
+        services.AddScoped<IGenericRepository<FlightInformation>, GenericRepository<FlightInformation>>();
+        services.AddScoped<IGenericRepository<FlightFare>, GenericRepository<FlightFare>>();
+        services.AddScoped<IGenericRepository<Payment>, GenericRepository<Payment>>();
+        services.AddScoped<IGenericRepository<BookingOrder>, GenericRepository<BookingOrder>>();
+        services.AddScoped<IGenericRepository<ReservedSeat>, GenericRepository<ReservedSeat>>();
+    }
+}
+```
+Just like in the Services, we also add the dependencies as a Scoped service.
+
+This is important because we want to quickly use a DbContext which in turn holds a connection to the database. If we use it and quickly return it to the connection pool, we can avoid issues with resource exhaustion.
+
+
+### Data
+
+We are using MySql. So we must install the following MySqlConnector and the Pomelo.EntityFramework.MySql libraries.
+Let's add these 2 lines to our Package reference.
+
+1. `<PackageReference Include="MySqlConnector" Version="2.3.5" />`
+2. `<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.1" />`
+
+
+To use our model, we use classes to represent our data. Each class in the model is used to create tables in the database.
+
+We declare properties of the class and also configure relationships.
+
+The models are in `Model` folder. 
+
+We also wish to do some relations that are not automatically done by the framework.
+
+These configurations are applied to the model and is used to configure how the tables should be created during table creation:
+e.g:
+```
+public class BookingConfiguration : IEntityTypeConfiguration<Booking>
+    {
+        public void Configure(EntityTypeBuilder<Booking> entity)
+        {
+            entity.HasOne(d => d.BookingOrder).WithMany(p => p.Bookings)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.BookingOrderId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+
+            entity.HasOne(d => d.FlightInformation).WithMany(p => p.Bookings)
+                .HasPrincipalKey(p => p.Id)
+                .HasForeignKey(d => d.FlightId)
+                .OnDelete(DeleteBehavior.ClientSetNull);
+
+            entity.HasOne(d => d.FlightFare).WithMany(p => p.Bookings)
+               .HasPrincipalKey(p => p.Id)
+               .HasForeignKey(d => d.FlightFareId)
+               .OnDelete(DeleteBehavior.ClientSetNull);
+        }
+    }
+```
+ The above code for the `Booking.cs` model configures the foreign key relationship.
+
+
+To make use of our models, we create a `FlightBookingDbContext.cs` where we declare all our models and also apply the configurations:
+
+We also added a change in the `OnModelCreating()` method of the `FlightDbContext` to make sure that when a model (data in the database) is updated, the `UpdatedAt` and `CreatedAt` is saved as `UTC`. 
+
+```
+foreach (var entityType in modelBuilder.Model.GetEntityTypes())
+    {
+        foreach (var property in entityType.GetProperties())
+        {
+            if (property.ClrType == typeof(DateTime))
+            {
+                modelBuilder.Entity(entityType.ClrType)
+                    .Property<DateTime>(property.Name)
+                    .HasConversion(
+                    v => v.ToUniversalTime(),
+                    v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
+            }
+            else if (property.ClrType == typeof(DateTime?))
+            {
+                modelBuilder.Entity(entityType.ClrType)
+                    .Property<DateTime?>(property.Name)
+                    .HasConversion(
+                    v => v.HasValue ? v.Value.ToUniversalTime() : v,
+                    v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);
+            }
+        }
+    }
+```
+
+
+To get our database schema updated:
+
+Once we have configured our models, and added the `FlightBookingContext`.
+We also configure the `FlightBookingContext` in the `ConfigureService` method in our `Startup.cs` and initialize it.
+
+```
+ string mysqlConnectionString = Configuration.GetConnectionString("FlightBookingServiceDb_Mysql")!;
+ var mySqlServerVersion = new MySqlServerVersion(new Version(8, 0, 36));
+ services.AddDbContext<FlightBookingContext>(options =>
+ {
+     options.UseMySql(mysqlConnectionString, mySqlServerVersion, opt => opt.EnableRetryOnFailure())
+                    .LogTo(Console.WriteLine, LogLevel.Warning)
+                    .EnableSensitiveDataLogging()
+                    .EnableDetailedErrors();
+ });
+
+```
+The code indicates that we get our connection string from appsettings.json
+To get the version of MySql, run this on the MySql server:
+
+> SELECT VERSION();
+
+Once we have our models, configuration and DbContext ready, we need to run Migrations.
+
+Migrations take a snapshot of our models and configuration and defines how they will be used to updated the database schema at that point in time.
+
+To run migrations, open the Package Manager Console and run:
+
+> Add-Migration InitialCreate
+
+This will create a migration named `InitialCreateMysql`. 
+
+We then run 
+
+>Update-Database
+
+This will configure the database with the code generated in `InitialCreateMysql`.
+
+Whenever we make a change to our models and configuration, we must create a new migration and update our database so that the database schema is kept updated
+
+If we wish to use a different database, we first configure the DbContext. E.g if using Sql Server:
+
+```
+ services.AddDbContext<FlightBookingContext>(options =>
+ {
+    options.UseSqlServer(Configuration.GetConnectionString("FlightBookingServiceDb"));
+ });
+
+```
+
+Then we must create a new migration. __It is important to note that Migrations are scoped to a database. So we need a new migration when we switched to a different database__
+
+To run migrations, open the Package Manager Console and run:
+
+> Add-Migration InitialCreateMysql
+
+This will create a migration named `InitialCreateMysql`. 
+
+We then run 
+
+>Update-Database
+
+
+The `ConfigSettings` contains a strongly type mapping of the content of appsettings.json and helps to avoid errors
+
+Our DTO folder contains DTOs for models. These are basically data structure we use to transfer data around
+
+
+## Running this Project
+
+1. Open the solution in Visual Studio. Automatically, nugets are installed.
+
+2. Start your MySql Server. The project currently uses MySql version 8.0.36. If you wish to use a different version, update the version in ``Startup.cs`
+
+```
+    var mySqlServerVersion = new MySqlServerVersion(new Version(8, 0, 36));
+```
+
+3. Add your database connection string in appsettings.json and appsettings.Development.json
+
+3. In Visual Studio, go to Tools -> Nuget Package Manager -> Package Manager Console. Click the Package Manager Console and it open at the bottom
+
+4. In the Package Manager Console, Run
+   > Update-Database
+
+   The Database and all tables will be created using the `InitialMysqlMigration` that is included in the Migrations folder.
+
+5. Press F5 or run the project by clicking the play button.
+
+6. Included in the project in the `Program.cs` is a method that seeds the database with some default data. The `DatabaseSeeding.cs` contains the code that adds `FlightInformation`, `FlightFares` and `ReservedSeats`
+    Once you run the project for the first time, if all goes well, the data is added to the database.
+
+
+
+Useful Links:
+https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
+https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/providers?tabs=dotnet-core-cli
+https://learn.microsoft.com/en-us/ef/core/modeling/relationships
+https://learn.microsoft.com/en-us/ef/ef6/fundamentals/working-with-dbcontext
+
+
+
+
-- 
GitLab