# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Vaessl is an AI-powered integration bridge that accepts user text/image inputs, processes them through an LLM pipeline (via LiteLLM), and exports structured data to management systems (Homebox, WikiJS). The backend uses a provider pattern for extensibility. The frontend has a working connection management dashboard. ## Commands ### Backend (Spring Boot + Gradle, inside `backend/`) ```bash ./gradlew build # compile and package ./gradlew test # run all tests ./gradlew test --tests com.vaessl.app.connection.ConnectionServiceTest # single test class ``` ### Frontend (React + Vite, inside `frontend/`) ```bash npm run dev # start dev server npm run build # TypeScript check + Vite build npm run lint # ESLint npm run test # Vitest watch mode npm run test:ui # Vitest visual dashboard ``` ## Environment Copy `.env.local` (not committed) into `backend/` with: - `DB_URL`, `DB_TEST_URL`, `DB_USERNAME`, `DB_PASSWORD` — PostgreSQL (test container on port 5434) - `PG_DRIVER_CLASS_NAME` — PostgreSQL JDBC driver class - `OPENAI_KEY`, `OPENAI_BASE_URL` — LiteLLM gateway (provider-agnostic, configured for gpt-4o-mini) - `FRONTEND_LOCAL_URL`, `FRONTEND_PUBLIC_URL` — allowed CORS origins for the backend Frontend (optional, defaults to `/api`): - `VITE_API_URL` — backend base URL used by `api/client.ts` ## Architecture ### Backend (`backend/src/main/java/com/vaessl/app/`) Server context path is `/api`. Main endpoints: - `POST /api/login` — authenticates a service, stores connection ID in session - `GET /api/connections/status` — lists connected services for the current session - `DELETE /api/connections/{serviceType}` — removes a service from the session; invalidates the session if no connections remain Four main modules: **`config/`** - `CorsConfig`: env-driven allowed origins (`FRONTEND_LOCAL_URL`, `FRONTEND_PUBLIC_URL`); `allowCredentials(true)` is required for session cookies to work cross-origin - `SessionConfig`: JDBC-backed Spring Session with a persistent cookie (`SameSite=Lax`, `HttpOnly`) **`connection/`** — core business logic - `ConnectionProvider` interface: each integrated app (Homebox, WikiJS) implements `login()` and declares its `ServiceType` - `ConnectionService`: auto-discovers providers via Spring injection, dispatches login by `ServiceType` - `ConnectionController`: stores `{serviceType}_CONNECTION_ID` in `HttpSession` after login; reads session attributes to build status responses - Entity (`Connection`) uses **Single Table Inheritance** — one `connections` table with app-specific nullable columns **`dto/`** — `ConnectionRequest`, `LoginResult`, `AuthResponse`, `ConnectionStatusResponse` **`exception/`** — `GlobalExceptionHandler` via `@ControllerAdvice` ### Frontend (`frontend/src/`) React 19 + TypeScript + SCSS, Vite 8 build. - `api/client.ts` — typed `apiFetch` wrapper; always sends `credentials: 'include'` for session cookies; base URL from `VITE_API_URL` (defaults to `/api`) - `api/connections.ts` — connection-specific API calls - `types/connection.ts` — shared types: `LoginRequest`, `AuthResponse`, `ConnectionStatus` - `components/Dashboard` — main view listing connected services - `components/ConnectModal` — login form for adding a service connection - `components/ServiceCard` — per-service status display ### Data & AI - PostgreSQL + pgvector (semantic search via embeddings); also used as the Spring Session store (JDBC) - LiteLLM as a unified AI proxy; Spring AI OpenAI starter wired to it - Processing pipeline (Phase 2): stage in DB → LLM inference → refine via UI → export to target app ### Testing Strategy Integration tests spin up a **mirrored PostgreSQL container** on port 5434 (same schema as production). WireMock mocks external HTTP APIs (Homebox, WikiJS). Do not mock the database in integration tests — the mirrored container strategy exists specifically to catch schema/migration divergence.