Files
portainer-core/services/library-desk/WEBHOOK_SETUP.md
T
jpmschweitzerandClaude Opus 4.5 b74b5bc2c8 feat(library-desk): add wiki change detection via PostgreSQL LISTEN/NOTIFY
- Add WikiChangeListener service for PostgreSQL notifications
- Add webhooks router for HTTP webhook fallback
- Add asyncpg dependency for PostgreSQL async support
- Include setup scripts and documentation for triggers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 21:35:18 +01:00

7.5 KiB

Wiki.js Webhook Setup Guide

Complete guide to enable automatic processing of user-edited wiki pages.

Overview

When you manually edit pages in Wiki.js, the webhook system ensures they're processed identically to AI-generated content:

  • Vectors updated - Qdrant embeddings refreshed
  • Graph updated - Entities extracted, relationships created
  • Bidirectional links - Automatic entity linking both ways
  • Deletions handled - Clean removal from vectors + graph
  • Moves processed - Path updates propagated to graph

Step 1: Configure Wiki.js Webhook

Access Wiki.js Administration

  1. Log into Wiki.js as administrator
  2. Navigate to AdministrationWebhooks
  3. Click Add New Webhook

Webhook Configuration

Field Value
Name Library Desk Integration
Endpoint URL http://library-desk:8089/webhooks/wikijs
Content Type application/json
Events ☑ page.create
☑ page.update
☑ page.delete
☑ page.rename
Status Active

Authentication Header

Add custom header for API authentication:

Authorization: Bearer af88ed8f44bed81bdb20d0534f1c4547340b29e2aba4963f61a71b993d7eb6e5

(Use your actual Library Desk API key from .env)

Step 2: Verify Webhook Endpoint

Test the webhook health endpoint:

curl http://192.168.86.149:8089/webhooks/health

Expected response:

{
  "status": "ok",
  "service": "webhooks"
}

Step 3: Test Webhook Integration

Test 1: Page Creation

  1. Create a new page in Wiki.js
  2. Add content mentioning existing entities (e.g., "Docker", "Kubernetes")
  3. Save the page

Expected Result:

  • Vectors created in Qdrant
  • Document node created in Neo4j
  • Entities extracted and linked
  • Bidirectional links added (new page links to entities, entities' pages link back)

Test 2: Page Update

  1. Edit an existing page
  2. Add new content with entity mentions
  3. Save changes

Expected Result:

  • Vectors updated in Qdrant (old removed, new added)
  • Graph updated with new entities
  • Entity links refreshed

Test 3: Page Deletion

  1. Delete a page from Wiki.js

Expected Result:

  • Vectors removed from Qdrant
  • Document node removed from Neo4j
  • Orphaned entities cleaned up (entities only mentioned in this page)
  • Broken relationships removed

Test 4: Page Move/Rename

  1. Move a page to different location (e.g., /tech/docker/infrastructure/docker)
  2. Or rename the page

Expected Result:

  • Document node path updated in Neo4j
  • Entity links updated if title changed
  • Vectors remain valid (no re-embedding needed unless content changed)

Event Processing Details

page.create

User creates page → Webhook → Library Desk
  ├─ Ingest page (vector + graph)
  ├─ Extract entities
  ├─ Forward linking (page → entities)
  └─ Backward linking (entities → page)

page.update

User edits page → Webhook → Library Desk
  ├─ Re-ingest page (force refresh)
  ├─ Update entities
  ├─ Refresh forward links
  └─ Refresh backward links

page.delete

User deletes page → Webhook → Library Desk
  ├─ Remove vectors from Qdrant
  ├─ Find orphaned entities
  ├─ Delete Document node
  ├─ Delete orphaned entities
  └─ Clean broken relationships

page.rename

User moves/renames page → Webhook → Library Desk
  ├─ Update Document node path
  ├─ Update title if changed
  ├─ Re-link entities if title changed
  └─ Update references

Monitoring Webhook Activity

Check Logs

# Library Desk logs
docker logs library-desk --follow | grep webhook

# Look for:
# - "Received Wiki.js webhook: page.create"
# - "Processing page.update for page 123"
# - "Cleanup complete for deleted page 456"

Verify Processing

After making changes in Wiki.js, verify:

1. Vectors Updated:

curl -X POST http://192.168.86.149:8089/query/hybrid \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "your page content", "user": "jpmschweitzer"}'

2. Graph Updated:

// In Neo4j Browser
MATCH (d:Document {page_id: 123})
OPTIONAL MATCH (d)-[:MENTIONS]->(e)
RETURN d, collect(e.name) as entities

3. Entity Links Added: Visit the page in Wiki.js and verify entity names are hyperlinked.

Troubleshooting

Webhook Not Triggering

Problem: Changes in Wiki.js don't trigger processing

Solutions:

  1. Check webhook configuration in Wiki.js Admin
  2. Verify endpoint URL is correct: http://library-desk:8089/webhooks/wikijs
  3. Check authorization header is set
  4. Verify library-desk is running: docker ps | grep library-desk
  5. Check library-desk logs: docker logs library-desk --tail 50

Processing Failures

Problem: Webhook triggers but processing fails

Solutions:

  1. Check library-desk logs for errors
  2. Verify Neo4j is accessible
  3. Verify Qdrant is accessible
  4. Check Ollama is running (for embeddings)
  5. Verify user mapping in extract_user_from_email()

Orphaned Entities

Problem: Deleted pages leave entities behind

Solution: Manually clean orphaned entities:

// Find orphaned entities (no MENTIONS relationships)
MATCH (e:User_Jpmschweitzer)
WHERE NOT e:Document
AND NOT EXISTS {(d:Document)-[:MENTIONS]->(e)}
DETACH DELETE e
RETURN count(e) as deleted

Problem: Entity links broken after page moves

Solution: Re-run entity linking on all pages:

curl -X POST http://192.168.86.149:8089/entity-linking/link-all \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user": "jpmschweitzer"}'

Performance Considerations

Background Processing

Webhook handler processes events in the background to avoid blocking Wiki.js:

  • Webhook response: <100ms (immediate acknowledgment)
  • Processing: 2-10s (runs asynchronously)
  • No impact on Wiki.js editing experience

Rate Limiting

For bulk operations (importing many pages):

  • Consider temporarily disabling webhook
  • Use batch ingestion endpoint instead: /ingest/batch
  • Re-enable webhook after bulk import

Advanced Configuration

Custom User Mapping

By default, user is extracted from email (user@domainuser).

Customize in /services/library-desk/src/routers/webhooks.py:

def extract_user_from_email(email: str) -> str:
    # Option 1: Map specific emails to users
    user_map = {
        "admin@example.com": "admin",
        "john.doe@example.com": "jpmschweitzer"
    }
    return user_map.get(email, email.split("@")[0])

Event Filtering

To process only certain pages, add filtering in webhook handler:

# Only process pages in /tech/ path
if not payload.page.get("path", "").startswith("/tech/"):
    logger.info(f"Skipping page outside /tech/: {payload.page.get('path')}")
    return

Disable Bidirectional Linking

To only do forward linking (page → entities) without backward linking:

Edit process_wiki_page_change():

# Comment out the bidirectional linking call
# link_stats = await consolidation_service._apply_bidirectional_entity_linking(...)

Summary

With webhooks configured:

User Action Automatic Processing
Create page Ingest + entity link (bidirectional)
Edit page Re-ingest + refresh links
Delete page Clean vectors + graph + orphaned entities
Move page Update paths + refresh links

Result: User-edited and AI-generated pages are indistinguishable in the knowledge base!