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 Administration → Webhooks
  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@domain → user).

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!