Folder Structure

Package by Feature

shopease/
 ├── pom.xml, Dockerfile, docker-compose.yml, .github/workflows/ci.yml
 └── src/
      ├── main/java/com/shopease/
      │    ├── ShopEaseApplication.java
      │    ├── common/        ApiError, GlobalExceptionHandler, AuditAspect, PerformanceAspect
      │    ├── config/        AsyncConfig, CacheConfig, SecurityConfig, OpenApiConfig, CorsConfig
      │    ├── catalog/       Product, Category, ProductController, ProductService, ProductRepository, dto/
      │    ├── cart/          CartItem, CartController, CartService, CartRepository
      │    ├── order/         Order, OrderItem, OrderController, OrderService, OrderPlacedEvent, listeners/
      │    ├── payment/       PaymentGateway, RazorpayGateway, PaymentWebhookController, PaymentHealthIndicator
      │    ├── user/          User, AuthController, UserService, JwtService
      │    ├── files/         ImageStorageService, FileController
      │    └── jobs/          ShopEaseJobs (reports, cart cleanup)
      ├── main/resources/
      │    ├── application.yml, application-dev.yml, application-prod.yml
      │    └── db/migration/  V1__init.sql, V2__add_product_images.sql
      └── test/java/com/shopease/   ...ControllerTest (@WebMvcTest), ...IT (@SpringBootTest + Testcontainers)

Tip: Package by feature keeps related classes together, so a feature can move into its own service later with little change.

Profiles

Example

application.yml

spring:
  application:
    name: shopease
  jpa:
    open-in-view: false
  threads:
    virtual:
      enabled: true
server:
  shutdown: graceful
  compression:
    enabled: true
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    url: jdbc:h2:mem:shopease
---
spring:
  config:
    activate:
      on-profile: prod
  datasource:
    url: ${SPRING_DATASOURCE_URL}
  jpa:
    hibernate:
      ddl-auto: validate