/joboffer

Domain Driven Design, Event Sourcing, CQRS, Spring Boot

Primary LanguageJava

Problem

Build a backend service that handles a (very simple) recruiting process. The process requires two types of objects: job offers and applications from candidates. minimum required fields for the objects are:

  • Offer:

    • jobTitle (unique)
    • startDate
    • numberOfApplications
  • Application:

    • related offer
    • candidate email (unique per Offer)
    • resume text
    • applicationStatus (APPLIED, INVITED, REJECTED, HIRED)

Not all of the fields have to be persisted. You may use ad hoc calculation, event sourcing, or whatever you see fit. These are the fields that must be returned by the API. You may add fields where necessary.

Use cases

  • user has to be able to create a job offer and read a single and list all offers.
  • candidate has to be able to apply for an offer.
  • user has to be able to read one and list all applications per offer.
  • user has to be able to progress the status of an application.
  • user has to be able to track the number of applications.
  • status change triggers a notification (*)
  • a log output will suffice as a notification here, but you should design it as if each status change triggers a completely different business case.

Install

  • run application (no pre-req) ./mvnw spring-boot:run
  • if jdk 1.8+ and mvn 3.x+ is installed mvn spring-boot:run
  • Explore application through Swagger UI http://localhost:8080/swagger-ui.html

Software Architecture

Patterns used:

  • Event Sourcing
  • CQRS
  • DDD

JobOffer "1" *-- "0..n" JobApplication
JobApplication "1" *-- "1" JobApplicationStatus
  • Aggregate Root: Job
  • Agregates: JobApplication
  • Value Objects: JobApplicationStatus

Generic sequence diagram

sequenceDiagram
	CommandController->>+CommandHandler: handle(command)
	CommandHandler->>+EventStore: events: load(aggregateId)
	CommandHandler->>+Aggregate: apply(events)
	CommandHandler->>Aggregate: events: handle(command)
	CommandHandler->>EventStore: store(events)
	EventStore->>+EventPublisher: publish(events)
	EventPublisher-xReadHandler: handle(event)
	ReadHandler->>Repository: save(readDto)