This commit addresses multiple critical fixes and adds new functionality for the NaviDocs local testing environment (port 8083): Search Fixes: - Fixed search to use backend /api/search instead of direct Meilisearch - Resolves network accessibility issue when accessing from external IPs - Search now works from http://172.29.75.55:8083/search PDF Text Selection: - Added PDF.js text layer for selectable text - Imported pdf_viewer.css for proper text layer styling - Changed text layer opacity to 1 for better interaction - Added user-select: text for improved text selection - Pink selection highlight (rgba(255, 92, 178, 0.3)) Database Cleanup: - Created cleanup scripts to remove 20 duplicate documents - Removed 753 orphaned entries from Meilisearch index - Cleaned 17 document folders from filesystem - Kept only newest version of each document - Scripts: clean-duplicates.js, clean-meilisearch-orphans.js Auto-Fill Feature: - New /api/upload/quick-ocr endpoint for first-page OCR - Automatically extracts metadata from PDFs on file selection - Detects: boat make, model, year, name, and document title - Checks both OCR text and filename for boat name - Auto-fills upload form with extracted data - Shows loading indicator during metadata extraction - Graceful fallback to filename if OCR fails Tenant Management: - Updated organization ID to use boat name as tenant - Falls back to "Liliane 1" for single-tenant setup - Each boat becomes a unique tenant in the system Files Changed: - client/src/views/DocumentView.vue - Text layer implementation - client/src/composables/useSearch.js - Backend API integration - client/src/components/UploadModal.vue - Auto-fill feature - server/routes/quick-ocr.js - OCR endpoint (new) - server/index.js - Route registration - server/scripts/* - Cleanup utilities (new) Testing: All features tested on local deployment at http://172.29.75.55:8083 - Backend: http://localhost:8001 - Frontend: http://localhost:8083 - Meilisearch: http://localhost:7700 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
/**
|
|
* Clean orphaned entries from Meilisearch index
|
|
* Removes documents that no longer exist in the database
|
|
*/
|
|
|
|
import { getMeilisearchClient } from '../config/meilisearch.js';
|
|
import { getDb } from '../db/db.js';
|
|
|
|
const INDEX_NAME = process.env.MEILISEARCH_INDEX_NAME || 'navidocs-pages';
|
|
|
|
async function cleanOrphans() {
|
|
console.log('Cleaning orphaned Meilisearch entries...\n');
|
|
|
|
const db = getDb();
|
|
const client = getMeilisearchClient();
|
|
|
|
try {
|
|
const index = await client.getIndex(INDEX_NAME);
|
|
|
|
// Get all document IDs from database
|
|
const validDocIds = db.prepare('SELECT id FROM documents').all().map(row => row.id);
|
|
console.log(`Found ${validDocIds.length} valid documents in database\n`);
|
|
|
|
// Get all documents from Meilisearch
|
|
let offset = 0;
|
|
const limit = 1000;
|
|
let hasMore = true;
|
|
const orphanedIds = [];
|
|
|
|
console.log('Scanning Meilisearch index for orphaned entries...');
|
|
|
|
while (hasMore) {
|
|
const results = await index.getDocuments({ offset, limit });
|
|
|
|
for (const doc of results.results) {
|
|
// Extract docId from the Meilisearch document
|
|
const docId = doc.docId;
|
|
|
|
if (docId && !validDocIds.includes(docId)) {
|
|
orphanedIds.push(doc.id); // Use the Meilisearch document ID
|
|
}
|
|
}
|
|
|
|
offset += limit;
|
|
hasMore = results.results.length === limit;
|
|
}
|
|
|
|
console.log(`Found ${orphanedIds.length} orphaned entries in Meilisearch\n`);
|
|
|
|
if (orphanedIds.length === 0) {
|
|
console.log('No orphaned entries found. Index is clean!');
|
|
return;
|
|
}
|
|
|
|
console.log('Deleting orphaned entries...');
|
|
|
|
// Delete in batches of 100
|
|
const batchSize = 100;
|
|
for (let i = 0; i < orphanedIds.length; i += batchSize) {
|
|
const batch = orphanedIds.slice(i, i + batchSize);
|
|
await index.deleteDocuments(batch);
|
|
console.log(` Deleted batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(orphanedIds.length / batchSize)} (${batch.length} entries)`);
|
|
}
|
|
|
|
console.log('\n=== Cleanup Summary ===');
|
|
console.log(`Orphaned entries removed: ${orphanedIds.length}`);
|
|
console.log('\nMeilisearch cleanup complete!');
|
|
} catch (err) {
|
|
console.error('Meilisearch cleanup failed:', err.message);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
// Run cleanup
|
|
cleanOrphans()
|
|
.then(() => process.exit(0))
|
|
.catch(err => {
|
|
console.error('Cleanup failed:', err);
|
|
process.exit(1);
|
|
});
|