diff --git a/pom.xml b/pom.xml
index 163ad53..98888f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,6 +35,12 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.postgresql
+ postgresql
+ compile
+
+
com.fasterxml.jackson.module
jackson-module-kotlin
@@ -47,7 +53,40 @@
org.jetbrains.kotlin
kotlin-stdlib
-
+
+ jakarta.inject
+ jakarta.inject-api
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ com.h2database
+ h2
+ test
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ runtime
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ runtime
+ 0.11.5
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/kotlin/com/coded/spring/ordering/Orders/OnlineOrderController.kt b/src/main/kotlin/com/coded/spring/ordering/Orders/OnlineOrderController.kt
new file mode 100644
index 0000000..d25a6c4
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/Orders/OnlineOrderController.kt
@@ -0,0 +1,29 @@
+package com.coded.spring.ordering.Orders
+
+
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+class OnlineOrderController(
+ private val ordersService: OrdersService,
+
+){
+ @GetMapping("/home")
+ fun onlineOrder() = "Start Ordering Food!"
+
+ @GetMapping("/orders/v1/orders")
+ fun getOrders(): List = ordersService.listOrders()
+
+ @PostMapping("/orders/v1/orders")
+ fun orderFood(@RequestBody request: CreateOrderRequest) = ordersService.createOrder(request.userId,request.restaurant)
+
+}
+
+data class CreateOrderRequest(
+ val userId: Long,
+ val restaurant:String,
+
+)
diff --git a/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersRepository.kt b/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersRepository.kt
new file mode 100644
index 0000000..b802c06
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersRepository.kt
@@ -0,0 +1,29 @@
+package com.coded.spring.ordering.Orders
+
+
+import com.coded.spring.ordering.users.UserEntity
+import jakarta.inject.Named
+import jakarta.persistence.*
+import org.springframework.data.jpa.repository.JpaRepository
+
+@Named
+interface OrdersRepository : JpaRepository
+
+@Entity
+@Table(name = "orders")
+data class OrderEntity(
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ var id: Long? = null,
+
+ @ManyToOne
+ val user: UserEntity,
+ val restaurant:String,
+
+// @OneToMany(mappedBy = "orderId")
+// val items: List? = null
+
+
+ ){
+ constructor() : this(null, UserEntity(),"")
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersService.kt b/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersService.kt
new file mode 100644
index 0000000..1fa1762
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/Orders/OrdersService.kt
@@ -0,0 +1,34 @@
+package com.coded.spring.ordering.Orders
+
+
+
+import jakarta.inject.Named
+import com.coded.spring.ordering.users.UsersRepository
+
+@Named
+class OrdersService(
+ private val ordersRepository: OrdersRepository,
+ private val usersRepository: UsersRepository,
+) {
+
+ fun listOrders(): List = ordersRepository.findAll().map {
+ Order(
+ userId = it.user.id,
+ restaurant = it.restaurant
+ )
+ }
+
+
+ fun createOrder(userId: Long,restaurant:String){
+ val user = usersRepository.findById(userId).get()
+ val newOrder = OrderEntity(user=user, restaurant = restaurant)
+ ordersRepository.save(newOrder)
+ }
+ }
+
+
+data class Order(
+ val userId: Long?,
+ val restaurant: String
+
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/authentication/AuthenticationController.kt b/src/main/kotlin/com/coded/spring/ordering/authentication/AuthenticationController.kt
new file mode 100644
index 0000000..12bd9be
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/authentication/AuthenticationController.kt
@@ -0,0 +1,47 @@
+package com.coded.spring.ordering.authentication
+
+
+import com.coded.spring.ordering.authentication.jwt.JwtService
+import org.springframework.http.HttpStatus
+import org.springframework.http.ResponseEntity
+import org.springframework.security.authentication.*
+import org.springframework.security.core.userdetails.UserDetailsService
+import org.springframework.security.core.userdetails.UsernameNotFoundException
+import org.springframework.web.bind.annotation.*
+
+
+@RestController
+@RequestMapping("/auth")
+class AuthenticationController(
+ private val authenticationManager: AuthenticationManager,
+ private val userDetailsService: UserDetailsService,
+ private val jwtService: JwtService
+) {
+
+ @PostMapping("/login")
+ fun login(@RequestBody request: AuthenticationRequest): ResponseEntity<*> {
+ val authToken = UsernamePasswordAuthenticationToken(request.username, request.password)
+ val authentication = authenticationManager.authenticate(authToken)
+ try {
+ authenticationManager.authenticate(authToken)
+ } catch (e: BadCredentialsException) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid username or password")
+ } catch (e: DisabledException) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User is disabled")
+ } catch (e: LockedException) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).body("User is locked")
+ }
+
+ val token = jwtService.generateToken(request.username)
+ return ResponseEntity.ok(AuthenticationResponse(token))
+ }
+}
+
+data class AuthenticationRequest(
+ val username: String,
+ val password: String
+)
+
+data class AuthenticationResponse(
+ val token: String
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/authentication/CustomUserDetailsService.kt b/src/main/kotlin/com/coded/spring/ordering/authentication/CustomUserDetailsService.kt
new file mode 100644
index 0000000..84c4a1e
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/authentication/CustomUserDetailsService.kt
@@ -0,0 +1,19 @@
+package com.coded.spring.ordering.authentication
+
+import com.coded.spring.ordering.users.UsersRepository
+import org.springframework.security.core.userdetails.*
+import org.springframework.stereotype.Service
+
+@Service
+class CustomUserDetailsService(
+ private val usersRepository: UsersRepository
+) : UserDetailsService {
+ override fun loadUserByUsername(username: String): UserDetails {
+ val user = usersRepository.findByUsername(username)
+ ?: throw UsernameNotFoundException("User not found")
+
+ return User.builder()
+ .username(user.username)
+ .password(user.password).build()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/authentication/SecurityConfig.kt b/src/main/kotlin/com/coded/spring/ordering/authentication/SecurityConfig.kt
new file mode 100644
index 0000000..b092583
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/authentication/SecurityConfig.kt
@@ -0,0 +1,58 @@
+package com.coded.spring.ordering.authentication
+
+
+import com.coded.spring.ordering.authentication.jwt.JwtAuthenticationFilter
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.security.authentication.AuthenticationManager
+import org.springframework.security.authentication.AuthenticationProvider
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
+import org.springframework.security.config.annotation.web.builders.HttpSecurity
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
+import org.springframework.security.config.http.SessionCreationPolicy
+import org.springframework.security.core.userdetails.UserDetailsService
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
+import org.springframework.security.crypto.password.PasswordEncoder
+import org.springframework.security.web.SecurityFilterChain
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
+
+
+@Configuration
+@EnableWebSecurity
+class SecurityConfig(
+ private val jwtAuthFilter: JwtAuthenticationFilter,
+ private val userDetailsService: UserDetailsService
+) {
+
+ @Bean
+ fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
+ http.csrf { it.disable() }
+ .authorizeHttpRequests {
+ it.requestMatchers("/auth/**", "/users/v1/users").permitAll()
+ .anyRequest().authenticated()
+ }
+ .sessionManagement {
+ it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ }
+ .authenticationProvider(authenticationProvider())
+ .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter::class.java)
+
+ return http.build()
+ }
+
+ @Bean
+ fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()
+
+ @Bean
+ fun authenticationManager(config: AuthenticationConfiguration): AuthenticationManager =
+ config.authenticationManager
+
+ @Bean
+ fun authenticationProvider(): AuthenticationProvider {
+ val provider = DaoAuthenticationProvider()
+ provider.setUserDetailsService(userDetailsService)
+ provider.setPasswordEncoder(passwordEncoder())
+ return provider
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtAuthenticationFilter.kt b/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtAuthenticationFilter.kt
new file mode 100644
index 0000000..f180b7c
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtAuthenticationFilter.kt
@@ -0,0 +1,45 @@
+package com.coded.spring.ordering.authentication.jwt
+
+import jakarta.servlet.FilterChain
+import jakarta.servlet.http.*
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
+import org.springframework.security.core.context.SecurityContextHolder
+import org.springframework.security.core.userdetails.UserDetailsService
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
+import org.springframework.stereotype.Component
+import org.springframework.web.filter.OncePerRequestFilter
+
+@Component
+class JwtAuthenticationFilter(
+ private val jwtService: JwtService,
+ private val userDetailsService: UserDetailsService
+) : OncePerRequestFilter() {
+
+ override fun doFilterInternal(
+ request: HttpServletRequest,
+ response: HttpServletResponse,
+ filterChain: FilterChain
+ ) {
+ val authHeader = request.getHeader("Authorization")
+ if (authHeader == null || !authHeader.startsWith("Bearer ")) {
+ filterChain.doFilter(request, response)
+ return
+ }
+
+ val token = authHeader.substring(7)
+ val username = jwtService.extractUsername(token)
+
+ if (SecurityContextHolder.getContext().authentication == null) {
+ if (jwtService.isTokenValid(token, username)) {
+ val userDetails = userDetailsService.loadUserByUsername(username)
+ val authToken = UsernamePasswordAuthenticationToken(
+ userDetails, null, userDetails.authorities
+ )
+ authToken.details = WebAuthenticationDetailsSource().buildDetails(request)
+ SecurityContextHolder.getContext().authentication = authToken
+ }
+ }
+
+ filterChain.doFilter(request, response)
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtService.kt b/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtService.kt
new file mode 100644
index 0000000..c877c7c
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/authentication/jwt/JwtService.kt
@@ -0,0 +1,42 @@
+package com.coded.spring.ordering.authentication.jwt
+
+import io.jsonwebtoken.*
+import io.jsonwebtoken.security.Keys
+import org.springframework.stereotype.Component
+import java.util.*
+import javax.crypto.SecretKey
+
+@Component
+class JwtService {
+
+ private val secretKey: SecretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256)
+ private val expirationMs: Long = 1000 * 60 * 60
+
+ fun generateToken(username: String): String {
+ val now = Date()
+ val expiry = Date(now.time + expirationMs)
+
+ return Jwts.builder()
+ .setSubject(username)
+ .setIssuedAt(now)
+ .setExpiration(expiry)
+ .signWith(secretKey)
+ .compact()
+ }
+
+ fun extractUsername(token: String): String =
+ Jwts.parserBuilder()
+ .setSigningKey(secretKey)
+ .build()
+ .parseClaimsJws(token)
+ .body
+ .subject
+
+ fun isTokenValid(token: String, username: String): Boolean {
+ return try {
+ extractUsername(token) == username
+ } catch (e: Exception) {
+ false
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/items/ItemsController.kt b/src/main/kotlin/com/coded/spring/ordering/items/ItemsController.kt
new file mode 100644
index 0000000..93c9242
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/items/ItemsController.kt
@@ -0,0 +1,25 @@
+package com.coded.spring.ordering.items
+
+
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+class ItemsController(
+ private val itemsService: ItemsService,
+
+ ){
+
+
+ @PostMapping("/items/v1/items")
+ fun addItem(@RequestBody request: CreateItemRequest) = itemsService.addItem(request.orderId,request.name,request.quantity)
+
+}
+
+data class CreateItemRequest(
+ val name: String,
+ val quantity: Int,
+ val orderId: Long
+
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/items/ItemsRepository.kt b/src/main/kotlin/com/coded/spring/ordering/items/ItemsRepository.kt
new file mode 100644
index 0000000..d2ee4ec
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/items/ItemsRepository.kt
@@ -0,0 +1,22 @@
+package com.coded.spring.ordering.items
+
+import com.coded.spring.ordering.Orders.OrderEntity
+import jakarta.persistence.*
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface ItemsRepository: JpaRepository{
+}
+
+@Entity
+@Table(name="items")
+data class ItemEntity(
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ val id: Long? = null,
+ val name: String,
+ val quantity: Int,
+ @ManyToOne
+ val order: OrderEntity
+){
+ constructor() : this(null, "", 0, OrderEntity())
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/items/ItemsService.kt b/src/main/kotlin/com/coded/spring/ordering/items/ItemsService.kt
new file mode 100644
index 0000000..c9b11f4
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/items/ItemsService.kt
@@ -0,0 +1,33 @@
+package com.coded.spring.ordering.items
+
+import com.coded.spring.ordering.Orders.OrderEntity
+import com.coded.spring.ordering.Orders.OrdersRepository
+import com.coded.spring.ordering.users.UserEntity
+import jakarta.inject.Named
+import com.coded.spring.ordering.users.UsersRepository
+
+@Named
+class ItemsService(
+ private val itemsRepository: ItemsRepository,
+ private val ordersRepository: OrdersRepository
+) {
+
+
+
+ fun addItem( orderId: Long,name: String,quantity: Int){
+ val order = ordersRepository.findById(orderId).get()
+ val newItem = ItemEntity(name = name, quantity=quantity,order=order)
+ itemsRepository.save(newItem)
+
+
+ }
+}
+
+
+data class Item(
+ val userId: Long?,
+ val name: String,
+ val quantity: Int,
+ val orderId: Long
+
+ )
\ No newline at end of file
diff --git a/src/main/kotlin/com/coded/spring/ordering/menu/MenuController.kt b/src/main/kotlin/com/coded/spring/ordering/menu/MenuController.kt
new file mode 100644
index 0000000..15369de
--- /dev/null
+++ b/src/main/kotlin/com/coded/spring/ordering/menu/MenuController.kt
@@ -0,0 +1,27 @@
+package com.coded.spring.ordering.menu
+
+
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+class MenuController(
+ private val menuService: MenuService,
+
+ ){
+
+ @GetMapping("/menu/v1/menu")
+ fun getMenu(): List