update CLAUDE.md to reflect the sync/vector package layout
Documents the homebox/, sync/, and vector/ packages as they actually exist now (the doc still described a since-renamed ai/ package and a VectorStoreConfig class that was never added - PgVectorStore is auto-configured from application.yaml). Also flags what's still pending rather than implying it's done: HomeboxAiSearchProvider is an unimplemented stub, SearchService doesn't route on aiSearch yet, and /sync isn't wired to login or the frontend.
This commit is contained in:
@@ -49,13 +49,15 @@ Package-by-feature layout. Server context path is `/api`. Main endpoints:
|
||||
- `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
|
||||
- `POST /api/search` — paged search against the requested service; returns 401 if no active session
|
||||
- `POST /api/sync` — triggers a vector-store sync for the requested service; returns 401 if no active session. Not yet triggered on login or called from the frontend — manual/internal trigger only for now.
|
||||
|
||||
Six packages:
|
||||
Eight packages:
|
||||
|
||||
**`shared/`** — cross-cutting types used by more than one feature package
|
||||
|
||||
- `ServiceType` (enum): identifies each integrated app (e.g. `HOMEBOX`); used in both `connection/` and `search/`
|
||||
- `ServiceProvider` (interface): base for `ConnectionProvider` and `SearchProvider`; declares `getServiceType()`
|
||||
- `ServiceType` (enum): identifies each integrated app (e.g. `HOMEBOX`); used across `connection/`, `search/`, `sync/`
|
||||
- `ServiceProvider` (interface): base for `ConnectionProvider`, `SearchProvider`, `SyncProvider`; declares `getServiceType()`
|
||||
- `ServiceItem`: normalized item shape (`id`, `title`, `description`, `extraData`) returned by both search and sync fetches
|
||||
- `Endpoint` (enum): API path constants for all external service calls
|
||||
- `SessionKeys`: builds session attribute names of the form `{SERVICE_TYPE}_CONNECTION_ID`
|
||||
|
||||
@@ -67,29 +69,40 @@ Six packages:
|
||||
**`connection/`** — connecting to and persisting service credentials
|
||||
|
||||
- `ConnectionProvider` interface: extends `ServiceProvider`; each integrated app implements `login()` and credential checking
|
||||
- `ConnectionIdentifiable` interface: `appUrl()`/`username()`/`serviceType()`; implemented by `SearchRequest` and `SyncRequest` so `HomeboxItemClient` can resolve the underlying connection regardless of which feature is calling it
|
||||
- `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 (`ConnectionEntity`) uses **Single Table Inheritance** — one `connections` table with app-specific nullable columns
|
||||
- `HomeboxConnectionProvider` / `HomeboxEntity`: Homebox-specific implementation
|
||||
- `HomeboxConnectionProvider` / `HomeboxConnectionEntity`: Homebox-specific implementation
|
||||
|
||||
**`ai/`** — shared AI infrastructure used by multiple features (search, future image analysis)
|
||||
**`homebox/`** — shared Homebox API access
|
||||
|
||||
- `EmbeddingService`: wraps Spring AI's `EmbeddingModel`; reused by any feature that needs to generate vectors
|
||||
- `VectorStoreConfig`: Spring bean configuration for `PgVectorStore` (pgvector-backed `VectorStore`)
|
||||
- All classes here are provider-agnostic — the OpenAI starter is pointed at LiteLLM, so the underlying model is configurable without code changes
|
||||
- `HomeboxItemClient`: fetches a page of items from the Homebox entities API and maps them to `ServiceItem`; used by both `HomeboxSearchProvider` (keyword search) and `HomeboxSyncProvider` (vector-store sync) so the fetch/mapping logic isn't duplicated
|
||||
|
||||
**`vector/`** — vectorization
|
||||
|
||||
- `EmbeddingService`: embeds `ServiceItem`s into pgvector's `VectorStore` and prunes entries that no longer exist upstream. Document ID is `{connectionId}:{itemId}`, so re-syncing upserts existing items instead of duplicating them. Deliberately stateless (only field is the injected `VectorStore`) since it's a singleton bean — the per-sync ID accumulator used for pruning is owned by the caller (`HomeboxSyncProvider`), not held as instance state
|
||||
- `PgVectorStore` itself is auto-configured by `spring-ai-starter-vector-store-pgvector` from `application.yaml` (`spring.ai.vectorstore.pgvector.dimensions`) — no manual config class in this codebase
|
||||
|
||||
**`search/`** — querying connected services (keyword and AI)
|
||||
|
||||
- `SearchProvider` interface: extends `ServiceProvider`; each integrated app implements `getSearchResults()`
|
||||
- `SearchService`: maintains two provider maps — keyword providers and AI providers; routes based on `SearchRequest.aiSearch` flag
|
||||
- `SearchService`: dispatches by `ServiceType` via a single provider map — **does not yet route on `SearchRequest.aiSearch`**; `HomeboxSearchProvider` and `HomeboxAiSearchProvider` both currently register for `ServiceType.HOMEBOX`, so only one wins the registration (known gap, pending AI search work)
|
||||
- `SearchController`: guards with session check before delegating to `SearchService`
|
||||
- `SearchRequest`: includes `aiSearch: boolean` — when true, routes to AI provider instead of keyword provider
|
||||
- `SearchRequest`: includes `aiSearch: boolean` (not yet consumed, see above) and implements `ConnectionIdentifiable`
|
||||
- `PagedSearchResponse`: includes nullable `summary` field — populated only for AI search results; null for keyword search
|
||||
- `HomeboxSearchProvider`: keyword search via Homebox API; unchanged from original implementation
|
||||
- `HomeboxAiSearchProvider`: AI search via pgvector similarity; returns ranked items + generated summary
|
||||
- `HomeboxSyncService`: fetches all Homebox items page by page, embeds them via `EmbeddingService`, stores in `VectorStore`; triggered on connection login (background sync)
|
||||
- `HomeboxSearchProvider`: keyword search; delegates the remote fetch to `HomeboxItemClient`
|
||||
- `HomeboxAiSearchProvider`: **stub only** — `getSearchResults` throws `UnsupportedOperationException`; the actual similarity search + summary generation is pending
|
||||
|
||||
**AI search flow:** on login → background sync indexes all Homebox items into pgvector. On AI search → embed query → pgvector similarity search → top N results passed to `ChatClient` for summary generation → return list + summary. Sync is idempotent (delete-then-reindex per connection).
|
||||
**`sync/`** — indexing connected services into the vector store
|
||||
|
||||
- `SyncProvider` interface: extends `ServiceProvider`; each integrated app implements `syncVectorStore()`
|
||||
- `SyncService`: dispatches by `ServiceType` via a provider map, same pattern as `SearchService`
|
||||
- `SyncController`: session-gated `POST /sync`; not currently called by the frontend or triggered on login
|
||||
- `SyncRequest`: implements `ConnectionIdentifiable`
|
||||
- `HomeboxSyncProvider`: pages through the full Homebox catalog via `HomeboxItemClient`, embedding each page through `EmbeddingService.vectorizeData` and collecting every item ID seen along the way. Once the full page loop finishes, calls `EmbeddingService.deleteStaleVectorEntries` **once** with the complete ID set, removing any previously indexed item no longer present upstream. Order matters — pruning per page instead of once at the end would treat items on other pages as stale and delete them too.
|
||||
|
||||
**Pending work (not yet implemented):** `HomeboxAiSearchProvider`'s actual similarity search + summary generation; `SearchService` routing two provider maps by `aiSearch`; triggering `/sync` on login or from the frontend; a frontend sync button and AI search UI.
|
||||
|
||||
**`exception/`** — `GlobalExceptionHandler` via `@ControllerAdvice`
|
||||
|
||||
@@ -110,7 +123,7 @@ React 19 + TypeScript + SCSS, Vite 6 build. Package-by-feature under `components
|
||||
|
||||
- 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 — `OPENAI_BASE_URL` points to LiteLLM, not OpenAI directly, keeping the underlying model provider configurable
|
||||
- `spring-ai-starter-vector-store-pgvector` provides `PgVectorStore`; configured in `ai/VectorStoreConfig`
|
||||
- `spring-ai-starter-vector-store-pgvector` provides `PgVectorStore`, auto-configured from `application.yaml` (no manual config class)
|
||||
- Embedding dimensions must stay consistent with the configured LiteLLM embedding model — changing models requires re-syncing all indexed items
|
||||
- Processing pipeline (Phase 2): stage in DB → LLM inference → refine via UI → export to target app
|
||||
|
||||
|
||||
Reference in New Issue
Block a user