--- 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 org.springframework.boot spring-boot-starter-parent 4.0.3 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.postgresql postgresql runtime org.springframework.boot spring-boot-starter-test test ``` 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 ```