## Project Intent Vaessl is a **technical playground** and proof-of-concept designed to showcase a complete, professional-grade software lifecycle. The primary goal is not just to build a functional utility, but to demonstrate a multi-experience approach to full-stack engineering, DevOps, and AI integration. This project serves as a transparent portfolio of my take on: * **Infrastructure:** Moving from local-machine to browser-based development environment hosted on my Proxmox server. * **Modern AI Orchestration:** Building a system that actually uses AI to do heavy lifting, like identifying objects and understanding natural language using Spring AI and LiteLLM. * **Architectural Foresight:** Designing with abstraction layers early to ensure the system can scale from a single-target tool to a multi-app bridge without significant refactoring. --- ## What is Vaessl? Vaessl acts as a translator between user inputs via text or image and digital management systems. It performs image and semantic search analysis before serving results from applications (e.g., Homebox, WikiJS) via REST API. ### Core Functionality * **Connection Management:** Users connect to supported services (e.g. Homebox) via a credential login flow. Tokens are stored in a JDBC-backed HTTP session, enabling secure multi-service connections per browser session. * **AI-Powered Analysis:** The system utilises **LiteLLM** as a unified gateway to process inputs via LLM of choice *(pipeline in progress)*. * **Semantic Discovery:** By utilising **Spring AI** and **pgvector**, Vaessl will store description embeddings to enable intent-based search (e.g., finding a "Wrench" by searching for "tool to fix a leaky pipe") *(planned)*. --- ## Technical Stack | Layer | Technology | | :--- | :--- | | **Backend** | Spring Boot 4.1.0, Java 25 (LTS), Spring AI | | **Frontend** | React 19, Vite 8, SCSS | | **Database** | PostgreSQL + `pgvector` | | **AI Gateway** | LiteLLM (Unified API proxy) | | **DevOps** | Docker, Portainer, Hoppscotch (API testing), Gitea Actions, Jenkins |   ![Vaessl stack illustration](assets/images/vaessl-stack-illustration.png) --- ## Infrastructure & Methodology ### 1. Centralized Development (Code-Server) To maintain a zero-footprint local setup, I develop within a custom **code-server** Docker instance. * **Custom Image:** The environment is baked with a specific toolchain (OpenJDK 25, Node.js 24) to ensure absolute environment parity. * **Remote Access:** Secured via Pangolin tunnel, allowing for secure, remote development without exposing ports to the public internet. ### 2. Abstraction & Scalability A core requirement was to prevent vendor or application lock-in: * **Provider Pattern:** Both connection and search logic are fully abstracted behind `ConnectionProvider` and `SearchProvider` interfaces. Adding a new service (e.g. WikiJS) means implementing those interfaces — no changes to core dispatch logic required. * **AI Agnostic:** LiteLLM abstracts the AI provider, allowing the backend to switch between cloud APIs and local inference engines (Ollama) without code changes. ### 3. Testing Strategy * **Database Parity:** Mirrored PostgreSQL containers are used for development and testing (`vaessl-db` vs `vaessl-test-db`). This ensures JPA operations are tested against the real PostgreSQL engine and `pgvector` extension, not mocks. * **WireMock:** External HTTP APIs (Homebox, WikiJS) are stubbed in integration tests using WireMock, isolating tests from live service availability. * **Frontend:** A Vitest-based stack provides a fast feedback loop for UI components. --- ## Architecture Overview ### Backend (`backend/src/main/java/com/vaessl/app/`) Package-by-feature layout. Server context path is `/api`. | Package | Purpose | | :--- | :--- | | `shared/` | Cross-cutting types: `ServiceType` enum, `ServiceProvider` base interface, `Endpoint` enum, `SessionKeys` utility | | `config/` | CORS (env-driven allowed origins) and JDBC-backed Spring Session | | `connection/` | Login, session management, credential persistence (Single Table Inheritance) | | `search/` | Paged search against connected services, guarded by active session | | `exception/` | `GlobalExceptionHandler` via `@ControllerAdvice`; domain exceptions mapped to typed HTTP responses | **REST Endpoints:** | Method | Path | Description | | :--- | :--- | :--- | | `POST` | `/api/login` | Authenticates a service and stores its connection ID in the session | | `GET` | `/api/connections/status` | Lists all connected services for the current session | | `DELETE` | `/api/connections/{serviceType}` | Removes a service from the session; invalidates the session if none remain | | `POST` | `/api/search` | Paged search against a connected service; returns 401 if no active session | ### Frontend (`frontend/src/`) React 19 + TypeScript + SCSS, Vite 8 build. Package-by-feature under `components/`. | Module | Description | | :--- | :--- | | `api/` | Typed `apiFetch` wrapper + per-feature API call modules (`connections.ts`, `searches.ts`) | | `types/` | Shared TS types aligned with backend records (`ServiceType`, `LoginRequest`, `SearchResponse`, etc.) | | `components/connections/` | `Dashboard`, `ConnectModal`, `ServiceCard` — full connection management UI | | `components/search/` | `SearchModal` — search dialog with paged result rendering | | `components/ui/` | Shared primitives (`ActionButton`, `Modal`) | --- ## Roadmap ### Phase 1: Foundation * [x] Deployment of core infrastructure (PostgreSQL, LiteLLM, Hoppscotch via Docker). * [x] Custom Code-Server image build and deployment. * [x] Spring Boot skeleton with Java 25 and Gradle Kotlin DSL. ### Phase 2: Connection & Basic Search (Current) * [x] Provider-pattern abstraction for connections and search. * [x] Homebox authentication — login, session-tracked token, expiry checking. * [x] Paged search against Homebox entities via REST. * [x] React connection management dashboard (connect, disconnect, status). * [x] React search modal with paged results. * [x] Integration test suite (WireMock + mirrored PostgreSQL container). * [ ] Image/text input → LLM inference → staging table workflow. * [ ] Data refinement UI for reviewing and approving LLM-processed results. ### Phase 3: Semantic Search & Expansion * [ ] Spring AI vector embeddings with pgvector for intent-based search. * [ ] Additional API targets (WikiJS). * [ ] Public-facing demo. --- ## Setup & Deployment 1. Clone the repository. 2. Copy `.env.local` into `backend/` with: ```env DB_URL=jdbc:postgresql://192.168.1.{subnet}:{port}/vaessl DB_TEST_URL=jdbc:postgresql://192.168.1.{subnet}:{port}/vaessl_test DB_USERNAME={username} DB_PASSWORD={password} PG_DRIVER_CLASS_NAME=org.postgresql.Driver OPENAI_KEY={api-key} OPENAI_BASE_URL=https://{litellm-host}/v1 FRONTEND_LOCAL_URL=http://localhost:5173 FRONTEND_PUBLIC_URL=https://{your-public-domain} ``` 3. Start the pgvector-enabled PostgreSQL instances (production + test) — use the official `pgvector/pgvector` Docker image or install the extension into your existing PostgreSQL instance. 4. Install frontend dependencies and build the backend: ```bash # Frontend cd frontend && npm install # Backend cd backend && ./gradlew build ``` 5. Run the backend and frontend dev servers: ```bash # Backend cd backend && ./gradlew bootRun # Frontend cd frontend && npm run dev ```