Files
fete/docs/agents/research/2026-03-04-t1-monorepo-setup.md
nitrix a55174b323 T-1: initialize monorepo structure with backend and frontend scaffolds
Backend: Spring Boot 3.5.11 on Java 25, Maven with wrapper, hexagonal
architecture package layout (domain/application/adapter/config), health
endpoint with integration test. Originally planned for Spring Boot 4.0
but pivoted due to massive package reorganization in 4.0 (see addenda
in research and plan docs).

Frontend: Vue 3 scaffolded via create-vue with TypeScript, Vue Router,
Vitest, ESLint, Prettier. Pivoted from Svelte due to ecosystem maturity
concerns (broken router ecosystem for Svelte 5).

Also: extended .gitignore for Java/Maven and Node/Vue artifacts, updated
CLAUDE.md with tech stack, build commands, agent documentation sections,
and document integrity rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:32:18 +01:00

20 KiB

date, git_commit, branch, topic, tags, status
date git_commit branch topic tags status
2026-03-04T00:19:03+01:00 7b460dd322 master T-1: Initialize monorepo structure — Tech stack research
research
codebase
t-1
scaffolding
spring-boot
vue
maven
vite
hexagonal-architecture
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:

<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.33.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