https://github.com/abasheger/terubase
Maven plugin for Spring Boot/JPA projects that scans entity metadata, creates seed-data plans, validates INSERT-only SQL, and exports data.sql or Flyway-ready files.
https://github.com/abasheger/terubase
developer-tools hibernate java jpa seed-data spring-boot test-data
Last synced: 6 days ago
JSON representation
Maven plugin for Spring Boot/JPA projects that scans entity metadata, creates seed-data plans, validates INSERT-only SQL, and exports data.sql or Flyway-ready files.
- Host: GitHub
- URL: https://github.com/abasheger/terubase
- Owner: AbaSheger
- License: mit
- Created: 2026-05-31T03:36:32.000Z (27 days ago)
- Default Branch: main
- Last Pushed: 2026-06-07T17:54:01.000Z (20 days ago)
- Last Synced: 2026-06-07T19:22:22.595Z (20 days ago)
- Topics: developer-tools, hibernate, java, jpa, seed-data, spring-boot, test-data
- Language: Java
- Homepage:
- Size: 271 KB
- Stars: 1
- Watchers: 0
- Forks: 1
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
TeruBase
Build-time JPA metadata planning and reviewed SQL export for Maven projects.
TeruBase is a Maven plugin that inspects compiled, field-annotated JPA entities,
writes schema-context and seed-plan files, checks that reviewed SQL contains
only `INSERT` statements, and copies it to Spring Boot `data.sql` or a Flyway
migration path.
The preferred path is the Maven plugin. It discovers JPA entities at build time
and writes reviewable artifacts without requiring an AI account:
```xml
io.github.abasheger
terubase-maven-plugin
0.1.2
```
```bash
mvn -B -ntp compile terubase:plan
```
```text
target/terubase/schema-context.json
target/terubase/seed-plan.md
```
The command also prints an AI handoff: the files an AI tool must be able to
read, a short instruction, the expected SQL save path, and the export commands.
The plugin does not generate row values or call an AI provider. Create
`target/terubase/generated-seed.sql` yourself or with an AI assistant, review
it, then export it as Spring Boot's familiar `data.sql`:
```bash
mvn -B -ntp terubase:export-data-sql
```
```text
src/main/resources/data.sql
```
If Hibernate creates your schema with `spring.jpa.hibernate.ddl-auto`, also set
`spring.jpa.defer-datasource-initialization=true` so Spring runs `data.sql`
after the tables exist.
Projects using Flyway can instead run `mvn -B -ntp terubase:export-flyway`.
TeruBase is local-first tooling. It is not a generic fake-data generator, an H2
console clone, a production database API, or an enterprise test-data-management
platform.
The runtime starter remains available as an optional local playground. The
Maven plugin can copy reviewed SQL to a Flyway migration path, but it does not
run Flyway or replace a migration tool.
## Why TeruBase?
- Write deterministic JSON and Markdown artifacts from compiled JPA classes.
- Record IDs, generated values, Java enums, explicit `@Column` metadata, and
common relationship annotation types.
- Print a clear handoff for creating SQL with a developer's chosen AI tool.
- Reject blank exports and statements that are not `INSERT` statements.
- Copy reviewed SQL to Spring Boot `data.sql` or a fixed Flyway migration path.
## Working With AI Coding Assistants
Codex, Copilot, Cursor, Claude, ChatGPT, and other coding assistants can draft
seed SQL. TeruBase complements them by providing a deterministic workflow around
the generated output.
The Maven plugin:
- scans your compiled Spring Boot/JPA model
- records explicit `@Table` and `@Column` names, Java enums, IDs, generated
values, and common relationship annotation types
- creates reusable schema-context and seed-plan artifacts
- checks reviewed SQL as `INSERT`-only
- copies reviewed SQL into `data.sql` or a Flyway migration path
- keeps AI optional and export-first
The assistant remains responsible for drafting row values. TeruBase supplies
project metadata and planning artifacts, checks the reviewed result as
`INSERT`-only, and copies it to the selected Spring Boot or Flyway path.
See [AI coding assistants and TeruBase](docs/AI_ASSISTANTS_AND_TERUBASE.md) for the
division of responsibilities.
## Try It in 5 Minutes
TeruBase requires Java 21. The runtime starter is built and tested with Spring
Boot 3.4.6; compatibility with later Spring Boot releases is not yet claimed.
Add the Maven plugin to a Spring Boot/JPA project's `pom.xml`:
```xml
io.github.abasheger
terubase-maven-plugin
0.1.2
com.example.yourapp
```
Run the goal from the Maven module whose compiled output contains the entity
classes. The current goal does not aggregate entity classes from child modules.
Generate non-AI planning artifacts from compiled project classes:
```bash
mvn -B -ntp compile terubase:plan
```
This writes:
```text
target/terubase/schema-context.json
target/terubase/seed-plan.md
```
The terminal prints this instruction with absolute paths to the two generated
files:
```text
Generate INSERT-only seed SQL using and . Follow the relationships, constraints, row count, and SQL dialect in those files. Return SQL only.
```
A terminal AI agent may be able to read those paths. For a browser chat, upload
both files first; pasting local paths alone does not give the chat access.
To copy a reviewed `target/terubase/generated-seed.sql` file into Spring Boot's
`data.sql`:
```bash
mvn -B -ntp terubase:export-data-sql
```
This writes:
```text
src/main/resources/data.sql
```
For applications where Hibernate creates the schema, configure:
```yaml
spring:
jpa:
defer-datasource-initialization: true
```
For a Flyway migration instead:
```bash
mvn -B -ntp terubase:export-flyway
```
AI generation is not built into the Maven plugin. You can use any AI assistant
to draft SQL from the generated artifacts, or use the optional runtime starter's
OpenAI-compatible endpoint.
### Maven Plugin Limits
- Entity inspection recognizes Jakarta Persistence (`jakarta.persistence`)
annotations. It does not recognize legacy `javax.persistence` annotations.
- The goal scans only the current Maven project's compiled output directory. In
a multi-module build, run it in the module containing the entities.
- When `entityBasePackage` is omitted, the package filter defaults to the
current project's `groupId`, or `com` when no group ID is available.
- Entity inspection supports field annotations, not JPA property access. It
currently records every non-static field and does not exclude fields marked
`@Transient`.
- An explicit `@Table` name is recorded; otherwise `tableName` falls back to the
Java class name. Fields always include their Java names, while column metadata
is present only for explicit `@Column` annotations. The plugin does not apply
a Hibernate physical naming strategy.
- The plugin records common relationship annotation types, but not `@JoinColumn`
or `@JoinTable` details.
- The plan always includes generic insert-order text, including a join-table
hint. Those lines are instructions, not proof that matching metadata was
discovered, and they are not a foreign-key dependency graph.
- The configured row count and dialect are written into the plan for the SQL
author or AI tool; the plugin does not enforce either one.
- SQL checking is syntactic and `INSERT`-only. It does not connect to the host
database or verify tables, columns, constraints, values, or dialect syntax.
- Export goals overwrite their configured output file.
- `terubase:plan` fails when it discovers no entities. Compile the module that
contains the entities and verify `entityBasePackage` when this happens.
### Example Output
A compact `schema-context.json` looks like this:
```json
{
"entities": [
{
"className": "com.example.invoice.Customer",
"simpleName": "Customer",
"tableName": "customers",
"fields": [
{
"name": "id",
"type": "java.lang.Long",
"id": true,
"generatedValue": true
},
{
"name": "email",
"type": "java.lang.String",
"column": {
"name": "email",
"nullable": false,
"unique": true
}
}
],
"insertOrderHint": "Parent or reference entity; insert before dependent child entities."
}
]
}
```
The matching `seed-plan.md` records the configured scenario, count, dialect,
discovered entities, and basic hints:
```markdown
# TeruBase Seed Plan
- Scenario: Generate realistic relationship-aware local development seed data.
- Target row count: 20
- SQL dialect: h2-postgresql-mode
- Discovered entities: 3
## Insert Order Hints
- Insert parent and reference tables first.
- Insert child tables with foreign keys second.
- Insert join tables last.
- Populate every nullable=false field.
```
After review, `terubase:export-data-sql` checks the file as `INSERT`-only and
copies it into `data.sql`:
```sql
-- TeruBase seed data
INSERT INTO customers (id, name, email) VALUES (1, 'Northstar Studio', 'billing@northstar.example');
INSERT INTO invoices (id, customer_id, invoice_number, total_amount) VALUES (10, 1, 'INV-2026-0001', 1200.00);
```
### Optional Starter Playground
Add the starter to a Spring Boot application when you want the local runtime
playground endpoints:
```xml
io.github.abasheger
terubase-spring-boot-starter
0.1.2
```
Add local-only configuration to `application-local.yml`:
```yaml
terubase:
enabled: true
entity-base-package: com.example.store.domain
sql-execution-enabled: false
```
The runtime starter is disabled unless `terubase.enabled=true` is set.
Start the application with the `local` profile, then inspect the built-in
scenarios:
```bash
curl http://localhost:8080/terubase/api/scenarios
```
Generate a seed plan from your discovered JPA entities:
```bash
curl "http://localhost:8080/terubase/api/seed-plan?scenarioId=saas-billing-demo&count=30"
```
The seed-plan response is metadata-only. It does not call AI or execute SQL.
Copy its `recommendedMockRequest` into `POST /terubase/api/mock` when you want
AI-generated SQL. The generated request keeps `execute=false`.
## Try the Invoice Demo
Generate Maven plugin artifacts from the invoice demo:
```bash
cd examples/invoice-demo
mvn -B -ntp compile terubase:plan
```
This writes:
```text
examples/invoice-demo/target/terubase/schema-context.json
examples/invoice-demo/target/terubase/seed-plan.md
```
To export reviewed SQL to `data.sql`, place reviewed `INSERT` statements in
`examples/invoice-demo/target/terubase/generated-seed.sql`, then run:
```bash
mvn -B -ntp terubase:export-data-sql
```
This writes:
```text
examples/invoice-demo/src/main/resources/data.sql
```
Use `mvn -B -ntp terubase:export-flyway` instead when the project uses Flyway.
You can also run the example Spring Boot app and use the local runtime
playground endpoints:
```bash
mvn -B -ntp spring-boot:run
```
See [`examples/invoice-demo/README.md`](examples/invoice-demo/README.md) for
plugin output, curl examples, and details.
## Architecture
### Maven Plugin
```mermaid
flowchart LR
A[JPA classes] --> B[Plan files]
B --> C[Draft and review SQL]
C --> D{Export}
D --> E[data.sql]
D --> F[Flyway file]
```
`terubase:plan` creates `schema-context.json` and `seed-plan.md`. A developer or
AI assistant drafts `generated-seed.sql`; TeruBase checks it as `INSERT`-only
before copying it to the selected output.
### Optional Runtime Starter
```mermaid
flowchart LR
A[JPA classes] --> B[Metadata and seed plan]
B --> C[AI provider]
C --> D[Review or export]
C --> E[Optional isolated H2]
```
The runtime starter is a separate, explicitly enabled local playground. The
Maven plugin does not start it or call an AI provider.
## Endpoints
| Method | Endpoint | Purpose |
| --- | --- | --- |
| `GET` | `/terubase/api/entities` | Discover JPA entity metadata. |
| `GET` | `/terubase/api/scenarios` | List built-in scenario templates. |
| `GET` | `/terubase/api/scenarios/{id}` | Get one built-in scenario template. |
| `GET` | `/terubase/api/seed-plan` | Build an AI-ready seed plan. |
| `POST` | `/terubase/api/mock` | Generate export-first AI seed SQL. |
| `POST` | `/terubase/api/export/sql` | Export reviewed `INSERT` statements as SQL. |
| `POST` | `/terubase/api/export/json` | Export reviewed `INSERT` statements as JSON. |
| `GET` | `/terubase/api/status` | Check isolated SQL service status. |
| `POST` | `/terubase/api/execute` | Execute SQL when explicitly enabled. |
## Safety Defaults
> Keep TeruBase local, export-first, and separate from production data.
- Use TeruBase only with `local`, `dev`, or `test` profiles.
- Never expose `/terubase/api/**` publicly.
- Never use real production records in prompts or examples.
- Keep AI generation export-first with `"execute": false`.
- Review generated SQL before optional isolated execution.
- Keep `sql-execution-enabled` disabled unless direct local SQL access is needed.
- Keep `force-enable-in-production` disabled.
## Configuration
The complete example is
[`application-terubase-example.yml`](terubase-spring-boot-starter/src/main/resources/application-terubase-example.yml).
All settings are flat `terubase.*` properties:
```yaml
terubase:
enabled: true
jdbc-url: jdbc:h2:mem:terubase_isolated_db;DB_CLOSE_DELAY=-1;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH
username: sa
password: ""
entity-base-package: com.example.store.domain
open-ai-chat-completions-url: https://api.openai.com/v1/chat/completions
open-ai-model: gpt-4o
max-mock-rows: 100
sql-execution-enabled: false
force-enable-in-production: false
```
TeruBase auto-configuration is blocked when the `prod` or `production` Spring
profile is active. It is also disabled by default in every profile. Enable it
explicitly for local use with `terubase.enabled=true`. An intentional
production override requires both:
```yaml
terubase:
enabled: true
force-enable-in-production: true
```
## Main Workflow
### Discover Entities
```http
GET /terubase/api/entities
```
When `terubase.entity-base-package` is set, TeruBase scans that package. When it
is omitted, the runtime starter derives candidate packages from application
bean definitions and falls back to `com` if none are found. It returns JPA
metadata for columns, IDs, generated values, enums, relationships, join
columns, join tables, and deterministic insert-order hints. The hints guide
seed generation; they are not a full database dependency planner.
Runtime metadata inspection is also field-based. It does not inspect
property/getter mappings, apply Hibernate physical naming strategies, or
exclude fields marked `@Transient`.
### Choose a Scenario
```http
GET /terubase/api/scenarios
GET /terubase/api/scenarios/{id}
```
Built-in IDs:
- `ecommerce-demo`
- `saas-billing-demo`
- `crm-demo`
- `banking-lite-demo`
- `task-management-demo`
- `inventory-management-demo`
- `learning-management-demo`
- `event-registration-demo`
- `qa-edge-cases`
- `frontend-dashboard-demo`
### Build an AI-Ready Seed Plan
```http
GET /terubase/api/seed-plan?scenarioId=saas-billing-demo&count=30
```
The response combines scenario intent with discovered metadata and returns a
`schemaPrompt` plus a `recommendedMockRequest`. This endpoint does not require
an API key and does not call AI. Its `count` cannot exceed
`terubase.max-mock-rows`, so the recommended request is accepted by `/mock`.
### Generate Export-First Seed SQL
```http
POST /terubase/api/mock
Content-Type: application/json
{
"count": 20,
"apiKey": "your-local-api-key",
"schema": "",
"scenario": "Generate a fictional SaaS billing demo with overdue invoices",
"dialect": "h2-postgresql-mode",
"execute": false
}
```
`execute=false` returns SQL for review without running it. TeruBase accepts only
`INSERT` statements from AI output. It blocks unsupported or destructive SQL.
API keys are request-only: never commit, store, or log them.
### Export Generated Data
Export reviewed statements as SQL:
```http
POST /terubase/api/export/sql
Content-Type: application/json
{
"statements": [
"insert into customer (id, name) values (1, 'Sara')"
],
"filename": "demo-seed.sql"
}
```
Or as JSON:
```http
POST /terubase/api/export/json
Content-Type: application/json
{
"scenario": "Fictional SaaS billing demo",
"statements": [
"insert into customer (id, name) values (1, 'Sara')"
]
}
```
Export endpoints do not execute SQL or write files to disk. They accept only
`INSERT` statements and return content for review, local seed files, CI
fixtures, and demos.
### Optional Local Execution
AI-generated SQL can run against TeruBase's isolated H2 database by setting
`"execute": true` in `POST /terubase/api/mock`. Batch execution is transactional
and rolls back on failure.
For direct local SQL access, explicitly enable:
```yaml
terubase:
sql-execution-enabled: true
```
Then use:
```http
GET /terubase/api/status
POST /terubase/api/execute
Content-Type: application/json
{
"sql": "select 1 as value"
}
```
## Build
```bash
mvn -B -ntp clean verify
```
## License
MIT License.