---
date: 2026-03-04T00:19:03+01:00
git_commit: 7b460dd322359dc1fa3ca0dc950a91c607163977
branch: master
topic: "T-1: Initialize monorepo structure — Tech stack research"
tags: [research, codebase, t-1, scaffolding, spring-boot, vue, maven, vite, hexagonal-architecture]
status: complete
---

# Research: T-1 — Initialize Monorepo Structure

## Research Question

What are the current versions, scaffolding approaches, and architectural patterns needed to implement T-1 (Initialize monorepo structure) with the specified tech stack: Java (latest LTS), Spring Boot, Maven, hexagonal/onion architecture backend + Svelte with Vite frontend?

## Summary

This research covers all technical aspects needed for T-1. The spec requires a monorepo with `backend/` and `frontend/` directories, both building successfully as empty scaffolds. The key findings and open decisions are:

1. **Java 25** is the current LTS (Sep 2025). Spring Boot **4.0.3** is the latest stable — but **3.5.x** is more battle-tested. This is an architectural decision.
2. **Svelte 5** is stable (since Oct 2024). The SPA router ecosystem for plain Svelte 5 is weak — **SvelteKit in SPA mode** is the pragmatic alternative.
3. **Hexagonal architecture**: Single Maven module with package-level separation + ArchUnit enforcement. Base package `com.fete`.
4. **TypeScript** for the frontend is recommended but is a decision point.

## Detailed Findings

### 1. Java Version

**Java 25 (LTS)** — released September 16, 2025.

- Premier support through Sep 2030, extended support through Sep 2033.
- Supersedes Java 21 (Sep 2023) as the current LTS.
- Java 21 is still supported but free updates end Sep 2026.
- Next LTS: Java 29 (Sep 2027).

**Recommendation:** Java 25. Longest support runway, both Spring Boot 3.5 and 4.0 support it.

### 2. Spring Boot Version

Two actively supported lines as of March 2026:

| Version | Latest Patch | OSS Support Ends | Java Baseline | Key Dependencies |
|---------|-------------|-------------------|---------------|-----------------|
| **4.0.x** | 4.0.3 | Dec 2026 | Java 17+ (up to 25) | Spring Framework 7.0, Jakarta EE 11, Hibernate 7.1, Jackson 3.0, Tomcat 11.0 |
| **3.5.x** | 3.5.11 | Jun 2026 | Java 17+ (up to 25) | Spring Framework 6.x, Jakarta EE 10, Hibernate 6.x, Jackson 2.x, Tomcat 10.x |

**Trade-offs:**

| Factor | Spring Boot 4.0 | Spring Boot 3.5 |
|--------|----------------|-----------------|
| Support runway | Dec 2026 (longer) | Jun 2026 (shorter) |
| Ecosystem maturity | Jackson 3.0 + Hibernate 7.1 are new major versions; fewer community examples | Battle-tested, large ecosystem of examples |
| Migration burden | None (greenfield) | None (greenfield) |
| Forward-looking | Yes | Will need migration to 4.x eventually |

**Decision needed:** Spring Boot 4.0 (forward-looking) vs. 3.5 (more battle-tested). Both support Java 25.

### 3. Maven

- **Maven version:** 3.9.12 (latest stable; Maven 4.0.0 is still RC).
- **Maven Wrapper:** Yes, include it. Modern "only-script" distribution — no binary JAR in repo. Scripts `mvnw`/`mvnw.cmd` + `.mvn/wrapper/maven-wrapper.properties` are committed.
- Benefits: deterministic builds in Docker, no Maven pre-install requirement for contributors or CI.

**Minimal dependencies for Spring Boot + PostgreSQL:**

```xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.0.3</version>  <!-- or 3.5.11 -->
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
```

Note: For the empty scaffold (T-1), JPA autoconfig must be excluded or deferred since there's no DB yet. Either omit `spring-boot-starter-data-jpa` until T-4, or add `spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration` to `application.properties`.

### 4. Svelte + Vite Frontend

