Spring Boot governance

# Architectural governance for AI-generated Spring Boot code

Spring Boot is the enterprise-weight ecosystem: layered architecture, auto-configuration driven by classpath dependencies, and production-grade management through Actuator. Those are deliberate decisions an AI coding agent can quietly undo — calling a repository from a controller, adding an unvetted starter, or opening an actuator endpoint. Mneme governs that intent before generation through repo-native rules, not a bespoke Spring parser.

JVM ecosystem · Repo-native rules

## Why governance matters in Spring Boot

Spring Boot's value comes from convention: auto-configuration wires beans based on what is on the classpath, and Actuator exposes health, metrics, and management endpoints for production. Enterprise teams layer their own intentional architecture on top — controller, service, repository, and domain packages with a strict dependency direction, an approved set of starters, defined transaction boundaries, and a hardened security and observability posture.

An AI coding agent optimizing for a passing build does not know any of that is load-bearing. It will reach for the repository from a controller, add a starter to "just make it work," or relax a security rule to unblock a test. Each shortcut is plausible in isolation and corrosive in aggregate. Mneme keeps the enterprise architecture in the agent's context and checks the diff before it merges.

## What Mneme can govern

Mneme governs the architectural decisions a Spring Boot team has already made — expressed as repo-native rules in a decision corpus, not as a built-in Spring rule pack. Common surfaces:

- Layered boundaries — controller, service, repository, and domain responsibilities stay separated.
- Package structure and dependency direction — the approved module layout and import direction are preserved.
- Approved starters and dependencies — additions to the build are constrained to a vetted list.
- Spring Security configuration — authentication and authorization rules are not silently weakened.
- Actuator exposure — management endpoint exposure follows the approved policy.
- Transaction boundaries — `@Transactional` ownership stays in the service layer.
- DTO, persistence, exception-handling, and observability conventions — organization-specific patterns hold.

Five concrete examples of what the governance layer catches in Spring Boot repos under AI-assisted development:

### Controller accessing the repository directly

Layer boundary

Rule. Controllers call application services. They must not inject or call repositories directly.

    // AI-generated in web/UserController.java
    @RestController
    class UserController {
        private final UserRepository repo;   // repository injected into the web layer

        @GetMapping("/users/{id}")
        User get(@PathVariable Long id) {
            return repo.findById(id).orElseThrow();
        }
    }

repository in web layer missing service abstraction

### Unapproved starter added to the build

Dependency

Rule. New dependencies require architectural review. The approved list lives in `.mneme`.

    <!-- AI added to pom.xml during a refactor -->
    <dependency>
      <groupId>org.unvetted</groupId>
      <artifactId>spring-boot-starter-quick-fix</artifactId>
    </dependency>

unapproved starter dependency policy breach

### Actuator endpoints over-exposed

Observability / Security

Rule. Production exposes only `health` and `info`. No wildcard exposure, no value disclosure.

    # AI-generated in application.properties
    management.endpoints.web.exposure.include=*
    management.endpoint.env.show-values=always

actuator over-exposure sensitive endpoint disclosure

### Spring Security weakened to unblock a test

Security

Rule. No blanket `permitAll()` and no disabling CSRF on stateful endpoints.

    // AI-generated in config/SecurityConfig.java
    http.csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(reg -> reg.anyRequest().permitAll());

authorization bypass security config regression

### Transaction boundary moved into the controller

Transaction boundary

Rule. `@Transactional` belongs on service methods. The web layer must not own transactions.

    // AI-generated in web/TransferController.java
    @PostMapping("/transfer")
    @Transactional   // transaction boundary in the web layer
    void transfer(@RequestBody TransferRequest req) {
        accountService.debit(req.from(), req.amount());
        accountService.credit(req.to(), req.amount());
    }

transaction ownership drift broken atomicity boundary

## Example governance decisions

These are illustrative rules a Spring Boot team would author in its own decision corpus. Mneme does not ship them as defaults — it enforces the decisions you record.

decision · jvm-001 Layer boundary

Controllers may call application services but must not access repositories directly.

A repository injected into or called from a controller is surfaced as a boundary violation.

decision · jvm-002 Dependency

New dependencies require architectural review before they are added to the build.

A starter or library added to `pom.xml` or `build.gradle` outside the approved list is flagged.

decision · jvm-003 Observability / Security

Production actuator endpoints must follow the approved exposure and security policy.

Wildcard exposure or disclosing endpoint values in a production profile is treated as a regression.

## How governance fits the workflow

Mneme sits between your architectural decisions and the AI coding tools writing Java. The loop is the same one Mneme runs for any repository:

1. #### Decisions and ADRs are recorded

   Your architectural decisions live as records in `.mneme/project_memory.json` — each with a scope, constraints, and anti-patterns. ADRs can be imported into the same corpus.

2. #### Mneme retrieves the relevant intent

   On a prompt or a file write, Mneme retrieves the decisions in scope for the change and injects them into the agent's context — governance before generation, not review after the fact.

3. #### The AI coding agent changes the code

   Claude Code, Cursor, Copilot, or a custom agent edits controllers, services, repositories, configuration, and the build with that context in hand.

4. #### Mneme checks the proposed change

   `mneme check` evaluates the diff against the corpus: a matched constraint surfaces as `WARN`, an anti-pattern hit as `FAIL`. Aligned changes pass cleanly.

5. #### CI gates the merge

   In `--mode strict` a `WARN` exits 1 and a `FAIL` exits 2, so the regression blocks the PR; `--mode warn` annotates without blocking. One corpus serves the editor, the terminal agent, and the CI runner.

## Where it fits in a Java codebase

Spring Boot governance is repository-level governance applied to a layered JVM project: paths, package boundaries, dependency direction, and configuration files such as `pom.xml`, `build.gradle`, and `application.properties`. The decision corpus lives at `.mneme/project_memory.json`; `mneme check --mode strict` gates PR diffs in CI. Java sits at the repo-level tier today — Spring-aware semantic packs are roadmap, not a current claim. See the full coverage matrix for where Java fits.

Bring existing decisions in through ADR import, set up the editor and terminal with the Cursor and Claude Code integrations, and gate merges with GitHub Actions.

Coverage matrix Where Java fits → Canonical doc with capabilities, limitations, and roadmap per language and framework. Integration GitHub Copilot → Govern the assistant most enterprise Java teams already run, on the same corpus. Concept Architectural drift → The slow erosion of layered architecture that governance is built to stop. Use case Coding assistant governance → End-to-end workflow with Claude Code, Cursor, and GitHub Actions on one corpus.