diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 813c0e4..7c214a7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,4 +1,4 @@
-name: Java CI with Maven (multi-job)
+name: CI
on:
workflow_dispatch:
diff --git a/google-cloud-sql/docs/automate-table-creation-using-terraform.md b/google-cloud-sql/docs/automate-table-creation-using-terraform.md
new file mode 100644
index 0000000..461bdae
--- /dev/null
+++ b/google-cloud-sql/docs/automate-table-creation-using-terraform.md
@@ -0,0 +1,32 @@
+# Automate table creation using Terraform
+
+### Example
+
+```hcl
+# run after instance+db+user exist
+resource "null_resource" "init_table" {
+ depends_on = [google_sql_database.db, google_sql_user.user]
+
+ provisioner "local-exec" {
+ interpreter = ["/bin/bash", "-c"]
+ command = <<-EOT
+ set -euo pipefail
+ # Start proxy
+ cloud-sql-proxy ${google_sql_database_instance.pg.connection_name} --port 5432 &
+ PID=$!
+ # Wait for port
+ for i in {1..30}; do nc -z 127.0.0.1 5432 && break; sleep 1; done
+ # Apply DDL
+ PGPASSWORD='${var.db_password}' psql -h 127.0.0.1 -p 5432 -U '${var.db_user}' -d '${var.db_name}' <<'SQL'
+ CREATE TABLE IF NOT EXISTS widgets (
+ id UUID PRIMARY KEY,
+ name TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ meta JSONB
+ );
+ SQL
+ kill $PID
+ EOT
+ }
+}
+```
diff --git a/google-cloud-sql/docs/cloud-sql-auth-proxy.md b/google-cloud-sql/docs/cloud-sql-auth-proxy.md
new file mode 100644
index 0000000..900717b
--- /dev/null
+++ b/google-cloud-sql/docs/cloud-sql-auth-proxy.md
@@ -0,0 +1,230 @@
+# Cloud SQL Auth Proxy
+
+### Set instance connection name
+
+```bash
+export INSTANCE_CONNECTION_NAME="lofty-root-378503:us-central1:jm-pg-demo"
+```
+
+### Run the CloudSQL auth proxy
+
+Remove any old proxy container:
+
+```bash
+docker rm -f csql-proxy 2>/dev/null || true
+```
+
+Then use one of the below options:
+
+#### Executable
+
+```bash
+# CLI option
+# Download from: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
+./cloud-sql-proxy ${INSTANCE_CONNECTION_NAME} --port 5432 &
+PROXY_PID=$!
+```
+
+#### Docker
+
+```bash
+
+export CREDENTIALS_PATH="/Users/admin/.config/gcloud/sa-private-key.json"
+docker run -d --name csql-proxy -p 127.0.0.1:5400:5432 \
+ -v "$GOOGLE_APPLICATION_CREDENTIALS:/creds/key.json:ro" \
+ gcr.io/cloud-sql-connectors/cloud-sql-proxy:2 \
+ --address 0.0.0.0 --port 5432 \
+ --credentials-file=/creds/key.json "$INSTANCE_CONNECTION_NAME"
+```
+
+### Wait for proxy to listen
+
+```bash
+for i in {1..30}; do nc -z 127.0.0.1 5433 && echo "proxy ready" && break; sleep 1; done
+```
+
+### Check if proxy is running
+
+```bash
+docker ps -a | grep csql-proxy || true
+```
+
+### Verify proxy is running on a specific port
+
+```bash
+nc -z 127.0.0.1 5400 && echo "proxy up" || echo "proxy not up"
+```
+
+### Check proxy logs
+
+```bash
+docker logs csql-proxy --tail=200 || true
+```
+
+### Check if port is in use
+
+```bash
+lsof -iTCP:5432 -sTCP:LISTEN || true
+```
+
+### List available ports
+
+#### Common Postgres ports
+
+```bash
+for p in 5432 5433 5434 5435 5436; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) && echo "❌ $p in use" || echo "✅ $p free"; done
+```
+
+#### Scan a wider port range
+
+```bash
+for p in {5400..5450}; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) || echo "✅ $p free"; done
+```
+
+#### Pick the first available port
+
+```bash
+for p in {5400..5450}; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) || { echo "First free port: $p"; break; }; done
+```
+
+### Test connection
+
+```bash
+export TF_VAR_db_user=username
+export TF_VAR_db_password=password
+export TF_VAR_db_name=jm_demo_db
+```
+
+Have the proxy running and healthy to `127.0.0.1:5432`.
+Make sure nothing else is using port `5432`.
+If it is, pick another port (e.g., 5433) and update your `psql` command.
+
+Then run:
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -c "select 1;"
+```
+
+### If the test is successful
+
+Assuming the file `/src/test/resources/init.sql` exists:
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -f init.sql
+```
+
+You can also create the table directly from the command line:
+
+```bash
+cat > init.sql <<'SQL'
+PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5400 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" -v ON_ERROR_STOP=1 <<'SQL'
+CREATE TABLE IF NOT EXISTS widgets (
+ id UUID PRIMARY KEY,
+ name TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ meta JSONB
+);
+SQL
+```
+
+### Single insert
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -c "INSERT INTO widgets (id, name, meta) VALUES (gen_random_uuid(), 'Test Widget', '{\"color\":\"red\",\"size\":10}');"
+```
+
+### Multiple inserts
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -c "
+INSERT INTO widgets (id, name, meta) VALUES
+ (gen_random_uuid(), 'Widget A', '{\"type\":\"alpha\"}'),
+ (gen_random_uuid(), 'Widget B', '{\"type\":\"beta\"}'),
+ (gen_random_uuid(), 'Widget C', '{\"type\":\"gamma\"}');
+"
+```
+
+### Insert rows from a file
+
+```bash
+cat > /tmp/insert_widgets.sql <<'SQL'
+INSERT INTO widgets (id, name, meta) VALUES
+ (gen_random_uuid(), 'Widget X', '{"size":42}'),
+ (gen_random_uuid(), 'Widget Y', '{"color":"blue"}');
+SQL
+
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -f insert_widgets.sql
+```
+
+### Read all rows in a table
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql \
+ -h 127.0.0.1 -p 5400 \
+ -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
+ -c "SELECT * FROM widgets;"
+```
+
+### Open an interactive psql session
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5400 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name"
+```
+
+```sql
+INSERT INTO widgets (id, name, meta) VALUES (gen_random_uuid(), 'Widget ABC', '{"shape":"sphere"}');
+SELECT * FROM widgets;
+```
+
+### List tables
+
+```psql
+\l
+```
+
+### Drop tables
+
+```bash
+DROP TABLE widgets;
+```
+
+### Exit `psql`
+
+```psql
+exit
+```
+
+---
+
+### Grant create/use to a user
+
+```bash
+PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5432 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" -c \
+"GRANT USAGE ON SCHEMA public TO $TF_VAR_db_user; GRANT CREATE ON SCHEMA public TO $TF_VAR_db_user;"
+```
+
+Verify `roles/cloudsql.client` on the user's service account.
+
+---
+
+### Stop the CloudSQL auth proxy
+
+```bash
+kill $PROXY_PID 2>/dev/null || true
+# or: docker rm -f csql-proxy
+```
diff --git a/google-cloud-sql/pom.xml b/google-cloud-sql/pom.xml
index 38e4486..33e8ded 100644
--- a/google-cloud-sql/pom.xml
+++ b/google-cloud-sql/pom.xml
@@ -13,6 +13,7 @@
org.squidmin.java.spring.maven.cloudsql
google-cloud-sql
0.0.1-SNAPSHOT
+
google-cloud-sql
google-cloud-sql
diff --git a/google-cloud-sql/src/main/java/org/squidmin/java/spring/maven/cloudsql/controller/CloudSqlController.java b/google-cloud-sql/src/main/java/org/squidmin/java/spring/maven/cloudsql/controller/CloudSqlController.java
index 33fe685..53facd6 100644
--- a/google-cloud-sql/src/main/java/org/squidmin/java/spring/maven/cloudsql/controller/CloudSqlController.java
+++ b/google-cloud-sql/src/main/java/org/squidmin/java/spring/maven/cloudsql/controller/CloudSqlController.java
@@ -13,7 +13,7 @@ public class CloudSqlController {
public CloudSqlController() {}
@GetMapping(
- value = "/placeholder",
+ value = "/insert-rows",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
diff --git a/google-cloud-sql/src/test/resources/application-test.yml b/google-cloud-sql/src/test/resources/application-test.yml
new file mode 100644
index 0000000..ac29fc0
--- /dev/null
+++ b/google-cloud-sql/src/test/resources/application-test.yml
@@ -0,0 +1,3 @@
+spring:
+ application:
+ name: google-cloud-sql
diff --git a/google-cloud-sql/src/test/resources/init.sql b/google-cloud-sql/src/test/resources/init.sql
new file mode 100644
index 0000000..664bd59
--- /dev/null
+++ b/google-cloud-sql/src/test/resources/init.sql
@@ -0,0 +1,6 @@
+CREATE TABLE IF NOT EXISTS widgets (
+ id UUID PRIMARY KEY,
+ name TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ meta JSONB
+);
diff --git a/google-cloud-sql/src/test/resources/insert_widgets.sql b/google-cloud-sql/src/test/resources/insert_widgets.sql
new file mode 100644
index 0000000..c39a65f
--- /dev/null
+++ b/google-cloud-sql/src/test/resources/insert_widgets.sql
@@ -0,0 +1,3 @@
+INSERT INTO widgets (id, name, meta)
+VALUES (gen_random_uuid(), 'Widget X', '{"size":42}'),
+ (gen_random_uuid(), 'Widget Y', '{"color":"blue"}');