This project combines a Quarkus REST backend with a Vite/React Todo UI using the Quarkiverse Quinoa extension. Redis is used as a lightweight data store backing the Todo API.
- Backend: Quarkus 3 + RESTEasy Reactive + Quarkus Redis Client. The Java code is organized into domain, application, infrastructure, and presentation packages under
src/main/java/io/github/yuokada/practice. - Frontend: React (Vite) with the main logic in
src/main/webui/src/App.jsx. - Storage: Redis (DevServices or
redis://localhost:6379/0). Tasks are stored as theTodoTaskrecord. - Quinoa: Bridges Quarkus and the Vite app. In dev mode it proxies the Vite dev server; in prod it serves the built
dist/index.htmland assets.
The backend now follows a simple Clean Architecture-style package split.
io.github.yuokada.practice.domain.modelHolds business data types such asTodoTask,Status, andIncrement. These classes do not depend on Quarkus or Redis APIs.io.github.yuokada.practice.domain.repositoryDefines repository interfaces used by the application layer, such asTodoRepository,TodoAsyncRepository, andIncrementRepository.io.github.yuokada.practice.application.serviceContains use-case services likeTodoService,TodoAsyncService, andIncrementService. These services depend on repository interfaces, not on Redis-specific implementations.io.github.yuokada.practice.infrastructure.redisContains Redis-backed implementations such asRedisTodoRepository,RedisTodoAsyncRepository, andRedisIncrementRepository. Quarkus Redis datasource access is isolated here.io.github.yuokada.practice.infrastructure.dynamodbContains DynamoDB-backed implementations such asDynamoDbTodoRepository,DynamoDbTodoAsyncRepository,DynamoDbIncrementRepository, andDynamoDbClientProducer. AWS SDK v2 access is isolated here.io.github.yuokada.practice.presentation.restContains JAX-RS resource interfaces and implementations such asTodoResourceImpl,TodoAsyncResourceImpl, andIncrementResource. This layer maps HTTP requests and responses to application services.
Dependency direction:
presentation->application->domaininfrastructure->domain
In practice, this means REST resources do not talk to Redis directly, and application services do not import Quarkus Redis APIs.
| Purpose | Command | Notes |
|---|---|---|
| Backend + frontend live coding | ./mvnw compile quarkus:dev |
Launches Quarkus dev mode and Quinoa-managed Vite dev server at http://localhost:8080. Dev UI at /q/dev. |
| Backend tests | ./mvnw test |
Uses Redis DevServices or local Redis depending on config. |
| Package JAR | ./mvnw package |
Artifacts end up in target/quarkus-app/. |
| Native build | ./mvnw package -Pnative |
Add -Dquarkus.native.container-build=true to build via container. |
| Start local Valkey | docker compose up valkey -d |
Exposes Valkey on localhost:6379 for local dev. |
| Start DynamoDB Local | docker compose up dynamodb-local -d |
Exposes DynamoDB Local on localhost:8000. |
| Init DynamoDB tables | ./scripts/init-dynamodb.sh |
Creates todo_tasks and app_counters tables. Requires AWS CLI. |
| Frontend lint/check | cd src/main/webui && npm run biome:check |
Runs Biome without modifying files. |
| Frontend dev only | cd src/main/webui && npm run dev |
Runs Vite standalone (default port 5173). |
| Frontend build | cd src/main/webui && npm run build |
Updates Quinoa’s source dist/ folder. |
| Build container image (Jib) | ./mvnw package -Dquarkus.container-image.build=true |
Produces an OCI image via Jib; append -Dquarkus.container-image.push=true to push. |
Toolchain:
- Java: Temurin 25
- Node.js: 24.14.0
src/main/resources/application.properties contains:
quarkus.quinoa.dev-server-port=5173
quarkus.quinoa.build-dir=dist
quarkus.quinoa.index-page=index.html
quarkus.quinoa.enable-spa-routing=trueThis mimics the setup recommended in the Advanced Guides. Dev mode proxies Vite, while prod serves the generated dist/index.html and falls back to it for SPA routing.
Base URL: http://localhost:8080/api/todos
| Method | Path | Description |
|---|---|---|
GET / |
Fetch all tasks | |
GET /{id} |
Fetch a single task | |
POST / |
Create a task ({"title":"...", "completed":false}) |
|
PUT /{id} |
Update title/completed | |
DELETE /{id} |
Delete a task (404 when missing) |
Additional async endpoints (/api/async/todos) and increment examples are exposed from the presentation layer. OpenAPI definitions are emitted into openapi-definition/.
see also: http://localhost:8080/q/swagger-ui/
App.jsximplements list rendering, creation form, completion toggles, and deletion, all backed by fetch calls to/api/todos.App.cssprovides a lightweight card-style layout with responsive tweaks.- Error/loading states feed back to the UI via status messages.
The backend storage can be switched at runtime via app.repository.type in application.properties.
| Value | Backend |
|---|---|
redis |
Valkey/Redis |
dynamodb (default) |
DynamoDB (or DynamoDB Local) |
To use DynamoDB Local in dev mode:
%dev.app.repository.type=dynamodb
%dev.app.dynamodb.endpoint-override=http://localhost:8000Steps:
docker compose up dynamodb-local -d./scripts/init-dynamodb.sh./mvnw compile quarkus:dev
- DevServices: Leaving
%dev.quarkus.redis.hostscommented lets Quarkus start Redis automatically in dev/test. - Local Redis: Set
%dev.quarkus.redis.hosts=redis://localhost:6379/0to reuse an existing instance. - Docker Compose:
docker compose up -dstarts the local Valkey container defined incompose.yaml; stop it withdocker compose down. - Seed scripts (
users.redis,test-task.redis) help bootstrap data when needed.
- Tests live under
src/test/java/...and rely on Quarkus JUnit5 + RestAssured. %test.quarkus.redis.load-script=test-task.redisloads fixtures for deterministic results.
- The dependency
quarkus-container-image-jibis included and configured viaapplication.properties. - Default image coordinates:
io.github.yuokada.practice/quarkus-react-todo-app:latest-jib. - Build locally:
./mvnw package -Dquarkus.container-image.build=true - Push to a registry:
./mvnw package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true - Override registry/name/tag as needed with
quarkus.container-image.*properties or system properties (see Quarkus container image guide).
- RESTEasy Reactive (guide): Build reactive REST services with Quarkus.
- Quinoa (guide): Develop, build, and serve SPA frontends alongside Quarkus services.
- DynamoDB support plan:
docs/dynamodb-support-plan.md - Reactive return type notes:
docs/reactive-return-types.md - Redis reactive tutorial:
docs/redis-reactive-tutorial.md
Live code the backend and frontend together with minimal configuration—Quinoa proxies the framework dev server during development and serves the generated assets in production.
This project uses Quinoa to wire a Vite/React frontend into the Quarkus application lifecycle.
- @vitejs/plugin-react uses Babel for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
Easily start your Reactive RESTful Web Services
- Redis Extension Reference Guide - Quarkus
- Using the Redis Client - Quarkus
- Dev Services for Redis - Quarkus
- valkey/valkey - Docker Image
For more contributor-oriented details (naming, linting, etc.), see AGENTS.md.