**Current versions:**
- Svelte: **5.53.6** (stable since Oct 2024, runes-based reactivity)
- Vite: **7.3.1** (stable; Vite 8 is in beta)

**Svelte 5 key changes from Svelte 4:**
- Reactive state: `let count = $state(0)` (explicit rune) instead of implicit `let count = 0`
- Derived values: `$derived()` replaces `$:` blocks
- Props: `$props()` replaces `export let`
- Reactivity works in `.svelte.ts` files too (not just components)

### 5. SvelteKit vs. Plain Svelte — Decision Point

The spec says "Svelte with Vite as bundler" for an SPA with a separate REST backend.

**Option A: Plain Svelte + Vite + third-party router**

| Pro | Con |
|-----|-----|
| Simpler mental model | Router ecosystem broken for Svelte 5: `svelte-spa-router` has no Svelte 5 support (issue #318) |
| Literal spec wording | Only unmaintained/low-adoption alternatives exist |
| No unused SSR concepts | Violates dependency statute ("actively maintained") |

**Option B: SvelteKit in SPA mode (adapter-static + `ssr: false`)**

| Pro | Con |
|-----|-----|
| Built-in file-based routing (maintained by Svelte team) | Has SSR concepts that exist but are unused |
| First-class Vitest integration (T-4 requirement) | Slightly larger framework footprint |
| SPA config is 3 lines of code | SEO concerns (irrelevant for this app) |
| Output is static HTML/JS/CSS — no Node.js runtime needed | |
| `npx sv create` scaffolds TS/ESLint/Vitest in one step | |

**SPA configuration (total effort):**
1. `npm i -D @sveltejs/adapter-static`
2. `svelte.config.js`: `adapter: adapter({ fallback: '200.html' })`
3. `src/routes/+layout.js`: `export const ssr = false;`

**Decision needed:** SvelteKit in SPA mode (pragmatic, solves the router problem) vs. plain Svelte + Vite (minimalist, but router ecosystem is a real problem).

### 6. TypeScript vs. JavaScript — Decision Point

**Arguments for TypeScript:**
- Java backend is strongly typed; TS catches API contract drift at compile time.
- Svelte 5 has first-class TS support, including TS in markup.
- The API client layer (T-4) benefits most from type safety.
- Zero-config in both SvelteKit and the `svelte-ts` Vite template.
- Rich Harris: "TypeScript for apps, JSDoc for libraries." This is an app.

**Arguments against:**
- KISS/grugbrain principle — TS adds cognitive overhead.
- Svelte's compiler already catches many errors.

**Verdict from research:** TS overhead in Svelte 5 is minimal (`let count: number = $state(0)` vs. `let count = $state(0)`). The real value is in the API client layer and shared types.

### 7. Node.js Version

| Version | Status | End of Life |
|---------|--------|-------------|
| Node.js 24 | Active LTS | ~April 2028 |
| Node.js 22 | Active LTS | April 2027 |
| Node.js 20 | Maintenance LTS | April 2026 (EOL imminent) |

**Recommendation:** Target Node.js 22 LTS as minimum. Docker image should use `node:22-alpine`.

### 8. Hexagonal Architecture — Package Structure

**Approach:** Single Maven module with package-level separation. Multi-module Maven is overkill for a small app. ArchUnit test enforces dependency rules.

**Package structure:**

```
com.fete
├── FeteApplication.java                     # @SpringBootApplication
├── domain/
│   ├── model/                               # Entities, value objects (plain Java, no framework annotations)
│   └── port/
│       ├── in/                              # Driving port interfaces (use cases)
│       └── out/                             # Driven port interfaces (repositories)
├── application/
│   └── service/                             # Use case implementations (@Service)
├── adapter/
│   ├── in/
│   │   └── web/                             # REST controllers, DTOs, mappers
│   └── out/
│       └── persistence/                     # JPA entities, Spring Data repos, mappers
└── config/                                  # @Configuration classes
```

**Dependency flow (strict):**
```
domain  →  nothing
application  →  domain only
adapter  →  application + domain
config  →  everything (wiring)
```

**Spring annotations by layer:**

| Layer | Annotations | Rationale |
|-------|-------------|-----------|
| `domain.model` | None | Plain Java — no framework coupling |
| `domain.port` | None | Plain Java interfaces |
| `application.service` | `@Service` only | Pragmatic compromise for component scanning |
| `adapter.in.web` | `@RestController`, `@GetMapping`, etc. | Framework adapter layer |
| `adapter.out.persistence` | `@Entity`, `@Repository`, `@Table`, etc. | Framework adapter layer |
| `config` | `@Configuration`, `@Bean` | Wiring layer |

**Domain purity:** Persistence has its own JPA entity classes (e.g., `EventJpaEntity`) separate from domain model classes. Mappers convert between them.

**Empty directory markers:** Use `package-info.java` in each leaf package. Documents package purpose, allows Git to track the directory, and aids component scanning.

**Base package:** `com.fete` (Maven convention, clean, short).

### 9. .gitignore

The existing `.gitignore` covers IDE files (`.idea/`, `.vscode/`, `*.iml`), OS files (`.DS_Store`, `Thumbs.db`), and Claude settings. The following sections need to be added:

**Java/Maven:**
- `*.class`, `*.jar`, `*.war`, `*.ear`, `*.nar` — compiled artifacts
- `target/` — Maven build output
- Maven release plugin files (`pom.xml.tag`, `pom.xml.releaseBackup`, etc.)
- `.mvn/wrapper/maven-wrapper.jar` — downloaded automatically
- Eclipse files (`.classpath`, `.project`, `.settings/`, `.factorypath`)
- Spring Boot (`.springBeans`, `.sts4-cache`)
- Java crash logs (`hs_err_pid*`, `replay_pid*`)
- `*.log`

**Node.js/Svelte/Vite:**
- `node_modules/`
- `dist/`, `build/` — build output
- `.svelte-kit/` — SvelteKit generated files
- `vite.config.js.timestamp-*`, `vite.config.ts.timestamp-*` — Vite temp files
- `.env`, `.env.*` (but NOT `.env.example`)
- `npm-debug.log*`

**Editor files:**
- `*.swp`, `*.swo`, `*~` — Vim/editor backup files
- `\#*\#`, `.#*` — Emacs

**Committed (NOT ignored):**
- `mvnw`, `mvnw.cmd`, `.mvn/wrapper/maven-wrapper.properties`
- `package-lock.json`

### 10. Existing Repository State

The repository currently contains:
- `CLAUDE.md` — Project statutes
- `README.md` — With tech stack docs and docker-compose example
- `LICENSE` — GPL
- `.gitignore` — Partial (IDE + OS only)
- `Ideen.md` — German idea document
- `spec/` — User stories, personas, setup tasks, implementation phases
- `.ralph/` — Ralph loop infrastructure
- `ralph.sh` — Ralph loop runner
- `review-findings.md` — Review notes

No `backend/` or `frontend/` directories exist yet. No `Dockerfile` exists yet (listed in README project structure, but deferred to T-2).

## Decisions Required Before Implementation

These are architectural decisions that require approval per CLAUDE.md governance statutes:

| # | Decision | Options | Recommendation |
|---|----------|---------|----------------|
| 1 | Spring Boot version | 4.0.3 (latest, longer support) vs. 3.5.11 (battle-tested, shorter support) | 4.0.3 — greenfield project, no migration burden, longer support |
| 2 | SvelteKit vs. plain Svelte | SvelteKit SPA mode vs. plain Svelte + third-party router | SvelteKit SPA mode — router ecosystem for plain Svelte 5 is broken |
| 3 | TypeScript vs. JavaScript | TypeScript (type safety on API boundary) vs. JavaScript (simpler) | TypeScript — minimal overhead in Svelte 5, catches API contract drift |
| 4 | Spring Boot JPA in T-1? | Include `spring-boot-starter-data-jpa` now (exclude autoconfig) vs. add it in T-4 | Defer to T-4 — T-1 is "empty scaffold", JPA needs a datasource |

## Code References

- `spec/setup-tasks.md` — T-1 acceptance criteria
- `spec/implementation-phases.md:9-14` — Phase 0 task order
- `CLAUDE.md:36-43` — Dependency statutes
- `Ideen.md:76-78` — Tech stack decisions (already made)
- `.gitignore` — Current state (needs extension)
- `README.md:112-119` — Documented project structure (target)

## Architecture Documentation

### Target Repository Layout (after T-1)

```
fete/
├── backend/
│   ├── pom.xml
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── .mvn/wrapper/maven-wrapper.properties
│   └── src/
│       ├── main/
│       │   ├── java/com/fete/
│       │   │   ├── FeteApplication.java
│       │   │   ├── domain/model/           (package-info.java)
│       │   │   ├── domain/port/in/         (package-info.java)
│       │   │   ├── domain/port/out/        (package-info.java)
│       │   │   ├── application/service/    (package-info.java)
│       │   │   ├── adapter/in/web/         (package-info.java)
│       │   │   ├── adapter/out/persistence/(package-info.java)
│       │   │   └── config/                 (package-info.java)
│       │   └── resources/
│       │       └── application.properties
│       └── test/java/com/fete/
│           └── FeteApplicationTest.java
├── frontend/
│   ├── package.json
│   ├── package-lock.json
│   ├── svelte.config.js
│   ├── vite.config.ts
│   ├── tsconfig.json
│   ├── src/
│   │   ├── app.html
│   │   ├── routes/
│   │   │   ├── +layout.js              (ssr = false)
│   │   │   └── +page.svelte
│   │   └── lib/
│   └── static/
├── spec/
├── .gitignore                          (extended)
├── CLAUDE.md
├── README.md
├── LICENSE
└── Ideen.md
```

### Build Commands (Target State)

| What | Command |
|------|---------|
| Backend build | `cd backend && ./mvnw package` |
| Backend test | `cd backend && ./mvnw test` |
| Frontend install | `cd frontend && npm install` |
| Frontend build | `cd frontend && npm run build` |
| Frontend test | `cd frontend && npm test` |
| Frontend dev | `cd frontend && npm run dev` |

## Open Questions

All resolved — see Follow-up Research below.

## Follow-up Research: Frontend Pivot to Vue 3 (2026-03-04)

### Context

During decision review, the developer raised concerns about the Svelte 5 ecosystem maturity (specifically the broken third-party router situation signaling a smaller, less mature ecosystem). After comparing Svelte 5 vs Vue 3 on ecosystem size, community support, team size, and stability, the decision was made to pivot from Svelte to **Vue 3**.

### Rationale

- Vue 3 has a significantly larger ecosystem and community
- Official, battle-tested packages for all needs (Vue Router, Pinia, Vitest)
- Vite was created by Evan You (Vue's creator) — first-class integration
- Vue 3 Composition API is modern and elegant while being mature (stable since 2020)
- Larger team, broader funding, more StackOverflow answers and tutorials

### Vue 3 Stack — Research Findings

**Current versions (March 2026):**

| Package | Version | Notes |
|---------|---------|-------|
| Vue | 3.5.29 | Stable. Vue 3.6 (Vapor Mode) is in beta |
| Vue Router | 5.0.3 | Includes file-based routing from unplugin-vue-router. Drop-in from v4 for manual routes |
| Vite | 7.3.1 | Stable. Vite 8 (Rolldown) is in beta |
| Vitest | 4.0.18 | Stable. Browser Mode graduated from experimental |
| @vue/test-utils | 2.4.6 | Official component testing utilities |
| create-vue | 3.22.0 | Official scaffolding tool |
| Node.js | 24 LTS | Latest LTS, support through ~April 2028 |

**Scaffolding:** `npm create vue@latest` (official Vue CLI scaffolding). Interactive prompts offer TypeScript, Vue Router, Pinia, Vitest, ESLint, Prettier out of the box.

**Selected options for fete:**
- TypeScript: **Yes**
- Vue Router: **Yes**
- Pinia: **No** — Composition API (`ref`/`reactive`) + localStorage is sufficient for this app's simple state
- Vitest: **Yes**
- ESLint: **Yes**
- Prettier: **Yes**
- E2E testing: **No** (not needed for T-1)

**Project structure (scaffolded by create-vue):**

```
frontend/
├── public/
│   └── favicon.ico
├── src/
│   ├── assets/              # Static assets (CSS, images)
│   ├── components/          # Reusable components
│   ├── composables/         # Composition API composables (added manually)
│   ├── router/              # Vue Router config (index.ts)
│   ├── views/               # Route-level page components
│   ├── App.vue              # Root component
│   └── main.ts              # Entry point
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── vite.config.ts
├── eslint.config.js
├── .prettierrc.json
├── env.d.ts
└── README.md
```

**Key conventions:**
- `src/views/` for route page components (not `src/pages/` — that's Nuxt)
- `src/components/` for reusable components
- `src/composables/` for Composition API composables (e.g., `useStorage.ts`)
- `src/router/index.ts` for route definitions

### Resolved Decisions

| # | Decision | Resolution |
|---|----------|------------|
| 1 | Spring Boot version | ~~**4.0.3**~~ → **3.5.11** — see addendum below |
| 2 | Frontend framework | **Vue 3** — pivot from Svelte due to ecosystem maturity concerns |
| 3 | TypeScript | **Yes** — confirmed by developer |
| 4 | Node.js version | **24 LTS** (latest LTS) |
| 5 | Base package | **`de.fete`** (not `com.fete`) |
| 6 | JPA in T-1 | **Defer to T-4** — T-1 is empty scaffold, JPA needs a datasource |
| 7 | State management | **No Pinia** — Composition API + localStorage sufficient |

### Addendum: Spring Boot 4.0 → 3.5 Pivot (2026-03-04)

During T-1 implementation, Spring Boot 4.0.3 proved unworkable for the scaffold phase. The 4.0 release massively reorganized internal packages — test infrastructure classes (`TestRestTemplate`, `AutoConfigureMockMvc`, etc.) were moved into new modules with different package paths. The Spring Boot 4.0 Migration Guide did not cover these changes adequately, and resolving the issues required extensive trial-and-error with undocumented class locations and missing transitive dependencies.

**Decision:** Pivot to **Spring Boot 3.5.11** (latest 3.5.x patch). This is the battle-tested line with OSS support through June 2026. Since this is a greenfield project, migrating to 4.x later (once the ecosystem and documentation have matured) is straightforward.

**Impact:** None on architecture or feature scope. The hexagonal package structure, dependency choices, and all other decisions remain unchanged. Only the Spring Boot parent version in `pom.xml` changed.

### Updated Target Repository Layout

```
fete/
├── backend/
│   ├── pom.xml
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── .mvn/wrapper/maven-wrapper.properties
│   └── src/
│       ├── main/
│       │   ├── java/de/fete/
│       │   │   ├── FeteApplication.java
│       │   │   ├── domain/model/           (package-info.java)
│       │   │   ├── domain/port/in/         (package-info.java)
│       │   │   ├── domain/port/out/        (package-info.java)
│       │   │   ├── application/service/    (package-info.java)
│       │   │   ├── adapter/in/web/         (package-info.java)
│       │   │   ├── adapter/out/persistence/(package-info.java)
│       │   │   └── config/                 (package-info.java)
│       │   └── resources/
│       │       └── application.properties
│       └── test/java/de/fete/
│           └── FeteApplicationTest.java
├── frontend/
│   ├── public/
│   ├── src/
│   │   ├── assets/
│   │   ├── components/
│   │   ├── composables/
│   │   ├── router/index.ts
│   │   ├── views/
│   │   ├── App.vue
│   │   └── main.ts
│   ├── index.html
│   ├── package.json
│   ├── package-lock.json
│   ├── tsconfig.json
│   ├── vite.config.ts
│   └── eslint.config.js
├── spec/
├── .gitignore                          (extended)
├── CLAUDE.md
├── README.md
├── LICENSE
└── Ideen.md
```
