/** * Final Document Migration Script * * Migrates 22 curated public documents to production with: * - Correct categories (5 total: getting-started, research-theory, technical-reference, advanced-topics, business-leadership) * - Proper ordering (1-10 range) * - Archives remaining documents * - Migrates research paper to production * * Usage: node scripts/migrate-documents-final.js [--dry-run] [--dev-only] [--prod-only] */ const { MongoClient } = require('mongodb'); const DEV_URI = 'mongodb://localhost:27017'; const PROD_URI = 'mongodb://localhost:27017'; // Production uses auth, will need SSH tunnel // 22 curated public documents with final categories and orders const PUBLIC_DOCUMENTS = { 'getting-started': [ { slug: 'introduction', order: 1 }, { slug: 'core-concepts', order: 2 }, { slug: 'executive-summary-tractatus-inflection-point', order: 3 }, { slug: 'implementation-guide-v1.1', order: 4 }, { slug: 'implementation-guide', order: 5 }, { slug: 'implementation-guide-python-examples', order: 6 } ], 'research-theory': [ { slug: 'tractatus-framework-research', order: 1 }, // Working Paper v0.1 { slug: 'pluralistic-values-research-foundations', order: 2 }, { slug: 'the-27027-incident-a-case-study-in-pattern-recognition-bias', order: 3 }, { slug: 'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery', order: 4 }, { slug: 'llm-integration-feasibility-research-scope', order: 5 }, { slug: 'research-topic-concurrent-session-architecture', order: 6 }, { slug: 'research-topic-rule-proliferation-transactional-overhead', order: 7 } ], 'technical-reference': [ { slug: 'technical-architecture', order: 1 }, { slug: 'api-reference-complete', order: 2 }, { slug: 'api-javascript-examples', order: 3 }, { slug: 'api-python-examples', order: 4 }, { slug: 'openapi-specification', order: 5 } ], 'advanced-topics': [ { slug: 'value-pluralism-faq', order: 1 }, { slug: 'tractatus-ai-safety-framework-core-values-and-principles', order: 2 }, { slug: 'organizational-theory-foundations', order: 3 } ], 'business-leadership': [ { slug: 'business-case-tractatus-framework', order: 1 } ] }; async function migrateDatabase(dbName, client, dryRun = false) { console.log(`\n${'═'.repeat(70)}`); console.log(` MIGRATING DATABASE: ${dbName}`); console.log(`${'═'.repeat(70)}\n`); const db = client.db(dbName); const collection = db.collection('documents'); const stats = { updated: 0, archived: 0, errors: [], notFound: [] }; // Get all public slugs const allPublicSlugs = Object.values(PUBLIC_DOCUMENTS).flat().map(d => d.slug); console.log(`Public documents to migrate: ${allPublicSlugs.length}\n`); // Update each public document for (const [category, docs] of Object.entries(PUBLIC_DOCUMENTS)) { console.log(`\nšŸ“ Category: ${category} (${docs.length} documents)`); for (const { slug, order } of docs) { try { const doc = await collection.findOne({ slug }); if (!doc) { console.log(` āš ļø NOT FOUND: ${slug}`); stats.notFound.push(slug); continue; } if (dryRun) { console.log(` [DRY RUN] Would update: ${doc.title}`); console.log(` Category: ${doc.category} → ${category}`); console.log(` Order: ${doc.order} → ${order}`); console.log(` Visibility: ${doc.visibility} → public`); } else { await collection.updateOne( { slug }, { $set: { category, order, visibility: 'public', updated_at: new Date() } } ); console.log(` āœ“ Updated: ${doc.title}`); stats.updated++; } } catch (error) { console.error(` āœ— Error updating ${slug}: ${error.message}`); stats.errors.push({ slug, error: error.message }); } } } // Archive all other documents console.log(`\n\nšŸ“¦ Archiving documents not in public list...\n`); try { if (dryRun) { const toArchive = await collection.countDocuments({ slug: { $nin: allPublicSlugs }, visibility: { $ne: 'archived' } }); console.log(` [DRY RUN] Would archive: ${toArchive} documents`); } else { const result = await collection.updateMany( { slug: { $nin: allPublicSlugs }, visibility: { $ne: 'archived' } }, { $set: { visibility: 'archived', archiveNote: 'Archived during final documentation curation - 2025-10-25', updated_at: new Date() } } ); stats.archived = result.modifiedCount; console.log(` āœ“ Archived: ${stats.archived} documents`); } } catch (error) { console.error(` āœ— Error archiving documents: ${error.message}`); stats.errors.push({ task: 'archiving', error: error.message }); } // Summary console.log(`\n${'═'.repeat(70)}`); console.log(` MIGRATION SUMMARY - ${dbName}`); console.log(`${'═'.repeat(70)}\n`); console.log(` āœ… Updated: ${stats.updated}`); console.log(` šŸ“¦ Archived: ${stats.archived}`); console.log(` āš ļø Not found: ${stats.notFound.length}`); console.log(` āœ— Errors: ${stats.errors.length}\n`); if (stats.notFound.length > 0) { console.log(` Not found slugs:`); stats.notFound.forEach(slug => console.log(` - ${slug}`)); console.log(''); } if (stats.errors.length > 0) { console.log(` Errors:`); stats.errors.forEach(e => console.log(` - ${e.slug || e.task}: ${e.error}`)); console.log(''); } return stats; } async function run() { const args = process.argv.slice(2); const dryRun = args.includes('--dry-run'); const devOnly = args.includes('--dev-only'); const prodOnly = args.includes('--prod-only'); console.log('═'.repeat(70)); console.log(' FINAL DOCUMENT MIGRATION'); console.log('═'.repeat(70)); console.log(`\nMode: ${dryRun ? 'DRY RUN (no changes)' : 'LIVE MIGRATION'}`); console.log(`Target: ${devOnly ? 'Development only' : prodOnly ? 'Production only' : 'Both databases'}\n`); if (dryRun) { console.log('āš ļø DRY RUN MODE - No changes will be made\n'); } const client = new MongoClient(DEV_URI); try { await client.connect(); // Migrate development database if (!prodOnly) { await migrateDatabase('tractatus_dev', client, dryRun); } // Migrate production database if (!devOnly) { console.log('\n\nāš ļø PRODUCTION MIGRATION REQUIRES SSH TUNNEL'); console.log('Run this command first:'); console.log(' ssh -i ~/.ssh/tractatus_deploy -L 27018:localhost:27017 ubuntu@vps-93a693da.vps.ovh.net -N\n'); console.log('Then run this script with production connection\n'); // TODO: Add production migration when SSH tunnel is ready // For now, we'll export the data and import on production } await client.close(); console.log('\nāœ… Migration complete!\n'); if (!dryRun && !prodOnly) { console.log('Next steps:'); console.log(' 1. Review changes in development database'); console.log(' 2. Test http://localhost:9000/docs.html'); console.log(' 3. Export research paper for production:'); console.log(' node scripts/export-research-paper.js'); console.log(' 4. Deploy to production\n'); } process.exit(0); } catch (error) { console.error('Migration error:', error); await client.close(); process.exit(1); } } run();