jpmschweitzerandClaude 748d1cbfae test(integration): mark the 20 tests that need Neo4j and give them a runnable home
D-26 requires `make test` to pass with no network; T-55's audit measured 426
passed/29 skipped with network vs. 412 passed/23 skipped/20 ERRORS inside an
unprivileged network namespace. All 20 errors trace to a real Bolt connection
opened at fixture setup (neo4j_client -> client.connect()), not to test logic.

The ticket's own summary said all 20 were in test_entity_linking.py; tracing
the actual error list showed only 5 were (TestEntityLinkingIntegration,
TestEntityLinkingMultiTenancy, plus the trailing module-level cleanup test).
The other 15 are every test in test_hybrid_rag.py, whose hybrid_rag_service
fixture resolves graph_service -> neo4j_client regardless of what the test
body itself exercises -- including the RRF-fusion and context-formatting
classes that read as pure logic. There is no unit/integration split inside
that file without restructuring its fixture graph, which is out of scope
here; the whole module is marked instead of picking classes apart from
underneath a shared fixture chain.

The fix is the mechanism this repo already had and had never wired to a
target: tests/conftest.py's `integration` pytest marker plus its
RUN_INTEGRATION_TESTS/TEST_TENANT gate (test_integration.py,
test_tenant_isolation_live.py, test_quality_report_live.py and
TestWikiChangeListenerIntegration already used it). Applying the same marker
here means `make test` skips these 20 the same way it already skipped the
other 23 -- no file move, no new fixture layer, matching repo precedent
exactly rather than inventing a second convention beside it.

`make test-integration` is the D-26 home: sets RUN_INTEGRATION_TESTS=1,
selects `-m integration`, and treats pytest's own "no tests collected" exit
code (5) as a hard failure rather than a pass, so a marker that gets renamed
or lost fails loudly instead of the target quietly collecting zero and going
green.

Verified (unshare -rn sh -c 'ip link set lo up; ...' after confirming the
positive control -- a live :8089 returning HTTP 200 outside returns curl exit
7 inside):
  make test, no network:   412 passed, 43 skipped, exit 0  (was 20 ERRORS)
  make test, with network: 412 passed, 43 skipped, exit 0  (unchanged; the 14
    of these 20 that were previously counted in the 426 passed now skip by
    default -- reclassified, not lost; the other 6 already skipped for an
    unrelated reason before this change)
  make test-integration, these 20, with network: 14 passed, 6 skipped
    (test_wiki_page's own pytest.skip when it can't create a wiki page -- a
    pre-existing soft-skip, unrelated to this change), 0 failed, exit 0
  make test-integration mutated to select a nonexistent marker: FAIL,
    "selected 0 tests", exit 2 -- confirmed loud, then reverted

Not fixed here: the other 23 tests already carrying `integration` include
three files (test_integration.py, test_tenant_isolation_live.py,
test_quality_report_live.py) that fail under `make test-integration` today
because they call the local dev server on :8778, which was not running in
this session -- a pre-existing "never proven runnable" gap this same ticket
family exists to find, but a different set of tests than the one measured
here.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 15:40:41 +02:00
2026-08-16 19:32:13 +02:00
2026-08-16 19:32:13 +02:00

Library Desk - API Coordination Service

FastAPI service that coordinates all Library operations

Overview

Library Desk is the central coordination layer for The Library system, providing a unified API for:

  • HybridRAG Queries - Combines Neo4j (structure) + Qdrant (semantics) + SearXNG (web)
  • Document Ingestion - Parse, chunk, embed, and index documents
  • Entity Extraction - NLP to identify classes, functions, concepts
  • Relationship Mapping - Link entities in Neo4j knowledge graph
  • Mind Map Generation - Query Neo4j graph → Render D3.js visualizations
  • Wiki.js Proxy - CRUD operations for dossiers
  • Deduplication - Vector similarity + graph analysis

Architecture

Library Desk API (FastAPI)
    ├── Neo4j (knowledge graph)
    ├── Qdrant (vector search)
    ├── Wiki.js (wiki operations)
    ├── SearXNG (web search)
    ├── Ollama (embeddings)
    └── Redis (caching)

Requirements

  • Python: 3.12+
  • Dependencies: See requirements.txt

Configuration

Environment variables (set in Portainer stack):

# Required
LIBRARY_API_KEY=<generate-with-openssl-rand-hex-32>
NEO4J_PASSWORD=<neo4j-password>
WIKIJS_API_KEY=<from-wiki-admin-panel>

