spring-services 1.3.0 is a coordinate-breaking and DB-breaking release with one small public
API break (a single @Configuration class was renamed). Three coupled changes land together:
- Maven multi-module reactor (coordinate change). The
com.open-elements:spring-servicescoordinate is now the reactor parent (packaging=pom) and no longer ships a jar with classes. A consumer that keeps depending on the bare coordinate will fail to compile. The library is split intospring-services-core(all seven entities, single persistence unit) plus optional feature modules —spring-services-slack,spring-services-mcp,spring-services-email,spring-services-search,spring-services-dbbackup— an everything bundlespring-services-all, and a BOMspring-services-bom. Heavy/rare libraries (slack-api-client, the MCP SDK,spring-boot-starter-mail) are no longer pulled unless the matching module is present. - Dedicated schema. All seven library tables (
users,api_keys,audit_log,comments,settings,tags,webhooks) now live in a fixed database schemaoe_spring_servicesinstead of the application's default (public) schema. They stay in a single JPA persistence unit (oneEntityManagerFactory, oneTransactionManager) — library-internal foreign keys and atomic transactions are unchanged. - Real Spring Boot starter. The library is now auto-configured via
SpringServicesCoreAutoConfiguration(registered inMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports). Adding the dependency is enough — a consuming application no longer needs@Import(FullSpringServiceConfig.class),@EntityScan, or@EnableJpaRepositoriesto wire the library, and its own entities/repositories keep being discovered.FullSpringServiceConfigis retained (the starter itself@Imports it), so an existing@Import(FullSpringServiceConfig.class)still compiles and works — it simply becomes redundant.
Apart from one renamed @Configuration class (LanguageConfig → TranslationConfig, see below),
there are no public Java API changes (method signatures, DTOs, annotations, records, enums are
unchanged). The breaks are at the build-coordinate level (the parent pom carries no classes), the
database level (the new code will not start against the old public-schema tables until you move
them), and — only for à-la-carte consumers who imported it directly — the LanguageConfig rename.
The library ships no runtime migrations — you apply the SQL below with your own migration tool
(Flyway/Liquibase), in version order.
⚠️ Read the warnings before you run anything. Applied incorrectly (e.g. withspring.jpa.hibernate.ddl-auto=update), this upgrade causes silent data loss. It also requires downtime — it is not safe for rolling/HA deploys against a shared database.
This file is a self-contained prompt for an agent (Claude Code, etc.) to run inside a consumer repo. Paste it verbatim.
You are working inside a Spring Boot service that depends on com.open-elements:spring-services.
Goal: upgrade from 1.2.0 to 1.3.0. This release turns the library into a Maven reactor (you must
change the dependency coordinate), moves the library's tables into a dedicated oe_spring_services
schema, and makes the library an auto-configured starter. Follow the steps and the warnings exactly.
Do not improvise the database migration.
The old single coordinate no longer ships classes — it is now a parent pom. Choose one of two migration paths.
Path A — everything (drop-in). Replace spring-services with spring-services-all:
<!-- before -->
<dependency>
<groupId>com.open-elements</groupId>
<artifactId>spring-services</artifactId>
<version>1.2.0</version>
</dependency>
<!-- after -->
<dependency>
<groupId>com.open-elements</groupId>
<artifactId>spring-services-all</artifactId>
<version>1.3.0</version>
</dependency>spring-services-all bundles core plus every feature module, reproducing the pre-split behaviour.
Path B — à-la-carte (only what you use). Import the BOM once, then declare spring-services-core
plus only the feature modules you need, without versions:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.open-elements</groupId>
<artifactId>spring-services-bom</artifactId>
<version>1.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.open-elements</groupId>
<artifactId>spring-services-core</artifactId>
</dependency>
<!-- add only the features you use, e.g.: -->
<dependency>
<groupId>com.open-elements</groupId>
<artifactId>spring-services-slack</artifactId>
</dependency>
</dependencies>Feature module artifact ids: spring-services-slack, spring-services-mcp,
spring-services-email, spring-services-search, spring-services-dbbackup.
The library now registers itself via
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. The dependency
alone now wires everything, and your own entities/repositories continue to be discovered.
FullSpringServiceConfig is retained, not removed. The starter auto-configuration itself
@Imports it, so if your 1.2.0 application wired the library with @Import(FullSpringServiceConfig.class)
it still compiles and works — the import just becomes redundant (the config is applied once; Spring
dedups the repeated @Import by class). Removing it is optional cleanup, not a required fix.
The @EntityScan("com.openelements.spring.base") /
@EnableJpaRepositories("com.openelements.spring.base") that existed only to wire the library
should be removed, though: a lingering manual @EntityScan makes EntityScanPackages non-empty
and thereby suppresses Boot's additive default scan of your application's own package (see the
exception below). Delete these library-only scan annotations; keep @Import(FullSpringServiceConfig.class)
or drop it, as you prefer.
Exception — explicit
@EntityScan. If your application declares its own@EntityScan("com.example…")for its own entities, that suppresses the additive fallback and the library entities will not be found. In that case add the library root to your scan, e.g.@EntityScan({"com.example…", "com.openelements.spring.base"})(or a shared common root).
Each feature module self-activates when it is on the classpath (via its own auto-configuration),
gated by the same enable properties the features already used (e.g. openelements.mcp.enabled,
openelements.meilisearch.enabled, openelements.db-backup.enabled). Slack and email activate when
their module is present. You do not need @Import to wire a feature — adding the module is enough.
The seven library tables are now mapped with @Table(schema = "oe_spring_services"). Your database
must contain that schema, and the tables must live in it, before the 1.3.0 application starts. This is
what the migration SQL below does.
The public @Configuration class com.openelements.spring.base.services.translation.LanguageConfig
was renamed to com.openelements.spring.base.services.translation.TranslationConfig. There is no
back-compat alias — the old name is gone. This only affects consumers who referenced the class
directly (à-la-carte wiring); the vast majority who used @Import(FullSpringServiceConfig.class) (or
the new starter) are unaffected, because FullSpringServiceConfig now imports TranslationConfig
internally.
// before (1.2.0) — only if you imported it directly
import com.openelements.spring.base.services.translation.LanguageConfig;
@Import(LanguageConfig.class)
// after (1.3.0)
import com.openelements.spring.base.services.translation.TranslationConfig;
@Import(TranslationConfig.class)The class's behaviour is unchanged — it is the same component scan over the translation package,
only the type name changed.
Aside from the LanguageConfig → TranslationConfig rename above, no public method signatures,
types, annotations, records, enums, or message strings changed between 1.2.0 and 1.3.0. A full
public-type inventory diff of 1.2.0 → 1.3.0 shows exactly one removed type (LanguageConfig); every
other new type is purely additive (the new *AutoConfiguration classes, DbSchema, and the new
spring-services-mcp module). Nothing else to migrate in application code beyond the dependency
coordinate and the schema move.
Note for explicit-import consumers. In 1.2.0,
FullSpringServiceConfig(shipped in the single jar) also aggregated the Slack, email, search, and db-backup configurations. In 1.3.0 those features live in separate modules and self-activate via their own auto-configurations, so the coreFullSpringServiceConfigno longer imports them. If you rely on@Import(FullSpringServiceConfig.class)for those features, make sure the corresponding feature module (orspring-services-all) is on the classpath — the module then wires the feature itself; you do not add its@Importback.
Add the following as a new versioned migration in your own Flyway/Liquibase timeline (e.g.
V<next>__move_spring_services_to_dedicated_schema.sql). Apply migrations in version order.
Existing application — tables currently in public (the normal case):
CREATE SCHEMA IF NOT EXISTS oe_spring_services;
-- PostgreSQL moves each table together with its constraints and indexes; foreign keys between these
-- tables keep pointing at the moved tables, so order does not matter for referential integrity.
ALTER TABLE users SET SCHEMA oe_spring_services;
ALTER TABLE api_keys SET SCHEMA oe_spring_services;
ALTER TABLE audit_log SET SCHEMA oe_spring_services;
ALTER TABLE comments SET SCHEMA oe_spring_services;
ALTER TABLE settings SET SCHEMA oe_spring_services;
ALTER TABLE tags SET SCHEMA oe_spring_services;
ALTER TABLE webhooks SET SCHEMA oe_spring_services;New application — no existing spring-services tables:
CREATE SCHEMA IF NOT EXISTS oe_spring_services;
-- Then create the seven tables inside oe_spring_services (DDL generated from the entities or
-- hand-written). In dev you may instead let Hibernate create them with
-- spring.jpa.properties.hibernate.hbm2ddl.create_namespaces=true — never in production.ddl-auto=update/createcauses silent data loss. If you runspring.jpa.hibernate.ddl-autoinupdateorcreatemode, Hibernate sees the schema-qualified tables missing and creates fresh empty tables inoe_spring_services, orphaning your existing data inpublic. Apply the migration scripts above with a real migration tool and setddl-autotovalidateornonefor this upgrade.- Downtime required — not rolling-safe.
ALTER TABLE … SET SCHEMAis a hard cut: the instant it runs,public.<table>is gone, and any still-running old (1.2.0) instance — which expectspublic— breaks. The upgrade is stop-the-world: stop the app, run the migration, start 1.3.0. It is not safe for rolling/HA deploys against a shared database. - Required database privileges. The migration role needs DDL rights and table ownership
(
CREATE SCHEMA,ALTER TABLE … SET SCHEMA). The application's runtime role then needsUSAGEonoe_spring_services(and the schema on itssearch_pathif you run any consumer-side native SQL against library tables). Do not assume the application role is a full-privilege DB owner; grant the migration and runtime privileges separately.
- Find the consumer's build file that declares
com.open-elements:spring-services. - Replace the coordinate per Path A (switch to
spring-services-all) or Path B (BOM +-core+ chosen feature modules). Bump the version to1.3.0. - Remove any
@EntityScan/@EnableJpaRepositoriesthat existed only to wire the library — unless you use@EntityScanfor your own entities, in which case addcom.openelements.spring.baseto it.@Import(FullSpringServiceConfig.class)is now optional (the class is retained and still compiles); you may leave it or drop it — do not treat it as a required change. - If (and only if) you imported
LanguageConfigdirectly, rename the reference toTranslationConfig(packagecom.openelements.spring.base.services.translation). If you only usedFullSpringServiceConfigor the starter, skip this. - Add the migration SQL above as a new versioned script in your own Flyway/Liquibase timeline.
- Ensure
spring.jpa.hibernate.ddl-autoisvalidateornonefor this deploy (notupdate/create). - Grant the runtime DB role
USAGEonoe_spring_services. - Resolve dependencies (
mvn -U dependency:resolveor./gradlew --refresh-dependencies). - Deploy with downtime: stop the old instance, run the migration, start 1.3.0.
- Compile and run the consumer's test suite to verify the build is green.
- Do not keep depending on the bare
com.open-elements:spring-servicescoordinate — it is now a parent pom and carries no classes. - Do not re-add
slack-api-client, the MCP SDK, orspring-boot-starter-mailby hand — pull the corresponding feature module instead, which brings the dependency transitively. - Do not run this upgrade with
ddl-auto=update/create— you will orphan your data. - Do not attempt a rolling/zero-downtime deploy against a shared database.
- Do not mix explicit module versions with the BOM import; let the BOM manage them.
- Do not delete
@Import(FullSpringServiceConfig.class)believing the class was removed — it was not. Removing it is optional cleanup; the class still exists and still compiles. - Do not create a
LanguageConfigshim/alias to avoid the rename — update the reference toTranslationConfiginstead. And do not touchTranslationConfigunless you actually imported the oldLanguageConfigdirectly. - Do not rename columns, change the single-
DataSourcesetup, or introduce a secondEntityManagerFactory"to isolate the library" — the design is deliberately one persistence unit. - Do not point your application's own entities at
oe_spring_services— that schema is library-owned. Your entities stay in your own schema; a cross-schema FK from your table to a library table (referencing the immutableidPK) is supported, but never the reverse. - Do not bundle unrelated upgrades or feature work into this version bump.