Skip to main content
ElastiCORE 3.0 is a release candidate: 3.0.261022-rc1 on Maven Central. Projects on the 2.2 line: see the 2.2 documentation.
Version: 3.0

Tutorial: the pet store

The pet store is the YAPS shop of the Java EE 7 sample (agoncal-application-petstore-ee7), rebuilt as ElastiCORE 3.0 + Spring Boot 4, hexagonal Java. It is a sample module of the ElastiCORE repository - generated, compiled and run on every generator change - and the public demo.

Try itpetstore.elasticore.io - sign in as user / user, or as the administrator xsko / xsko. The data resets when the server restarts
The sourceelasticore-project/elasticore-sample-petstore
The DSLsrc/main/resources/blueprint/petstore/ - env.yml, model/entity.yml, enum.yml, dto.yml, metrics.yml
API docs/swagger-ui.html
The DSL next to the code/dsl-guide.html ("DSL Guide" in the shop's header) - per business area: the rule, the DSL, the answers checked, what was hand-written, what the DSL cannot do

What the DSL says​

Business ruleDSL
anyone browses the catalog, only the administrator edits it@access(read=public)
an order is the signed-in customer's; reading and cancelling it are theirs, shipping the administrator's@owner(customerId) @access(read=owner, create=user, cancel=owner)
a customer cannot make themselves an administratorrole: UserRole @access(admin)
passwords as hashes only; sign-inpassword: string(255)! @password, login: ... @login, @signin
an order is placed, then shipped or cancelled; a shipped order cannot be cancelledstates: status: { initial: PLACED, ship: PLACED -> SHIPPED, cancel: PLACED -> CANCELLED }
a line's price is the price when orderedunitCost: money(10.2) @snapshot(item.unitCost)
subtotals and the total@compute(unitCost * quantity), @compute(sum(lines.subTotal))
the card number is never answered; an address's required fields answer 400the value objects' @writeonly and !
a home address and a card are requiredhomeAddress: Address! @Embedded, creditCard: CreditCard! @Embedded

What was written by hand​

FileWhat
domain/model/PurchaseOrder.javathe VAT and discount policy (from settings), the home address as the default delivery address
application/PurchaseOrderService.javathe policy values injected; place() when an order is first saved
adapter/in/web/shop/AccountController.javasign up and be signed in at once (sign-in, sign-out and me are generated)
DemoAccounts.java, PetstoreApplication.javathe demo accounts, two beans

Everything else - entities, DTOs, mapper, repositories, services, controllers, access checks, state transitions, price calculation, the TypeScript client - is generated. The screen (web/src) uses the generated client's labels (OrderStatusLabel), validation (validateAddress), server errors (ApiError.fieldErrors) and button checks (canCancel).

Running it​

From a clone of the ElastiCORE repository:

./gradlew :elasticore-project:elasticore-sample-petstore:test       # MockMvc flow tests
./gradlew :elasticore-project:elasticore-sample-petstore:webBuild # the screen (Node.js needed)
./gradlew :elasticore-project:elasticore-sample-petstore:run # http://localhost:8080

Locally the demo accounts are user / user and admin / admin (petstore.demo-accounts=false turns them off). The database is an in-memory H2, filled from data.sql at start-up.

The steps​

  1. The catalog - categories, products, items: public reading, search, sorting, money with a rule.
  2. Customers who sign in - value objects, @password, @signin, a role only the administrator sets, sign-up.
  3. Orders - the lifecycle, prices kept and summed, the shop's own policy.
  4. The back office, events, metrics and messages - shipping, the events, the measures for BI, Korean error messages, the screen.
  5. Evolving a generated project - a change request on a finished shop: stock, reviews, a courier API, BI measures - measured with Claude Code and the agent kit.

The build file of the sample, abridged:

build.gradle (elasticore-sample-petstore)
elasticore {
architecture = 'hexagonal'
language = 'java'
// Read off the Spring Boot Gradle plugin in a project; this build's
// Gradle predates the Boot 4 plugin, so it is said here.
springBoot = '4'
// The model as an Apache Ossie semantic model too: blueprint/semantic_model.yml
rules = ['ossie-export']
}