- Add /documents router with webhook, upload, search, health endpoints - Create DocumentSyncService for indexing documents to vectors/graph - Add PaperlessClient for REST API integration - Configure dependency injection for Paperless client - Add document models for webhook payloads and responses - Event-driven architecture via Paperless workflow webhooks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
333 lines
11 KiB
Markdown
333 lines
11 KiB
Markdown
# Memory Management System - Implementation Plan
|
||
|
||
## Overview
|
||
|
||
A three-tier memory architecture for Library Desk with intelligent orchestration:
|
||
|
||
| Tier | Storage | Purpose | TTL |
|
||
|------|---------|---------|-----|
|
||
| **Volatile** | Qdrant (vectors) | Weather, news, financial, ephemeral context | 5min - 2hr |
|
||
| **Documents** | Paperless-ngx + ClamAV (host) | Git mirrors, PDFs, video, images | Permanent |
|
||
| **Knowledge** | Wiki + Neo4j | Personal dossiers, research, summaries | Permanent |
|
||
|
||
**Implementation Priority**: Cleanup → Volatile → Documents → Test Data Cleanup
|
||
|
||
### Phase Status
|
||
|
||
| Phase | Status | Version |
|
||
|-------|--------|---------|
|
||
| Phase 1: Cleanup System | ✅ Complete | v1.4.0 |
|
||
| Phase 2: Volatile Memory | ✅ Complete | v1.4.3 |
|
||
| Phase 3: Document Storage | ✅ Planned | See [DOCUMENT_STORAGE_PLAN.md](DOCUMENT_STORAGE_PLAN.md) |
|
||
| Phase 4: Test Data Cleanup | ✅ Complete | v1.4.4 |
|
||
|
||
---
|
||
|
||
## Phase 1: Cleanup System Completion ✅
|
||
|
||
### Current State
|
||
- **COMPLETE** - All Phase 1 tasks implemented
|
||
- Redis timestamp tracking for last cleanup
|
||
- Bidirectional orphan detection between vectors and graph
|
||
- Scheduler integration endpoints ready
|
||
|
||
### Tasks
|
||
|
||
#### 1.1 Add Scheduler Integration Points ✅
|
||
**Files**: `src/routers/maintenance.py`
|
||
|
||
- [x] Add `last_cleanup` timestamp tracking in Redis
|
||
- [x] Return cleanup stats in format scheduler can log
|
||
- [x] Added `RedisDep` to cleanup endpoints
|
||
|
||
#### 1.2 Bidirectional Orphan Detection ✅
|
||
**Files**: `src/services/graph_service.py`, `src/services/vector_service.py`
|
||
|
||
- [x] `find_documents_without_vectors()` - graph nodes with no vectors
|
||
- [x] `find_chunks_without_graph_nodes()` - vectors with no graph node
|
||
- [x] Updated maintenance endpoints to use bidirectional checks
|
||
- [x] Added `chunks_without_graph` and `docs_without_vectors` to response models
|
||
|
||
#### 1.3 Scheduler Configuration ✅
|
||
**Scheduler-side task definition:**
|
||
```json
|
||
{
|
||
"task_name": "library_reconcile_index",
|
||
"schedule": "0 4 * * *",
|
||
"endpoint": "POST /maintenance/reconcile-index?user=jpmschweitzer",
|
||
"description": "Daily index reconciliation - cleanup + reindex missing"
|
||
}
|
||
```
|
||
|
||
- [x] Documented in `LIBRARIAN_INTEGRATION.md`
|
||
- [x] Added `reconcile-index` endpoint (cleanup + reindex missing)
|
||
- [x] Lightweight health check mode for uptime monitoring
|
||
- [x] Detailed health check mode for dashboards
|
||
|
||
---
|
||
|
||
## Phase 2: Volatile Memory System ✅
|
||
|
||
### Architecture (Final Implementation)
|
||
|
||
```
|
||
┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
|
||
│ Library-Desk │◄───│ Scheduler │───►│ External APIs │
|
||
│ │ │ │ │ (weather, news) │
|
||
│ VolatileCache │ │ Refresh │ └─────────────────┘
|
||
│ Service │ │ Jobs │
|
||
└────────┬────────┘ └──────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ Qdrant │
|
||
│ (volatile_{user})│
|
||
└─────────────────┘
|
||
```
|
||
|
||
**Key design decisions:**
|
||
- Vector storage in Qdrant (not Redis) for semantic search
|
||
- Collection per user: `volatile_{user}`
|
||
- TTL via `ttl_expiry` timestamp in payload
|
||
- Natural language conversion for embedding structured data
|
||
- Integrated into HybridRAG with priority boost
|
||
|
||
### Endpoints (Implemented)
|
||
|
||
| Endpoint | Method | Purpose |
|
||
|----------|--------|---------|
|
||
| `/volatile/search?q=...` | GET | Semantic search across volatile data |
|
||
| `/volatile/store?namespace=...&key=...` | POST | Store/update record |
|
||
| `/volatile/{namespace}/{key}` | GET | Retrieve specific record |
|
||
| `/volatile/{namespace}/{key}` | DELETE | Remove record |
|
||
| `/volatile/stats` | GET | Cache statistics |
|
||
| `/volatile/scheduled` | GET | Records needing refresh |
|
||
| `/volatile/namespaces` | GET | List available namespaces |
|
||
| `/maintenance/cleanup/volatile` | POST | Purge expired records |
|
||
|
||
### Namespaces
|
||
|
||
| Namespace | Default TTL | Use Case |
|
||
|-----------|-------------|----------|
|
||
| weather | 30 min | Current conditions, forecasts |
|
||
| news | 1 hour | Headlines, breaking news |
|
||
| financial | 5 min | Stock prices, exchange rates |
|
||
| transit | 5 min | Train/bus schedules, delays |
|
||
| traffic | 10 min | Commute times, road conditions |
|
||
| air_quality | 1 hour | Pollution, pollen counts |
|
||
| sports | 1 min | Live scores, matches |
|
||
| social | 10 min | Social notifications |
|
||
| system | 1 min | Service health status |
|
||
| context | 1 hour | Session state |
|
||
| custom | 1 hour | User-defined data |
|
||
|
||
---
|
||
|
||
## Phase 3: Document Storage (Research + Implementation)
|
||
|
||
### Research Scope
|
||
|
||
Evaluate FOSS self-hosted options for:
|
||
- Git repository mirroring
|
||
- PDF/document storage with metadata
|
||
- Image/video blob storage
|
||
- Full-text search capability
|
||
|
||
**Constraints**:
|
||
- Must be self-hosted, Docker-deployable
|
||
- Performance is priority (can wrap complexity in API)
|
||
- No cloud dependencies
|
||
|
||
**Candidates to evaluate**:
|
||
1. MinIO (S3-compatible object storage) + metadata in Neo4j
|
||
2. Paperless-ngx (document management with OCR)
|
||
3. SeaweedFS (distributed file system)
|
||
4. Custom: filesystem + Neo4j metadata
|
||
|
||
### Category Descriptors
|
||
|
||
**Wiki page structure for document collections**:
|
||
```markdown
|
||
# FastAPI Documentation
|
||
|
||
## Overview
|
||
[LLM-generated summary from web search about FastAPI]
|
||
|
||
## Collection Statistics
|
||
- **Documents**: 342 files
|
||
- **Last Sync**: 2025-12-24 03:30 UTC
|
||
- **Source**: github.com/tiangolo/fastapi
|
||
- **Coverage**: API reference, tutorials, deployment guides
|
||
|
||
## What's Included
|
||
[LLM summary of collection contents based on document analysis]
|
||
|
||
## Related Topics
|
||
- [[Python Web Frameworks]]
|
||
- [[REST API Design]]
|
||
```
|
||
|
||
### Tasks
|
||
|
||
#### 3.1 Storage Research
|
||
**Deliverable**: Evaluation document comparing options
|
||
|
||
#### 3.2 Storage Service Implementation
|
||
**New file**: `src/services/document_store_service.py`
|
||
(Details pending research results)
|
||
|
||
#### 3.3 Category Descriptor Generation
|
||
**File**: `src/services/consolidation_service.py`
|
||
|
||
Add LLM-powered category descriptor generation:
|
||
1. Web search for topic overview
|
||
2. Analyze collection contents
|
||
3. Generate/update wiki page with template
|
||
|
||
---
|
||
|
||
## Phase 4: LLM Tester Data Cleanup ✅
|
||
|
||
### Problem
|
||
|
||
LLM testing creates accumulated cruft across the system:
|
||
- Wiki.js pages under `llm-tester/` and `llm_tester/` paths
|
||
- Graph nodes (Document, Entity) linked to test pages
|
||
- Vector chunks in Qdrant for test content
|
||
|
||
This data accumulates over time and clutters Wiki.js visually (no separate tenant scope for tests).
|
||
|
||
### Solution
|
||
|
||
Add a maintenance endpoint to purge all LLM tester artifacts across wiki, graph, and vectors.
|
||
|
||
### Tasks
|
||
|
||
#### 4.1 Identify Test Data Patterns ✅
|
||
**Patterns matched** (security-restricted to test user namespace):
|
||
- `users/llm-tester/*`
|
||
- `users/llm_tester/*`
|
||
|
||
#### 4.2 Add Cleanup Endpoint ✅
|
||
**File**: `src/routers/maintenance.py`
|
||
|
||
```python
|
||
@router.post("/cleanup/test-data")
|
||
async def cleanup_test_data(
|
||
dry_run: bool = Query(default=True),
|
||
wiki: WikiJSDep = None,
|
||
vector_service: VectorServiceDep = None,
|
||
graph_service: GraphServiceDep = None,
|
||
api_key: str = Depends(verify_api_key)
|
||
):
|
||
"""
|
||
Purge LLM tester data from wiki, graph, and vectors.
|
||
|
||
**Security**: Only deletes pages in the test user namespace:
|
||
- users/llm-tester/*
|
||
- users/llm_tester/*
|
||
|
||
Use dry_run=true to preview what would be deleted.
|
||
"""
|
||
```
|
||
|
||
#### 4.3 Implementation Steps ✅
|
||
|
||
1. **Wiki cleanup**: Delete pages via GraphQL mutation
|
||
2. **Graph cleanup**: Delete Document nodes using `delete_page()` method
|
||
3. **Vector cleanup**: Delete chunks using `delete_page_chunks()` method
|
||
|
||
#### 4.4 Scheduler Integration ✅
|
||
**Recommended schedule**: Weekly (Sunday 3:00 AM)
|
||
|
||
```json
|
||
{
|
||
"task_name": "test_data_cleanup",
|
||
"schedule": "0 3 * * 0",
|
||
"endpoint": "POST /maintenance/cleanup/test-data?dry_run=false",
|
||
"description": "Weekly cleanup of LLM test data"
|
||
}
|
||
```
|
||
|
||
### Files to Modify
|
||
|
||
- `src/routers/maintenance.py` - Add cleanup endpoint
|
||
- `src/services/wiki_service.py` - Add bulk delete by path pattern (if needed)
|
||
- `src/services/graph_service.py` - May need pattern-based node deletion
|
||
- `src/services/vector_service.py` - Add pattern-based chunk deletion
|
||
|
||
---
|
||
|
||
## Files Modified/Created
|
||
|
||
### Phase 1 (Cleanup) ✅
|
||
- `src/routers/maintenance.py` - Timestamp tracking, cleanup endpoints
|
||
- `src/services/graph_service.py` - Bidirectional validation
|
||
- `src/services/vector_service.py` - Cross-reference checks
|
||
- `LIBRARIAN_INTEGRATION.md` - Scheduler config docs
|
||
|
||
### Phase 2 (Volatile) ✅
|
||
- `src/services/volatile_service.py` - Qdrant-based volatile cache
|
||
- `src/routers/volatile.py` - Simplified endpoints
|
||
- `src/models/volatile.py` - Namespaces and models
|
||
- `src/models/hybrid_rag.py` - Volatile config options
|
||
- `src/services/hybrid_rag_service.py` - Volatile integration
|
||
- `src/clients/qdrant_client.py` - Expiry filter methods
|
||
- `tests/test_volatile.py` - 37 tests
|
||
|
||
### Phase 3 (Documents)
|
||
- `docs/DOCUMENT_STORAGE_RESEARCH.md` - **NEW**
|
||
- `src/services/document_store_service.py` - **NEW** (post-research)
|
||
- `src/routers/documents.py` - **NEW** (post-research)
|
||
|
||
### Phase 4 (Test Data Cleanup)
|
||
- `src/routers/maintenance.py` - Add cleanup endpoint
|
||
- `src/services/wiki_service.py` - Bulk delete by path pattern
|
||
- `src/services/graph_service.py` - Pattern-based node deletion
|
||
- `src/services/vector_service.py` - Pattern-based chunk deletion
|
||
|
||
---
|
||
|
||
## Resolved Design Decisions
|
||
|
||
1. **Volatile Storage**: Qdrant vectors (not Redis) for semantic search capability
|
||
2. **Collection Naming**: `volatile_{user}` for per-user isolation
|
||
3. **TTL Mechanism**: `ttl_expiry` timestamp in payload, background cleanup job
|
||
4. **HybridRAG Integration**: Volatile as third source with RRF priority boost
|
||
5. **Biographer Qdrant**: Same Qdrant instance, different collection
|
||
6. **Scheduler API**: Has REST API for task registration
|
||
|
||
---
|
||
|
||
## Future Consideration: Dedicated API Integrations
|
||
|
||
For volatile data where quality/consistency matters (weather, financial), consider:
|
||
- OpenWeatherMap API for weather (daily refresh cycle)
|
||
- Financial data API (Alpha Vantage, Yahoo Finance)
|
||
- News APIs (NewsAPI, GDELT)
|
||
- **NOS.nl** - Explicit source for Dutch news
|
||
|
||
This would live in a new `src/clients/` module with:
|
||
- `weather_client.py` - Daily refresh cycle
|
||
- `financial_client.py`
|
||
- `news_client.py` - Include NOS.nl scraper/API for Dutch coverage
|
||
|
||
These provide structured, reliable data vs. SearXNG web scraping. Implementation deferred to later phase.
|
||
|
||
---
|
||
|
||
## Refresh Schedules
|
||
|
||
**Note:** TTL should be longer than refresh interval to prevent data gaps.
|
||
|
||
| Volatile Type | TTL | Refresh Cycle | Refresh Interval | Sources |
|
||
|---------------|-----|---------------|------------------|---------|
|
||
| Weather | 86400s (24hr) | Daily | Every 24hr | OpenWeatherMap |
|
||
| Dutch News | 28800s (8hr) | 4x daily | Every 6hr | NOS.nl |
|
||
| Global News | 28800s (8hr) | 4x daily | Every 6hr | NewsAPI, GDELT |
|
||
| Financial | 600s (10min) | On-demand | N/A | Alpha Vantage |
|
||
|
||
**TTL Logic:**
|
||
- TTL = Refresh Interval × 1.5 (buffer for failed refreshes)
|
||
- On-demand data gets shorter TTL since it's fetched when needed
|