# Optional (defaults provided)
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
QDRANT_HOST=qdrant
QDRANT_PORT=6333
WIKIJS_URL=http://wiki:3000
SEARXNG_URL=http://searxng:8080
OLLAMA_URL=http://ollama:11434
OLLAMA_MODEL=mistral-nemo-large:latest
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
REDIS_HOST=redis-shared
REDIS_PORT=6379
REDIS_DB=2

API Endpoints

System

  • GET / - Root endpoint
  • GET /health - Health check (public)
  • GET /stats - System statistics (authenticated)

Query (All require API key)

  • POST /query/hybrid - HybridRAG (graph + vector + web)
  • POST /query/semantic - Vector search only
  • POST /query/graph - Graph traversal only
  • GET /query/related/{id} - Find related content

Content Management (Future)

  • POST /ingest/document - Index new document
  • POST /ingest/wiki-page - Sync Wiki.js page
  • POST /wiki/dossier - Create dossier (proxies to Wiki.js)
  • PUT /wiki/dossier/{id} - Update dossier
  • DELETE /wiki/dossier/{id} - Delete dossier

Graph Operations (Future)

  • GET /graph/entities - List entities
  • GET /graph/mindmap/{id} - Generate mind map
  • POST /graph/query - Execute Cypher query

Deduplication (Future)

  • POST /deduplicate/find - Find duplicates
  • POST /deduplicate/merge - Merge duplicates

Development

Local Setup

# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Run development server
uvicorn src.main:app --reload --host 0.0.0.0 --port 8089

Project Structure

Following FastAPI Best Practices:

library-desk/
├── src/
│   ├── __init__.py           # Package initialization
│   ├── main.py               # FastAPI application
│   ├── config.py             # Pydantic settings
│   └── [future modules]      # Domain-specific modules
├── requirements.txt          # Python dependencies
└── README.md                 # This file

Future structure (as features are added):

library-desk/
├── src/
│   ├── query/                # Query domain
│   │   ├── router.py
│   │   ├── schemas.py
│   │   ├── service.py
│   │   └── dependencies.py
│   ├── graph/                # Graph domain
│   ├── wiki/                 # Wiki domain
│   └── ingest/               # Ingestion domain

Best Practices Implemented

Async routes for I/O operations Dependency injection for configuration and auth Pydantic models for request/response validation Modular settings using Pydantic Settings API key authentication with Bearer tokens OpenAPI documentation auto-generated Proper logging with structured format CORS middleware configured Health checks for monitoring Minor version locking (~=) in requirements CVE-checked dependencies (Dec 2025)

API Documentation

Once running, access:

Authentication

All protected endpoints require a Bearer token:

curl -H "Authorization: Bearer ${LIBRARY_API_KEY}" \
  http://localhost:8089/stats

Testing

# Run tests (when implemented)
pytest

# With coverage
pytest --cov=src --cov-report=term

Deployment

Deployed via Portainer stack: /stacks/library-desk.yml

The container:

  • Runs on port 8089
  • Auto-creates venv on startup
  • Installs dependencies from requirements.txt
  • Starts uvicorn with 2 workers
  • Mounts source code for live editing

Monitoring

  • Uptime Kuma: Monitor /health endpoint
  • Logs: docker logs library-desk
  • Stats: GET /stats (requires API key)

Scheduler Integration

See LIBRARIAN_INTEGRATION.md for details on how The Scheduler (Librarian) integrates with Library Desk for automated documentation indexing.

Key Workflow:

  1. Scheduler mirrors docs to Gitea (daily 03:00)
  2. Scheduler syncs to Library Desk (daily 03:30)
  3. Library Desk ingests, chunks, embeds, and indexes
  4. Content becomes searchable via HybridRAG

Future Enhancements

  • Implement HybridRAG query logic
  • Add Neo4j connection pooling
  • Add Qdrant client initialization
  • Implement Wiki.js API proxy
  • Add entity extraction (spaCy/NLP)
  • Implement mind map generation
  • Add deduplication logic
  • Implement Scheduler integration endpoints (see LIBRARIAN_INTEGRATION.md)
  • Add comprehensive tests
  • Add rate limiting
  • Add request tracing

References

License

Part of Portainer Core infrastructure.

Support

S
Description
The libary desk api in the tower-of-joy project. The toolkit for The Librarian in Tatlock's household
Readme
1.1 MiB
2026-08-16 19:32:18 +02:00
Languages
Python 97.7%
JavaScript 1.5%
Makefile 0.5%
Shell 0.3%