A small end-to-end Clojure project that exercises a fairly complete toolchain: a Ring/Reitit/Jetty server backed by SQLite on one side, a cljfx desktop client on the other, and a layered test suite plus static-analysis and build aliases glueing it together.
The name is an Idiocracy reference — if no one has ever introduced themselves to the server, it greets you as "Not Sure".
hello-not-sure/
├── deps.edn # deps, aliases (server/client/test/lint/fmt/security/build)
├── build.clj # tools.build — two uberjars
├── tests.edn # Kaocha test-suite layout (unit / db / http)
├── .clj-kondo/config.edn # linter config
├── .cljfmt.edn # formatter config
├── README.md
├── resources/
├── src/
│ └── hello_not_sure/
│ ├── common.clj # pure helpers shared by server + client
│ ├── server/
│ │ ├── core.clj # -main, CLI parsing
│ │ ├── system.clj # lifecycle (datasource + Jetty)
│ │ ├── routes.clj # Reitit routes + Malli schemas + Swagger
│ │ ├── handlers.clj # request handlers
│ │ └── db.clj # next.jdbc + HoneySQL
│ └── client/
│ ├── core.clj # cljfx GUI
│ └── http.clj # hato HTTP wrapper
└── test/
└── hello_not_sure/
├── unit/common_test.clj # pure-function unit tests
├── db/db_test.clj # in-memory SQLite, per-test fixture
└── http/http_test.clj # Jetty on random port, per-test fixture
Three layers, deliberately thin:
- Pure layer (
hello-not-sure.common) — string normalization and the "Not Sure" default. No I/O. Cheap to test, reusable on both server and client. - Persistence layer (
hello-not-sure.server.db) —next.jdbcfor the driver andHoneySQLfor query construction. The datasource is a value passed in, so the same code runs against a file-backed SQLite in production and an in-memory SQLite in tests. - Web layer (
hello-not-sure.server.routes+handlers+system) — Reitit routes carry Malli schemas, which drive request/response coercion and the auto-generated OpenAPI document. Muuntaja handles JSON-in/JSON-out via Jsonista. Swagger UI is mounted at/swagger-ui. Jetty is started bysystem/start, which returns a value containing theserver(for.stop) and theport(useful for tests on:port 0).
The client mirrors that split: client.http is a tiny hato wrapper that
returns parsed maps, and client.core is the cljfx UI with a state atom and
a defmulti event handler — no HTTP code in the view, no UI code in the HTTP
layer.
Tests follow the same layering — one suite per layer in tests.edn, so you
can run e.g. only the fast unit tests during a tight loop.
| Method | Path | Body | Response |
|---|---|---|---|
| POST | /name |
{"name": "Joe"} |
201 {"name": "Joe"} |
| GET | /name |
— | 200 {"name": "<latest or Not Sure>"} |
| GET | /swagger.json |
— | OpenAPI document |
| GET | /swagger-ui |
— | Swagger UI |
# Start the server on http://localhost:3000 (db file: ./db.sqlite)
clj -M:server
# Start the cljfx client (talks to http://localhost:3000 by default)
clj -M:client
# …or point it at a different server:
clj -M:client http://localhost:8080Open Swagger UI at http://localhost:3000/swagger-ui while the server is up.
Kaocha is configured with three independently-runnable suites:
clj -M:test # run everything
clj -M:test --focus :unit # only pure-function tests
clj -M:test --focus :db # only database integration tests
clj -M:test --focus :http # only HTTP integration testsunit— no fixtures, no I/O.db—use-fixtures :eachrebuilds the schema in an in-memory SQLite database per test, so tests can't leak state into each other.http—use-fixtures :eachstarts a fresh Jetty on:port 0(random) backed by an in-memory SQLite for each test. The suite exercises the real Ring stack end-to-end with full per-test isolation.
clj -M:lint # clj-kondo over src + test
clj -M:fmt # cljfmt check
clj -M:fmt-fix # cljfmt fix
clj -M:security # clj-watson dependency vulnerability scan
clj -M:coverage # cloverage HTML report -> target/coverage/index.html
clj -M:outdated # antq report of newer dependency versionsbuild.clj uses tools.build to produce two uberjars under target/.
clj -T:build clean
clj -T:build server-uber # target/hello-not-sure-server-0.1.0.jar
clj -T:build client-uber # target/hello-not-sure-client-0.1.0.jar
clj -T:build all # clean + both uberjars
java -jar target/hello-not-sure-server-0.1.0.jar
java -jar target/hello-not-sure-client-0.1.0.jar