{"id":15565026,"url":"https://github.com/conorheffron/ironoc-db","last_synced_at":"2026-04-01T23:06:49.172Z","repository":{"id":23698127,"uuid":"27070206","full_name":"conorheffron/ironoc-db","owner":"conorheffron","description":"Sample Data Manager with Thymeleaf Frontend \u0026 Spring Boot Backend (using JPA for DAO layer)","archived":false,"fork":false,"pushed_at":"2026-03-28T20:03:54.000Z","size":8337,"stargazers_count":20,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-28T21:26:09.263Z","etag":null,"topics":["docker-container","gke","google-cloud-platform","gradle-wrapper","gradle9","h2-database","java","jdk25","jpa-hibernate","kubernetes","lombok","lombok-gradle","micro-service","minikube","minikube-cluster","slf4j-loggers","spring-boot-4","thymeleaf-spring","thymeleaf-template-engine"],"latest_commit_sha":null,"homepage":"http://34.147.243.27:8080/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"angular/angular","license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/conorheffron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["conorheffron"]}},"created_at":"2014-11-24T10:01:36.000Z","updated_at":"2026-03-28T20:00:07.000Z","dependencies_parsed_at":"2024-04-17T00:26:45.446Z","dependency_job_id":"25844db2-2f3d-42eb-ac42-634128d4b5c0","html_url":"https://github.com/conorheffron/ironoc-db","commit_stats":{"total_commits":379,"total_committers":3,"mean_commits":"126.33333333333333","dds":0.2295514511873351,"last_synced_commit":"d76c19628c9d5f7ecddc4a26b0848e222edc8248"},"previous_names":["cph39/ironoc-db","conorheffron/ironoc-db"],"tags_count":168,"template":false,"template_full_name":null,"purl":"pkg:github/conorheffron/ironoc-db","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conorheffron%2Fironoc-db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conorheffron%2Fironoc-db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conorheffron%2Fironoc-db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conorheffron%2Fironoc-db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/conorheffron","download_url":"https://codeload.github.com/conorheffron/ironoc-db/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/conorheffron%2Fironoc-db/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292804,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker-container","gke","google-cloud-platform","gradle-wrapper","gradle9","h2-database","java","jdk25","jpa-hibernate","kubernetes","lombok","lombok-gradle","micro-service","minikube","minikube-cluster","slf4j-loggers","spring-boot-4","thymeleaf-spring","thymeleaf-template-engine"],"created_at":"2024-10-02T16:48:51.680Z","updated_at":"2026-04-01T23:06:49.149Z","avatar_url":"https://github.com/conorheffron.png","language":"Java","funding_links":["https://github.com/sponsors/conorheffron"],"categories":[],"sub_categories":[],"readme":"# ironoc-db\n\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n[![Gradle Package](https://github.com/conorheffron/ironoc-db/actions/workflows/gradle-publish.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/gradle-publish.yml)\n\n[![Java CI with Gradle](https://github.com/conorheffron/ironoc-db/actions/workflows/gradle.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/gradle.yml)\n\n[![Codacy Security Scan](https://github.com/conorheffron/ironoc-db/actions/workflows/codacy.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/codacy.yml)\n\n[![Docker Image CI](https://github.com/conorheffron/ironoc-db/actions/workflows/docker-image.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/docker-image.yml)\n\n[![Docker Publish](https://github.com/conorheffron/ironoc-db/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/docker-publish.yml)\n\n![Proof HTML](https://github.com/conorheffron/ironoc-db/actions/workflows/proof-html.yml/badge.svg)\n\n![Auto Assign](https://github.com/conorheffron/ironoc-db/actions/workflows/auto-assign.yml/badge.svg)\n\n## Sonar (Static Application Security Testing SAST tool)\n\n[![SonarQube](https://github.com/conorheffron/ironoc-db/actions/workflows/sonar.yml/badge.svg)](https://github.com/conorheffron/ironoc-db/actions/workflows/sonar.yml)\n\n[![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=conorheffron_ironoc-db)](https://sonarcloud.io/summary/new_code?id=conorheffron_ironoc-db)\n\n[Sonar Scan Analysis \u0026 JaCoCo Test Coverage Report - Overall Summary](https://sonarcloud.io/summary/overall?id=conorheffron_ironoc-db\u0026branch=main)\n\n# Sample Data Manager\n================\n\n## Docker Hub\n[ironoc-db docker hub](https://hub.docker.com/repository/docker/conorheffron/ironoc-db/general)\n\n## Summary\nThis project is a sample data manager. It provides a basic template for Java/Spring developers. \nThis project also includes form validation of controller model objects and request parameters.\nUsers can view, add, delete person objects from the database via web UI.\n\n## Technologies Used\nJava 25, Spring Boot 4, Thymeleaf Templates, Hibernate, MySQL or H2 databases supported, Gradle 9, \n    GKE, Docker, minikube, \u0026 kubectl.\n\n## Project Structure\n```shell\nsrc\n├── integration-test\n│   └── java\n│       └── com.ironoc.db.controller\n│           ├── CustomErrorControllerIntegrationTest.java\n│           └── PersonControllerIntegrationTest.java\n├── main\n│   ├── java\n│   │   └── com\n│   │       └── ironoc\n│   │           └── db\n│   │               ├── App.java\n│   │               ├── config\n│   │               │   └── IronocDbConfig.java\n│   │               ├── controller\n│   │               │   ├── CustomErrorController.java\n│   │               │   ├── PersonController.java\n│   │               │   └── VersionController.java\n│   │               ├── dao\n│   │               │   └── PersonDao.java\n│   │               ├── enums\n│   │               │   └── DataSourceKey.java\n│   │               ├── model\n│   │               │   ├── Employer.java\n│   │               │   └── Person.java\n│   │               └── service\n│   │                   ├── GoogleCloudClient.java\n│   │                   ├── GoogleCloudClientImpl.java\n│   │                   ├── PersonService.java\n│   │                   └── PersonServiceImpl.java\n│   ├── META-INF\n│   │   └── MANIFEST.MF\n│   └── resources\n│       ├── application-h2.properties\n│       ├── application.properties\n│       ├── db\n│       │   ├── data-h2.sql\n│       │   ├── data-mysql.sql\n│       │   └── ddl.sql\n│       ├── log4j.xml\n│       ├── static\n│       │   ├── favicon.ico\n│       │   ├── img\n│       │   │   └── robot-logo.png\n│       │   ├── ironoc-db-banner.txt\n│       │   └── style\n│       │       └── main.css\n│       └── templates\n│           ├── add-employee.html\n│           ├── edit-person.html\n│           ├── employee-list.html\n│           ├── error404.html\n│           ├── index.html\n│           └── navbar.html\n└── test\n    ├── java\n    │   └── com\n    │       └── ironoc\n    │           └── db\n    │               ├── AppTest.java\n    │               ├── config\n    │               │   └── IronocDbConfigTest.java\n    │               ├── controller\n    │               │   ├── CustomErrorControllerTest.java\n    │               │   ├── PersonControllerTest.java\n    │               │   └── VersionControllerTest.java\n    │               └── service\n    │                   ├── GoogleCloudClientServiceTest.java\n    │                   └── PersonServiceTest.java\n    └── resources\n        └── application.properties\n```\n\n## Run\n### - See `src/main/resources/db/ddl.sql` for sample Schema to get started with ironoc-db instances using MySQL or H2\n```shell\ndocker pull mysql:latest\n```\n```shell\ndocker run -d --name test-mysql -e MYSQL_ROOT_PASSWORD=mypassword -p 3307:3306 mysql\n```\n```shell\ndocker logs test-mysql\n```\n```shell\ndocker exec -it test-mysql bash\n```\n```shell\ndocker ps\n```\n\n![create-db-connection](./screenshots/db-connection.png?raw=true \"Create DB Connection\")\n![create-test-schema](./screenshots/create-schema.png?raw=true \"Create Test Schema\")\n![load-db](./screenshots/run-starter-db-script.png?raw=true \"Load DB\")\n![verify-db](./screenshots/verify-db-load.png?raw=true \"Verify DB\")\n\n## Create Network\n```shell\ndocker network create my-network\n```\n```shell\ndocker inspect network my-network \n```\n\n## Link mysql container to same network for access:\n```\ndocker network connect my-network test-mysql\n```\n\n## Inspect network configurations \u0026 update application properties with IPv4Address instead of localhost if mac user (IPv4Address for my-sql etc.)\n- Get IPv4Address from inspect cmd and test connection from MySql workbench with new host IP. Run StarterDb.sql.\n```shell\ndocker inspect network my-network \n```\n\n## Build ironoc-db, run unit \u0026 integration tests, \u0026 generate war file.\n```shell\n./gradlew clean build\n```\n\n## Login to gcloud project for authentication tokens etc. for save to local workspace\n### Accept \u0026 allow browser prompts.\n### Note: This is for direct app run, need to to do this in container or pod for virtualization.\n```shell\ngcloud auth application-default login\n```\n\n## Verify credentials (set appropriate svc / user account \u0026 project name)\n```shell\ngcloud config list\n```\n\n## Run `com.ironoc.db.App.java` directly from IntelliJ (can use localhost for spring.datasource.url) or \n## via CLI (build \u0026 spin up docker image, use docker network IP address for test-mysql process):\n```shell\ndocker image build -t ironoc-db .\n```\n```shell\ndocker compose up -d\n```\n```shell\ndocker ps\n```\n```shell\ndocker logs ironoc-db-web-1 -f\n```\n\n### Run locally with Gradle \u0026 H2 database\n```shell\n./gradlew bootRun --args='--spring.profiles.active=h2'\n```\n\n### Run locally with Gradle \u0026 MySQL database (Default run profile)\n```shell\n./gradlew bootRun --args='--spring.profiles.active=default'\n```\n\n```shell\ndocker compose down\n```\n\n![docker-cli](./screenshots/CLI-docker.png?raw=true \"CLI Docker\")\n\n## Tear-down:\n```shell\ndocker stop test-mysql\n```\n```shell\ndocker remove test-mysql\n```\n\n## Run ironoc-db on local k8s cluster\n```shell  \n%   minikube start --driver=docker  \n😄  minikube v1.35.0 on Darwin 15.3.1\n❗  Both driver=docker and vm-driver=virtualbox have been set.\n\n    Since vm-driver is deprecated, minikube will default to driver=docker.\n\n    If vm-driver is set in the global config, please run \"minikube config unset vm-driver\" to resolve this warning.\n                        \n✨  Using the docker driver based on user configuration\n📌  Using Docker Desktop driver with root privileges\n👍  Starting \"minikube\" primary control-plane node in \"minikube\" cluster\n🚜  Pulling base image v0.0.46 ...\n💾  Downloading Kubernetes v1.32.0 preload ...\n    \u003e preloaded-images-k8s-v18-v1...:  333.57 MiB / 333.57 MiB  100.00% 22.49 M\n    \u003e gcr.io/k8s-minikube/kicbase...:  500.31 MiB / 500.31 MiB  100.00% 14.30 M\n🔥  Creating docker container (CPUs=2, Memory=4000MB) ...\n🐳  Preparing Kubernetes v1.32.0 on Docker 27.4.1 ...\n    ▪ Generating certificates and keys ...\n    ▪ Booting up control plane ...\n    ▪ Configuring RBAC rules ...\n🔗  Configuring bridge CNI (Container Networking Interface) ...\n🔎  Verifying Kubernetes components...\n    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5\n🌟  Enabled addons: storage-provisioner, default-storageclass\n🏄  Done! kubectl is now configured to use \"minikube\" cluster and \"default\" namespace by default\n\n\n%   kubectl cluster-info \nKubernetes control plane is running at https://127.0.0.1:54912\nCoreDNS is running at https://127.0.0.1:54912/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy\n\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n\n\n%   minikube dashboard \n🔌  Enabling dashboard ...\n    ▪ Using image docker.io/kubernetesui/metrics-scraper:v1.0.8\n    ▪ Using image docker.io/kubernetesui/dashboard:v2.7.0\n💡  Some dashboard features require the metrics-server addon. To enable all features please run:\n\n        minikube addons enable metrics-server\n\n🤔  Verifying dashboard health ...\n🚀  Launching proxy ...\n🤔  Verifying proxy health ...\n🎉  Opening http://127.0.0.1:54976/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...\n```\n- Then change namespace in browser after creation of 'ironoc-db' namespace.\n\n![minikube-dash](./screenshots/minikube-dash.png?raw=true \"Minikube Dashboard\")\n```shell\n%   docker images\nREPOSITORY                    TAG       IMAGE ID       CREATED        SIZE\ngcr.io/k8s-minikube/kicbase   v0.0.45   e7c9bc3bc515   3 months ago   1.81GB\ngcr.io/k8s-minikube/kicbase   \u003cnone\u003e    81df28859520   3 months ago   1.81GB\n\n\n%   docker image build -t ironoc-db .\n[+] Building 174.7s (11/11) FINISHED                                                                                                                                                                                                                                            docker:desktop-linux\n =\u003e [internal] load build definition from Dockerfile                                                                                                                                                                                                                                            0.0s\n =\u003e =\u003e transferring dockerfile: 340B                                                                                                                                                                                                                                                            0.0s\n =\u003e [internal] load metadata for docker.io/library/gradle:8.13.0-jdk23-alpine                                                                                                                                                                                                                   1.4s\n =\u003e [auth] library/gradle:pull token for registry-1.docker.io                                                                                                                                                                                                                                   0.0s\n =\u003e [internal] load .dockerignore                                                                                                                                                                                                                                                               0.0s\n =\u003e =\u003e transferring context: 2B                                                                                                                                                                                                                                                                 0.0s\n =\u003e [internal] load build context                                                                                                                                                                                                                                                               0.6s\n =\u003e =\u003e transferring context: 2.48MB                                                                                                                                                                                                                                                             0.6s\n =\u003e CACHED [1/5] FROM docker.io/library/gradle:8.13.0-jdk23-alpine@sha256:2deae0129d5d2659e5aa890138420398708c7ab54250985bbfb08046611d8e27                                                                                                                                                      3.5s\n =\u003e =\u003e resolve docker.io/library/gradle:8.13.0-jdk23-alpine@sha256:2deae0129d5d2659e5aa890138420398708c7ab54250985bbfb08046611d8e27                                                                                                                                                             3.4s\n =\u003e [2/5] COPY . /home/gradle                                                                                                                                                                                                                                                                   6.2s\n =\u003e [3/5] RUN apk update \u0026\u0026 apk upgrade --no-cache                                                                                                                                                                                                                                              7.9s\n =\u003e [4/5] RUN apk add gcompat                                                                                                                                                                                                                                                                   1.4s \n =\u003e [5/5] RUN gradle build                                                                                                                                                                                                                                                                    117.0s \n =\u003e exporting to image                                                                                                                                                                                                                                                                         36.3s \n =\u003e =\u003e exporting layers                                                                                                                                                                                                                                                                        25.4s \n =\u003e =\u003e exporting manifest sha256:38618720756428d821efcfa62dc4ec9a30695aceeb1c1109a628350a85f6ba34                                                                                                                                                                                               0.0s \n =\u003e =\u003e exporting config sha256:774368a010c8731bd8287ad62fb7b3c7744642dc398a5cefe72bbe49b4666c45                                                                                                                                                                                                 0.0s \n =\u003e =\u003e exporting attestation manifest sha256:723a48372e275ddd28aa039aef88bfe1ca5bf9f7cb59f4bfb9c9679b90faca9e                                                                                                                                                                                   0.0s \n =\u003e =\u003e exporting manifest list sha256:446306dc3c57370dfb771b12a1d538cf1e6c40fb749065dfae9cecc045d6da9f                                                                                                                                                                                          0.0s \n =\u003e =\u003e naming to docker.io/library/ironoc-db:latest                                                                                                                                                                                                                                             0.0s\n =\u003e =\u003e unpacking to docker.io/library/ironoc-db:latest                                                                                                                                                                                                                                         10.7s\n\nView build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/wbu3i027e2wyq3oi661jykphk\n\nWhat's next:\n    View a summary of image vulnerabilities and recommendations → docker scout quickview \n\n\n%   docker images                       \nREPOSITORY                    TAG       IMAGE ID       CREATED         SIZE\nironoc-db                     latest    1e287e0f161e   7 minutes ago   1.79GB\ngcr.io/k8s-minikube/kicbase   v0.0.45   e7c9bc3bc515   3 months ago    1.81GB\ngcr.io/k8s-minikube/kicbase   \u003cnone\u003e    81df28859520   3 months ago    1.81GB\n\n\n%   minikube image load ironoc-db:latest\n\n%   kubectl create ns ironoc-db-ns\nnamespace/ironoc-db-ns created\n\n\n%   kubectl get ns\nNAME                   STATUS   AGE\ndefault                Active   27m\nironoc-db-ns           Active   7s\nkube-node-lease        Active   27m\nkube-public            Active   27m\nkube-system            Active   27m\nkubernetes-dashboard   Active   14m\n\n\n%   kubectl apply -f ./kubernetes/ironoc-db-local.yml --namespace=ironoc-db-ns \ndeployment.apps/ironoc-db-app-deployment created\nhorizontalpodautoscaler.autoscaling/ironoc-db-app-deployment-hpa-kbij created\n\n\n%   kubectl get pods --namespace=ironoc-db-ns\nNAME                                        READY   STATUS    RESTARTS   AGE\nironoc-db-app-deployment-d5c59b4c5-rzmhz   1/1     Running   0          10s\n\n\n%   kubectl get deployment --namespace=ironoc-db-ns\nNAME                       READY   UP-TO-DATE   AVAILABLE   AGE\nironoc-db-app-deployment   1/1     1            1           17s\n```\n![minikube-dash-deployments](./screenshots/minikube-dash-deployments.png?raw=true \"ironoc-db kube Deployment\")\n```shell\n%   kubectl expose deployment ironoc-db-app-deployment --type=NodePort --namespace=ironoc-db-ns\n\nservice/ironoc-db-app-deployment exposed\n\n\n%   kubectl get services --namespace=ironoc-db-ns\nNAME                       TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE\nironoc-db-app-deployment   NodePort   10.96.135.232   \u003cnone\u003e        8080:31797/TCP   8s\n\n\n%   minikube service ironoc-db-app-deployment --url --namespace=ironoc-db-ns\nhttp://127.0.0.1:55519\n❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.\n```\n- Open a new terminal tab \u0026 follow the logs\n```shell\n%   kubectl get pods --namespace=ironoc-db-ns\nNAME                                        READY   STATUS    RESTARTS   AGE\nironoc-db-app-deployment-d5c59b4c5-rzmhz   1/1     Running   0          2m54s\n\n\n%   kubectl logs ironoc-db-app-deployment-d5c59b4c5-rzmhz -f --namespace=ironoc-db-ns\nStarting a Gradle Daemon, 1 incompatible and 1 stopped Daemons could not be reused, use --status for details\n\u003e Task :bootBuildInfo\n\u003e Task :compileJava UP-TO-DATE\n\u003e Task :processResources UP-TO-DATE\n\u003e Task :classes\n\u003e Task :resolveMainClassName\n\n\u003e Task :bootRun\n\n.__ __________                                  ________             __           ___.                            \n|__|\\______   \\  ____    ____    ____    ____   \\______ \\  _____   _/  |_ _____   \\_ |__  _____     ______  ____  \n|  | |       _/ /  _ \\  /    \\  /  _ \\ _/ ___\\   |    |  \\ \\__  \\  \\   __\\\\__  \\   | __ \\ \\__  \\   /  ___/_/ __ \\ \n|  | |    |   \\(  \u003c_\u003e )|   |  \\(  \u003c_\u003e )\\  \\___   |    `   \\ / __ \\_ |  |   / __ \\_ | \\_\\ \\ / __ \\_ \\___ \\ \\  ___/ \n|__| |____|_  / \\____/ |___|  / \\____/  \\___  \u003e /_______  /(____  / |__|  (____  / |___  /(____  //____  \u003e \\___  \u003e\n            \\/              \\/              \\/          \\/      \\/             \\/      \\/      \\/      \\/      \\/ \n\n\n2025-05-20T00:46:38.947Z  INFO 150 --- [           main] com.ironoc.db.App                        : Starting App using Java 24.0.1 with PID 150 (/home/gradle/build/classes/java/main started by root in /home/gradle)\n2025-05-20T00:46:38.952Z  INFO 150 --- [           main] com.ironoc.db.App                        : The following 1 profile is active: \"h2\"\n2025-05-20T00:46:40.736Z  INFO 150 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.\n2025-05-20T00:46:40.816Z  INFO 150 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 67 ms. Found 1 JPA repository interface.\n2025-05-20T00:46:42.198Z  INFO 150 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)\n2025-05-20T00:46:42.262Z  INFO 150 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]\n2025-05-20T00:46:42.263Z  INFO 150 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/11.0.7]\n2025-05-20T00:46:42.708Z  INFO 150 --- [           main] org.apache.jasper.servlet.TldScanner     : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n2025-05-20T00:46:42.718Z  INFO 150 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext\n2025-05-20T00:46:42.719Z  INFO 150 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3603 ms\n2025-05-20T00:46:42.802Z  INFO 150 --- [           main] c.i.db.service.GoogleCloudClientImpl     : Entering GoogleCloudClient.getSecret for secretVersion=projects/902038140834/secrets/MY_SQL_PASSWORD/versions/latest\n2025-05-20T00:46:43.377Z  INFO 150 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]\n2025-05-20T00:46:43.426Z  INFO 150 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.6.13.Final\n2025-05-20T00:46:43.476Z  INFO 150 --- [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled\n2025-05-20T00:46:43.876Z  INFO 150 --- [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer\n2025-05-20T00:46:43.907Z  WARN 150 --- [           main] org.hibernate.orm.deprecation            : HHH90000025: H2Dialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)\n2025-05-20T00:46:43.923Z  INFO 150 --- [           main] org.hibernate.orm.connections.pooling    : HHH10001005: Database info:\n        Database JDBC URL [undefined/unknown]\n        Database driver: undefined/unknown\n        Database version: 2.1.214\n        Autocommit mode: undefined/unknown\n        Isolation level: \u003cunknown\u003e\n        Minimum pool size: undefined/unknown\n        Maximum pool size: undefined/unknown\n2025-05-20T00:46:45.066Z  INFO 150 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)\nHibernate: drop table if exists employer cascade \n2025-05-20T00:46:45.082Z  INFO 150 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...\n2025-05-20T00:46:45.297Z  INFO 150 --- [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:ironoc_db user=ROOT\n2025-05-20T00:46:45.300Z  INFO 150 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.\nHibernate: drop table if exists person cascade \nHibernate: create table employer (start_year integer, employee_id bigint, employer_id bigint generated by default as identity, employer_name varchar(255), title varchar(255), primary key (employer_id))\nHibernate: create table person (age integer not null check ((age\u003c=90) and (age\u003e=1)), title varchar(5) not null, id bigint generated by default as identity, first_name varchar(30) not null, surname varchar(30) not null, primary key (id))\nHibernate: alter table if exists employer add constraint FKncw2hjus3cwslwhelmj9kryiu foreign key (employee_id) references person\n2025-05-20T00:46:45.363Z  INFO 150 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'\n2025-05-20T00:46:46.122Z  WARN 150 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning\n2025-05-20T00:46:46.149Z  INFO 150 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index\n2025-05-20T00:46:46.810Z  INFO 150 --- [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:ironoc_db'\n2025-05-20T00:46:47.022Z  INFO 150 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'\n2025-05-20T00:46:47.040Z  INFO 150 --- [           main] com.ironoc.db.App                        : Started App in 9.124 seconds (process running for 9.703)\n.\n.\n.\n2025-05-20T00:49:03.513Z  INFO 150 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'\n2025-05-20T00:49:03.513Z  INFO 150 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'\n2025-05-20T00:49:03.519Z  INFO 150 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 6 ms\n2025-05-20T00:49:03.613Z  INFO 150 --- [nio-8080-exec-1] c.ironoc.db.controller.PersonController  : Entering personController.home: map={applicationVersion=Version: 6.2.2}\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title from person p1_0\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\n2025-05-20T00:49:12.061Z  INFO 150 --- [nio-8080-exec-5] c.ironoc.db.controller.PersonController  : Entering personController.deletePersonBySurname: map={applicationVersion=Version: 6.2.2}, id=1000\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title,e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from person p1_0 left join employer e1_0 on p1_0.id=e1_0.employee_id where p1_0.id=?\nHibernate: delete from employer where employer_id=?\nHibernate: delete from employer where employer_id=?\nHibernate: delete from person where id=?\n2025-05-20T00:49:12.197Z  INFO 150 --- [nio-8080-exec-6] c.ironoc.db.controller.PersonController  : Entering personController.home: map={applicationVersion=Version: 6.2.2}\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title from person p1_0\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\n2025-05-20T00:49:28.488Z  INFO 150 --- [nio-8080-exec-7] c.ironoc.db.controller.PersonController  : Entering personController.addPerson: map={applicationVersion=Version: 6.2.2, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=null, employers=null), org.springframework.validation.BindingResult.person=org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'person' on field 'age': rejected value [null]; codes [NotNull.person.age,NotNull.age,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age]]; default message [Age is not defined.]}, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=null, employers=null)\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title from person p1_0\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\n2025-05-20T00:49:30.888Z  INFO 150 --- [nio-8080-exec-8] c.ironoc.db.controller.PersonController  : Entering personController.addPerson: map={applicationVersion=Version: 6.2.2, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=99, employers=null), org.springframework.validation.BindingResult.person=org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'person' on field 'age': rejected value [99]; codes [Max.person.age,Max.age,Max.java.lang.Integer,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age],90]; default message [Age is greater than 90.]}, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=99, employers=null)\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title from person p1_0\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\n2025-05-20T00:49:36.350Z  INFO 150 --- [nio-8080-exec-9] c.ironoc.db.controller.PersonController  : Entering personController.addPerson: map={applicationVersion=Version: 6.2.2, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=23, employers=null), org.springframework.validation.BindingResult.person=org.springframework.validation.BeanPropertyBindingResult: 0 errors}, person=Person(id=null, title=Mr , firstName=Conor, surname=Heffron, age=23, employers=null)\nHibernate: insert into person (age,first_name,surname,title,id) values (?,?,?,?,default)\n2025-05-20T00:49:36.394Z  INFO 150 --- [io-8080-exec-10] c.ironoc.db.controller.PersonController  : Entering personController.home: map={applicationVersion=Version: 6.2.2}\nHibernate: select p1_0.id,p1_0.age,p1_0.first_name,p1_0.surname,p1_0.title from person p1_0\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\nHibernate: select e1_0.employee_id,e1_0.employer_id,e1_0.employer_name,e1_0.start_year,e1_0.title from employer e1_0 where e1_0.employee_id=?\n```  \n\n![minikube-dash-logs](./screenshots/minikube-dash-logs.png?raw=true \"ironoc-db kube logs viewer\")\n\n![deployment](./screenshots/deployment.png?raw=true \"ironoc-db local k8s Deployment\")\n\n```shell\n% minikube delete\n🔥  Deleting \"minikube\" in docker ...\n🔥  Deleting container \"minikube\" ...\n🔥  Removing /Users/conorheffron/.minikube/machines/minikube ...\n💀  Removed all traces of the \"minikube\" cluster.\n```\n\n## Alternatively, Docker Desktop is good if you prefer to not use the terminal/command line (CLI)\n![docker-desktop-containers](./screenshots/docker-desktop-containers.png?raw=true \"Docker Desktop containers\")\n\n## Can tail the logs by scrolling within the container logs:\n![docker-desktop-ironoc-db-logs](./screenshots/docker-desktop-ironoc-db-logs.png?raw=true \"Docker Desktop ironoc-db logs\")\n\n## Screenshot Home\n![Home](./screenshots/DBManager.png?raw=true \"Home Page\")\n\n## Screenshot Form Validation Error for Add Person Call\n![ui-form-validation](./screenshots/ui-form-validation.png?raw=true \"UI form validation\")\n\n## Screenshot Form Validation Error for Edit Operation\n![ui-edit-validation](./screenshots/ui-edit-validation.png?raw=true \"UI Edit validation\")\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconorheffron%2Fironoc-db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconorheffron%2Fironoc-db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconorheffron%2Fironoc-db/lists"}