153 lines
7.2 KiB
Markdown
153 lines
7.2 KiB
Markdown
## 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 |
|
|
|
|
|
|

|
|
|
|
---
|
|
|
|
## 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
|
|
```
|