Skip to content

Spring Boot Todos

A REST API for managing todos, built with Java/Spring Boot and PostgreSQL. Demonstrates deploying a database-backed Java application on AppMecca with Spring Data JPA and Flyway migrations.

Overview

Repository git@gitlab.com:appmecca-sample-apps/spring-boot-todos.git
Tech Stack Java 21 / Spring Boot / Spring Data JPA / Flyway
Services api (port 8080)
Database Yes
Cache None
URL Pattern https://spring-boot-todos-api.{env}.appmecca.net

What This App Demonstrates

  • Deploying a database-backed Java application on AppMecca
  • Flyway database migrations with versioned SQL files
  • Spring Data JPA with the repository pattern for data access
  • REST API with full CRUD operations against PostgreSQL
  • The database.enabled: true configuration pattern

appmecca.yaml

containers:
  - name: api
    dockerfile: Dockerfile
    context: .

deploy:
  - name: api
    container: api
    port: 8080
    health_check:
      path: /health
      startup_timeout: 300
    resources:
      memory: "512m"

database:
  enabled: true

The only addition compared to Hello Java is database.enabled: true. AppMecca provisions a PostgreSQL database on first deploy and injects DATABASE_URL, DB_HOST, DB_PORT, DB_NAME, DB_USER and DB_PASSWORD into every container of the app automatically.

Never hardcode the database name

The database and user names are opaque, generated identifiers of the form am_<hash>_db and am_<hash>_user — derived from the app and branch, so each branch gets its own isolated database. They are never spring-boot-todos_db. Always read DATABASE_URL (or the DB_* pair).

Give the JVM room, and time

The two extra settings above are not optional decoration for a Spring Boot app:

  • resources.memory: "512m". The platform default is 128 MB, which the JVM plus Tomcat plus Flyway will blow through during startup — the container is killed (exit code 137) seconds into boot. Note the unit suffix is required: 512m or 1g. A bare 512 means 512 bytes, and 512mb is not a recognised form.
  • health_check.startup_timeout: 300. The default is 120 seconds. A cold JVM with migrations to apply frequently needs longer, and a deploy that runs out of startup budget is rolled back. The range is 30-600.

Step-by-Step Deployment

1. Register the app

mecca register git@gitlab.com:appmecca-sample-apps/spring-boot-todos.git -e dev

2. Build the container

mecca build trigger -e dev -g git@gitlab.com:appmecca-sample-apps/spring-boot-todos.git
Expected output
Build started: build-xxxxxxxx
Cloning repository...
Building container: api
Pushing to the image registry: appmecca-dev-spring-boot-todos
Build complete. Duration: 90s

Java builds are slower than scripted languages because the Gradle build must download dependencies and compile the source code. Subsequent builds with cached Docker layers are faster.

3. Deploy

mecca app deploy -e dev spring-boot-todos
Expected output
Deploying spring-boot-todos to dev...
Deployment queued: deploy-xxxxxxxx
Waiting for agents...
Container started: spring-boot-todos-api
Health check passed: /health -> 200 OK
Deployment complete.

Services:
  api: https://spring-boot-todos-api.dev.appmecca.net

4. Verify

mecca app show -e dev spring-boot-todos

Test the API:

# Health check
curl https://spring-boot-todos-api.dev.appmecca.net/health
{"status": "healthy"}
# Create a todo
curl -X POST https://spring-boot-todos-api.dev.appmecca.net/api/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Deploy more apps", "done": false}'

# List all todos
curl https://spring-boot-todos-api.dev.appmecca.net/api/todos

# Update a todo
curl -X PUT https://spring-boot-todos-api.dev.appmecca.net/api/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# Delete a todo
curl -X DELETE https://spring-boot-todos-api.dev.appmecca.net/api/todos/1

API Endpoints

Method Path Description
GET /health Health check
GET /api/todos List all todos
POST /api/todos Create a todo
PUT /api/todos/:id Update a todo
DELETE /api/todos/:id Delete a todo

Key Concepts

Flyway database migrations (versioned SQL files)

Flyway manages database schema changes using versioned SQL files in src/main/resources/db/migration/. Files follow the naming convention V1__Create_todos_table.sql, V2__Add_priority_column.sql, etc. Spring Boot auto-detects Flyway on the classpath and runs pending migrations on startup -- no entrypoint script is needed for the migration step. Flyway tracks which migrations have been applied in a flyway_schema_history table.

Spring Data JPA (repository pattern)

Spring Data JPA eliminates boilerplate data access code. You define a repository interface extending JpaRepository<Todo, Long>, and Spring generates the implementation at runtime. Standard CRUD operations (findAll, findById, save, deleteById) are provided without writing any SQL. Custom queries can be declared as method signatures (e.g., findByDone(boolean done)) and Spring derives the SQL automatically.

Any language, same workflow

AppMecca does not care what language your application is written in. As long as your container listens on the declared port and responds to health checks, the deployment workflow is identical.

What's Next?